@@ -3271,40 +3271,74 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
3271
3271
}
3272
3272
3273
3273
val fun = preSelectOverloaded(fun0)
3274
+ val argslen = args.length
3274
3275
3275
3276
fun.tpe match {
3276
3277
case OverloadedType (pre, alts) =>
3277
3278
def handleOverloaded = {
3278
3279
val undetparams = context.undetparams
3280
+
3281
+ def funArgTypes (tps : List [Type ]) = tps.map { tp =>
3282
+ val relTp = tp.asSeenFrom(pre, fun.symbol.owner)
3283
+ val argTps = functionOrSamArgTypes(relTp)
3284
+ // println(s"funArgTypes $argTps from $relTp")
3285
+ argTps.map(approximateAbstracts)
3286
+ }
3287
+
3288
+ def functionProto (argTps : List [Type ]): Type =
3289
+ try functionType(funArgTypes(argTps).transpose.map(lub), WildcardType )
3290
+ catch { case _ : IllegalArgumentException => WildcardType }
3291
+
3292
+ // To propagate as much information as possible to typedFunction, which uses the expected type to
3293
+ // infer missing parameter types for Function trees that we're typing as arguments here,
3294
+ // we expand the parameter types for all alternatives to the expected argument length,
3295
+ // then transpose to get a list of alternative argument types (push down the overloading to the arguments).
3296
+ // Thus, for each `arg` in `args`, the corresponding `argPts` in `altArgPts` is a list of expected types
3297
+ // for `arg`. Depending on which overload is picked, only one of those expected types must be met, but
3298
+ // we're in the process of figuring that out, so we'll approximate below by normalizing them to function types
3299
+ // and lubbing the argument types (we treat SAM and FunctionN types equally, but non-function arguments
3300
+ // do not receive special treatment: they are typed under WildcardType.)
3301
+ val altArgPts =
3302
+ if (settings.isScala212 && args.exists(treeInfo.isFunctionMissingParamType))
3303
+ try alts.map(alt => formalTypes(alt.info.paramTypes, argslen)).transpose // do least amount of work up front
3304
+ catch { case _ : IllegalArgumentException => args.map(_ => Nil ) } // fail safe in case formalTypes fails to align to argslen
3305
+ else args.map(_ => Nil ) // will type under argPt == WildcardType
3306
+
3279
3307
val (args1, argTpes) = context.savingUndeterminedTypeParams() {
3280
3308
val amode = forArgMode(fun, mode)
3281
- def typedArg0 (tree : Tree ) = typedArg(tree, amode, BYVALmode , WildcardType )
3282
- args.map {
3283
- case arg @ AssignOrNamedArg (Ident (name), rhs) =>
3284
- // named args: only type the righthand sides ("unknown identifier" errors otherwise)
3285
- // the assign is untyped; that's ok because we call doTypedApply
3286
- val typedRhs = typedArg0(rhs)
3287
- val argWithTypedRhs = treeCopy.AssignOrNamedArg (arg, arg.lhs, typedRhs)
3288
-
3289
- // TODO: SI-8197/SI-4592: check whether this named argument could be interpreted as an assign
3309
+
3310
+ map2(args, altArgPts) { (arg, argPts) =>
3311
+ def typedArg0 (tree : Tree ) = {
3312
+ // if we have an overloaded HOF such as `(f: Int => Int)Int <and> (f: Char => Char)Char`,
3313
+ // and we're typing a function like `x => x` for the argument, try to collapse
3314
+ // the overloaded type into a single function type from which `typedFunction`
3315
+ // can derive the argument type for `x` in the function literal above
3316
+ val argPt =
3317
+ if (argPts.nonEmpty && treeInfo.isFunctionMissingParamType(tree)) functionProto(argPts)
3318
+ else WildcardType
3319
+
3320
+ val argTyped = typedArg(tree, amode, BYVALmode , argPt)
3321
+ (argTyped, argTyped.tpe.deconst)
3322
+ }
3323
+
3324
+ arg match {
3325
+ // SI-8197/SI-4592 call for checking whether this named argument could be interpreted as an assign
3290
3326
// infer.checkNames must not use UnitType: it may not be a valid assignment, or the setter may return another type from Unit
3291
- //
3292
- // var typedAsAssign = true
3293
- // val argTyped = silent(_.typedArg(argWithTypedRhs, amode, BYVALmode, WildcardType)) orElse { errors =>
3294
- // typedAsAssign = false
3295
- // argWithTypedRhs
3296
- // }
3297
- //
3298
- // TODO: add an assignmentType field to NamedType, equal to:
3299
- // assignmentType = if (typedAsAssign) argTyped.tpe else NoType
3300
-
3301
- (argWithTypedRhs, NamedType (name, typedRhs.tpe.deconst))
3302
- case arg @ treeInfo.WildcardStarArg (repeated) =>
3303
- val arg1 = typedArg0(arg)
3304
- (arg1, RepeatedType (arg1.tpe.deconst))
3305
- case arg =>
3306
- val arg1 = typedArg0(arg)
3307
- (arg1, arg1.tpe.deconst)
3327
+ // TODO: just make it an error to refer to a non-existent named arg, as it's far more likely to be
3328
+ // a typo than an assignment passed as an argument
3329
+ case AssignOrNamedArg (lhs@ Ident (name), rhs) =>
3330
+ // named args: only type the righthand sides ("unknown identifier" errors otherwise)
3331
+ // the assign is untyped; that's ok because we call doTypedApply
3332
+ typedArg0(rhs) match {
3333
+ case (rhsTyped, tp) => (treeCopy.AssignOrNamedArg (arg, lhs, rhsTyped), NamedType (name, tp))
3334
+ }
3335
+ case treeInfo.WildcardStarArg (_) =>
3336
+ typedArg0(arg) match {
3337
+ case (argTyped, tp) => (argTyped, RepeatedType (tp))
3338
+ }
3339
+ case _ =>
3340
+ typedArg0(arg)
3341
+ }
3308
3342
}.unzip
3309
3343
}
3310
3344
if (context.reporter.hasErrors)
@@ -3335,7 +3369,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
3335
3369
case mt @ MethodType (params, _) =>
3336
3370
val paramTypes = mt.paramTypes
3337
3371
// repeat vararg as often as needed, remove by-name
3338
- val argslen = args.length
3339
3372
val formals = formalTypes(paramTypes, argslen)
3340
3373
3341
3374
/* Try packing all arguments into a Tuple and apply `fun`
0 commit comments