diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ff448b9b838c..4ea1cd481e43 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -1606,32 +1606,31 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer if desugared.isEmpty then val inferredParams: List[untpd.ValDef] = for ((param, i) <- params.zipWithIndex) yield - val (formalBounds, isErased) = protoFormal(i) - val param0 = - if (!param.tpt.isEmpty) param - else - val formal = formalBounds.loBound - val isBottomFromWildcard = (formalBounds ne formal) && formal.isExactlyNothing - val knownFormal = isFullyDefined(formal, ForceDegree.failBottom) - // If the expected formal is a TypeBounds wildcard argument with Nothing as lower bound, - // try to prioritize inferring from target. See issue 16405 (tests/run/16405.scala) - val paramType = - // Strip inferred erased annotation, to avoid accidentally inferring erasedness - val formal0 = if !isErased then formal.stripAnnots(_.symbol != defn.ErasedParamAnnot) else formal - if knownFormal && !isBottomFromWildcard then - formal0 - else - inferredFromTarget(param, formal, calleeType, isErased, paramIndex).orElse( - if knownFormal then formal0 - else errorType(AnonymousFunctionMissingParamType(param, tree, inferredType = formal, expectedType = pt), param.srcPos) - ) - val paramTpt = untpd.TypedSplice( - (if knownFormal then InferredTypeTree() else untpd.TypeTree()) - .withType(paramType.translateFromRepeated(toArray = false)) - .withSpan(param.span.endPos) + if (!param.tpt.isEmpty) param + else + val (formalBounds, isErased) = protoFormal(i) + val formal = formalBounds.loBound + val isBottomFromWildcard = (formalBounds ne formal) && formal.isExactlyNothing + val knownFormal = isFullyDefined(formal, ForceDegree.failBottom) + // If the expected formal is a TypeBounds wildcard argument with Nothing as lower bound, + // try to prioritize inferring from target. See issue 16405 (tests/run/16405.scala) + val paramType = + // Strip inferred erased annotation, to avoid accidentally inferring erasedness + val formal0 = if !isErased then formal.stripAnnots(_.symbol != defn.ErasedParamAnnot) else formal + if knownFormal && !isBottomFromWildcard then + formal0 + else + inferredFromTarget(param, formal, calleeType, isErased, paramIndex).orElse( + if knownFormal then formal0 + else errorType(AnonymousFunctionMissingParamType(param, tree, inferredType = formal, expectedType = pt), param.srcPos) ) - cpy.ValDef(param)(tpt = paramTpt) - if isErased then param0.withAddedFlags(Flags.Erased) else param0 + val paramTpt = untpd.TypedSplice( + (if knownFormal then InferredTypeTree() else untpd.TypeTree()) + .withType(paramType.translateFromRepeated(toArray = false)) + .withSpan(param.span.endPos) + ) + val param0 = cpy.ValDef(param)(tpt = paramTpt) + if isErased then param0.withAddedFlags(Flags.Erased) else param0 desugared = desugar.makeClosure(Nil, inferredParams, fnBody, resultTpt, tree.span) typed(desugared, pt) diff --git a/tests/pos/i18276a.scala b/tests/pos/i18276a.scala new file mode 100644 index 000000000000..46c2722fd8be --- /dev/null +++ b/tests/pos/i18276a.scala @@ -0,0 +1,15 @@ +import scala.language.implicitConversions + +case class Assign(left: String, right: String) +class SyntaxAnalyser extends ParsersBase { + val x: Parser[String ~ String] = ??? + val y: Parser[Assign] = x.map(Assign.apply) +} + +class ParsersBase { + trait ~[+T, +U] + abstract class Parser[+T]: + def map[U](f: T => U): Parser[U] = ??? + + given [A, B, X]: Conversion[(A, B) => X, (A ~ B) => X] = ??? +} diff --git a/tests/pos/i18276b.scala b/tests/pos/i18276b.scala new file mode 100644 index 000000000000..a4d905293472 --- /dev/null +++ b/tests/pos/i18276b.scala @@ -0,0 +1,9 @@ +import scala.language.implicitConversions + +def foo(a: Int): Int = ??? +def bar(f: () => Int): Int = ??? + +given f: Conversion[Int => Int, () => Int] = ??? + +def test1: Int = bar(foo) // implicit conversion applied to foo +def test2: Int = bar(f(foo))