@@ -2116,7 +2116,7 @@ trait Applications extends Compatibility {
21162116 * Two trials: First, without implicits or SAM conversions enabled. Then,
21172117 * if the first finds no eligible candidates, with implicits and SAM conversions enabled.
21182118 */
2119- def resolveOverloaded (alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
2119+ def resolveOverloaded (alts : List [TermRef ], pt : Type , srcPos : SrcPos )(using Context ): List [TermRef ] =
21202120 record(" resolveOverloaded" )
21212121
21222122 /** Is `alt` a method or polytype whose result type after the first value parameter
@@ -2154,7 +2154,7 @@ trait Applications extends Compatibility {
21542154 case Nil => chosen
21552155 case alt2 :: Nil => alt2
21562156 case alts2 =>
2157- resolveOverloaded(alts2, pt) match {
2157+ resolveOverloaded(alts2, pt, srcPos ) match {
21582158 case alt2 :: Nil => alt2
21592159 case _ => chosen
21602160 }
@@ -2169,12 +2169,12 @@ trait Applications extends Compatibility {
21692169 val alts0 = alts.filterConserve(_.widen.stripPoly.isImplicitMethod)
21702170 if alts0 ne alts then return resolve(alts0)
21712171 else if alts.exists(_.widen.stripPoly.isContextualMethod) then
2172- return resolveMapped(alts, alt => stripImplicit(alt.widen), pt)
2172+ return resolveMapped(alts, alt => stripImplicit(alt.widen), pt, srcPos )
21732173 case _ =>
21742174
2175- var found = withoutMode(Mode .ImplicitsEnabled )(resolveOverloaded1(alts, pt))
2175+ var found = withoutMode(Mode .ImplicitsEnabled )(resolveOverloaded1(alts, pt, srcPos ))
21762176 if found.isEmpty && ctx.mode.is(Mode .ImplicitsEnabled ) then
2177- found = resolveOverloaded1(alts, pt)
2177+ found = resolveOverloaded1(alts, pt, srcPos )
21782178 found match
21792179 case alt :: Nil => adaptByResult(alt, alts) :: Nil
21802180 case _ => found
@@ -2221,10 +2221,44 @@ trait Applications extends Compatibility {
22212221 * It might be called twice from the public `resolveOverloaded` method, once with
22222222 * implicits and SAM conversions enabled, and once without.
22232223 */
2224- private def resolveOverloaded1 (alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
2224+ private def resolveOverloaded1 (alts : List [TermRef ], pt : Type , srcPos : SrcPos )(using Context ): List [TermRef ] =
22252225 trace(i " resolve over $alts%, %, pt = $pt" , typr, show = true ) {
22262226 record(s " resolveOverloaded1 " , alts.length)
22272227
2228+ val sv = Feature .sourceVersion
2229+ val isOldPriorityVersion : Boolean = sv.isAtMost(SourceVersion .`3.6`)
2230+ val isWarnPriorityChangeVersion = sv == SourceVersion .`3.6` || sv == SourceVersion .`3.7-migration`
2231+
2232+ inline def warnOnPriorityChange (oldCands : List [TermRef ], newCands : List [TermRef ])(f : List [TermRef ] => List [TermRef ]): List [TermRef ] =
2233+
2234+ def doWarn (oldChoice : String , newChoice : String ): Unit =
2235+ val (change, whichChoice) =
2236+ if isOldPriorityVersion
2237+ then (" will change" , " Current choice " )
2238+ else (" has changed" , " Previous choice" )
2239+
2240+ val msg = // uses oldCands as the list of alternatives since they should be a superset of newCands
2241+ em """ Overloading resolution for ${err.expectedTypeStr(pt)} between alternatives
2242+ | ${oldCands map (_.info)}%\n %
2243+ | $change.
2244+ | $whichChoice : $oldChoice
2245+ |New choice from Scala 3.7: $newChoice"""
2246+
2247+ report.warning(msg, srcPos)
2248+ end doWarn
2249+
2250+ lazy val oldRes = f(oldCands)
2251+ val newRes = f(newCands)
2252+
2253+ if isWarnPriorityChangeVersion then (oldRes, newRes) match
2254+ case (oldAlt :: Nil , newAlt :: Nil ) if oldAlt != newAlt => doWarn(oldAlt.info.show, newAlt.info.show)
2255+ case (oldAlt :: Nil , Nil ) => doWarn(oldAlt.info.show, " none" )
2256+ case (Nil , newAlt :: Nil ) => doWarn(" none" , newAlt.info.show)
2257+ case _ => // neither scheme has determined an alternative
2258+
2259+ if isOldPriorityVersion then oldRes else newRes
2260+ end warnOnPriorityChange
2261+
22282262 def isDetermined (alts : List [TermRef ]) = alts.isEmpty || alts.tail.isEmpty
22292263
22302264 /** The shape of given tree as a type; cannot handle named arguments. */
@@ -2372,7 +2406,7 @@ trait Applications extends Compatibility {
23722406 TypeOps .boundsViolations(targs1, tp.paramInfos, _.substParams(tp, _), NoType ).isEmpty
23732407 val alts2 = alts1.filter(withinBounds)
23742408 if isDetermined(alts2) then alts2
2375- else resolveMapped(alts1, _.widen.appliedTo(targs1.tpes), pt1)
2409+ else resolveMapped(alts1, _.widen.appliedTo(targs1.tpes), pt1, srcPos )
23762410
23772411 case pt =>
23782412 val compat = alts.filterConserve(normalizedCompatible(_, pt, keepConstraint = false ))
@@ -2430,37 +2464,37 @@ trait Applications extends Compatibility {
24302464 candidates
24312465 else
24322466 val found = narrowMostSpecific(candidates)
2433- if found.length <= 1 then found
2467+ if isDetermined( found) then found
24342468 else
24352469 val deepPt = pt.deepenProto
24362470 deepPt match
24372471 case pt @ FunProto (_, PolyProto (targs, resType)) =>
24382472 // try to narrow further with snd argument list and following type params
2439- resolveMapped(found,
2440- skipParamClause(pt.typedArgs().tpes, targs.tpes), resType)
2473+ warnOnPriorityChange(candidates, found) :
2474+ resolveMapped(_, skipParamClause(pt.typedArgs().tpes, targs.tpes), resType, srcPos )
24412475 case pt @ FunProto (_, resType : FunOrPolyProto ) =>
24422476 // try to narrow further with snd argument list
2443- resolveMapped(found,
2444- skipParamClause(pt.typedArgs().tpes, Nil ), resType)
2477+ warnOnPriorityChange(candidates, found) :
2478+ resolveMapped(_, skipParamClause(pt.typedArgs().tpes, Nil ), resType, srcPos )
24452479 case _ =>
24462480 // prefer alternatives that need no eta expansion
24472481 val noCurried = alts.filterConserve(! resultIsMethod(_))
24482482 val noCurriedCount = noCurried.length
24492483 if noCurriedCount == 1 then
24502484 noCurried
24512485 else if noCurriedCount > 1 && noCurriedCount < alts.length then
2452- resolveOverloaded1(noCurried, pt)
2486+ resolveOverloaded1(noCurried, pt, srcPos )
24532487 else
24542488 // prefer alternatves that match without default parameters
24552489 val noDefaults = alts.filterConserve(! _.symbol.hasDefaultParams)
24562490 val noDefaultsCount = noDefaults.length
24572491 if noDefaultsCount == 1 then
24582492 noDefaults
24592493 else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
2460- resolveOverloaded1(noDefaults, pt)
2494+ resolveOverloaded1(noDefaults, pt, srcPos )
24612495 else if deepPt ne pt then
24622496 // try again with a deeper known expected type
2463- resolveOverloaded1(alts, deepPt)
2497+ resolveOverloaded1(alts, deepPt, srcPos )
24642498 else
24652499 candidates
24662500 }
@@ -2494,7 +2528,7 @@ trait Applications extends Compatibility {
24942528 * type is mapped with `f`, alternatives with non-existing types or symbols are dropped, and the
24952529 * expected type is `pt`. Map the results back to the original alternatives.
24962530 */
2497- def resolveMapped (alts : List [TermRef ], f : TermRef => Type , pt : Type )(using Context ): List [TermRef ] =
2531+ def resolveMapped (alts : List [TermRef ], f : TermRef => Type , pt : Type , srcPos : SrcPos )(using Context ): List [TermRef ] =
24982532 val reverseMapping = alts.flatMap { alt =>
24992533 val t = f(alt)
25002534 if t.exists && alt.symbol.exists then
@@ -2517,7 +2551,7 @@ trait Applications extends Compatibility {
25172551 }
25182552 val mapped = reverseMapping.map(_._1)
25192553 overload.println(i " resolve mapped: ${mapped.map(_.widen)}%, % with $pt" )
2520- resolveOverloaded(mapped, pt)(using ctx.retractMode(Mode .SynthesizeExtMethodReceiver ))
2554+ resolveOverloaded(mapped, pt, srcPos )(using ctx.retractMode(Mode .SynthesizeExtMethodReceiver ))
25212555 .map(reverseMapping.toMap)
25222556
25232557 /** Try to typecheck any arguments in `pt` that are function values missing a
0 commit comments