@@ -888,35 +888,44 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
888888 * Normalization is as follows: If `tp2` contains a skolem to its refinement type,
889889 * rebase both itself and the member info of `tp` on a freshly created skolem type.
890890 */
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+ }
912918 case _ => false
913919 }
914- }
915920
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+ }
918928 }
919- }
920929
921930 final def ensureStableSingleton (tp : Type ): SingletonType = tp.stripTypeVar match {
922931 case tp : SingletonType if tp.isStable => tp
0 commit comments