Skip to content

Commit b2a2c12

Browse files
Resolve candidates by considering all argument lists
before starting to narrow most specific
1 parent 8c7e8bd commit b2a2c12

File tree

1 file changed

+58
-39
lines changed

1 file changed

+58
-39
lines changed

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

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,7 +2225,7 @@ trait Applications extends Compatibility {
22252225
* implicits and SAM conversions enabled, and once without.
22262226
*/
22272227
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):
22292229
record(s"resolveOverloaded1", alts.length)
22302230

22312231
val sv = Feature.sourceVersion
@@ -2378,7 +2378,10 @@ trait Applications extends Compatibility {
23782378
case _ => arg
23792379
end normArg
23802380

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
23822385
case pt @ FunProto(args, resultType) =>
23832386
val numArgs = args.length
23842387
def sizeFits(alt: TermRef): Boolean = alt.widen.stripPoly match {
@@ -2430,7 +2433,13 @@ trait Applications extends Compatibility {
24302433
else
24312434
record("resolveOverloaded.narrowedByShape", alts2.length)
24322435
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
24342443

24352444
case pt @ PolyProto(targs1, pt1) =>
24362445
val alts1 = alts.filterConserve(pt.canInstantiate)
@@ -2441,7 +2450,7 @@ trait Applications extends Compatibility {
24412450
TypeOps.boundsViolations(targs1, tp.paramInfos, _.substParams(tp, _), NoType).isEmpty
24422451
val alts2 = alts1.filter(withinBounds)
24432452
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)
24452454

24462455
case pt =>
24472456
val compat = alts.filterConserve(normalizedCompatible(_, pt, keepConstraint = false))
@@ -2465,48 +2474,58 @@ trait Applications extends Compatibility {
24652474
normalize(alt, IgnoredProto(pt)).widenSingleton.isInstanceOf[MethodType])
24662475
if convertible.length == 1 then convertible else compat
24672476
else compat
2468-
}
2477+
end resolveCandidates
24692478

24702479
def resultIsMethod(tp: Type): Boolean = tp.widen.stripPoly match
24712480
case tp: MethodType => stripInferrable(tp.resultType).isInstanceOf[MethodType]
24722481
case _ => false
24732482

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
24822489
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)
25072506
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)
25102529
end resolveOverloaded1
25112530

25122531
/** Is `formal` a product type which is elementwise compatible with `params`? */

0 commit comments

Comments
 (0)