Skip to content

Commit 8059fce

Browse files
authored
Merge pull request #10520 from dotty-staging/change-deriving-givens
Generate lazy vals in deriving
2 parents 89871d8 + 3afbae9 commit 8059fce

File tree

5 files changed

+77
-117
lines changed

5 files changed

+77
-117
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class Compiler {
6666
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
6767
new ProtectedAccessors, // Add accessors for protected members
6868
new ExtensionMethods, // Expand methods of value classes with extension methods
69-
new CacheAliasImplicits, // Cache RHS of parameterless alias implicits
69+
new UncacheGivenAliases, // Avoid caching RHS of simple parameterless given aliases
7070
new ByNameClosures, // Expand arguments to by-name parameters to closures
7171
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
7272
new SpecializeApplyMethods, // Adds specialized methods to FunctionN

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

Lines changed: 0 additions & 110 deletions
This file was deleted.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import MegaPhase._
5+
import core.DenotTransformers.{IdentityDenotTransformer}
6+
import core.Symbols._
7+
import core.Contexts._
8+
import core.Types._
9+
import core.Flags._
10+
import core.StdNames.nme
11+
import core.Constants.Constant
12+
import core.Decorators._
13+
import core.TypeErasure.erasure
14+
import ast.tpd
15+
16+
object UncacheGivenAliases:
17+
val name: String = "uncacheGivenAliases"
18+
19+
/** This phase optimizes alias givens represented as lazy vals to be uncached
20+
* if that does not change runtime behavior. A definition does not need to be
21+
* cached if its right hand side has a stable type and is of one of them forms
22+
*
23+
* this
24+
* this.y
25+
* y
26+
*/
27+
class UncacheGivenAliases extends MiniPhase with IdentityDenotTransformer:
28+
thisPhase =>
29+
import tpd._
30+
31+
override def phaseName: String = UncacheGivenAliases.name
32+
33+
private def needsCache(sym: Symbol, rhs: Tree)(using Context): Boolean = rhs.tpe match
34+
case rhsTpe @ TermRef(NoPrefix, _)
35+
if rhsTpe.isStable => false
36+
case rhsTpe @ TermRef(pre: ThisType, _)
37+
if rhsTpe.isStable && pre.cls == sym.owner.enclosingClass => false
38+
case rhsTpe: ThisType => false
39+
case _ => true
40+
41+
/** Transform
42+
*
43+
* lazy given val x = rhs
44+
*
45+
* to
46+
*
47+
* def x = rhs
48+
*
49+
* provided `rhs` has a stable type and is of one of them forms
50+
*
51+
* this
52+
* this.y
53+
* y
54+
*/
55+
override def transformValDef(tree: ValDef)(using Context): Tree =
56+
val sym = tree.symbol
57+
if sym.isAllOf(Given, Lazy) && !needsCache(sym, tree.rhs) then
58+
sym.copySymDenotation(
59+
initFlags = sym.flags &~ Lazy | Method,
60+
info = ExprType(sym.info))
61+
.installAfter(thisPhase)
62+
cpy.DefDef(tree)(tree.name, Nil, Nil, tree.tpt, tree.rhs)
63+
else tree
64+
end UncacheGivenAliases
65+
66+

compiler/src/dotty/tools/dotc/typer/Deriving.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ trait Deriving {
5454
// If we set the Synthetic flag here widenGiven will widen too far and the
5555
// derived instance will have too low a priority to be selected over a freshly
5656
// derived instance at the summoning site.
57+
val flags = if info.isInstanceOf[MethodOrPoly] then Given | Method else Given | Lazy
5758
synthetics +=
58-
newSymbol(ctx.owner, instanceName, Given | Method, info, coord = pos.span)
59+
newSymbol(ctx.owner, instanceName, flags, info, coord = pos.span)
5960
.entered
6061
}
6162

@@ -95,10 +96,12 @@ trait Deriving {
9596

9697
def addInstance(derivedParams: List[TypeSymbol], evidenceParamInfos: List[List[Type]], instanceTypes: List[Type]): Unit = {
9798
val resultType = typeClassType.appliedTo(instanceTypes)
98-
val methodOrExpr =
99-
if (evidenceParamInfos.isEmpty) ExprType(resultType)
99+
val monoInfo =
100+
if evidenceParamInfos.isEmpty then resultType
100101
else ImplicitMethodType(evidenceParamInfos.map(typeClassType.appliedTo), resultType)
101-
val derivedInfo = if (derivedParams.isEmpty) methodOrExpr else PolyType.fromParams(derivedParams, methodOrExpr)
102+
val derivedInfo =
103+
if derivedParams.isEmpty then monoInfo
104+
else PolyType.fromParams(derivedParams, monoInfo)
102105
addDerivedInstance(originalTypeClassType.typeSymbol.name, derivedInfo, derived.srcPos)
103106
}
104107

@@ -292,7 +295,8 @@ trait Deriving {
292295
}
293296

294297
def syntheticDef(sym: Symbol): Tree = inContext(ctx.fresh.setOwner(sym).setNewScope) {
295-
tpd.polyDefDef(sym.asTerm, typeclassInstance(sym))
298+
if sym.is(Method) then tpd.polyDefDef(sym.asTerm, typeclassInstance(sym))
299+
else tpd.ValDef(sym.asTerm, typeclassInstance(sym)(Nil)(Nil))
296300
}
297301

298302
synthetics.map(syntheticDef).toList

tests/semanticdb/metac.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ _empty_/Enums.Suits.Clubs. => case val static enum method Clubs
755755
_empty_/Enums.Suits.Diamonds. => case val static enum method Diamonds
756756
_empty_/Enums.Suits.Hearts. => case val static enum method Hearts
757757
_empty_/Enums.Suits.Spades. => case val static enum method Spades
758-
_empty_/Enums.Suits.derived$CanEqual(). => implicit method derived$CanEqual
758+
_empty_/Enums.Suits.derived$CanEqual. => implicit lazy val method derived$CanEqual
759759
_empty_/Enums.Suits.fromOrdinal(). => method fromOrdinal
760760
_empty_/Enums.Suits.fromOrdinal().(ordinal) => param ordinal
761761
_empty_/Enums.Suits.isBlack(). => method isBlack

0 commit comments

Comments
 (0)