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