Skip to content

Generate lazy vals in deriving #10520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class Compiler {
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
new ProtectedAccessors, // Add accessors for protected members
new ExtensionMethods, // Expand methods of value classes with extension methods
new CacheAliasImplicits, // Cache RHS of parameterless alias implicits
new UncacheGivenAliases, // Avoid caching RHS of simple parameterless given aliases
new ByNameClosures, // Expand arguments to by-name parameters to closures
new HoistSuperArgs, // Hoist complex arguments of supercalls to enclosing scope
new SpecializeApplyMethods, // Adds specialized methods to FunctionN
Expand Down
110 changes: 0 additions & 110 deletions compiler/src/dotty/tools/dotc/transform/CacheAliasImplicits.scala

This file was deleted.

66 changes: 66 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/UncacheGivenAliases.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package dotty.tools.dotc
package transform

import MegaPhase._
import core.DenotTransformers.{IdentityDenotTransformer}
import core.Symbols._
import core.Contexts._
import core.Types._
import core.Flags._
import core.StdNames.nme
import core.Constants.Constant
import core.Decorators._
import core.TypeErasure.erasure
import ast.tpd

object UncacheGivenAliases:
val name: String = "uncacheGivenAliases"

/** This phase optimizes alias givens represented as lazy vals to be uncached
* if that does not change runtime behavior. A definition does not need to be
* cached if its right hand side has a stable type and is of one of them forms
*
* this
* this.y
* y
*/
class UncacheGivenAliases extends MiniPhase with IdentityDenotTransformer:
thisPhase =>
import tpd._

override def phaseName: String = UncacheGivenAliases.name

private def needsCache(sym: Symbol, rhs: Tree)(using Context): Boolean = rhs.tpe match
case rhsTpe @ TermRef(NoPrefix, _)
if rhsTpe.isStable => false
case rhsTpe @ TermRef(pre: ThisType, _)
if rhsTpe.isStable && pre.cls == sym.owner.enclosingClass => false
case rhsTpe: ThisType => false
case _ => true

/** Transform
*
* lazy given val x = rhs
*
* to
*
* def x = rhs
*
* provided `rhs` has a stable type and is of one of them forms
*
* this
* this.y
* y
*/
override def transformValDef(tree: ValDef)(using Context): Tree =
val sym = tree.symbol
if sym.isAllOf(Given, Lazy) && !needsCache(sym, tree.rhs) then
sym.copySymDenotation(
initFlags = sym.flags &~ Lazy | Method,
info = ExprType(sym.info))
.installAfter(thisPhase)
cpy.DefDef(tree)(tree.name, Nil, Nil, tree.tpt, tree.rhs)
else tree
end UncacheGivenAliases


14 changes: 9 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/Deriving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ trait Deriving {
// If we set the Synthetic flag here widenGiven will widen too far and the
// derived instance will have too low a priority to be selected over a freshly
// derived instance at the summoning site.
val flags = if info.isInstanceOf[MethodOrPoly] then Given | Method else Given | Lazy
synthetics +=
newSymbol(ctx.owner, instanceName, Given | Method, info, coord = pos.span)
newSymbol(ctx.owner, instanceName, flags, info, coord = pos.span)
.entered
}

Expand Down Expand Up @@ -95,10 +96,12 @@ trait Deriving {

def addInstance(derivedParams: List[TypeSymbol], evidenceParamInfos: List[List[Type]], instanceTypes: List[Type]): Unit = {
val resultType = typeClassType.appliedTo(instanceTypes)
val methodOrExpr =
if (evidenceParamInfos.isEmpty) ExprType(resultType)
val monoInfo =
if evidenceParamInfos.isEmpty then resultType
else ImplicitMethodType(evidenceParamInfos.map(typeClassType.appliedTo), resultType)
val derivedInfo = if (derivedParams.isEmpty) methodOrExpr else PolyType.fromParams(derivedParams, methodOrExpr)
val derivedInfo =
if derivedParams.isEmpty then monoInfo
else PolyType.fromParams(derivedParams, monoInfo)
addDerivedInstance(originalTypeClassType.typeSymbol.name, derivedInfo, derived.srcPos)
}

Expand Down Expand Up @@ -292,7 +295,8 @@ trait Deriving {
}

def syntheticDef(sym: Symbol): Tree = inContext(ctx.fresh.setOwner(sym).setNewScope) {
tpd.polyDefDef(sym.asTerm, typeclassInstance(sym))
if sym.is(Method) then tpd.polyDefDef(sym.asTerm, typeclassInstance(sym))
else tpd.ValDef(sym.asTerm, typeclassInstance(sym)(Nil)(Nil))
}

synthetics.map(syntheticDef).toList
Expand Down
2 changes: 1 addition & 1 deletion tests/semanticdb/metac.expect
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ _empty_/Enums.Suits.Clubs. => case val static enum method Clubs
_empty_/Enums.Suits.Diamonds. => case val static enum method Diamonds
_empty_/Enums.Suits.Hearts. => case val static enum method Hearts
_empty_/Enums.Suits.Spades. => case val static enum method Spades
_empty_/Enums.Suits.derived$CanEqual(). => implicit method derived$CanEqual
_empty_/Enums.Suits.derived$CanEqual. => implicit lazy val method derived$CanEqual
_empty_/Enums.Suits.fromOrdinal(). => method fromOrdinal
_empty_/Enums.Suits.fromOrdinal().(ordinal) => param ordinal
_empty_/Enums.Suits.isBlack(). => method isBlack
Expand Down