@@ -604,7 +604,6 @@ trait Inferencing { this: Typer =>
604
604
// This is needed because it could establish singleton type upper bounds. See i2998.scala.
605
605
606
606
val tp = tree.tpe.widen
607
- val vs = variances(tp, pt)
608
607
609
608
// Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
610
609
// Reason: The errors might reflect unsatisfiable constraints. In that
@@ -628,135 +627,138 @@ trait Inferencing { this: Typer =>
628
627
// val y: List[List[String]] = List(List(1))
629
628
if state.reporter.hasUnreportedErrors then return tree
630
629
631
- def constraint = state.constraint
632
-
633
- trace(i " interpolateTypeVars( $tree: ${tree.tpe}, $pt, $qualifying) " , typr, (_ : Any ) => i " $qualifying\n $constraint\n ${ctx.gadt}" ) {
634
- // println(i"$constraint")
635
- // println(i"${ctx.gadt}")
636
-
637
- /** Values of this type report type variables to instantiate with variance indication:
638
- * +1 variable appears covariantly, can be instantiated from lower bound
639
- * -1 variable appears contravariantly, can be instantiated from upper bound
640
- * 0 variable does not appear at all, can be instantiated from either bound
641
- */
642
- type ToInstantiate = List [(TypeVar , Int )]
643
-
644
- val toInstantiate : ToInstantiate =
645
- val buf = new mutable.ListBuffer [(TypeVar , Int )]
646
- for tvar <- qualifying do
647
- if ! tvar.isInstantiated && constraint.contains(tvar) && tvar.nestingLevel >= ctx.nestingLevel then
648
- constrainIfDependentParamRef(tvar, tree)
649
- if ! tvar.isInstantiated then
650
- // isInstantiated needs to be checked again, since previous interpolations could already have
651
- // instantiated `tvar` through unification.
652
- val v = vs.computedVariance(tvar)
653
- if v == null then buf += ((tvar, 0 ))
654
- else if v.intValue != 0 then buf += ((tvar, v.intValue))
655
- else comparing(cmp =>
656
- if ! cmp.levelOK(tvar.nestingLevel, ctx.nestingLevel) then
657
- // Invariant: The type of a tree whose enclosing scope is level
658
- // N only contains type variables of level <= N.
659
- typr.println(i " instantiate nonvariant $tvar of level ${tvar.nestingLevel} to a type variable of level <= ${ctx.nestingLevel}, $constraint" )
660
- cmp.atLevel(ctx.nestingLevel, tvar.origin)
661
- else
662
- typr.println(i " no interpolation for nonvariant $tvar in $state" )
663
- )
664
- // constrainIfDependentParamRef could also have instantiated tvars added to buf before the check
665
- buf.filterNot(_._1.isInstantiated).toList
666
- end toInstantiate
667
-
668
- def typeVarsIn (xs : ToInstantiate ): TypeVars =
669
- xs.foldLeft(SimpleIdentitySet .empty: TypeVars )((tvs, tvi) => tvs + tvi._1)
670
-
671
- /** Filter list of proposed instantiations so that they don't constrain further
672
- * the current constraint.
673
- */
674
- def filterByDeps (tvs0 : ToInstantiate ): ToInstantiate =
675
- val excluded = // ignore dependencies from other variables that are being instantiated
676
- typeVarsIn(tvs0)
677
- def step (tvs : ToInstantiate ): ToInstantiate = tvs match
678
- case tvs @ (hd @ (tvar, v)) :: tvs1 =>
679
- def aboveOK = ! constraint.dependsOn(tvar, excluded, co = true )
680
- def belowOK = ! constraint.dependsOn(tvar, excluded, co = false )
681
- if v == 0 && ! aboveOK then
682
- step((tvar, 1 ) :: tvs1)
683
- else if v == 0 && ! belowOK then
684
- step((tvar, - 1 ) :: tvs1)
685
- else if v == - 1 && ! aboveOK || v == 1 && ! belowOK then
686
- typr.println(i " drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint" )
687
- step(tvs1)
688
- else // no conflict, keep the instantiation proposal
689
- tvs.derivedCons(hd, step(tvs1))
690
- case Nil =>
691
- Nil
692
- val tvs1 = step(tvs0)
693
- if tvs1 eq tvs0 then tvs1
694
- else filterByDeps(tvs1) // filter again with smaller excluded set
695
- end filterByDeps
696
-
697
- /** Instantiate all type variables in `tvs` in the indicated directions,
698
- * as described in the doc comment of `ToInstantiate`.
699
- * If a type variable A is instantiated from below, and there is another
700
- * type variable B in `buf` that is known to be smaller than A, wait and
701
- * instantiate all other type variables before trying to instantiate A again.
702
- * Dually, wait instantiating a type variable from above as long as it has
703
- * upper bounds in `buf`.
704
- *
705
- * This is done to avoid loss of precision when forming unions. An example
706
- * is in i7558.scala:
707
- *
708
- * type Tr[+V1, +O1 <: V1]
709
- * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ???
710
- * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl
711
- *
712
- * Here we interpolate at some point V2 and O2 given the constraint
713
- *
714
- * V2 >: V3, O2 >: O3, O2 <: V2
715
- *
716
- * where O3 and V3 are type refs with O3 <: V3.
717
- * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will
718
- * instantiate O2 to V3, leading to the final constraint
719
- *
720
- * V2 := V3, O2 := V3
721
- *
722
- * But if we instantiate O2 first to O3, and V2 next to V3, we get the
723
- * more flexible instantiation
724
- *
725
- * V2 := V3, O2 := O3
726
- */
727
- def doInstantiate (tvs : ToInstantiate ): Unit =
728
-
729
- /** Try to instantiate `tvs`, return any suspended type variables */
730
- def tryInstantiate (tvs : ToInstantiate ): ToInstantiate = tvs match
731
- case (hd @ (tvar, v)) :: tvs1 =>
732
- val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound)
733
- typr.println(
734
- i " interpolate ${if v == 0 then " non-occurring" else " " } $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint" )
735
- if tvar.isInstantiated then
736
- tryInstantiate(tvs1)
737
- else
738
- val suspend = tvs1.exists{ (following, _) =>
739
- if fromBelow
740
- then constraint.isLess(following.origin, tvar.origin)
741
- else constraint.isLess(tvar.origin, following.origin)
742
- }
743
- if suspend then
744
- typr.println(i " suspended: $hd" )
745
- hd :: tryInstantiate(tvs1)
746
- else
747
- tvar.instantiate(fromBelow)
748
- tryInstantiate(tvs1)
749
- case Nil => Nil
750
- if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs))
751
- end doInstantiate
752
-
753
- doInstantiate(filterByDeps(toInstantiate))
754
- }
630
+ instantiateTypeVars(tp, pt, qualifying, tree)
755
631
}
756
632
end if
757
633
tree
758
634
end interpolateTypeVars
759
635
636
+ def instantiateTypeVars (tp : Type , pt : Type , qualifying : List [TypeVar ], tree : Tree = EmptyTree )(using Context ): Unit =
637
+ trace(i " instantiateTypeVars( $tp, $pt, $qualifying, $tree) " , typr):
638
+ val state = ctx.typerState
639
+ def constraint = state.constraint
640
+
641
+ val vs = variances(tp, pt)
642
+
643
+ /** Values of this type report type variables to instantiate with variance indication:
644
+ * +1 variable appears covariantly, can be instantiated from lower bound
645
+ * -1 variable appears contravariantly, can be instantiated from upper bound
646
+ * 0 variable does not appear at all, can be instantiated from either bound
647
+ */
648
+ type ToInstantiate = List [(TypeVar , Int )]
649
+
650
+ val toInstantiate : ToInstantiate =
651
+ val buf = new mutable.ListBuffer [(TypeVar , Int )]
652
+ for tvar <- qualifying do
653
+ if ! tvar.isInstantiated && constraint.contains(tvar) && tvar.nestingLevel >= ctx.nestingLevel then
654
+ constrainIfDependentParamRef(tvar, tree)
655
+ if ! tvar.isInstantiated then
656
+ // isInstantiated needs to be checked again, since previous interpolations could already have
657
+ // instantiated `tvar` through unification.
658
+ val v = vs.computedVariance(tvar)
659
+ if v == null then buf += ((tvar, 0 ))
660
+ else if v.intValue != 0 then buf += ((tvar, v.intValue))
661
+ else comparing(cmp =>
662
+ if ! cmp.levelOK(tvar.nestingLevel, ctx.nestingLevel) then
663
+ // Invariant: The type of a tree whose enclosing scope is level
664
+ // N only contains type variables of level <= N.
665
+ typr.println(i " instantiate nonvariant $tvar of level ${tvar.nestingLevel} to a type variable of level <= ${ctx.nestingLevel}, $constraint" )
666
+ cmp.atLevel(ctx.nestingLevel, tvar.origin)
667
+ else
668
+ typr.println(i " no interpolation for nonvariant $tvar in $state" )
669
+ )
670
+ // constrainIfDependentParamRef could also have instantiated tvars added to buf before the check
671
+ buf.filterNot(_._1.isInstantiated).toList
672
+ end toInstantiate
673
+
674
+ def typeVarsIn (xs : ToInstantiate ): TypeVars =
675
+ xs.foldLeft(SimpleIdentitySet .empty: TypeVars )((tvs, tvi) => tvs + tvi._1)
676
+
677
+ /** Filter list of proposed instantiations so that they don't constrain further
678
+ * the current constraint.
679
+ */
680
+ def filterByDeps (tvs0 : ToInstantiate ): ToInstantiate =
681
+ val excluded = // ignore dependencies from other variables that are being instantiated
682
+ typeVarsIn(tvs0)
683
+ def step (tvs : ToInstantiate ): ToInstantiate = tvs match
684
+ case tvs @ (hd @ (tvar, v)) :: tvs1 =>
685
+ def aboveOK = ! constraint.dependsOn(tvar, excluded, co = true )
686
+ def belowOK = ! constraint.dependsOn(tvar, excluded, co = false )
687
+ if v == 0 && ! aboveOK then
688
+ step((tvar, 1 ) :: tvs1)
689
+ else if v == 0 && ! belowOK then
690
+ step((tvar, - 1 ) :: tvs1)
691
+ else if v == - 1 && ! aboveOK || v == 1 && ! belowOK then
692
+ typr.println(i " drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint" )
693
+ step(tvs1)
694
+ else // no conflict, keep the instantiation proposal
695
+ tvs.derivedCons(hd, step(tvs1))
696
+ case Nil =>
697
+ Nil
698
+ val tvs1 = step(tvs0)
699
+ if tvs1 eq tvs0 then tvs1
700
+ else filterByDeps(tvs1) // filter again with smaller excluded set
701
+ end filterByDeps
702
+
703
+ /** Instantiate all type variables in `tvs` in the indicated directions,
704
+ * as described in the doc comment of `ToInstantiate`.
705
+ * If a type variable A is instantiated from below, and there is another
706
+ * type variable B in `buf` that is known to be smaller than A, wait and
707
+ * instantiate all other type variables before trying to instantiate A again.
708
+ * Dually, wait instantiating a type variable from above as long as it has
709
+ * upper bounds in `buf`.
710
+ *
711
+ * This is done to avoid loss of precision when forming unions. An example
712
+ * is in i7558.scala:
713
+ *
714
+ * type Tr[+V1, +O1 <: V1]
715
+ * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ???
716
+ * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl
717
+ *
718
+ * Here we interpolate at some point V2 and O2 given the constraint
719
+ *
720
+ * V2 >: V3, O2 >: O3, O2 <: V2
721
+ *
722
+ * where O3 and V3 are type refs with O3 <: V3.
723
+ * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will
724
+ * instantiate O2 to V3, leading to the final constraint
725
+ *
726
+ * V2 := V3, O2 := V3
727
+ *
728
+ * But if we instantiate O2 first to O3, and V2 next to V3, we get the
729
+ * more flexible instantiation
730
+ *
731
+ * V2 := V3, O2 := O3
732
+ */
733
+ def doInstantiate (tvs : ToInstantiate ): Unit =
734
+
735
+ /** Try to instantiate `tvs`, return any suspended type variables */
736
+ def tryInstantiate (tvs : ToInstantiate ): ToInstantiate = tvs match
737
+ case (hd @ (tvar, v)) :: tvs1 =>
738
+ val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound)
739
+ typr.println(
740
+ i " interpolate ${if v == 0 then " non-occurring" else " " } $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint" )
741
+ if tvar.isInstantiated then
742
+ tryInstantiate(tvs1)
743
+ else
744
+ val suspend = tvs1.exists{ (following, _) =>
745
+ if fromBelow
746
+ then constraint.isLess(following.origin, tvar.origin)
747
+ else constraint.isLess(tvar.origin, following.origin)
748
+ }
749
+ if suspend then
750
+ typr.println(i " suspended: $hd" )
751
+ hd :: tryInstantiate(tvs1)
752
+ else
753
+ tvar.instantiate(fromBelow)
754
+ tryInstantiate(tvs1)
755
+ case Nil => Nil
756
+ if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs))
757
+ end doInstantiate
758
+
759
+ doInstantiate(filterByDeps(toInstantiate))
760
+ end instantiateTypeVars
761
+
760
762
/** If `tvar` represents a parameter of a dependent method type in the current `call`
761
763
* approximate it from below with the type of the actual argument. Skolemize that
762
764
* type if necessary to make it a Singleton.
0 commit comments