@@ -2112,15 +2112,71 @@ trait Applications extends Compatibility {
21122112 }
21132113 }
21142114
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+
21152172 /** Resolve overloaded alternative `alts`, given expected type `pt`.
21162173 * Two trials: First, without implicits or SAM conversions enabled. Then,
21172174 * if the first finds no eligible candidates, with implicits and SAM conversions enabled.
21182175 * Each trial applies the `resolve` parameter.
21192176 */
21202177 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 ] =
21242180
21252181 /** Is `alt` a method or polytype whose result type after the first value parameter
21262182 * section conforms to the expected type `resultType`? If `resultType`
@@ -2157,7 +2213,7 @@ trait Applications extends Compatibility {
21572213 case Nil => chosen
21582214 case alt2 :: Nil => alt2
21592215 case alts2 =>
2160- resolveOverloaded(resolve)(alts2, pt, srcPos ) match {
2216+ resolveOverloaded(resolve)(alts2, pt) match {
21612217 case alt2 :: Nil => alt2
21622218 case _ => chosen
21632219 }
@@ -2224,7 +2280,7 @@ trait Applications extends Compatibility {
22242280 * It might be called twice from the public `resolveOverloaded` method, once with
22252281 * implicits and SAM conversions enabled, and once without.
22262282 */
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 ] =
22282284 trace(i " resolve over $alts%, %, pt = $pt" , typr, show = true ):
22292285 record(s " resolveOverloaded1 " , alts.length)
22302286
@@ -2414,7 +2470,7 @@ trait Applications extends Compatibility {
24142470 val alts3 = narrowByTrees(alts2, pt.typedArgs(normArg(alts2, _, _)), resultType)
24152471
24162472 resultType.deepenProto match
2417- case resultType : FunOrPolyProto =>
2473+ case resultType : FunOrPolyProto if scheme.isNewPriority =>
24182474 narrowByNextParamClause(resolveCandidates)(alts3, pt.typedArgs(), resultType)
24192475 .fallbackTo(alts3) // see comment in narrowByNextParamClause
24202476 case _ =>
@@ -2472,35 +2528,31 @@ trait Applications extends Compatibility {
24722528 val deepPt = pt.deepenProto
24732529 deepPt match
24742530 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)
24762533 case _ =>
24772534 // prefer alternatives that need no eta expansion
24782535 val noCurried = alts.filterConserve(! resultIsMethod(_))
24792536 val noCurriedCount = noCurried.length
24802537 if noCurriedCount == 1 then
24812538 noCurried
24822539 else if noCurriedCount > 1 && noCurriedCount < alts.length then
2483- resolveOverloaded1(noCurried, pt)
2540+ resolveOverloaded1(scheme)( noCurried, pt)
24842541 else
24852542 // prefer alternatves that match without default parameters
24862543 val noDefaults = alts.filterConserve(! _.symbol.hasDefaultParams)
24872544 val noDefaultsCount = noDefaults.length
24882545 if noDefaultsCount == 1 then
24892546 noDefaults
24902547 else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
2491- resolveOverloaded1(noDefaults, pt)
2548+ resolveOverloaded1(scheme)( noDefaults, pt)
24922549 else if deepPt ne pt then
24932550 // try again with a deeper known expected type
2494- resolveOverloaded1(alts, deepPt)
2551+ resolveOverloaded1(scheme)( alts, deepPt)
24952552 else
24962553 candidates
24972554 end resolveOverloaded2
24982555
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).
25042556 val candidates = resolveCandidates(alts, pt)
25052557 record(" resolveOverloaded.narrowedApplicable" , candidates.length)
25062558 resolveOverloaded2(candidates, pt)
0 commit comments