From 7bbf9f046b78632f99f0dd670572f707ed2e0b3b Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 21 Mar 2022 15:20:19 +0100 Subject: [PATCH] Improve overloading resolution if expected type is not FunProto If expected type is a selection proto or similar we picked all alternatives that were compatible with it. But if the expected type was meant to be used after extension method expansion, then no alternative would be classified as compatible. We now drop all method alternatives in this case. If only one alternative remains, we pick that one. Fixes #14279 --- .../dotty/tools/dotc/typer/Applications.scala | 14 ++++++++++---- tests/pos/i14729.scala | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 tests/pos/i14729.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 43154022e3a0..0e8b049fa59e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1939,12 +1939,12 @@ trait Applications extends Compatibility { record("resolveOverloaded.FunProto", alts.length) val alts1 = narrowBySize(alts) - //report.log(i"narrowed by size: ${alts1.map(_.symbol.showDcl)}%, %") + overload.println(i"narrowed by size: ${alts1.map(_.symbol.showDcl)}%, %") if isDetermined(alts1) then alts1 else record("resolveOverloaded.narrowedBySize", alts1.length) val alts2 = narrowByShapes(alts1) - //report.log(i"narrowed by shape: ${alts2.map(_.symbol.showDcl)}%, %") + overload.println(i"narrowed by shape: ${alts2.map(_.symbol.showDcl)}%, %") if isDetermined(alts2) then alts2 else record("resolveOverloaded.narrowedByShape", alts2.length) @@ -1977,8 +1977,14 @@ trait Applications extends Compatibility { * new java.io.ObjectOutputStream(f) */ pt match { - case SAMType(mtp) => narrowByTypes(alts, mtp.paramInfos, mtp.resultType) - case _ => compat + case SAMType(mtp) => + narrowByTypes(alts, mtp.paramInfos, mtp.resultType) + case _ => + // pick any alternatives that are not methods since these might be convertible + // to the expected type, or be used as extension method arguments. + val convertible = alts.filterNot(alt => + normalize(alt, IgnoredProto(pt)).widenSingleton.isInstanceOf[MethodType]) + if convertible.length == 1 then convertible else compat } else compat } diff --git a/tests/pos/i14729.scala b/tests/pos/i14729.scala new file mode 100644 index 000000000000..03bb4038aa85 --- /dev/null +++ b/tests/pos/i14729.scala @@ -0,0 +1,19 @@ +class Foo(): + def normal: Unit = println("normal") + +extension (f: Foo) + def ext: Unit = println("ext") + +object Bar: + def makeFoo[A]: Foo = Foo() + def makeFoo[A](s: String): Foo = Foo() + +def tests: Unit = + Bar.makeFoo[Int].ext // error + + (Bar.makeFoo[Int]).ext // error + + val foo = Bar.makeFoo[Int] + foo.ext // ok + + Bar.makeFoo[Int].normal // ok