diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 48a5738b4074..e1c18fd24cbd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -614,7 +614,8 @@ trait Applications extends Compatibility { /** The degree to which an argument has to match a formal parameter */ enum ArgMatch: - case SubType // argument is a relaxed subtype of formal + case SubType // argument is a relaxed subtype of formal, SAM conversions are also allowed + case Comparing // same as compatible, subtyping in one direction disables SAM conversion in the other case Compatible // argument is compatible with formal case CompatibleCAP // capture-converted argument is compatible with formal @@ -635,21 +636,26 @@ trait Applications extends Compatibility { // matches expected type false case argtpe => - def SAMargOK = formal match { - case SAMType(sam) => argtpe <:< sam.toFunctionType(isJava = formal.classSymbol.is(JavaDefined)) - case _ => false - } - if argMatch == ArgMatch.SubType then - argtpe relaxed_<:< formal.widenExpr - else - isCompatible(argtpe, formal) - || ctx.mode.is(Mode.ImplicitsEnabled) && SAMargOK - || argMatch == ArgMatch.CompatibleCAP - && { - val argtpe1 = argtpe.widen - val captured = captureWildcards(argtpe1) - (captured ne argtpe1) && isCompatible(captured, formal.widenExpr) - } + val argtpe1 = argtpe.widen + + def isSAMargOK = + defn.isFunctionType(argtpe1) + && { + formal match + case SAMType(sam) => argtpe1 <:< sam.toFunctionType(isJava = formal.classSymbol.is(JavaDefined)) + case _ => false + } + && (argMatch != ArgMatch.Comparing || !(formal.widenExpr relaxed_<:< argtpe1)) + + ( if argMatch == ArgMatch.SubType then argtpe relaxed_<:< formal.widenExpr + else isCompatible(argtpe, formal) ) + || isSAMargOK//.showing(i"sam $argtpe, $formal, $argMatch = $result, ${formal.widenExpr relaxed_<:< argtpe1}") + || argMatch == ArgMatch.CompatibleCAP + && { + val captured = captureWildcards(argtpe1) + (captured ne argtpe1) && isCompatible(captured, formal.widenExpr) + } + end argOK /** The type of the given argument */ protected def argType(arg: Arg, formal: Type): Type @@ -1485,9 +1491,9 @@ trait Applications extends Compatibility { || { if tp1.isVarArgsMethod then tp2.isVarArgsMethod - && isApplicableMethodRef(alt2, tp1.paramInfos.map(_.repeatedToSingle), WildcardType, ArgMatch.Compatible) + && isApplicableMethodRef(alt2, tp1.paramInfos.map(_.repeatedToSingle), WildcardType, ArgMatch.Comparing) else - isApplicableMethodRef(alt2, tp1.paramInfos, WildcardType, ArgMatch.Compatible) + isApplicableMethodRef(alt2, tp1.paramInfos, WildcardType, ArgMatch.Comparing) } case tp1: PolyType => // (2) inContext(ctx.fresh.setExploreTyperState()) { @@ -1877,12 +1883,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) diff --git a/tests/neg/i11899.scala b/tests/neg/i11899.scala new file mode 100644 index 000000000000..3ae8fc496bfa --- /dev/null +++ b/tests/neg/i11899.scala @@ -0,0 +1,10 @@ +import java.util.function.Function + +class Future[T](val initial: T) { + def map[V](v: V): Unit = println(v) + def map[U](fn: Function[T, U]): Unit = println(fn(initial)) +} + +val f = new Future(42) +val fn = (i: Int) => i.toString +def test = f.map(fn) // error diff --git a/tests/run/i11938.scala b/tests/run/i11938.scala new file mode 100644 index 000000000000..1f8acd7fc2fc --- /dev/null +++ b/tests/run/i11938.scala @@ -0,0 +1,15 @@ +import java.util.function.Function + +class Future[T](val initial: T) { + def map[V](v: V): Unit = println(v) + //def map(v: String): Unit = println(v) + def map[U](fn: Function[T, U]): Unit = println(fn(initial)) +} + +object Test { + val f = new Future(42) + def fn(i: Int) = i.toString + def main(args: Array[String]): Unit = + f.map((i: Int) => i.toString) + f.map(fn) +} \ No newline at end of file