@@ -1698,58 +1698,68 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
1698
1698
*/
1699
1699
protected def hasMatchingMember (name : Name , tp1 : Type , tp2 : RefinedType ): Boolean =
1700
1700
trace(i " hasMatchingMember( $tp1 . $name :? ${tp2.refinedInfo}), mbr: ${tp1.member(name).info}" , subtyping) {
1701
- // If the member is an abstract type and the prefix is a path, compare the member itself
1702
- // instead of its bounds. This case is needed situations like:
1703
- //
1704
- // class C { type T }
1705
- // val foo: C
1706
- // foo.type <: C { type T {= , <: , >:} foo.T }
1707
- //
1708
- // or like:
1709
- //
1710
- // class C[T]
1711
- // C[?] <: C[TV]
1712
- //
1713
- // where TV is a type variable. See i2397.scala for an example of the latter.
1714
- def matchAbstractTypeMember (info1 : Type ) = info1 match {
1715
- case TypeBounds (lo, hi) if lo ne hi =>
1716
- tp2.refinedInfo match {
1717
- case rinfo2 : TypeBounds if tp1.isStable =>
1718
- val ref1 = tp1.widenExpr.select(name)
1719
- isSubType(rinfo2.lo, ref1) && isSubType(ref1, rinfo2.hi)
1720
- case _ =>
1721
- false
1722
- }
1723
- case _ => false
1724
- }
1725
1701
1726
- // A relaxed version of isSubType, which compares method types
1727
- // under the standard arrow rule which is contravarient in the parameter types,
1728
- // but only if `tp2.refinedName` is also defined in the underlying class of tp2.
1729
- // The reason for the "but only" retriction is that if `tp2.refinedName`
1730
- // is not otherwise defined, we will have to resort to reflection to invoke
1731
- // the member. And reflection needs to know exact parameter types. The relaxation is
1732
- // needed to correctly compare dependent function types.
1733
- // See {pos,neg}/i12211.scala as test cases.
1734
- def isSubInfo (info1 : Type , info2 : Type ): Boolean =
1735
- info2 match
1736
- case info2 : MethodType
1737
- if tp2.underlyingClassRef(refinementOK = true ).member(tp2.refinedName).exists =>
1738
- info1 match
1739
- case info1 : MethodType =>
1740
- matchingMethodParams(info1, info2, precise = false )
1741
- && isSubInfo(info1.resultType, info2.resultType.subst(info2, info1))
1742
- case _ => isSubType(info1, info2)
1743
- case _ => isSubType(info1, info2)
1744
-
1745
- def qualifies (m : SingleDenotation ) =
1746
- isSubInfo(m.info.widenExpr, tp2.refinedInfo.widenExpr)
1702
+ def qualifies (m : SingleDenotation ): Boolean =
1703
+ // If the member is an abstract type and the prefix is a path, compare the member itself
1704
+ // instead of its bounds. This case is needed situations like:
1705
+ //
1706
+ // class C { type T }
1707
+ // val foo: C
1708
+ // foo.type <: C { type T {= , <: , >:} foo.T }
1709
+ //
1710
+ // or like:
1711
+ //
1712
+ // class C[T]
1713
+ // C[?] <: C[TV]
1714
+ //
1715
+ // where TV is a type variable. See i2397.scala for an example of the latter.
1716
+ def matchAbstractTypeMember (info1 : Type ): Boolean = info1 match {
1717
+ case TypeBounds (lo, hi) if lo ne hi =>
1718
+ tp2.refinedInfo match {
1719
+ case rinfo2 : TypeBounds if tp1.isStable =>
1720
+ val ref1 = tp1.widenExpr.select(name)
1721
+ isSubType(rinfo2.lo, ref1) && isSubType(ref1, rinfo2.hi)
1722
+ case _ =>
1723
+ false
1724
+ }
1725
+ case _ => false
1726
+ }
1727
+
1728
+ // An additional check for type member matching: If the refinement of the
1729
+ // supertype `tp2` does not refer to a member symbol defined in the parent of `tp2`.
1730
+ // then the symbol referred to in the subtype must have a signature that coincides
1731
+ // in its parameters with the refinement's signature. The reason for the check
1732
+ // is that if the refinement does not refer to a member symbol, we will have to
1733
+ // resort to reflection to invoke the member. And reflection needs to know exact
1734
+ // erased parameter types. See neg/i12211.scala.
1735
+ def sigsOK (symInfo : Type , info2 : Type ) =
1736
+ tp2.underlyingClassRef(refinementOK = true ).member(name).exists
1737
+ || symInfo.isInstanceOf [MethodType ]
1738
+ && symInfo.signature.consistentParams(info2.signature)
1739
+
1740
+ // A relaxed version of isSubType, which compares method types
1741
+ // under the standard arrow rule which is contravarient in the parameter types,
1742
+ // but under the condition that signatures might have to match (see sigsOK)
1743
+ // This releaxed version is needed to correctly compare dependent function types.
1744
+ // See pos/i12211.scala.
1745
+ def isSubInfo (info1 : Type , info2 : Type , symInfo : Type ): Boolean =
1746
+ info2 match
1747
+ case info2 : MethodType =>
1748
+ info1 match
1749
+ case info1 : MethodType =>
1750
+ matchingMethodParams(info1, info2, precise = false )
1751
+ && isSubInfo(info1.resultType, info2.resultType.subst(info2, info1), symInfo.stripPoly.resultType)
1752
+ && sigsOK(symInfo, info2)
1753
+ case _ => isSubType(info1, info2)
1754
+ case _ => isSubType(info1, info2)
1755
+
1756
+ isSubInfo(m.info.widenExpr, tp2.refinedInfo.widenExpr, m.symbol.info)
1747
1757
|| matchAbstractTypeMember(m.info)
1758
+ end qualifies
1748
1759
1749
- tp1.member(name) match { // inlined hasAltWith for performance
1760
+ tp1.member(name) match // inlined hasAltWith for performance
1750
1761
case mbr : SingleDenotation => qualifies(mbr)
1751
1762
case mbr => mbr hasAltWith qualifies
1752
- }
1753
1763
}
1754
1764
1755
1765
final def ensureStableSingleton (tp : Type ): SingletonType = tp.stripTypeVar match {
0 commit comments