@@ -671,7 +671,6 @@ trait Inferencing { this: Typer =>
671
671
// This is needed because it could establish singleton type upper bounds. See i2998.scala.
672
672
673
673
val tp = tree.tpe.widen
674
- val vs = variances(tp, pt)
675
674
676
675
// Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
677
676
// Reason: The errors might reflect unsatisfiable constraints. In that
@@ -695,135 +694,138 @@ trait Inferencing { this: Typer =>
695
694
// val y: List[List[String]] = List(List(1))
696
695
if state.reporter.hasUnreportedErrors then return tree
697
696
698
- def constraint = state.constraint
699
-
700
- trace(i " interpolateTypeVars( $tree: ${tree.tpe}, $pt, $qualifying) " , typr, (_ : Any ) => i " $qualifying\n $constraint\n ${ctx.gadt}" ) {
701
- // println(i"$constraint")
702
- // println(i"${ctx.gadt}")
703
-
704
- /** Values of this type report type variables to instantiate with variance indication:
705
- * +1 variable appears covariantly, can be instantiated from lower bound
706
- * -1 variable appears contravariantly, can be instantiated from upper bound
707
- * 0 variable does not appear at all, can be instantiated from either bound
708
- */
709
- type ToInstantiate = List [(TypeVar , Int )]
710
-
711
- val toInstantiate : ToInstantiate =
712
- val buf = new mutable.ListBuffer [(TypeVar , Int )]
713
- for tvar <- qualifying do
714
- if ! tvar.isInstantiated && constraint.contains(tvar) && tvar.nestingLevel >= ctx.nestingLevel then
715
- constrainIfDependentParamRef(tvar, tree)
716
- if ! tvar.isInstantiated then
717
- // isInstantiated needs to be checked again, since previous interpolations could already have
718
- // instantiated `tvar` through unification.
719
- val v = vs.computedVariance(tvar)
720
- if v == null then buf += ((tvar, 0 ))
721
- else if v.intValue != 0 then buf += ((tvar, v.intValue))
722
- else comparing(cmp =>
723
- if ! cmp.levelOK(tvar.nestingLevel, ctx.nestingLevel) then
724
- // Invariant: The type of a tree whose enclosing scope is level
725
- // N only contains type variables of level <= N.
726
- typr.println(i " instantiate nonvariant $tvar of level ${tvar.nestingLevel} to a type variable of level <= ${ctx.nestingLevel}, $constraint" )
727
- cmp.atLevel(ctx.nestingLevel, tvar.origin)
728
- else
729
- typr.println(i " no interpolation for nonvariant $tvar in $state" )
730
- )
731
- // constrainIfDependentParamRef could also have instantiated tvars added to buf before the check
732
- buf.filterNot(_._1.isInstantiated).toList
733
- end toInstantiate
734
-
735
- def typeVarsIn (xs : ToInstantiate ): TypeVars =
736
- xs.foldLeft(SimpleIdentitySet .empty: TypeVars )((tvs, tvi) => tvs + tvi._1)
737
-
738
- /** Filter list of proposed instantiations so that they don't constrain further
739
- * the current constraint.
740
- */
741
- def filterByDeps (tvs0 : ToInstantiate ): ToInstantiate =
742
- val excluded = // ignore dependencies from other variables that are being instantiated
743
- typeVarsIn(tvs0)
744
- def step (tvs : ToInstantiate ): ToInstantiate = tvs match
745
- case tvs @ (hd @ (tvar, v)) :: tvs1 =>
746
- def aboveOK = ! constraint.dependsOn(tvar, excluded, co = true )
747
- def belowOK = ! constraint.dependsOn(tvar, excluded, co = false )
748
- if v == 0 && ! aboveOK then
749
- step((tvar, 1 ) :: tvs1)
750
- else if v == 0 && ! belowOK then
751
- step((tvar, - 1 ) :: tvs1)
752
- else if v == - 1 && ! aboveOK || v == 1 && ! belowOK then
753
- typr.println(i " drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint" )
754
- step(tvs1)
755
- else // no conflict, keep the instantiation proposal
756
- tvs.derivedCons(hd, step(tvs1))
757
- case Nil =>
758
- Nil
759
- val tvs1 = step(tvs0)
760
- if tvs1 eq tvs0 then tvs1
761
- else filterByDeps(tvs1) // filter again with smaller excluded set
762
- end filterByDeps
763
-
764
- /** Instantiate all type variables in `tvs` in the indicated directions,
765
- * as described in the doc comment of `ToInstantiate`.
766
- * If a type variable A is instantiated from below, and there is another
767
- * type variable B in `buf` that is known to be smaller than A, wait and
768
- * instantiate all other type variables before trying to instantiate A again.
769
- * Dually, wait instantiating a type variable from above as long as it has
770
- * upper bounds in `buf`.
771
- *
772
- * This is done to avoid loss of precision when forming unions. An example
773
- * is in i7558.scala:
774
- *
775
- * type Tr[+V1, +O1 <: V1]
776
- * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ???
777
- * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl
778
- *
779
- * Here we interpolate at some point V2 and O2 given the constraint
780
- *
781
- * V2 >: V3, O2 >: O3, O2 <: V2
782
- *
783
- * where O3 and V3 are type refs with O3 <: V3.
784
- * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will
785
- * instantiate O2 to V3, leading to the final constraint
786
- *
787
- * V2 := V3, O2 := V3
788
- *
789
- * But if we instantiate O2 first to O3, and V2 next to V3, we get the
790
- * more flexible instantiation
791
- *
792
- * V2 := V3, O2 := O3
793
- */
794
- def doInstantiate (tvs : ToInstantiate ): Unit =
795
-
796
- /** Try to instantiate `tvs`, return any suspended type variables */
797
- def tryInstantiate (tvs : ToInstantiate ): ToInstantiate = tvs match
798
- case (hd @ (tvar, v)) :: tvs1 =>
799
- val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound)
800
- typr.println(
801
- i " interpolate ${if v == 0 then " non-occurring" else " " } $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint" )
802
- if tvar.isInstantiated then
803
- tryInstantiate(tvs1)
804
- else
805
- val suspend = tvs1.exists{ (following, _) =>
806
- if fromBelow
807
- then constraint.isLess(following.origin, tvar.origin)
808
- else constraint.isLess(tvar.origin, following.origin)
809
- }
810
- if suspend then
811
- typr.println(i " suspended: $hd" )
812
- hd :: tryInstantiate(tvs1)
813
- else
814
- tvar.instantiate(fromBelow)
815
- tryInstantiate(tvs1)
816
- case Nil => Nil
817
- if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs))
818
- end doInstantiate
819
-
820
- doInstantiate(filterByDeps(toInstantiate))
821
- }
697
+ instantiateTypeVars(tp, pt, qualifying, tree)
822
698
}
823
699
end if
824
700
tree
825
701
end interpolateTypeVars
826
702
703
+ def instantiateTypeVars (tp : Type , pt : Type , qualifying : List [TypeVar ], tree : Tree = EmptyTree )(using Context ): Unit =
704
+ trace(i " instantiateTypeVars( $tp, $pt, $qualifying, $tree) " , typr):
705
+ val state = ctx.typerState
706
+ def constraint = state.constraint
707
+
708
+ val vs = variances(tp, pt)
709
+
710
+ /** Values of this type report type variables to instantiate with variance indication:
711
+ * +1 variable appears covariantly, can be instantiated from lower bound
712
+ * -1 variable appears contravariantly, can be instantiated from upper bound
713
+ * 0 variable does not appear at all, can be instantiated from either bound
714
+ */
715
+ type ToInstantiate = List [(TypeVar , Int )]
716
+
717
+ val toInstantiate : ToInstantiate =
718
+ val buf = new mutable.ListBuffer [(TypeVar , Int )]
719
+ for tvar <- qualifying do
720
+ if ! tvar.isInstantiated && constraint.contains(tvar) && tvar.nestingLevel >= ctx.nestingLevel then
721
+ constrainIfDependentParamRef(tvar, tree)
722
+ if ! tvar.isInstantiated then
723
+ // isInstantiated needs to be checked again, since previous interpolations could already have
724
+ // instantiated `tvar` through unification.
725
+ val v = vs.computedVariance(tvar)
726
+ if v == null then buf += ((tvar, 0 ))
727
+ else if v.intValue != 0 then buf += ((tvar, v.intValue))
728
+ else comparing(cmp =>
729
+ if ! cmp.levelOK(tvar.nestingLevel, ctx.nestingLevel) then
730
+ // Invariant: The type of a tree whose enclosing scope is level
731
+ // N only contains type variables of level <= N.
732
+ typr.println(i " instantiate nonvariant $tvar of level ${tvar.nestingLevel} to a type variable of level <= ${ctx.nestingLevel}, $constraint" )
733
+ cmp.atLevel(ctx.nestingLevel, tvar.origin)
734
+ else
735
+ typr.println(i " no interpolation for nonvariant $tvar in $state" )
736
+ )
737
+ // constrainIfDependentParamRef could also have instantiated tvars added to buf before the check
738
+ buf.filterNot(_._1.isInstantiated).toList
739
+ end toInstantiate
740
+
741
+ def typeVarsIn (xs : ToInstantiate ): TypeVars =
742
+ xs.foldLeft(SimpleIdentitySet .empty: TypeVars )((tvs, tvi) => tvs + tvi._1)
743
+
744
+ /** Filter list of proposed instantiations so that they don't constrain further
745
+ * the current constraint.
746
+ */
747
+ def filterByDeps (tvs0 : ToInstantiate ): ToInstantiate =
748
+ val excluded = // ignore dependencies from other variables that are being instantiated
749
+ typeVarsIn(tvs0)
750
+ def step (tvs : ToInstantiate ): ToInstantiate = tvs match
751
+ case tvs @ (hd @ (tvar, v)) :: tvs1 =>
752
+ def aboveOK = ! constraint.dependsOn(tvar, excluded, co = true )
753
+ def belowOK = ! constraint.dependsOn(tvar, excluded, co = false )
754
+ if v == 0 && ! aboveOK then
755
+ step((tvar, 1 ) :: tvs1)
756
+ else if v == 0 && ! belowOK then
757
+ step((tvar, - 1 ) :: tvs1)
758
+ else if v == - 1 && ! aboveOK || v == 1 && ! belowOK then
759
+ typr.println(i " drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint" )
760
+ step(tvs1)
761
+ else // no conflict, keep the instantiation proposal
762
+ tvs.derivedCons(hd, step(tvs1))
763
+ case Nil =>
764
+ Nil
765
+ val tvs1 = step(tvs0)
766
+ if tvs1 eq tvs0 then tvs1
767
+ else filterByDeps(tvs1) // filter again with smaller excluded set
768
+ end filterByDeps
769
+
770
+ /** Instantiate all type variables in `tvs` in the indicated directions,
771
+ * as described in the doc comment of `ToInstantiate`.
772
+ * If a type variable A is instantiated from below, and there is another
773
+ * type variable B in `buf` that is known to be smaller than A, wait and
774
+ * instantiate all other type variables before trying to instantiate A again.
775
+ * Dually, wait instantiating a type variable from above as long as it has
776
+ * upper bounds in `buf`.
777
+ *
778
+ * This is done to avoid loss of precision when forming unions. An example
779
+ * is in i7558.scala:
780
+ *
781
+ * type Tr[+V1, +O1 <: V1]
782
+ * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ???
783
+ * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl
784
+ *
785
+ * Here we interpolate at some point V2 and O2 given the constraint
786
+ *
787
+ * V2 >: V3, O2 >: O3, O2 <: V2
788
+ *
789
+ * where O3 and V3 are type refs with O3 <: V3.
790
+ * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will
791
+ * instantiate O2 to V3, leading to the final constraint
792
+ *
793
+ * V2 := V3, O2 := V3
794
+ *
795
+ * But if we instantiate O2 first to O3, and V2 next to V3, we get the
796
+ * more flexible instantiation
797
+ *
798
+ * V2 := V3, O2 := O3
799
+ */
800
+ def doInstantiate (tvs : ToInstantiate ): Unit =
801
+
802
+ /** Try to instantiate `tvs`, return any suspended type variables */
803
+ def tryInstantiate (tvs : ToInstantiate ): ToInstantiate = tvs match
804
+ case (hd @ (tvar, v)) :: tvs1 =>
805
+ val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound)
806
+ typr.println(
807
+ i " interpolate ${if v == 0 then " non-occurring" else " " } $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint" )
808
+ if tvar.isInstantiated then
809
+ tryInstantiate(tvs1)
810
+ else
811
+ val suspend = tvs1.exists{ (following, _) =>
812
+ if fromBelow
813
+ then constraint.isLess(following.origin, tvar.origin)
814
+ else constraint.isLess(tvar.origin, following.origin)
815
+ }
816
+ if suspend then
817
+ typr.println(i " suspended: $hd" )
818
+ hd :: tryInstantiate(tvs1)
819
+ else
820
+ tvar.instantiate(fromBelow)
821
+ tryInstantiate(tvs1)
822
+ case Nil => Nil
823
+ if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs))
824
+ end doInstantiate
825
+
826
+ doInstantiate(filterByDeps(toInstantiate))
827
+ end instantiateTypeVars
828
+
827
829
/** If `tvar` represents a parameter of a dependent method type in the current `call`
828
830
* approximate it from below with the type of the actual argument. Skolemize that
829
831
* type if necessary to make it a Singleton.
0 commit comments