@@ -2048,6 +2048,13 @@ trait Applications extends Compatibility {
20482048 def resolveOverloaded (alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
20492049 record(" resolveOverloaded" )
20502050
2051+ // A local cache for widenings of alternatives.
2052+ // If a type is provisonal, its denotation will not cached.
2053+ // Hence, using `widen` on provisional types everywhere will recompute denotations repeatedly.
2054+ // Given the denotation will not change in this part, we can safely cache the result.
2055+ val altsWidenMap = mutable.HashMap .empty[TermRef , Type ]
2056+ def widen (ref : TermRef ): Type = altsWidenMap.getOrElseUpdate(ref, ref.widen)
2057+
20512058 /** Is `alt` a method or polytype whose result type after the first value parameter
20522059 * section conforms to the expected type `resultType`? If `resultType`
20532060 * is a `IgnoredProto`, pick the underlying type instead.
@@ -2095,15 +2102,15 @@ trait Applications extends Compatibility {
20952102 pt match
20962103 case pt : FunProto =>
20972104 if pt.applyKind == ApplyKind .Using then
2098- val alts0 = alts.filterConserve(_. widen.stripPoly.isImplicitMethod)
2105+ val alts0 = alts.filterConserve(alt => widen(alt) .stripPoly.isImplicitMethod)
20992106 if alts0 ne alts then return resolve(alts0)
2100- else if alts.exists(_. widen.stripPoly.isContextualMethod) then
2101- return resolveMapped(alts, alt => stripImplicit(alt. widen), pt)
2107+ else if alts.exists(alt => widen(alt) .stripPoly.isContextualMethod) then
2108+ return resolveMapped(alts, alt => stripImplicit(widen(alt) ), pt)
21022109 case _ =>
21032110
2104- var found = withoutMode(Mode .ImplicitsEnabled )(resolveOverloaded1(alts, pt))
2111+ var found = withoutMode(Mode .ImplicitsEnabled )(resolveOverloaded1(alts, pt, altsWidenMap ))
21052112 if found.isEmpty && ctx.mode.is(Mode .ImplicitsEnabled ) then
2106- found = resolveOverloaded1(alts, pt)
2113+ found = resolveOverloaded1(alts, pt, altsWidenMap )
21072114 found match
21082115 case alt :: Nil => adaptByResult(alt, alts) :: Nil
21092116 case _ => found
@@ -2113,16 +2120,15 @@ trait Applications extends Compatibility {
21132120 * - the result is applied to value arguments and alternative is not a method, or
21142121 * - the result is applied to type arguments and alternative is not polymorphic
21152122 */
2116- val tryApply : Type => Boolean = alt => pt match {
2117- case pt : FunProto => ! alt. widen.stripPoly.isInstanceOf [MethodType ]
2118- case pt : PolyProto => ! alt. widen.isInstanceOf [PolyType ]
2123+ def tryApply ( alt : TermRef ) : Boolean = pt match
2124+ case pt : FunProto => ! widen(alt) .stripPoly.isInstanceOf [MethodType ]
2125+ case pt : PolyProto => ! widen(alt) .isInstanceOf [PolyType ]
21192126 case _ => false
2120- }
21212127
21222128 /** Replace each alternative by its apply members where necessary */
21232129 def applyMembers (alt : TermRef ): List [TermRef ] =
21242130 if (tryApply(alt)) {
2125- val qual = alt. widen match {
2131+ val qual = widen(alt) match {
21262132 case pt : PolyType =>
21272133 wildApprox(pt.resultType)
21282134 case _ =>
@@ -2150,10 +2156,12 @@ trait Applications extends Compatibility {
21502156 * It might be called twice from the public `resolveOverloaded` method, once with
21512157 * implicits and SAM conversions enabled, and once without.
21522158 */
2153- private def resolveOverloaded1 (alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
2159+ private def resolveOverloaded1 (alts : List [TermRef ], pt : Type , altsWidenMap : mutable. HashMap [ TermRef , Type ] )(using Context ): List [TermRef ] =
21542160 trace(i " resolve over $alts%, %, pt = $pt" , typr, show = true ) {
21552161 record(s " resolveOverloaded1 " , alts.length)
21562162
2163+ def widen (ref : TermRef ): Type = altsWidenMap.getOrElseUpdate(ref, ref.widen)
2164+
21572165 def isDetermined (alts : List [TermRef ]) = alts.isEmpty || alts.tail.isEmpty
21582166
21592167 /** The shape of given tree as a type; cannot handle named arguments. */
@@ -2197,7 +2205,7 @@ trait Applications extends Compatibility {
21972205 // If ref refers to a method whose parameter at index `idx` is a function type,
21982206 // the arity of that function, otherise -1.
21992207 def paramCount (ref : TermRef ) =
2200- val formals = ref. widen.firstParamTypes
2208+ val formals = widen(ref) .firstParamTypes
22012209 if formals.length > idx then
22022210 formals(idx).dealias match
22032211 case defn.FunctionNOf (args, _, _) => args.length
@@ -2222,7 +2230,7 @@ trait Applications extends Compatibility {
22222230 val candidates = pt match {
22232231 case pt @ FunProto (args, resultType) =>
22242232 val numArgs = args.length
2225- def sizeFits (alt : TermRef ): Boolean = alt. widen.stripPoly match {
2233+ def sizeFits (alt : TermRef ): Boolean = widen(alt) .stripPoly match {
22262234 case tp : MethodType =>
22272235 val ptypes = tp.paramInfos
22282236 val numParams = ptypes.length
@@ -2277,12 +2285,12 @@ trait Applications extends Compatibility {
22772285 val alts1 = alts.filterConserve(pt.canInstantiate)
22782286 if isDetermined(alts1) then alts1
22792287 else
2280- def withinBounds (alt : TermRef ) = alt. widen match
2288+ def withinBounds (alt : TermRef ) = widen(alt) match
22812289 case tp : PolyType =>
22822290 TypeOps .boundsViolations(targs1, tp.paramInfos, _.substParams(tp, _), NoType ).isEmpty
22832291 val alts2 = alts1.filter(withinBounds)
22842292 if isDetermined(alts2) then alts2
2285- else resolveMapped(alts1, _. widen.appliedTo(targs1.tpes), pt1)
2293+ else resolveMapped(alts1, alt => widen(alt) .appliedTo(targs1.tpes), pt1)
22862294
22872295 case pt =>
22882296 val compat = alts.filterConserve(normalizedCompatible(_, pt, keepConstraint = false ))
@@ -2327,9 +2335,9 @@ trait Applications extends Compatibility {
23272335 case _ =>
23282336 NoType
23292337 }
2330- skip(alt. widen)
2338+ skip(widen(alt) )
23312339
2332- def resultIsMethod (tp : Type ): Boolean = tp. widen.stripPoly match
2340+ def resultIsMethod (tp : TermRef ): Boolean = widen(tp) .stripPoly match
23332341 case tp : MethodType => stripInferrable(tp.resultType).isInstanceOf [MethodType ]
23342342 case _ => false
23352343
@@ -2359,18 +2367,18 @@ trait Applications extends Compatibility {
23592367 if noCurriedCount == 1 then
23602368 noCurried
23612369 else if noCurriedCount > 1 && noCurriedCount < alts.length then
2362- resolveOverloaded1(noCurried, pt)
2370+ resolveOverloaded1(noCurried, pt, altsWidenMap )
23632371 else
23642372 // prefer alternatves that match without default parameters
23652373 val noDefaults = alts.filterConserve(! _.symbol.hasDefaultParams)
23662374 val noDefaultsCount = noDefaults.length
23672375 if noDefaultsCount == 1 then
23682376 noDefaults
23692377 else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
2370- resolveOverloaded1(noDefaults, pt)
2378+ resolveOverloaded1(noDefaults, pt, altsWidenMap )
23712379 else if deepPt ne pt then
23722380 // try again with a deeper known expected type
2373- resolveOverloaded1(alts, deepPt)
2381+ resolveOverloaded1(alts, deepPt, altsWidenMap )
23742382 else
23752383 candidates
23762384 }
0 commit comments