@@ -48,15 +48,12 @@ object Implicits {
48
48
/** A common base class of contextual implicits and of-type implicits which
49
49
* represents a set of implicit references.
50
50
*/
51
- abstract class ImplicitRefs (initctx : Context ) {
52
- implicit val ctx : Context =
53
- if (initctx == NoContext ) initctx else initctx retractMode Mode .ImplicitsEnabled
54
-
51
+ abstract class ImplicitRefs extends Showable {
55
52
/** The nesting level of this context. Non-zero only in ContextialImplicits */
56
53
def level : Int = 0
57
54
58
55
/** The implicit references */
59
- def refs : List [TermRef ]
56
+ def refs ( implicit ctx : Context ) : List [TermRef ]
60
57
61
58
/** Return those references in `refs` that are compatible with type `pt`. */
62
59
protected def filterMatching (pt : Type )(implicit ctx : Context ): List [Candidate ] = track(" filterMatching" ) {
@@ -131,67 +128,80 @@ object Implicits {
131
128
}
132
129
133
130
if (refs.isEmpty) Nil
134
- else refs.filter(refMatches(_)(ctx.fresh.addMode(Mode .TypevarsMissContext ).setExploreTyperState)) // create a defensive copy of ctx to avoid constraint pollution
135
- .map(Candidate (_, level))
131
+ else {
132
+ val filteringCtx = ctx.fresh
133
+ .retractMode(Mode .ImplicitsEnabled )
134
+ .addMode(Mode .TypevarsMissContext )
135
+ .setExploreTyperState // create a defensive copy of ctx to avoid constraint pollution
136
+ refs.filter(refMatches(_)(filteringCtx)).map(Candidate (_, level))
137
+ }
136
138
}
139
+
140
+ def toText (printer : Printer ): Text = printer.toText(this )
137
141
}
138
142
139
143
/** The implicit references coming from the implicit scope of a type.
140
144
* @param tp the type determining the implicit scope
141
145
* @param companionRefs the companion objects in the implicit scope.
142
146
*/
143
- class OfTypeImplicits (tp : Type , val companionRefs : TermRefSet )(initctx : Context ) extends ImplicitRefs (initctx) {
144
- assert(initctx.typer != null )
145
- lazy val refs : List [TermRef ] = {
146
- val buf = new mutable.ListBuffer [TermRef ]
147
- for (companion <- companionRefs) buf ++= companion.implicitMembers
148
- buf.toList
147
+ class OfTypeImplicits (val tp : Type , val companionRefs : TermRefSet ) extends ImplicitRefs {
148
+ private [this ] var myRefs : List [TermRef ] = _
149
+ def refs (implicit ctx : Context ): List [TermRef ] = {
150
+ if (myRefs == null ) {
151
+ val buf = new mutable.ListBuffer [TermRef ]
152
+ for (companion <- companionRefs) buf ++= companion.implicitMembers
153
+ myRefs = buf.toList
154
+ }
155
+ myRefs
149
156
}
150
157
158
+ private [this ] var myEligible : List [Candidate ] = _
151
159
/** The candidates that are eligible for expected type `tp` */
152
- lazy val eligible : List [Candidate ] =
153
- /* >|>*/ track(" eligible in tpe" ) /* <|<*/ {
154
- /* >|>*/ ctx.traceIndented(i " eligible( $tp), companions = ${companionRefs.toList}%, % " , implicitsDetailed, show = true ) /* <|<*/ {
155
- if (refs.nonEmpty && monitored) record(s " check eligible refs in tpe " , refs.length)
156
- filterMatching(tp)
160
+ def eligible (implicit ctx : Context ): List [Candidate ] = {
161
+ if (myEligible == null ) {
162
+ /* >|>*/ track(" eligible in tpe" ) /* <|<*/ {
163
+ /* >|>*/ ctx.traceIndented(i " eligible( $tp), companions = ${companionRefs.toList}%, % " , implicitsDetailed, show = true ) /* <|<*/ {
164
+ if (refs.nonEmpty && monitored) record(s " check eligible refs in tpe " , refs.length)
165
+ myEligible = filterMatching(tp)
166
+ }
157
167
}
158
168
}
159
-
160
- override def toString =
161
- i " OfTypeImplicits( $tp), companions = ${companionRefs.toList}%, %; refs = $refs%, %. "
169
+ myEligible
170
+ }
162
171
}
163
172
164
173
/** The implicit references coming from the context.
165
- * @param refs the implicit references made visible by the current context.
174
+ * @param myRefs the implicit references made visible by the current context.
166
175
* Note: The name of the reference might be different from the name of its symbol.
167
176
* In the case of a renaming import a => b, the name of the reference is the renamed
168
177
* name, b, whereas the name of the symbol is the original name, a.
169
- * @param outerCtx the next outer context that makes visible further implicits
170
178
*/
171
- class ContextualImplicits (val refs : List [TermRef ], val outerImplicits : ContextualImplicits )( initctx : Context ) extends ImplicitRefs (initctx) {
179
+ class ContextualImplicits (myRefs : List [TermRef ], val outerImplicits : ContextualImplicits , private val ictx : Context ) extends ImplicitRefs {
172
180
private val eligibleCache = new mutable.AnyRefMap [Type , List [Candidate ]]
173
181
182
+ override def refs (implicit ctx : Context ) = myRefs
183
+
174
184
/** The level increases if current context has a different owner or scope than
175
185
* the context of the next-outer ImplicitRefs. This is however disabled under
176
186
* Scala2 mode, since we do not want to change the implicit disambiguation then.
177
187
*/
178
188
override val level : Int =
179
189
if (outerImplicits == null ) 1
180
- else if (ctx .scala2Mode ||
181
- (ctx .owner eq outerImplicits.ctx .owner) &&
182
- (ctx .scope eq outerImplicits.ctx .scope)) outerImplicits.level
190
+ else if (ictx .scala2Mode ||
191
+ (ictx .owner eq outerImplicits.ictx .owner) &&
192
+ (ictx .scope eq outerImplicits.ictx .scope)) outerImplicits.level
183
193
else outerImplicits.level + 1
184
194
185
195
/** Is this the outermost implicits? This is the case if it either the implicits
186
196
* of NoContext, or the last one before it.
187
197
*/
188
- private def isOuterMost = {
198
+ def isOuterMost = {
189
199
val finalImplicits = NoContext .implicits
190
200
(this eq finalImplicits) || (outerImplicits eq finalImplicits)
191
201
}
192
202
193
203
/** The implicit references that are eligible for type `tp`. */
194
- def eligible (tp : Type ): List [Candidate ] = /* >|>*/ track(s " eligible in ctx " ) /* <|<*/ {
204
+ def eligible (tp : Type )( implicit ctx : Context ) : List [Candidate ] = /* >|>*/ track(s " eligible in ctx " ) /* <|<*/ {
195
205
if (tp.hash == NotCached ) computeEligible(tp)
196
206
else eligibleCache get tp match {
197
207
case Some (eligibles) =>
@@ -203,7 +213,7 @@ object Implicits {
203
213
if (monitored) record(s " elided eligible refs " , elided(this ))
204
214
eligibles
205
215
case None =>
206
- if (ctx eq NoContext ) Nil
216
+ if (ictx eq NoContext ) Nil
207
217
else {
208
218
val savedEphemeral = ctx.typerState.ephemeral
209
219
ctx.typerState.ephemeral = false
@@ -217,8 +227,8 @@ object Implicits {
217
227
}
218
228
}
219
229
220
- private def computeEligible (tp : Type ): List [Candidate ] = /* >|>*/ ctx.traceIndented(i " computeEligible $tp in $refs%, % " , implicitsDetailed) /* <|<*/ {
221
- if (monitored) record(s " check eligible refs in ctx " , refs.length)
230
+ private def computeEligible (tp : Type )( implicit ctx : Context ) : List [Candidate ] = /* >|>*/ ctx.traceIndented(i " computeEligible $tp in $refs%, % " , implicitsDetailed) /* <|<*/ {
231
+ if (monitored) record(s " check eligible refs in ictx " , refs.length)
222
232
val ownEligible = filterMatching(tp)
223
233
if (isOuterMost) ownEligible
224
234
else ownEligible ::: {
@@ -227,21 +237,16 @@ object Implicits {
227
237
}
228
238
}
229
239
230
- override def toString = {
231
- val own = i " (implicits: $refs%, %) "
232
- if (isOuterMost) own else own + " \n " + outerImplicits
233
- }
234
-
235
240
/** This context, or a copy, ensuring root import from symbol `root`
236
241
* is not present in outer implicits.
237
242
*/
238
243
def exclude (root : Symbol ): ContextualImplicits =
239
244
if (this == NoContext .implicits) this
240
245
else {
241
246
val outerExcluded = outerImplicits exclude root
242
- if (ctx .importInfo.site.termSymbol == root) outerExcluded
247
+ if (ictx .importInfo.site(ictx) .termSymbol(ictx) == root) outerExcluded
243
248
else if (outerExcluded eq outerImplicits) this
244
- else new ContextualImplicits (refs , outerExcluded)(ctx )
249
+ else new ContextualImplicits (myRefs , outerExcluded, ictx )
245
250
}
246
251
}
247
252
@@ -355,14 +360,8 @@ trait ImplicitRunInfo { self: RunInfo =>
355
360
356
361
private val implicitScopeCache = mutable.AnyRefMap [Type , OfTypeImplicits ]()
357
362
358
- /** The implicit scope of a type `tp`
359
- * @param liftingCtx A context to be used when computing the class symbols of
360
- * a type. Types may contain type variables with their instances
361
- * recorded in the current context. To find out the instance of
362
- * a type variable, we need the current context, the current
363
- * runinfo context does not do.
364
- */
365
- def implicitScope (rootTp : Type , liftingCtx : Context ): OfTypeImplicits = {
363
+ /** The implicit scope of a type `tp` */
364
+ def implicitScope (rootTp : Type )(implicit ctx : Context ): OfTypeImplicits = {
366
365
367
366
val seen : mutable.Set [Type ] = mutable.Set ()
368
367
val incomplete : mutable.Set [Type ] = mutable.Set ()
@@ -374,7 +373,6 @@ trait ImplicitRunInfo { self: RunInfo =>
374
373
* abstract types are eliminated.
375
374
*/
376
375
object liftToClasses extends TypeMap {
377
- override implicit protected val ctx : Context = liftingCtx
378
376
override def stopAtStatic = true
379
377
def apply (tp : Type ) = tp match {
380
378
case tp : TypeRef if tp.symbol.isAbstractOrAliasType =>
@@ -440,7 +438,7 @@ trait ImplicitRunInfo { self: RunInfo =>
440
438
if (companion.exists) addRef(companion.valRef)
441
439
cls.classParents foreach addParentScope
442
440
}
443
- tp.classSymbols(liftingCtx) foreach addClassScope
441
+ tp.classSymbols foreach addClassScope
444
442
case _ =>
445
443
// We exclude lower bounds to conform to SLS 7.2:
446
444
// "The parts of a type T are: [...] if T is an abstract type, the parts of its upper bound"
@@ -466,7 +464,8 @@ trait ImplicitRunInfo { self: RunInfo =>
466
464
iscope(liftedTp, isLifted = true ).companionRefs
467
465
else
468
466
collectCompanions(tp)
469
- val result = new OfTypeImplicits (tp, refs)(ctx)
467
+ val result = new OfTypeImplicits (tp, refs)
468
+
470
469
if (ctx.typerState.ephemeral)
471
470
record(" ephemeral cache miss: implicitScope" )
472
471
else if (canCache &&
@@ -600,7 +599,7 @@ trait Implicits { self: Typer =>
600
599
def lazyImplicitCtx (lazyImplicit : Symbol ): Context = {
601
600
val lctx = ctx.fresh
602
601
for (delayedRef <- ctx.property(DelayedImplicit ))
603
- lctx.setImplicits(new ContextualImplicits (delayedRef :: Nil , ctx.implicits)( ctx))
602
+ lctx.setImplicits(new ContextualImplicits (delayedRef :: Nil , ctx.implicits, ctx))
604
603
lctx.setProperty(DelayedImplicit , lazyImplicit.termRef)
605
604
}
606
605
@@ -900,7 +899,7 @@ trait Implicits { self: Typer =>
900
899
}
901
900
}
902
901
903
- def implicitScope (tp : Type ): OfTypeImplicits = ctx.runInfo.implicitScope(tp, ctx )
902
+ def implicitScope (tp : Type ): OfTypeImplicits = ctx.runInfo.implicitScope(tp)
904
903
}
905
904
906
905
final class ExplainedImplicitSearch (pt : Type , argument : Tree , pos : Position )(implicit ctx : Context )
0 commit comments