Skip to content

Commit 0827db2

Browse files
committed
Cache alias implicits with lazy vals
1 parent 65d956e commit 0827db2

File tree

1 file changed

+23
-51
lines changed

1 file changed

+23
-51
lines changed

compiler/src/dotty/tools/dotc/transform/CacheAliasImplicits.scala

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,18 @@ object CacheAliasImplicits {
2727
* is cached. It applies to all alias implicits that have neither type parameters
2828
* nor a given clause. Example: The alias
2929
*
30-
* implicit a for TC = rhs
30+
* given a as TC = rhs
3131
*
32-
* is expanded before this phase
32+
* is expanded before this phase to:
3333
*
3434
* implicit def a: TC = rhs
3535
*
3636
* It is then expanded further as follows:
3737
*
38-
* 1. If `rhs` is a simple name `x` (possibly with a `this.` prefix), leave the definition as is.
39-
* 2. Otherwise, if `rhs` is a pure path, replace the definition with
38+
* 1. If `rhs` is a simple name `x` (possibly with a `this.` prefix) that
39+
* refers to a value, leave it as is.
4040
*
41-
* implicit val a: TC = rhs
42-
*
43-
* 3. Otherwise, if `TC` is a reference type, replace the definition with
44-
*
45-
* private[this] var a$_cache: TC = null
46-
* implicit def a: TC = { if (a$_cache == null) a$_cache = rhs; a$_cache }
47-
*
48-
* 4. Otherwise `TC` is a value type. Replace the definition with
41+
* 2. Otherwise, replace the definition with
4942
*
5043
* lazy implicit val a: TC = rhs
5144
*/
@@ -56,47 +49,26 @@ class CacheAliasImplicits extends MiniPhase with IdentityDenotTransformer { this
5649

5750
override def transformDefDef(tree: DefDef)(implicit ctx: Context): Tree = {
5851
val sym = tree.symbol
59-
sym.info match {
60-
case ExprType(rhsType) if sym.is(Given, butNot = CacheAliasImplicits.NoCacheFlags) =>
61-
// If rhs is a simple TermRef, leave a def.
62-
tree.rhs.tpe match {
63-
case TermRef(pre, _) =>
64-
pre match {
65-
case NoPrefix => return tree
66-
case pre: ThisType if pre.cls == ctx.owner.enclosingClass => return tree
67-
case _ =>
68-
}
69-
case _ =>
52+
val rhsType = tree.rhs.tpe
53+
val isCached = sym.info match {
54+
case _: ExprType if sym.is(Given, butNot = CacheAliasImplicits.NoCacheFlags) =>
55+
rhsType match {
56+
case TermRef(NoPrefix, _)
57+
if rhsType.isStable => false
58+
case TermRef(pre: ThisType, _)
59+
if rhsType.isStable && pre.cls == sym.owner.enclosingClass => false
60+
case _ => true
7061
}
71-
def makeVal(additionalFlags: FlagSet) = {
72-
sym.copySymDenotation(
73-
initFlags = sym.flags &~ Method | additionalFlags,
74-
info = rhsType)
75-
.installAfter(thisPhase)
76-
cpy.ValDef(tree)(tree.name, tree.tpt, tree.rhs)
77-
}
78-
if (isPurePath(tree.rhs)) makeVal(EmptyFlags)
79-
else if (rhsType.classSymbol.isValueClass ||
80-
!erasure(rhsType).typeSymbol.derivesFrom(defn.ObjectClass)) makeVal(Lazy)
81-
else {
82-
val cacheFlags = if (ctx.owner.isClass) Private | Local | Mutable else Mutable
83-
val cacheSym =
84-
ctx.newSymbol(ctx.owner, CacheName(tree.name), cacheFlags, rhsType, coord = sym.coord)
85-
.enteredAfter(thisPhase)
86-
val cacheDef = ValDef(cacheSym, tpd.defaultValue(rhsType))
87-
val cachingDef = cpy.DefDef(tree)(rhs =
88-
Block(
89-
If(
90-
ref(cacheSym).select(defn.Any_==).appliedTo(nullLiteral),
91-
Assign(ref(cacheSym), tree.rhs),
92-
unitLiteral) :: Nil,
93-
ref(cacheSym)
94-
)
95-
)
96-
Thicket(cacheDef, cachingDef)
97-
}
98-
case _ => tree
62+
case _ => false
63+
}
64+
if (isCached) {
65+
sym.copySymDenotation(
66+
initFlags = sym.flags &~ Method | Lazy,
67+
info = rhsType)
68+
.installAfter(thisPhase)
69+
cpy.ValDef(tree)(tree.name, tree.tpt, tree.rhs)
9970
}
71+
else tree
10072
}
10173
}
10274

0 commit comments

Comments
 (0)