@@ -1698,8 +1698,6 @@ 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
- val rinfo2 = tp2.refinedInfo
1702
-
1703
1701
// If the member is an abstract type and the prefix is a path, compare the member itself
1704
1702
// instead of its bounds. This case is needed situations like:
1705
1703
//
@@ -1725,8 +1723,28 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
1725
1723
case _ => false
1726
1724
}
1727
1725
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
+
1728
1745
def qualifies (m : SingleDenotation ) =
1729
- isSubType(m.info.widenExpr, rinfo2.widenExpr) || matchAbstractTypeMember(m.info)
1746
+ isSubInfo(m.info.widenExpr, tp2.refinedInfo.widenExpr)
1747
+ || matchAbstractTypeMember(m.info)
1730
1748
1731
1749
tp1.member(name) match { // inlined hasAltWith for performance
1732
1750
case mbr : SingleDenotation => qualifies(mbr)
@@ -1841,15 +1859,20 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
1841
1859
}
1842
1860
1843
1861
/** Do the parameter types of `tp1` and `tp2` match in a way that allows `tp1`
1844
- * to override `tp2` ? This is the case if they're pairwise `=:=`.
1862
+ * to override `tp2` ? Two modes: precise or not.
1863
+ * If `precise` is set (which is the default) this is the case if they're pairwise `=:=`.
1864
+ * Otherwise parameters in `tp2` must be subtypes of corresponding parameters in `tp1`.
1845
1865
*/
1846
- def matchingMethodParams (tp1 : MethodType , tp2 : MethodType ): Boolean = {
1866
+ def matchingMethodParams (tp1 : MethodType , tp2 : MethodType , precise : Boolean = true ): Boolean = {
1847
1867
def loop (formals1 : List [Type ], formals2 : List [Type ]): Boolean = formals1 match {
1848
1868
case formal1 :: rest1 =>
1849
1869
formals2 match {
1850
1870
case formal2 :: rest2 =>
1851
1871
val formal2a = if (tp2.isParamDependent) formal2.subst(tp2, tp1) else formal2
1852
- isSameTypeWhenFrozen(formal1, formal2a) && loop(rest1, rest2)
1872
+ val paramsMatch =
1873
+ if precise then isSameTypeWhenFrozen(formal1, formal2a)
1874
+ else isSubTypeWhenFrozen(formal2a, formal1)
1875
+ paramsMatch && loop(rest1, rest2)
1853
1876
case nil =>
1854
1877
false
1855
1878
}
0 commit comments