Skip to content

Commit 2e7f927

Browse files
committed
Fix #3352: defaults parameters require named type in compatibility check
In implicit search, if the expected type is applying type and the candidate is a TermRef to a method with default parameters, we need the TermRef to the method in order for `TestApplication` to insert default parameters. Otherwise, by widening the TermRef to MethodType, the information about default parameters is lost, which may incorrectly disqualify a candidate.
1 parent 174444d commit 2e7f927

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,15 @@ object ProtoTypes {
4141
/** Test compatibility after normalization in a fresh typerstate. */
4242
def normalizedCompatible(tp: Type, pt: Type)(implicit ctx: Context) = ctx.typerState.test {
4343
val normTp = normalize(tp, pt)
44-
isCompatible(normTp, pt) || pt.isRef(defn.UnitClass) && normTp.isParameterless
44+
isCompatible(normTp, pt) ||
45+
pt.isRef(defn.UnitClass) && normTp.isParameterless ||
46+
pt.isInstanceOf[ApplyingProto] && isCompatible(tp, pt)
47+
// Note for the last line:
48+
// Avoid widening of `tp` if the expected type is `ApplyingProto`, as
49+
// default parameters require a TermRef to insert the default values,
50+
// widening to MethodType will incorrectly disqualify a valid candidate.
51+
//
52+
// Check note in `SelectionProto.isMatchedBy` and tests/pos/i3352.scala
4553
}
4654

4755
private def disregardProto(pt: Type)(implicit ctx: Context): Boolean = pt.dealias match {
@@ -101,7 +109,19 @@ object ProtoTypes {
101109
val mbr = if (privateOK) tp1.member(name) else tp1.nonPrivateMember(name)
102110
def qualifies(m: SingleDenotation) =
103111
memberProto.isRef(defn.UnitClass) ||
104-
compat.normalizedCompatible(m.info, memberProto)
112+
compat.normalizedCompatible(m.info, memberProto) ||
113+
memberProto.isInstanceOf[ApplyingProto] && compat.normalizedCompatible(m.namedType, memberProto)
114+
// Note for the last line:
115+
// If the expected type is an applying type and `m` refers to a method,
116+
// `m.info` will get a method type, which loses the information about default
117+
// parameters for methods. When the expected type is an application taking
118+
// default values, compatibility check will fail due to mismatch in the number
119+
// of parameters.
120+
//
121+
// To make `TestApplication` succeed, we need to try `m.namedType` here so
122+
// that default parameters will be inserted.
123+
//
124+
// check tests/pos/i3352.scala
105125
mbr match { // hasAltWith inlined for performance
106126
case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
107127
case _ => mbr hasAltWith qualifies

tests/pos/i3352.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Test {
2+
class Foo {
3+
def bar(x: String): Int = 1
4+
}
5+
6+
implicit class FooOps(foo: Foo) {
7+
def bar(x: Int, y: Int = 2): Int = 2 // compiles with no default argument
8+
}
9+
10+
def test(foo: Foo): Unit = {
11+
foo.bar(1)
12+
}
13+
}

0 commit comments

Comments
 (0)