@@ -881,35 +881,44 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
881
881
* Normalization is as follows: If `tp2` contains a skolem to its refinement type,
882
882
* rebase both itself and the member info of `tp` on a freshly created skolem type.
883
883
*/
884
- protected def hasMatchingMember (name : Name , tp1 : Type , tp2 : RefinedType ): Boolean = {
885
- val rinfo2 = tp2.refinedInfo
886
- val mbr = tp1.member(name)
887
-
888
- def qualifies (m : SingleDenotation ) = isSubType(m.info, rinfo2)
889
-
890
- def memberMatches : Boolean = mbr match { // inlined hasAltWith for performance
891
- case mbr : SingleDenotation => qualifies(mbr)
892
- case _ => mbr hasAltWith qualifies
893
- }
894
-
895
- // special case for situations like:
896
- // class C { type T }
897
- // val foo: C
898
- // foo.type <: C { type T {= , <: , >:} foo.T }
899
- def selfReferentialMatch = tp1.isInstanceOf [SingletonType ] && {
900
- rinfo2 match {
901
- case rinfo2 : TypeBounds =>
902
- val mbr1 = tp1.select(name)
903
- ! defn.isBottomType(tp1.widen) &&
904
- (mbr1 =:= rinfo2.hi || (rinfo2.hi ne rinfo2.lo) && mbr1 =:= rinfo2.lo)
884
+ protected def hasMatchingMember (name : Name , tp1 : Type , tp2 : RefinedType ): Boolean =
885
+ /* >|>*/ ctx.traceIndented(i " hasMatchingMember( $tp1 . $name :? ${tp2.refinedInfo}), mbr: ${tp1.member(name).info}" , subtyping) /* <|<*/ {
886
+ val rinfo2 = tp2.refinedInfo
887
+
888
+ // If the member is an abstract type, compare the member itself
889
+ // instead of its bounds. This case is needed situations like:
890
+ //
891
+ // class C { type T }
892
+ // val foo: C
893
+ // foo.type <: C { type T {= , <: , >:} foo.T }
894
+ //
895
+ // or like:
896
+ //
897
+ // class C[T]
898
+ // C[_] <: C[TV]
899
+ //
900
+ // where TV is a type variable. See i2397.scala for an example of the latter.
901
+ def matchAbstractTypeMember (info1 : Type ) = info1 match {
902
+ case TypeBounds (lo, hi) if lo ne hi =>
903
+ tp2.refinedInfo match {
904
+ case rinfo2 : TypeBounds =>
905
+ val ref1 = tp1.widenExpr.select(name)
906
+ (rinfo2.variance > 0 || isSubType(rinfo2.lo, ref1)) &&
907
+ (rinfo2.variance < 0 || isSubType(ref1, rinfo2.hi))
908
+ case _ =>
909
+ false
910
+ }
905
911
case _ => false
906
912
}
907
- }
908
913
909
- /* >|>*/ ctx.traceIndented(i " hasMatchingMember( $tp1 . $name :? ${tp2.refinedInfo}) ${mbr.info.show} $rinfo2" , subtyping) /* <|<*/ {
910
- memberMatches || selfReferentialMatch
914
+ def qualifies (m : SingleDenotation ) =
915
+ isSubType(m.info, rinfo2) || matchAbstractTypeMember(m.info)
916
+
917
+ tp1.member(name) match { // inlined hasAltWith for performance
918
+ case mbr : SingleDenotation => qualifies(mbr)
919
+ case mbr => mbr hasAltWith qualifies
920
+ }
911
921
}
912
- }
913
922
914
923
final def ensureStableSingleton (tp : Type ): SingletonType = tp.stripTypeVar match {
915
924
case tp : SingletonType if tp.isStable => tp
0 commit comments