@@ -671,7 +671,6 @@ trait Inferencing { this: Typer =>
671671 // This is needed because it could establish singleton type upper bounds. See i2998.scala.
672672
673673 val tp = tree.tpe.widen
674- val vs = variances(tp, pt)
675674
676675 // Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
677676 // Reason: The errors might reflect unsatisfiable constraints. In that
@@ -695,135 +694,138 @@ trait Inferencing { this: Typer =>
695694 // val y: List[List[String]] = List(List(1))
696695 if state.reporter.hasUnreportedErrors then return tree
697696
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)
822698 }
823699 end if
824700 tree
825701 end interpolateTypeVars
826702
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+
827829 /** If `tvar` represents a parameter of a dependent method type in the current `call`
828830 * approximate it from below with the type of the actual argument. Skolemize that
829831 * type if necessary to make it a Singleton.
0 commit comments