Skip to content

Commit 1f39eea

Browse files
committed
Attempt to re-consider wildcards when inferring prototypes
1 parent ccea1fc commit 1f39eea

File tree

2 files changed

+15
-9
lines changed

2 files changed

+15
-9
lines changed

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

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
11991199

12001200
/** Decompose function prototype into a list of parameter prototypes and a result
12011201
* prototype tree, using WildcardTypes where a type is not known.
1202+
* Note: parameter prototypes may be TypeBounds.
12021203
* For the result type we do this even if the expected type is not fully
12031204
* defined, which is a bit of a hack. But it's needed to make the following work
12041205
* (see typers.scala and printers/PlainPrinter.scala for examples).
@@ -1234,7 +1235,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
12341235
// if expected parameter type(s) are wildcards, approximate from below.
12351236
// if expected result type is a wildcard, approximate from above.
12361237
// this can type the greatest set of admissible closures.
1237-
(pt1.argTypesLo.init, typeTree(interpolateWildcards(pt1.argTypesHi.last)))
1238+
1239+
(pt1.argInfos.init, typeTree(interpolateWildcards(pt1.argInfos.last.hiBound)))
12381240
case RefinedType(parent, nme.apply, mt @ MethodTpe(_, formals, restpe))
12391241
if defn.isNonRefinedFunction(parent) && formals.length == defaultArity =>
12401242
(formals, untpd.DependentTypeTree(syms => restpe.substParams(mt, syms.map(_.termRef))))
@@ -1473,11 +1475,13 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14731475
}
14741476

14751477
var desugared: untpd.Tree = EmptyTree
1476-
if protoFormals.length == 1 && params.length != 1 && ptIsCorrectProduct(protoFormals.head) then
1477-
val isGenericTuple =
1478-
protoFormals.head.derivesFrom(defn.TupleClass)
1479-
&& !defn.isTupleClass(protoFormals.head.typeSymbol)
1480-
desugared = desugar.makeTupledFunction(params, fnBody, isGenericTuple)
1478+
if protoFormals.length == 1 && params.length != 1 then
1479+
val firstFormal = protoFormals.head.loBound
1480+
if ptIsCorrectProduct(firstFormal) then
1481+
val isGenericTuple =
1482+
firstFormal.derivesFrom(defn.TupleClass)
1483+
&& !defn.isTupleClass(firstFormal.typeSymbol)
1484+
desugared = desugar.makeTupledFunction(params, fnBody, isGenericTuple)
14811485
else if protoFormals.length > 1 && params.length == 1 then
14821486
def isParamRef(scrut: untpd.Tree): Boolean = scrut match
14831487
case untpd.Annotated(scrut1, _) => isParamRef(scrut1)
@@ -1499,12 +1503,14 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
14991503
for ((param, i) <- params.zipWithIndex) yield
15001504
if (!param.tpt.isEmpty) param
15011505
else
1502-
val formal = protoFormal(i)
1506+
val formalBounds = protoFormal(i)
1507+
val formal = formalBounds.loBound
1508+
val isBottomFromWildcard = (formalBounds ne formal) && formal.isExactlyNothing
15031509
val knownFormal = isFullyDefined(formal, ForceDegree.failBottom)
15041510
// If the expected formal is Nothin, try to prioritize inferring from target,
15051511
// if possible. See issue 16405 (tests/run/16405.scala)
15061512
val paramType =
1507-
if knownFormal && !formal.isExactlyNothing then
1513+
if knownFormal && !isBottomFromWildcard then
15081514
formal
15091515
else
15101516
val fromTarget = inferredFromTarget(param, formal, calleeType, paramIndex)

tests/neg/i8012.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ class C extends Q[?] // error: Type argument must be fully defined
99

1010
object O {
1111
def m(i: Int): Int = i
12-
val x: Q[_] = m
12+
val x: Q[_] = m // error: result type of lambda is an underspecified SAM type Q[?]
1313
}

0 commit comments

Comments
 (0)