diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bbec037ebef1..b58a923457cd 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5568,6 +5568,16 @@ object Types { else None } else None + + def isSamCompatible(lhs: Type, rhs: Type)(using Context): Boolean = rhs match + case SAMType(mt) if !isParamDependentRec(mt) => + lhs <:< mt.toFunctionType(isJava = rhs.classSymbol.is(JavaDefined)) + case _ => false + + def isParamDependentRec(mt: MethodType)(using Context): Boolean = + mt.isParamDependent || mt.resultType.match + case mt: MethodType => isParamDependentRec(mt) + case _ => false } // ----- TypeMaps -------------------------------------------------------------------- diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index fbed4b77d3fe..17b79ab0f801 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -695,9 +695,7 @@ trait Applications extends Compatibility { val argtpe1 = argtpe.widen def SAMargOK = - defn.isFunctionType(argtpe1) && formal.match - case SAMType(sam) => argtpe <:< sam.toFunctionType(isJava = formal.classSymbol.is(JavaDefined)) - case _ => false + defn.isFunctionType(argtpe1) && SAMType.isSamCompatible(argtpe, formal) isCompatible(argtpe, formal) // Only allow SAM-conversion to PartialFunction if implicit conversions diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2e7444af8e96..e42c0eec165f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1335,7 +1335,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case RefinedType(parent, nme.apply, mt @ MethodTpe(_, formals, restpe)) if (defn.isNonRefinedFunction(parent) || defn.isErasedFunctionType(parent)) && formals.length == defaultArity => (formals, untpd.DependentTypeTree(syms => restpe.substParams(mt, syms.map(_.termRef)))) - case SAMType(mt @ MethodTpe(_, formals, restpe)) => + case pt1 @ SAMType(mt @ MethodTpe(_, formals, _)) if !SAMType.isParamDependentRec(mt) => + val restpe = mt.resultType match + case mt: MethodType => mt.toFunctionType(isJava = pt1.classSymbol.is(JavaDefined)) + case tp => tp (formals, if (mt.isResultDependent) untpd.DependentTypeTree(syms => restpe.substParams(mt, syms.map(_.termRef))) @@ -4126,17 +4129,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // convert function literal to SAM closure tree match { case closure(Nil, id @ Ident(nme.ANON_FUN), _) - if defn.isFunctionType(wtp) && !defn.isFunctionType(pt) => - pt match { - case SAMType(sam) - if wtp <:< sam.toFunctionType(isJava = pt.classSymbol.is(JavaDefined)) => - // was ... && isFullyDefined(pt, ForceDegree.flipBottom) - // but this prevents case blocks from implementing polymorphic partial functions, - // since we do not know the result parameter a priori. Have to wait until the - // body is typechecked. - return toSAM(tree) - case _ => - } + if defn.isFunctionType(wtp) && !defn.isFunctionType(pt) && SAMType.isSamCompatible(wtp, pt) => + // was ... && isFullyDefined(pt, ForceDegree.flipBottom) + // but this prevents case blocks from implementing polymorphic partial functions, + // since we do not know the result parameter a priori. Have to wait until the + // body is typechecked. + return toSAM(tree) case _ => } diff --git a/tests/neg/i17183.check b/tests/neg/i17183.check new file mode 100644 index 000000000000..37e0c5fd75c2 --- /dev/null +++ b/tests/neg/i17183.check @@ -0,0 +1,14 @@ +-- [E081] Type Error: tests/neg/i17183.scala:11:24 --------------------------------------------------------------------- +11 |def test = Context(f = (_, _) => ???) // error // error + | ^ + | Missing parameter type + | + | I could not infer the type of the parameter _$1 of expanded function: + | (_$1, _$2) => ???. +-- [E081] Type Error: tests/neg/i17183.scala:11:27 --------------------------------------------------------------------- +11 |def test = Context(f = (_, _) => ???) // error // error + | ^ + | Missing parameter type + | + | I could not infer the type of the parameter _$2 of expanded function: + | (_$1, _$2) => ???. diff --git a/tests/neg/i17183.scala b/tests/neg/i17183.scala new file mode 100644 index 000000000000..a7d2d51c5935 --- /dev/null +++ b/tests/neg/i17183.scala @@ -0,0 +1,11 @@ +trait Dependency { + trait More +} + +trait MyFunc { + def apply(a: Int, b: String)(using dep: Dependency, more: dep.More): String +} + +case class Context(f: MyFunc) + +def test = Context(f = (_, _) => ???) // error // error diff --git a/tests/pos/i17183.scala b/tests/pos/i17183.scala new file mode 100644 index 000000000000..b53a2b138985 --- /dev/null +++ b/tests/pos/i17183.scala @@ -0,0 +1,9 @@ +trait Dependency + +trait MyFunc { + def apply(a: Int, b: String)(using Dependency): String +} + +case class Context(f: MyFunc) + +def test = Context(f = (_, _) => ???)