@@ -659,42 +659,38 @@ object TypeOps:
659
659
*/
660
660
private def instantiateToSubType (tp1 : NamedType , tp2 : Type )(using Context ): Type = {
661
661
/** expose abstract type references to their bounds or tvars according to variance */
662
- class AbstractTypeMap (maximize : Boolean )(using Context ) extends TypeMap {
663
- def expose (lo : Type , hi : Type ): Type =
664
- if (variance == 0 )
665
- newTypeVar(TypeBounds (lo, hi))
666
- else if (variance == 1 )
667
- if (maximize) hi else lo
668
- else
669
- if (maximize) lo else hi
662
+ class ApproximateTypeParams (using Context ) extends TypeMap {
663
+ val boundTypeParams = util.HashMap [TypeRef , TypeVar ]()
670
664
671
- def apply (tp : Type ): Type = tp match {
665
+ def apply (tp : Type ): Type = tp.dealias match {
672
666
case _ : MatchType =>
673
667
tp // break cycles
674
668
675
- case tp : TypeRef if isBounds(tp.underlying) =>
676
- val lo = this (tp.info.loBound)
677
- val hi = this (tp.info.hiBound)
678
- // See tests/patmat/gadt.scala tests/patmat/exhausting.scala tests/patmat/t9657.scala
679
- val exposed = expose(lo, hi)
680
- typr.println(s " $tp exposed to =====> $exposed" )
681
- exposed
682
-
683
- case AppliedType (tycon : TypeRef , args) if isBounds(tycon.underlying) =>
684
- val args2 = args.map(this )
685
- val lo = this (tycon.info.loBound).applyIfParameterized(args2)
686
- val hi = this (tycon.info.hiBound).applyIfParameterized(args2)
687
- val exposed = expose(lo, hi)
688
- typr.println(s " $tp exposed to =====> $exposed" )
689
- exposed
669
+ case tp : TypeRef if ! tp.symbol.isClass =>
670
+ def lo = apply(tp.underlying.loBound)
671
+ def hi = apply(tp.underlying.hiBound)
672
+ boundTypeParams.getOrElseUpdate(tp, newTypeVar(TypeBounds (lo, hi)))
673
+
674
+ case AppliedType (tycon : TypeRef , _) if ! tycon.dealias.typeSymbol.isClass =>
675
+ // Type inference cannot handle X[Y] <:< Int
676
+ // See tests/patmat/i3645g.scala
677
+ val bounds : TypeBounds = tycon.underlying match {
678
+ case TypeBounds (tl1 : HKTypeLambda , tl2 : HKTypeLambda ) =>
679
+ TypeBounds (tl1.resType, tl2.resType)
680
+ case TypeBounds (tl1 : HKTypeLambda , tp2) =>
681
+ TypeBounds (tl1.resType, tp2)
682
+ case TypeBounds (tp1, tl2 : HKTypeLambda ) =>
683
+ TypeBounds (tp1, tl2.resType)
684
+ }
685
+
686
+ newTypeVar(bounds)
690
687
691
- case _ =>
688
+ case tp =>
692
689
mapOver(tp)
693
690
}
694
691
}
695
692
696
- def minTypeMap (using Context ) = new AbstractTypeMap (maximize = false )
697
- def maxTypeMap (using Context ) = new AbstractTypeMap (maximize = true )
693
+ def approximateTypeParams (tp : Type )(using Context ) = new ApproximateTypeParams ().apply(tp)
698
694
699
695
// Prefix inference, replace `p.C.this.Child` with `X.Child` where `X <: p.C`
700
696
// Note: we need to strip ThisType in `p` recursively.
@@ -721,37 +717,25 @@ object TypeOps:
721
717
val tvars = tp1.typeParams.map { tparam => newTypeVar(tparam.paramInfo.bounds) }
722
718
val protoTp1 = inferThisMap.apply(tp1).appliedTo(tvars)
723
719
724
- val force = new ForceDegree .Value (
725
- tvar =>
726
- ! (ctx.typerState.constraint.entry(tvar.origin) `eq` tvar.origin.underlying) ||
727
- (tvar `eq` inferThisMap.prefixTVar), // always instantiate prefix
728
- IfBottom .flip
729
- )
730
-
731
720
// If parent contains a reference to an abstract type, then we should
732
721
// refine subtype checking to eliminate abstract types according to
733
722
// variance. As this logic is only needed in exhaustivity check,
734
723
// we manually patch subtyping check instead of changing TypeComparer.
735
- // See tests/patmat/i3645b.scala
736
- def parentQualify = tp1.widen.classSymbol.info.parents.exists { parent =>
737
- inContext(ctx.fresh.setNewTyperState()) {
738
- parent.argInfos.nonEmpty && minTypeMap.apply(parent) <:< maxTypeMap.apply(tp2)
739
- }
724
+ // See tests/patmat/3645b.scala
725
+ def parentQualify (tp1 : Type , tp2 : Type ) = tp1.widen.classSymbol.info.parents.exists { parent =>
726
+ parent.argInfos.nonEmpty && approximateTypeParams(parent) <:< tp2
740
727
}
741
728
742
- if (protoTp1 <:< tp2) {
729
+ def instantiate () : Type = {
743
730
maximizeType(protoTp1, NoSpan , fromScala2x = false )
744
731
wildApprox(protoTp1)
745
732
}
733
+
734
+ if (protoTp1 <:< tp2) instantiate()
746
735
else {
747
- val protoTp2 = maxTypeMap.apply(tp2)
748
- if (protoTp1 <:< protoTp2 || parentQualify)
749
- if (isFullyDefined(AndType (protoTp1, protoTp2), force)) protoTp1
750
- else wildApprox(protoTp1)
751
- else {
752
- typr.println(s " $protoTp1 <:< $protoTp2 = false " )
753
- NoType
754
- }
736
+ val protoTp2 = approximateTypeParams(tp2)
737
+ if (protoTp1 <:< protoTp2 || parentQualify(protoTp1, protoTp2)) instantiate()
738
+ else NoType
755
739
}
756
740
}
757
741
0 commit comments