@@ -2048,6 +2048,13 @@ trait Applications extends Compatibility {
2048
2048
def resolveOverloaded (alts : List [TermRef ], pt : Type )(using Context ): List [TermRef ] =
2049
2049
record(" resolveOverloaded" )
2050
2050
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
+
2051
2058
/** Is `alt` a method or polytype whose result type after the first value parameter
2052
2059
* section conforms to the expected type `resultType`? If `resultType`
2053
2060
* is a `IgnoredProto`, pick the underlying type instead.
@@ -2095,15 +2102,15 @@ trait Applications extends Compatibility {
2095
2102
pt match
2096
2103
case pt : FunProto =>
2097
2104
if pt.applyKind == ApplyKind .Using then
2098
- val alts0 = alts.filterConserve(_. widen.stripPoly.isImplicitMethod)
2105
+ val alts0 = alts.filterConserve(alt => widen(alt) .stripPoly.isImplicitMethod)
2099
2106
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)
2102
2109
case _ =>
2103
2110
2104
- var found = withoutMode(Mode .ImplicitsEnabled )(resolveOverloaded1(alts, pt))
2111
+ var found = withoutMode(Mode .ImplicitsEnabled )(resolveOverloaded1(alts, pt, altsWidenMap ))
2105
2112
if found.isEmpty && ctx.mode.is(Mode .ImplicitsEnabled ) then
2106
- found = resolveOverloaded1(alts, pt)
2113
+ found = resolveOverloaded1(alts, pt, altsWidenMap )
2107
2114
found match
2108
2115
case alt :: Nil => adaptByResult(alt, alts) :: Nil
2109
2116
case _ => found
@@ -2113,16 +2120,15 @@ trait Applications extends Compatibility {
2113
2120
* - the result is applied to value arguments and alternative is not a method, or
2114
2121
* - the result is applied to type arguments and alternative is not polymorphic
2115
2122
*/
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 ]
2119
2126
case _ => false
2120
- }
2121
2127
2122
2128
/** Replace each alternative by its apply members where necessary */
2123
2129
def applyMembers (alt : TermRef ): List [TermRef ] =
2124
2130
if (tryApply(alt)) {
2125
- val qual = alt. widen match {
2131
+ val qual = widen(alt) match {
2126
2132
case pt : PolyType =>
2127
2133
wildApprox(pt.resultType)
2128
2134
case _ =>
@@ -2150,10 +2156,12 @@ trait Applications extends Compatibility {
2150
2156
* It might be called twice from the public `resolveOverloaded` method, once with
2151
2157
* implicits and SAM conversions enabled, and once without.
2152
2158
*/
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 ] =
2154
2160
trace(i " resolve over $alts%, %, pt = $pt" , typr, show = true ) {
2155
2161
record(s " resolveOverloaded1 " , alts.length)
2156
2162
2163
+ def widen (ref : TermRef ): Type = altsWidenMap.getOrElseUpdate(ref, ref.widen)
2164
+
2157
2165
def isDetermined (alts : List [TermRef ]) = alts.isEmpty || alts.tail.isEmpty
2158
2166
2159
2167
/** The shape of given tree as a type; cannot handle named arguments. */
@@ -2197,7 +2205,7 @@ trait Applications extends Compatibility {
2197
2205
// If ref refers to a method whose parameter at index `idx` is a function type,
2198
2206
// the arity of that function, otherise -1.
2199
2207
def paramCount (ref : TermRef ) =
2200
- val formals = ref. widen.firstParamTypes
2208
+ val formals = widen(ref) .firstParamTypes
2201
2209
if formals.length > idx then
2202
2210
formals(idx).dealias match
2203
2211
case defn.FunctionNOf (args, _, _) => args.length
@@ -2222,7 +2230,7 @@ trait Applications extends Compatibility {
2222
2230
val candidates = pt match {
2223
2231
case pt @ FunProto (args, resultType) =>
2224
2232
val numArgs = args.length
2225
- def sizeFits (alt : TermRef ): Boolean = alt. widen.stripPoly match {
2233
+ def sizeFits (alt : TermRef ): Boolean = widen(alt) .stripPoly match {
2226
2234
case tp : MethodType =>
2227
2235
val ptypes = tp.paramInfos
2228
2236
val numParams = ptypes.length
@@ -2277,12 +2285,12 @@ trait Applications extends Compatibility {
2277
2285
val alts1 = alts.filterConserve(pt.canInstantiate)
2278
2286
if isDetermined(alts1) then alts1
2279
2287
else
2280
- def withinBounds (alt : TermRef ) = alt. widen match
2288
+ def withinBounds (alt : TermRef ) = widen(alt) match
2281
2289
case tp : PolyType =>
2282
2290
TypeOps .boundsViolations(targs1, tp.paramInfos, _.substParams(tp, _), NoType ).isEmpty
2283
2291
val alts2 = alts1.filter(withinBounds)
2284
2292
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)
2286
2294
2287
2295
case pt =>
2288
2296
val compat = alts.filterConserve(normalizedCompatible(_, pt, keepConstraint = false ))
@@ -2327,9 +2335,9 @@ trait Applications extends Compatibility {
2327
2335
case _ =>
2328
2336
NoType
2329
2337
}
2330
- skip(alt. widen)
2338
+ skip(widen(alt) )
2331
2339
2332
- def resultIsMethod (tp : Type ): Boolean = tp. widen.stripPoly match
2340
+ def resultIsMethod (tp : TermRef ): Boolean = widen(tp) .stripPoly match
2333
2341
case tp : MethodType => stripInferrable(tp.resultType).isInstanceOf [MethodType ]
2334
2342
case _ => false
2335
2343
@@ -2359,18 +2367,18 @@ trait Applications extends Compatibility {
2359
2367
if noCurriedCount == 1 then
2360
2368
noCurried
2361
2369
else if noCurriedCount > 1 && noCurriedCount < alts.length then
2362
- resolveOverloaded1(noCurried, pt)
2370
+ resolveOverloaded1(noCurried, pt, altsWidenMap )
2363
2371
else
2364
2372
// prefer alternatves that match without default parameters
2365
2373
val noDefaults = alts.filterConserve(! _.symbol.hasDefaultParams)
2366
2374
val noDefaultsCount = noDefaults.length
2367
2375
if noDefaultsCount == 1 then
2368
2376
noDefaults
2369
2377
else if noDefaultsCount > 1 && noDefaultsCount < alts.length then
2370
- resolveOverloaded1(noDefaults, pt)
2378
+ resolveOverloaded1(noDefaults, pt, altsWidenMap )
2371
2379
else if deepPt ne pt then
2372
2380
// try again with a deeper known expected type
2373
- resolveOverloaded1(alts, deepPt)
2381
+ resolveOverloaded1(alts, deepPt, altsWidenMap )
2374
2382
else
2375
2383
candidates
2376
2384
}
0 commit comments