Skip to content

Commit 5b6c079

Browse files
committed
Fix #10605: Avoid mismatched constraints when prototypes are context functions
Fixes #10605
1 parent 8acc1cb commit 5b6c079

File tree

2 files changed

+18
-9
lines changed

2 files changed

+18
-9
lines changed

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ object ProtoTypes {
3838
def isCompatible(tp: Type, pt: Type)(using Context): Boolean =
3939
(tp.widenExpr relaxed_<:< pt.widenExpr) || viewExists(tp, pt)
4040

41-
/** Like isCompatibe, but using a subtype comparison with necessary eithers
42-
* that don't unnecessarily truncate the constraint space, returning false instead.
41+
/** Like normalize and then isCompatible, but using a subtype comparison with
42+
* necessary eithers that does not unnecessarily truncate the constraint space,
43+
* returning false instead.
4344
*/
4445
def necessarilyCompatible(tp: Type, pt: Type)(using Context): Boolean =
45-
val tpw = tp.widenExpr
46-
val ptw = pt.widenExpr
47-
necessarySubType(tpw, ptw) || tpw.isValueSubType(ptw) || viewExists(tp, pt)
46+
val tpn = normalize(tp, pt, followIFT = !defn.isContextFunctionType(pt))
47+
necessarySubType(tpn, pt) || tpn.isValueSubType(pt) || viewExists(tpn, pt)
4848

4949
/** Test compatibility after normalization.
5050
* Do this in a fresh typerstate unless `keepConstraint` is true.
@@ -84,9 +84,9 @@ object ProtoTypes {
8484
case _ => true
8585
}
8686
case _: ValueTypeOrProto if !disregardProto(pt) =>
87-
necessarilyCompatible(normalize(mt, pt), pt)
87+
necessarilyCompatible(mt, pt)
8888
case pt: WildcardType if pt.optBounds.exists =>
89-
necessarilyCompatible(normalize(mt, pt), pt)
89+
necessarilyCompatible(mt, pt)
9090
case _ =>
9191
true
9292
}
@@ -607,7 +607,7 @@ object ProtoTypes {
607607
* of toString method. The problem is solved by dereferencing nullary method types if the corresponding
608608
* function type is not compatible with the prototype.
609609
*/
610-
def normalize(tp: Type, pt: Type)(using Context): Type = {
610+
def normalize(tp: Type, pt: Type, followIFT: Boolean = true)(using Context): Type = {
611611
Stats.record("normalize")
612612
tp.widenSingleton match {
613613
case poly: PolyType =>
@@ -632,7 +632,7 @@ object ProtoTypes {
632632
normalize(et.resultType, pt)
633633
case wtp =>
634634
val iftp = defn.asContextFunctionType(wtp)
635-
if iftp.exists then normalize(iftp.dropDependentRefinement.argInfos.last, pt)
635+
if iftp.exists && followIFT then normalize(iftp.dropDependentRefinement.argInfos.last, pt)
636636
else tp
637637
}
638638
}

tests/neg/i10605.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
def xa[A, B, X, Y](f: X => ((A, B) ?=> Y)) =
2+
(z: X) => (a: A, b: B) => f(z)(using a, b)
3+
4+
def superxa1(using String, Int): Nothing = ???
5+
def superxa2(using String, Int): Unit = ???
6+
7+
def main =
8+
xa(Function.const(superxa1)(_: Int)) // error
9+
xa(Function.const(superxa2)(_: Int)) // error

0 commit comments

Comments
 (0)