@@ -2225,7 +2225,7 @@ trait Applications extends Compatibility {
2225
2225
* implicits and SAM conversions enabled, and once without.
2226
2226
*/
2227
2227
private def resolveOverloaded1 (alts : List [TermRef ], pt : Type , srcPos : SrcPos )(using Context ): List [TermRef ] =
2228
- trace(i " resolve over $alts%, %, pt = $pt" , typr, show = true ) {
2228
+ trace(i " resolve over $alts%, %, pt = $pt" , typr, show = true ):
2229
2229
record(s " resolveOverloaded1 " , alts.length)
2230
2230
2231
2231
val sv = Feature .sourceVersion
@@ -2378,7 +2378,10 @@ trait Applications extends Compatibility {
2378
2378
case _ => arg
2379
2379
end normArg
2380
2380
2381
- val candidates = pt match {
2381
+ // Note it is important not to capture the outer ctx, for when it is passed to resolveMapped
2382
+ // (through narrowByNextParamClause) which retracts the Mode.SynthesizeExtMethodReceiver from the ctx
2383
+ // before continuing to `resolveCandidates`.
2384
+ def resolveCandidates (alts : List [TermRef ], pt : Type , srcPos : SrcPos )(using Context ): List [TermRef ] = pt match
2382
2385
case pt @ FunProto (args, resultType) =>
2383
2386
val numArgs = args.length
2384
2387
def sizeFits (alt : TermRef ): Boolean = alt.widen.stripPoly match {
@@ -2430,7 +2433,13 @@ trait Applications extends Compatibility {
2430
2433
else
2431
2434
record(" resolveOverloaded.narrowedByShape" , alts2.length)
2432
2435
pretypeArgs(alts2, pt)
2433
- narrowByTrees(alts2, pt.typedArgs(normArg(alts2, _, _)), resultType)
2436
+ val alts3 = narrowByTrees(alts2, pt.typedArgs(normArg(alts2, _, _)), resultType)
2437
+
2438
+ resultType.deepenProto match
2439
+ case resultType : FunOrPolyProto =>
2440
+ narrowByNextParamClause(resolveCandidates)(alts3, pt.typedArgs(), resultType)
2441
+ case _ =>
2442
+ alts3
2434
2443
2435
2444
case pt @ PolyProto (targs1, pt1) =>
2436
2445
val alts1 = alts.filterConserve(pt.canInstantiate)
@@ -2441,7 +2450,7 @@ trait Applications extends Compatibility {
2441
2450
TypeOps .boundsViolations(targs1, tp.paramInfos, _.substParams(tp, _), NoType ).isEmpty
2442
2451
val alts2 = alts1.filter(withinBounds)
2443
2452
if isDetermined(alts2) then alts2
2444
- else resolveMapped(_.widen.appliedTo(targs1.tpes))(alts1, pt1, srcPos)
2453
+ else resolveMapped(_.widen.appliedTo(targs1.tpes), resolveCandidates )(alts1, pt1, srcPos)
2445
2454
2446
2455
case pt =>
2447
2456
val compat = alts.filterConserve(normalizedCompatible(_, pt, keepConstraint = false ))
@@ -2465,48 +2474,58 @@ trait Applications extends Compatibility {
2465
2474
normalize(alt, IgnoredProto (pt)).widenSingleton.isInstanceOf [MethodType ])
2466
2475
if convertible.length == 1 then convertible else compat
2467
2476
else compat
2468
- }
2477
+ end resolveCandidates
2469
2478
2470
2479
def resultIsMethod (tp : Type ): Boolean = tp.widen.stripPoly match
2471
2480
case tp : MethodType => stripInferrable(tp.resultType).isInstanceOf [MethodType ]
2472
2481
case _ => false
2473
2482
2474
- record(" resolveOverloaded.narrowedApplicable" , candidates.length)
2475
- if pt.unusableForInference then
2476
- // `pt` might have become erroneous by typing arguments of FunProtos.
2477
- // If `pt` is erroneous, don't try to go further; report the error in `pt` instead.
2478
- candidates
2479
- else
2480
- val found = narrowMostSpecific(candidates)
2481
- if isDetermined(found) then found
2483
+ // Like resolveCandidates, we should not capture the outer ctx parameter.
2484
+ def resolveOverloaded2 (candidates : List [TermRef ], pt : Type , srcPos : SrcPos )(using Context ): List [TermRef ] =
2485
+ if pt.unusableForInference then
2486
+ // `pt` might have become erroneous by typing arguments of FunProtos.
2487
+ // If `pt` is erroneous, don't try to go further; report the error in `pt` instead.
2488
+ candidates
2482
2489
else
2483
- val deepPt = pt.deepenProto
2484
- deepPt match
2485
- case pt @ FunProto (_, resType : FunOrPolyProto ) =>
2486
- warnOnPriorityChange(candidates, found):
2487
- narrowByNextParamClause(resolveOverloaded1)(_, pt.typedArgs(), resType)
2488
- case _ =>
2489
- // prefer alternatives that need no eta expansion
2490
- val noCurried = alts.filterConserve(! resultIsMethod(_))
2491
- val noCurriedCount = noCurried.length
2492
- if noCurriedCount == 1 then
2493
- noCurried
2494
- else if noCurriedCount > 1 && noCurriedCount < alts.length then
2495
- resolveOverloaded1(noCurried, pt, srcPos)
2496
- else
2497
- // prefer alternatves that match without default parameters
2498
- val noDefaults = alts.filterConserve(! _.symbol.hasDefaultParams)
2499
- val noDefaultsCount = noDefaults.length
2500
- if noDefaultsCount == 1 then
2501
- noDefaults
2502
- else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
2503
- resolveOverloaded1(noDefaults, pt, srcPos)
2504
- else if deepPt ne pt then
2505
- // try again with a deeper known expected type
2506
- resolveOverloaded1(alts, deepPt, srcPos)
2490
+ val found = narrowMostSpecific(candidates)
2491
+ if isDetermined(found) then found
2492
+ else
2493
+ val deepPt = pt.deepenProto
2494
+ deepPt match
2495
+ case pt @ FunProto (_, resType : FunOrPolyProto ) =>
2496
+ warnOnPriorityChange(candidates, found):
2497
+ narrowByNextParamClause(resolveOverloaded1)(_, pt.typedArgs(), resType)
2498
+ case _ =>
2499
+ // prefer alternatives that need no eta expansion
2500
+ val noCurried = alts.filterConserve(! resultIsMethod(_))
2501
+ val noCurriedCount = noCurried.length
2502
+ if noCurriedCount == 1 then
2503
+ noCurried
2504
+ else if noCurriedCount > 1 && noCurriedCount < alts.length then
2505
+ resolveOverloaded1(noCurried, pt, srcPos)
2507
2506
else
2508
- candidates
2509
- }
2507
+ // prefer alternatves that match without default parameters
2508
+ val noDefaults = alts.filterConserve(! _.symbol.hasDefaultParams)
2509
+ val noDefaultsCount = noDefaults.length
2510
+ if noDefaultsCount == 1 then
2511
+ noDefaults
2512
+ else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
2513
+ resolveOverloaded1(noDefaults, pt, srcPos)
2514
+ else if deepPt ne pt then
2515
+ // try again with a deeper known expected type
2516
+ resolveOverloaded1(alts, deepPt, srcPos)
2517
+ else
2518
+ candidates
2519
+ end resolveOverloaded2
2520
+
2521
+ // First, we find the candidates by considering all parameter clauses.
2522
+ // Second, we determine the most specific again by considering all parameter clauses;
2523
+ // but restarting from the 1st argument list.
2524
+ // In both cases, considering subsequent argument lists only narrows the set of alternatives
2525
+ // (i.e. we do retry from the complete list of alternative mapped onto there next param clause).
2526
+ val candidates = resolveCandidates(alts, pt, srcPos)
2527
+ record(" resolveOverloaded.narrowedApplicable" , candidates.length)
2528
+ resolveOverloaded2(candidates, pt, srcPos)
2510
2529
end resolveOverloaded1
2511
2530
2512
2531
/** Is `formal` a product type which is elementwise compatible with `params`? */
0 commit comments