@@ -585,160 +585,172 @@ trait Inferencing { this: Typer =>
585585 if (ownedVars ne locked) && ! ownedVars.isEmpty then
586586 val qualifying = ownedVars -- locked
587587 if (! qualifying.isEmpty) {
588- typr.println(i " interpolate $tree: ${tree.tpe.widen} in $state, pt = $pt, owned vars = ${state.ownedVars.toList}%, %, qualifying = ${qualifying.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}" )
589588 val resultAlreadyConstrained =
590589 tree.isInstanceOf [Apply ] || tree.tpe.isInstanceOf [MethodOrPoly ]
591590 if (! resultAlreadyConstrained)
592591 constrainResult(tree.symbol, tree.tpe, pt)
593592 // This is needed because it could establish singleton type upper bounds. See i2998.scala.
594593
595- val tp = tree.tpe.widen
596- val vs = variances(tp, pt)
597-
598- // Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
599- // Reason: The errors might reflect unsatisfiable constraints. In that
600- // case interpolating without taking account the constraints risks producing
601- // nonsensical types that then in turn produce incomprehensible errors.
602- // An example is in neg/i1240.scala. Without the condition in the next code line
603- // we get for
604- //
605- // val y: List[List[String]] = List(List(1))
606- //
607- // i1430.scala:5: error: type mismatch:
608- // found : Int(1)
609- // required: Nothing
610- // val y: List[List[String]] = List(List(1))
611- // ^
612- // With the condition, we get the much more sensical:
613- //
614- // i1430.scala:5: error: type mismatch:
615- // found : Int(1)
616- // required: String
617- // val y: List[List[String]] = List(List(1))
618- if state.reporter.hasUnreportedErrors then return tree
619-
620- def constraint = state.constraint
621-
622- /** Values of this type report type variables to instantiate with variance indication:
623- * +1 variable appears covariantly, can be instantiated from lower bound
624- * -1 variable appears contravariantly, can be instantiated from upper bound
625- * 0 variable does not appear at all, can be instantiated from either bound
626- */
627- type ToInstantiate = List [(TypeVar , Int )]
628-
629- val toInstantiate : ToInstantiate =
630- val buf = new mutable.ListBuffer [(TypeVar , Int )]
631- for tvar <- qualifying do
632- if ! tvar.isInstantiated && constraint.contains(tvar) && tvar.nestingLevel >= ctx.nestingLevel then
633- constrainIfDependentParamRef(tvar, tree)
634- if ! tvar.isInstantiated then
635- // isInstantiated needs to be checked again, since previous interpolations could already have
636- // instantiated `tvar` through unification.
637- val v = vs(tvar)
638- if v == null then buf += ((tvar, 0 ))
639- else if v.intValue != 0 then buf += ((tvar, v.intValue))
640- else comparing(cmp =>
641- if ! cmp.levelOK(tvar.nestingLevel, ctx.nestingLevel) then
642- // Invariant: The type of a tree whose enclosing scope is level
643- // N only contains type variables of level <= N.
644- typr.println(i " instantiate nonvariant $tvar of level ${tvar.nestingLevel} to a type variable of level <= ${ctx.nestingLevel}, $constraint" )
645- cmp.atLevel(ctx.nestingLevel, tvar.origin)
646- else
647- typr.println(i " no interpolation for nonvariant $tvar in $state" )
648- )
649- buf.toList
650-
651- def typeVarsIn (xs : ToInstantiate ): TypeVars =
652- xs.foldLeft(SimpleIdentitySet .empty: TypeVars )((tvs, tvi) => tvs + tvi._1)
653-
654- /** Filter list of proposed instantiations so that they don't constrain further
655- * the current constraint.
656- */
657- def filterByDeps (tvs0 : ToInstantiate ): ToInstantiate =
658- val excluded = // ignore dependencies from other variables that are being instantiated
659- typeVarsIn(tvs0)
660- def step (tvs : ToInstantiate ): ToInstantiate = tvs match
661- case tvs @ (hd @ (tvar, v)) :: tvs1 =>
662- def aboveOK = ! constraint.dependsOn(tvar, excluded, co = true )
663- def belowOK = ! constraint.dependsOn(tvar, excluded, co = false )
664- if v == 0 && ! aboveOK then
665- step((tvar, 1 ) :: tvs1)
666- else if v == 0 && ! belowOK then
667- step((tvar, - 1 ) :: tvs1)
668- else if v == - 1 && ! aboveOK || v == 1 && ! belowOK then
669- typr.println(i " drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint" )
670- step(tvs1)
671- else // no conflict, keep the instantiation proposal
672- tvs.derivedCons(hd, step(tvs1))
673- case Nil =>
674- Nil
675- val tvs1 = step(tvs0)
676- if tvs1 eq tvs0 then tvs1
677- else filterByDeps(tvs1) // filter again with smaller excluded set
678- end filterByDeps
679-
680- /** Instantiate all type variables in `tvs` in the indicated directions,
681- * as described in the doc comment of `ToInstantiate`.
682- * If a type variable A is instantiated from below, and there is another
683- * type variable B in `buf` that is known to be smaller than A, wait and
684- * instantiate all other type variables before trying to instantiate A again.
685- * Dually, wait instantiating a type variable from above as long as it has
686- * upper bounds in `buf`.
687- *
688- * This is done to avoid loss of precision when forming unions. An example
689- * is in i7558.scala:
690- *
691- * type Tr[+V1, +O1 <: V1]
692- * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ???
693- * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl
694- *
695- * Here we interpolate at some point V2 and O2 given the constraint
696- *
697- * V2 >: V3, O2 >: O3, O2 <: V2
698- *
699- * where O3 and V3 are type refs with O3 <: V3.
700- * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will
701- * instantiate O2 to V3, leading to the final constraint
702- *
703- * V2 := V3, O2 := V3
704- *
705- * But if we instantiate O2 first to O3, and V2 next to V3, we get the
706- * more flexible instantiation
707- *
708- * V2 := V3, O2 := O3
709- */
710- def doInstantiate (tvs : ToInstantiate ): Unit =
711-
712- /** Try to instantiate `tvs`, return any suspended type variables */
713- def tryInstantiate (tvs : ToInstantiate ): ToInstantiate = tvs match
714- case (hd @ (tvar, v)) :: tvs1 =>
715- val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound)
716- typr.println(
717- i " interpolate ${if v == 0 then " non-occurring" else " " } $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint" )
718- if tvar.isInstantiated then
719- tryInstantiate(tvs1)
720- else
721- val suspend = tvs1.exists{ (following, _) =>
722- if fromBelow
723- then constraint.isLess(following.origin, tvar.origin)
724- else constraint.isLess(tvar.origin, following.origin)
725- }
726- if suspend then
727- typr.println(i " suspended: $hd" )
728- hd :: tryInstantiate(tvs1)
729- else
730- tvar.instantiate(fromBelow)
731- tryInstantiate(tvs1)
732- case Nil => Nil
733- if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs))
734- end doInstantiate
735-
736- doInstantiate(filterByDeps(toInstantiate))
594+ interpolateTypeVarsUnconstrained(tree, pt, locked)
737595 }
738596 end if
739597 tree
740598 end interpolateTypeVars
741599
600+ def interpolateTypeVarsUnconstrained (tree : Tree , pt : Type , locked : TypeVars )(using Context ): Unit =
601+ val state = ctx.typerState
602+ val ownedVars = state.ownedVars
603+ if (ownedVars eq locked) || ownedVars.isEmpty then return
604+ val qualifying = ownedVars -- locked
605+ if qualifying.isEmpty then return
606+
607+ val tp = tree.tpe.widen
608+
609+ typr.println(i " interpolate $tree: ${tree.tpe.widen} in $state, pt = $pt, owned vars = ${state.ownedVars.toList}%, %, qualifying = ${qualifying.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}" )
610+
611+ val vs = variances(tp, pt)
612+
613+ // Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
614+ // Reason: The errors might reflect unsatisfiable constraints. In that
615+ // case interpolating without taking account the constraints risks producing
616+ // nonsensical types that then in turn produce incomprehensible errors.
617+ // An example is in neg/i1240.scala. Without the condition in the next code line
618+ // we get for
619+ //
620+ // val y: List[List[String]] = List(List(1))
621+ //
622+ // i1430.scala:5: error: type mismatch:
623+ // found : Int(1)
624+ // required: Nothing
625+ // val y: List[List[String]] = List(List(1))
626+ // ^
627+ // With the condition, we get the much more sensical:
628+ //
629+ // i1430.scala:5: error: type mismatch:
630+ // found : Int(1)
631+ // required: String
632+ // val y: List[List[String]] = List(List(1))
633+ if state.reporter.hasUnreportedErrors then return
634+
635+ def constraint = state.constraint
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(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+ buf.toList
665+
666+ def typeVarsIn (xs : ToInstantiate ): TypeVars =
667+ xs.foldLeft(SimpleIdentitySet .empty: TypeVars )((tvs, tvi) => tvs + tvi._1)
668+
669+ /** Filter list of proposed instantiations so that they don't constrain further
670+ * the current constraint.
671+ */
672+ def filterByDeps (tvs0 : ToInstantiate ): ToInstantiate =
673+ val excluded = // ignore dependencies from other variables that are being instantiated
674+ typeVarsIn(tvs0)
675+ def step (tvs : ToInstantiate ): ToInstantiate = tvs match
676+ case tvs @ (hd @ (tvar, v)) :: tvs1 =>
677+ def aboveOK = ! constraint.dependsOn(tvar, excluded, co = true )
678+ def belowOK = ! constraint.dependsOn(tvar, excluded, co = false )
679+ if v == 0 && ! aboveOK then
680+ step((tvar, 1 ) :: tvs1)
681+ else if v == 0 && ! belowOK then
682+ step((tvar, - 1 ) :: tvs1)
683+ else if v == - 1 && ! aboveOK || v == 1 && ! belowOK then
684+ typr.println(i " drop $tvar, $v in $tp, $pt, qualifying = ${qualifying.toList}, tvs0 = ${tvs0.toList}%, %, excluded = ${excluded.toList}, $constraint" )
685+ step(tvs1)
686+ else // no conflict, keep the instantiation proposal
687+ tvs.derivedCons(hd, step(tvs1))
688+ case Nil =>
689+ Nil
690+ val tvs1 = step(tvs0)
691+ if tvs1 eq tvs0 then tvs1
692+ else filterByDeps(tvs1) // filter again with smaller excluded set
693+ end filterByDeps
694+
695+ /** Instantiate all type variables in `tvs` in the indicated directions,
696+ * as described in the doc comment of `ToInstantiate`.
697+ * If a type variable A is instantiated from below, and there is another
698+ * type variable B in `buf` that is known to be smaller than A, wait and
699+ * instantiate all other type variables before trying to instantiate A again.
700+ * Dually, wait instantiating a type variable from above as long as it has
701+ * upper bounds in `buf`.
702+ *
703+ * This is done to avoid loss of precision when forming unions. An example
704+ * is in i7558.scala:
705+ *
706+ * type Tr[+V1, +O1 <: V1]
707+ * extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ???
708+ * def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl
709+ *
710+ * Here we interpolate at some point V2 and O2 given the constraint
711+ *
712+ * V2 >: V3, O2 >: O3, O2 <: V2
713+ *
714+ * where O3 and V3 are type refs with O3 <: V3.
715+ * If we interpolate V2 first to V3 | O2, the widenUnion algorithm will
716+ * instantiate O2 to V3, leading to the final constraint
717+ *
718+ * V2 := V3, O2 := V3
719+ *
720+ * But if we instantiate O2 first to O3, and V2 next to V3, we get the
721+ * more flexible instantiation
722+ *
723+ * V2 := V3, O2 := O3
724+ */
725+ def doInstantiate (tvs : ToInstantiate ): Unit =
726+
727+ /** Try to instantiate `tvs`, return any suspended type variables */
728+ def tryInstantiate (tvs : ToInstantiate ): ToInstantiate = tvs match
729+ case (hd @ (tvar, v)) :: tvs1 =>
730+ val fromBelow = v == 1 || (v == 0 && tvar.hasLowerBound)
731+ typr.println(
732+ i " interpolate ${if v == 0 then " non-occurring" else " " } $tvar in $state in $tree: $tp, fromBelow = $fromBelow, $constraint" )
733+ if tvar.isInstantiated then
734+ tryInstantiate(tvs1)
735+ else
736+ val suspend = tvs1.exists{ (following, _) =>
737+ if fromBelow
738+ then constraint.isLess(following.origin, tvar.origin)
739+ else constraint.isLess(tvar.origin, following.origin)
740+ }
741+ if suspend then
742+ typr.println(i " suspended: $hd" )
743+ hd :: tryInstantiate(tvs1)
744+ else
745+ tvar.instantiate(fromBelow)
746+ tryInstantiate(tvs1)
747+ case Nil => Nil
748+ if tvs.nonEmpty then doInstantiate(tryInstantiate(tvs))
749+ end doInstantiate
750+
751+ doInstantiate(filterByDeps(toInstantiate))
752+ end interpolateTypeVarsUnconstrained
753+
742754 /** If `tvar` represents a parameter of a dependent method type in the current `call`
743755 * approximate it from below with the type of the actual argument. Skolemize that
744756 * type if necessary to make it a Singleton.
0 commit comments