@@ -585,160 +585,172 @@ trait Inferencing { this: Typer =>
585
585
if (ownedVars ne locked) && ! ownedVars.isEmpty then
586
586
val qualifying = ownedVars -- locked
587
587
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}" )
589
588
val resultAlreadyConstrained =
590
589
tree.isInstanceOf [Apply ] || tree.tpe.isInstanceOf [MethodOrPoly ]
591
590
if (! resultAlreadyConstrained)
592
591
constrainResult(tree.symbol, tree.tpe, pt)
593
592
// This is needed because it could establish singleton type upper bounds. See i2998.scala.
594
593
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)
737
595
}
738
596
end if
739
597
tree
740
598
end interpolateTypeVars
741
599
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
+
742
754
/** If `tvar` represents a parameter of a dependent method type in the current `call`
743
755
* approximate it from below with the type of the actual argument. Skolemize that
744
756
* type if necessary to make it a Singleton.
0 commit comments