@@ -1197,7 +1197,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1197
1197
)
1198
1198
end typedIf
1199
1199
1200
- /** Decompose function prototype into a list of parameter prototypes and a result prototype
1200
+ /** Decompose function prototype into a list of parameter prototypes, an optional list
1201
+ * describing whether the parameter prototypes come from WildcardTypes, and a result prototype
1201
1202
* tree, using WildcardTypes where a type is not known.
1202
1203
* For the result type we do this even if the expected type is not fully
1203
1204
* defined, which is a bit of a hack. But it's needed to make the following work
@@ -1206,7 +1207,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1206
1207
* def double(x: Char): String = s"$x$x"
1207
1208
* "abc" flatMap double
1208
1209
*/
1209
- private def decomposeProtoFunction (pt : Type , defaultArity : Int , pos : SrcPos )(using Context ): (List [Type ], untpd.Tree ) = {
1210
+ private def decomposeProtoFunction (pt : Type , defaultArity : Int , pos : SrcPos )(using Context ): (List [Type ], Option [ List [ Boolean ]], untpd.Tree ) = {
1210
1211
def typeTree (tp : Type ) = tp match {
1211
1212
case _ : WildcardType => new untpd.InferredTypeTree ()
1212
1213
case _ => untpd.InferredTypeTree (tp)
@@ -1234,18 +1235,26 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1234
1235
// if expected parameter type(s) are wildcards, approximate from below.
1235
1236
// if expected result type is a wildcard, approximate from above.
1236
1237
// this can type the greatest set of admissible closures.
1237
- (pt1.argTypesLo.init, typeTree(interpolateWildcards(pt1.argTypesHi.last)))
1238
+ // However, we still keep the information on whether expected parameter types were
1239
+ // wildcards, in case of types inferred from target being more specific
1240
+
1241
+ val fromWildcards = pt1.argInfos.init.map{
1242
+ case bounds @ TypeBounds (nt, at) if nt == defn.NothingType && at == defn.AnyType => true
1243
+ case bounds => false
1244
+ }
1245
+
1246
+ (pt1.argTypesLo.init, Some (fromWildcards), typeTree(interpolateWildcards(pt1.argTypesHi.last)))
1238
1247
case RefinedType (parent, nme.apply, mt @ MethodTpe (_, formals, restpe))
1239
1248
if defn.isNonRefinedFunction(parent) && formals.length == defaultArity =>
1240
- (formals, untpd.DependentTypeTree (syms => restpe.substParams(mt, syms.map(_.termRef))))
1249
+ (formals, None , untpd.DependentTypeTree (syms => restpe.substParams(mt, syms.map(_.termRef))))
1241
1250
case SAMType (mt @ MethodTpe (_, formals, restpe)) =>
1242
- (formals,
1251
+ (formals, None ,
1243
1252
if (mt.isResultDependent)
1244
1253
untpd.DependentTypeTree (syms => restpe.substParams(mt, syms.map(_.termRef)))
1245
1254
else
1246
1255
typeTree(restpe))
1247
1256
case _ =>
1248
- (List .tabulate(defaultArity)(alwaysWildcardType), untpd.TypeTree ())
1257
+ (List .tabulate(defaultArity)(alwaysWildcardType), None , untpd.TypeTree ())
1249
1258
}
1250
1259
}
1251
1260
}
@@ -1267,7 +1276,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1267
1276
* If both attempts fail, return `NoType`.
1268
1277
*/
1269
1278
def inferredFromTarget (
1270
- param : untpd.ValDef , formal : Type , calleeType : Type , paramIndex : Name => Int )(using Context ): Type =
1279
+ param : untpd.ValDef , formal : Type , calleeType : Type , paramIndex : Name => Int , isWildcardParam : Boolean )(using Context ): Type =
1271
1280
val target = calleeType.widen match
1272
1281
case mtpe : MethodType =>
1273
1282
val pos = paramIndex(param.name)
@@ -1280,7 +1289,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1280
1289
else NoType
1281
1290
case _ => NoType
1282
1291
if target.exists then formal <:< target
1283
- if isFullyDefined(formal, ForceDegree .flipBottom) then formal
1292
+ if ! isWildcardParam && isFullyDefined(formal, ForceDegree .flipBottom) then formal
1284
1293
else if target.exists && isFullyDefined(target, ForceDegree .flipBottom) then target
1285
1294
else NoType
1286
1295
@@ -1457,7 +1466,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1457
1466
case _ =>
1458
1467
}
1459
1468
1460
- val (protoFormals, resultTpt) = decomposeProtoFunction(pt, params.length, tree.srcPos)
1469
+ val (protoFormals, areWildcardParams, resultTpt) = decomposeProtoFunction(pt, params.length, tree.srcPos)
1461
1470
1462
1471
def protoFormal (i : Int ): Type =
1463
1472
if (protoFormals.length == params.length) protoFormals(i)
@@ -1500,13 +1509,21 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1500
1509
if (! param.tpt.isEmpty) param
1501
1510
else
1502
1511
val formal = protoFormal(i)
1512
+ val isWildcardParam = areWildcardParams.map(list => if i < list.length then list(i) else false ).getOrElse(false )
1503
1513
val knownFormal = isFullyDefined(formal, ForceDegree .failBottom)
1504
- val paramType =
1505
- if knownFormal then formal
1506
- else inferredFromTarget(param, formal, calleeType, paramIndex)
1507
- .orElse(errorType(AnonymousFunctionMissingParamType (param, tree, formal), param.srcPos))
1514
+ // Since decomposeProtoFunction eagerly approximates function arguments
1515
+ // from below, then in the case that the argument was also identified as
1516
+ // a wildcard type we try to prioritize inferring from target, if possible.
1517
+ // See issue 16405 (tests/run/16405.scala)
1518
+ val (usingFormal, paramType) =
1519
+ if ! isWildcardParam && knownFormal then (true , formal)
1520
+ else
1521
+ val fromTarget = inferredFromTarget(param, formal, calleeType, paramIndex, isWildcardParam)
1522
+ if fromTarget.exists then (false , fromTarget)
1523
+ else if knownFormal then (true , formal)
1524
+ else (false , errorType(AnonymousFunctionMissingParamType (param, tree, formal), param.srcPos))
1508
1525
val paramTpt = untpd.TypedSplice (
1509
- (if knownFormal then InferredTypeTree () else untpd.TypeTree ())
1526
+ (if usingFormal then InferredTypeTree () else untpd.TypeTree ())
1510
1527
.withType(paramType.translateFromRepeated(toArray = false ))
1511
1528
.withSpan(param.span.endPos)
1512
1529
)
@@ -1577,7 +1594,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
1577
1594
typedMatchFinish(tree, tpd.EmptyTree , defn.ImplicitScrutineeTypeRef , cases1, pt)
1578
1595
}
1579
1596
else {
1580
- val (protoFormals, _) = decomposeProtoFunction(pt, 1 , tree.srcPos)
1597
+ val (protoFormals, _, _ ) = decomposeProtoFunction(pt, 1 , tree.srcPos)
1581
1598
val checkMode =
1582
1599
if (pt.isRef(defn.PartialFunctionClass )) desugar.MatchCheck .None
1583
1600
else desugar.MatchCheck .Exhaustive
0 commit comments