@@ -2112,15 +2112,71 @@ trait Applications extends Compatibility {
2112
2112
}
2113
2113
}
2114
2114
2115
+ /** Overloadoing Priority Schemes, changing in `scala-3.7`.
2116
+ *
2117
+ * Old Scheme, until 3.7:
2118
+ * - First, determines the _candidates_ (subset of the alternatives) by:
2119
+ * + looking at the first paramater clause
2120
+ * - Second, determine the best candidate by:
2121
+ * + doing narrowMostSpecific on the first argument list;
2122
+ * + if still ambigous and there is another parameter clause, then
2123
+ * restarts narrowMostSpecific by mapping the problem onto the next parameter clause,
2124
+ * but still considering all candidates.
2125
+ *
2126
+ * New Scheme, from 3.7
2127
+ * - First, determines the candidates by:
2128
+ * + looking at first paramater clause;
2129
+ * + if still no determined and there is another parameter clause, then
2130
+ * looks at the next argument lists to narrow the candidates (not restarting from alts).
2131
+ * If that finds no alternative is applicable, fallback to the previous iteration
2132
+ * (see comment in narrowByNextParamClause for details).
2133
+ * - Second, determine the best candidate by, restoring all parameter clauses, and:
2134
+ * + doing narrowMostSpecific on the first argument list;
2135
+ * + if still ambigous and there is another parameter clause, then
2136
+ * continue narrowMostSpecific by mapping the problem onto the next parameter clause,
2137
+ * but only considering the alternatives found until now.
2138
+ */
2139
+ enum ResolveScheme :
2140
+ case Old
2141
+ case New
2142
+ def isNewPriority : Boolean = this == New
2143
+
2144
+ /** Resolve overloaded alternative `alts`, given expected type `pt`. Determines the current
2145
+ * priority scheme and emits warnings for changes in resolution in migration version.
2146
+ */
2147
+ def resolveOverloaded (alts : List [TermRef ], pt : Type , srcPos : SrcPos )(using Context ): List [TermRef ] =
2148
+ record(" resolveOverloaded" )
2149
+ lazy val oldRes = resolveOverloaded(resolveOverloaded1(ResolveScheme .Old ))(alts, pt)
2150
+ lazy val newRes = resolveOverloaded(resolveOverloaded1(ResolveScheme .New ))(alts, pt)
2151
+
2152
+ val sv = Feature .sourceVersion
2153
+ val isNewPriorityVersion = sv.isAtLeast(SourceVersion .`3.7`)
2154
+ val isWarnPriorityChangeVersion = sv == SourceVersion .`3.7-migration`
2155
+
2156
+ def doWarn (oldChoice : String , newChoice : String ): Unit = report.warning(
2157
+ em """ Overloading resolution for ${err.expectedTypeStr(pt)} between alternatives
2158
+ | ${alts map (_.info)}%\n %
2159
+ |has changed.
2160
+ |Previous choice : $oldChoice
2161
+ |New choice from Scala 3.7: $newChoice""" , srcPos)
2162
+
2163
+ if isWarnPriorityChangeVersion then (oldRes, newRes) match
2164
+ case (oldAlt :: Nil , newAlt :: Nil ) if oldAlt != newAlt => doWarn(oldAlt.info.show, newAlt.info.show)
2165
+ case (oldAlt :: Nil , Nil ) => doWarn(oldAlt.info.show, " none" )
2166
+ case (Nil , newAlt :: Nil ) => doWarn(" none" , newAlt.info.show)
2167
+ case _ => // neither scheme has determined an alternative
2168
+
2169
+ if isNewPriorityVersion then newRes else oldRes
2170
+ end resolveOverloaded
2171
+
2115
2172
/** Resolve overloaded alternative `alts`, given expected type `pt`.
2116
2173
* Two trials: First, without implicits or SAM conversions enabled. Then,
2117
2174
* if the first finds no eligible candidates, with implicits and SAM conversions enabled.
2118
2175
* Each trial applies the `resolve` parameter.
2119
2176
*/
2120
2177
def resolveOverloaded
2121
- (resolve : (List [TermRef ], Type ) => Context ?=> List [TermRef ] = resolveOverloaded1)
2122
- (alts : List [TermRef ], pt : Type , srcPos : SrcPos = NoSourcePosition )(using Context ): List [TermRef ] =
2123
- record(" resolveOverloaded" )
2178
+ (resolve : (List [TermRef ], Type ) => Context ?=> List [TermRef ])
2179
+ (alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
2124
2180
2125
2181
/** Is `alt` a method or polytype whose result type after the first value parameter
2126
2182
* section conforms to the expected type `resultType`? If `resultType`
@@ -2157,7 +2213,7 @@ trait Applications extends Compatibility {
2157
2213
case Nil => chosen
2158
2214
case alt2 :: Nil => alt2
2159
2215
case alts2 =>
2160
- resolveOverloaded(resolve)(alts2, pt, srcPos ) match {
2216
+ resolveOverloaded(resolve)(alts2, pt) match {
2161
2217
case alt2 :: Nil => alt2
2162
2218
case _ => chosen
2163
2219
}
@@ -2224,7 +2280,7 @@ trait Applications extends Compatibility {
2224
2280
* It might be called twice from the public `resolveOverloaded` method, once with
2225
2281
* implicits and SAM conversions enabled, and once without.
2226
2282
*/
2227
- private def resolveOverloaded1 (alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
2283
+ private def resolveOverloaded1 (scheme : ResolveScheme )( alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
2228
2284
trace(i " resolve over $alts%, %, pt = $pt" , typr, show = true ):
2229
2285
record(s " resolveOverloaded1 " , alts.length)
2230
2286
@@ -2414,7 +2470,7 @@ trait Applications extends Compatibility {
2414
2470
val alts3 = narrowByTrees(alts2, pt.typedArgs(normArg(alts2, _, _)), resultType)
2415
2471
2416
2472
resultType.deepenProto match
2417
- case resultType : FunOrPolyProto =>
2473
+ case resultType : FunOrPolyProto if scheme.isNewPriority =>
2418
2474
narrowByNextParamClause(resolveCandidates)(alts3, pt.typedArgs(), resultType)
2419
2475
.fallbackTo(alts3) // see comment in narrowByNextParamClause
2420
2476
case _ =>
@@ -2472,35 +2528,31 @@ trait Applications extends Compatibility {
2472
2528
val deepPt = pt.deepenProto
2473
2529
deepPt match
2474
2530
case pt @ FunProto (_, resType : FunOrPolyProto ) =>
2475
- narrowByNextParamClause(resolveOverloaded1)(found, pt.typedArgs(), resType)
2531
+ val alts1 = if scheme.isNewPriority then found else candidates
2532
+ narrowByNextParamClause(resolveOverloaded1(scheme))(alts1, pt.typedArgs(), resType)
2476
2533
case _ =>
2477
2534
// prefer alternatives that need no eta expansion
2478
2535
val noCurried = alts.filterConserve(! resultIsMethod(_))
2479
2536
val noCurriedCount = noCurried.length
2480
2537
if noCurriedCount == 1 then
2481
2538
noCurried
2482
2539
else if noCurriedCount > 1 && noCurriedCount < alts.length then
2483
- resolveOverloaded1(noCurried, pt)
2540
+ resolveOverloaded1(scheme)( noCurried, pt)
2484
2541
else
2485
2542
// prefer alternatves that match without default parameters
2486
2543
val noDefaults = alts.filterConserve(! _.symbol.hasDefaultParams)
2487
2544
val noDefaultsCount = noDefaults.length
2488
2545
if noDefaultsCount == 1 then
2489
2546
noDefaults
2490
2547
else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
2491
- resolveOverloaded1(noDefaults, pt)
2548
+ resolveOverloaded1(scheme)( noDefaults, pt)
2492
2549
else if deepPt ne pt then
2493
2550
// try again with a deeper known expected type
2494
- resolveOverloaded1(alts, deepPt)
2551
+ resolveOverloaded1(scheme)( alts, deepPt)
2495
2552
else
2496
2553
candidates
2497
2554
end resolveOverloaded2
2498
2555
2499
- // First, we find the candidates by considering all parameter clauses.
2500
- // Second, we determine the most specific again by considering all parameter clauses;
2501
- // but restarting from the 1st argument list.
2502
- // In both cases, considering subsequent argument lists only narrows the set of alternatives
2503
- // (i.e. we do retry from the complete list of alternative mapped onto there next param clause).
2504
2556
val candidates = resolveCandidates(alts, pt)
2505
2557
record(" resolveOverloaded.narrowedApplicable" , candidates.length)
2506
2558
resolveOverloaded2(candidates, pt)
0 commit comments