Skip to content

Commit 8508c0d

Browse files
committed
Draft: Overloading result-based pruning shouldn't prefer inapplicable alt
If an overloaded alternative in `alts` does not end up being part of the `candidate` list in `resolveOverloaded1`, then it is not applicable to the current arguments and should not be considered by `adaptByResult`. This avoids discarding working solutions in favor of invalid ones when the working solution involves a match type in the method result type that will fail `resultConforms`. Fixes #21410.
1 parent 3408ed7 commit 8508c0d

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2129,11 +2129,13 @@ trait Applications extends Compatibility {
21292129
return resolveMapped(alts, alt => stripImplicit(alt.widen), pt)
21302130
case _ =>
21312131

2132-
var found = withoutMode(Mode.ImplicitsEnabled)(resolveOverloaded1(alts, pt))
2132+
var candidatesAndFound = withoutMode(Mode.ImplicitsEnabled)(resolveOverloaded1(alts, pt))
2133+
def candidates = candidatesAndFound._1
2134+
def found = candidatesAndFound._2
21332135
if found.isEmpty && ctx.mode.is(Mode.ImplicitsEnabled) then
2134-
found = resolveOverloaded1(alts, pt)
2136+
candidatesAndFound = resolveOverloaded1(alts, pt)
21352137
found match
2136-
case alt :: Nil => adaptByResult(alt, alts) :: Nil
2138+
case alt :: Nil => adaptByResult(alt, candidates) :: Nil
21372139
case _ => found
21382140
end resolve
21392141

@@ -2178,7 +2180,7 @@ trait Applications extends Compatibility {
21782180
* It might be called twice from the public `resolveOverloaded` method, once with
21792181
* implicits and SAM conversions enabled, and once without.
21802182
*/
2181-
private def resolveOverloaded1(alts: List[TermRef], pt: Type)(using Context): List[TermRef] =
2183+
private def resolveOverloaded1(alts: List[TermRef], pt: Type)(using Context): (List[TermRef], List[TermRef]) =
21822184
trace(i"resolve over $alts%, %, pt = $pt", typr, show = true) {
21832185
record(s"resolveOverloaded1", alts.length)
21842186

@@ -2306,7 +2308,9 @@ trait Applications extends Compatibility {
23062308
else
23072309
record("resolveOverloaded.narrowedByShape", alts2.length)
23082310
pretypeArgs(alts2, pt)
2309-
narrowByTrees(alts2, pt.typedArgs(normArg(alts2, _, _)), resultType)
2311+
val alts3 = narrowByTrees(alts2, pt.typedArgs(normArg(alts2, _, _)), resultType)
2312+
overload.println(i"narrowed by trees: ${alts3.map(_.symbol.showDcl)}%, %")
2313+
alts3
23102314

23112315
case pt @ PolyProto(targs1, pt1) =>
23122316
val alts1 = alts.filterConserve(pt.canInstantiate)
@@ -2372,42 +2376,42 @@ trait Applications extends Compatibility {
23722376
if pt.unusableForInference then
23732377
// `pt` might have become erroneous by typing arguments of FunProtos.
23742378
// If `pt` is erroneous, don't try to go further; report the error in `pt` instead.
2375-
candidates
2379+
(candidates, candidates)
23762380
else
23772381
val found = narrowMostSpecific(candidates)
2378-
if found.length <= 1 then found
2382+
if found.length <= 1 then (candidates, found)
23792383
else
23802384
val deepPt = pt.deepenProto
23812385
deepPt match
23822386
case pt @ FunProto(_, PolyProto(targs, resType)) =>
23832387
// try to narrow further with snd argument list and following type params
2384-
resolveMapped(candidates,
2385-
skipParamClause(pt.typedArgs().tpes, targs.tpes), resType)
2388+
(candidates, resolveMapped(candidates,
2389+
skipParamClause(pt.typedArgs().tpes, targs.tpes), resType))
23862390
case pt @ FunProto(_, resType: FunOrPolyProto) =>
23872391
// try to narrow further with snd argument list
2388-
resolveMapped(candidates,
2389-
skipParamClause(pt.typedArgs().tpes, Nil), resType)
2392+
(candidates, resolveMapped(candidates,
2393+
skipParamClause(pt.typedArgs().tpes, Nil), resType))
23902394
case _ =>
23912395
// prefer alternatives that need no eta expansion
23922396
val noCurried = alts.filterConserve(!resultIsMethod(_))
23932397
val noCurriedCount = noCurried.length
23942398
if noCurriedCount == 1 then
2395-
noCurried
2399+
(candidates, noCurried)
23962400
else if noCurriedCount > 1 && noCurriedCount < alts.length then
23972401
resolveOverloaded1(noCurried, pt)
23982402
else
23992403
// prefer alternatves that match without default parameters
24002404
val noDefaults = alts.filterConserve(!_.symbol.hasDefaultParams)
24012405
val noDefaultsCount = noDefaults.length
24022406
if noDefaultsCount == 1 then
2403-
noDefaults
2407+
(candidates, noDefaults)
24042408
else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
24052409
resolveOverloaded1(noDefaults, pt)
24062410
else if deepPt ne pt then
24072411
// try again with a deeper known expected type
24082412
resolveOverloaded1(alts, deepPt)
24092413
else
2410-
candidates
2414+
(candidates, candidates)
24112415
}
24122416
end resolveOverloaded1
24132417

tests/pos/i21410.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class A
2+
object Test:
3+
type F[X] <: Any = X match
4+
case A => Int
5+
6+
def foo[T](x: String): T = ???
7+
def foo[U](x: U): F[U] = ???
8+
9+
val x1 = foo(A())
10+
val y: Int = x1
11+
12+
val x2: Int = foo(A()) // error

0 commit comments

Comments
 (0)