@@ -604,7 +604,6 @@ trait Inferencing { this: Typer =>
604604 // This is needed because it could establish singleton type upper bounds. See i2998.scala.
605605
606606 val tp = tree.tpe.widen
607- val vs = variances(tp, pt)
608607
609608 // Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
610609 // Reason: The errors might reflect unsatisfiable constraints. In that
@@ -628,135 +627,138 @@ trait Inferencing { this: Typer =>
628627 // val y: List[List[String]] = List(List(1))
629628 if state.reporter.hasUnreportedErrors then return tree
630629
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)
755631 }
756632 end if
757633 tree
758634 end interpolateTypeVars
759635
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+
760762 /** If `tvar` represents a parameter of a dependent method type in the current `call`
761763 * approximate it from below with the type of the actual argument. Skolemize that
762764 * type if necessary to make it a Singleton.
0 commit comments