Skip to content

Commit a18b3fa

Browse files
committed
Merge pull request #495 from dotty-staging/refactor/SuperAccessors
Refactor/super accessors
2 parents 6d1138e + 2b3591c commit a18b3fa

23 files changed

+562
-533
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Contexts._
66
import Periods._
77
import Symbols._
88
import Scopes._
9-
import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks, InstChecks}
9+
import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks}
1010
import reporting.ConsoleReporter
1111
import dotty.tools.dotc.core.Phases.Phase
1212
import dotty.tools.dotc.transform._
@@ -38,11 +38,9 @@ class Compiler {
3838
def phases: List[List[Phase]] =
3939
List(
4040
List(new FrontEnd),
41-
List(new InstChecks),
42-
List(new FirstTransform,
43-
new SyntheticMethods),
44-
List(new SuperAccessors),
45-
List(new Pickler), // Pickler needs to come last in a group since it should not pickle trees generated later
41+
List(new PostTyper),
42+
List(new Pickler),
43+
List(new FirstTransform),
4644
List(new RefChecks,
4745
new ElimRepeated,
4846
new NormalizeFlags,

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
244244
}
245245

246246
def Import(expr: Tree, selectors: List[untpd.Tree])(implicit ctx: Context): Import =
247-
ta.assignType(untpd.Import(expr, selectors), ctx.newImportSymbol(expr))
247+
ta.assignType(untpd.Import(expr, selectors), ctx.newImportSymbol(ctx.owner, expr))
248248

249249
def PackageDef(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef =
250250
ta.assignType(untpd.PackageDef(pid, stats), pid)

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ object SymDenotations {
211211
final def hasAnnotation(cls: Symbol)(implicit ctx: Context) =
212212
dropOtherAnnotations(annotations, cls).nonEmpty
213213

214+
/** Apply transform `f` to all annotations of this denotation */
215+
final def transformAnnotations(f: Annotation => Annotation)(implicit ctx: Context): Unit =
216+
annotations = annotations.mapConserve(f)
217+
214218
/** Optionally, the annotation matching the given class symbol */
215219
final def getAnnotation(cls: Symbol)(implicit ctx: Context): Option[Annotation] =
216220
dropOtherAnnotations(annotations, cls) match {

src/dotty/tools/dotc/core/Symbols.scala

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ trait Symbols { this: Context =>
228228
newSymbol(cls, nme.localDummyName(cls), EmptyFlags, NoType)
229229

230230
/** Create an import symbol pointing back to given qualifier `expr`. */
231-
def newImportSymbol(expr: Tree, coord: Coord = NoCoord) =
232-
newSymbol(NoSymbol, nme.IMPORT, EmptyFlags, ImportType(expr), coord = coord)
231+
def newImportSymbol(owner: Symbol, expr: Tree, coord: Coord = NoCoord) =
232+
newSymbol(owner, nme.IMPORT, EmptyFlags, ImportType(expr), coord = coord)
233233

234234
/** Create a class constructor symbol for given class `cls`. */
235235
def newConstructor(cls: ClassSymbol, flags: FlagSet, paramNames: List[TermName], paramTypes: List[Type], privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord) =
@@ -558,13 +558,17 @@ object Symbols {
558558
ctx.newSymbol(owner, name, flags, info, privateWithin, coord)
559559
}
560560

561-
implicit def defn(implicit ctx: Context): Definitions = ctx.definitions
562-
563561
/** Makes all denotation operations available on symbols */
564562
implicit def toDenot(sym: Symbol)(implicit ctx: Context): SymDenotation = sym.denot
565563

566564
/** Makes all class denotations available on class symbols */
567565
implicit def toClassDenot(cls: ClassSymbol)(implicit ctx: Context): ClassDenotation = cls.classDenot
568566

567+
/** The Definitions object */
568+
def defn(implicit ctx: Context): Definitions = ctx.definitions
569+
570+
/** The current class */
571+
def currentClass(implicit ctx: Context): ClassSymbol = ctx.owner.enclosingClass.asClass
572+
569573
var stubs: List[Symbol] = Nil // diagnostic
570574
}

src/dotty/tools/dotc/core/TypeApplications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ class TypeApplications(val self: Type) extends AnyVal {
279279
default
280280
}
281281
}
282-
282+
283283
/** Translate a type of the form From[T] to To[T], keep other types as they are.
284284
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
285285
*/

src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,10 +657,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
657657
}
658658

659659
def readIndexedStat(exprOwner: Symbol)(implicit ctx: Context): Tree = nextByte match {
660-
case TYPEDEF | VALDEF | DEFDEF | IMPORT =>
660+
case TYPEDEF | VALDEF | DEFDEF =>
661661
readIndexedDef()
662662
case IMPORT =>
663-
???
663+
readImport()
664664
case PACKAGE =>
665665
val start = currentAddr
666666
processPackage { (pid, end) => implicit ctx =>
@@ -670,6 +670,24 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
670670
readTerm()(ctx.withOwner(exprOwner))
671671
}
672672

673+
def readImport()(implicit ctx: Context): Tree = {
674+
readByte()
675+
readEnd()
676+
val expr = readTerm()
677+
def readSelectors(): List[untpd.Tree] = nextByte match {
678+
case RENAMED =>
679+
readByte()
680+
readEnd()
681+
untpd.Pair(untpd.Ident(readName()), untpd.Ident(readName())) :: readSelectors()
682+
case IMPORTED =>
683+
readByte()
684+
untpd.Ident(readName()) :: readSelectors()
685+
case _ =>
686+
Nil
687+
}
688+
Import(expr, readSelectors())
689+
}
690+
673691
def readIndexedStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] =
674692
until(end)(readIndexedStat(exprOwner))
675693

src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
114114
homogenize(tp) match {
115115
case tp: TypeType =>
116116
toTextRHS(tp)
117-
case tp: TermRef if !tp.denotationIsCurrent || tp.symbol.is(Module) =>
117+
case tp: TermRef if !tp.denotationIsCurrent || tp.symbol.is(Module) || tp.symbol.name.isImportName =>
118118
toTextRef(tp) ~ ".type"
119119
case tp: TermRef if tp.denot.isOverloaded =>
120120
"<overloaded " ~ toTextRef(tp) ~ ">"

src/dotty/tools/dotc/transform/ExtensionMethods.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
3131

3232
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[ElimRepeated])
3333

34+
override def runsAfterGroupsOf = Set(classOf[FirstTransform]) // need companion objects to exist
35+
3436
override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
3537
case ref: ClassDenotation if ref is ModuleClass =>
3638
ref.linkedClass match {

src/dotty/tools/dotc/transform/FirstTransform.scala

Lines changed: 3 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,13 @@ import StdNames._
2424

2525
/** The first tree transform
2626
* - ensures there are companion objects for all classes except module classes
27-
* - eliminates some kinds of trees: Imports, NamedArgs, all TypTrees other than TypeTree
28-
* - converts Select/Ident/SelectFromTypeTree nodes that refer to types to TypeTrees.
29-
* - inserts `.package` for selections of package object members
30-
* - checks the bounds of AppliedTypeTrees
27+
* - eliminates some kinds of trees: Imports, NamedArgs
3128
* - stubs out native methods
32-
* - removes java-defined ASTs
3329
*/
3430
class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer with AnnotationTransformer { thisTransformer =>
3531
import ast.tpd._
3632

3733
override def phaseName = "firstTransform"
38-
39-
override def runsAfter = Set(classOf[typer.InstChecks])
40-
// This phase makes annotations disappear in types, so InstChecks should
41-
// run before so that it can get at all annotations.
4234

4335
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp
4436

@@ -101,10 +93,7 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
10193
case stat => stat
10294
}
10395

104-
def skipJava(stats: List[Tree]): List[Tree] = // packages get a JavaDefined flag. Dont skip them
105-
stats.filter(t => !(t.symbol is(Flags.JavaDefined, Flags.Package)))
106-
107-
addMissingCompanions(reorder(skipJava(stats)))
96+
addMissingCompanions(reorder(stats))
10897
}
10998

11099
override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
@@ -119,47 +108,10 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
119108
override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] =
120109
ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisTransformer.next)))
121110

122-
private def normalizeType(tree: Tree)(implicit ctx: Context) =
123-
if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else tree
124-
125-
override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = tree.tpe match {
126-
case tpe: ThisType =>
127-
/*
128-
A this reference hide in a self ident, and be subsequently missed
129-
when deciding on whether outer accessors are needed and computing outer paths.
130-
We do this normalization directly after Typer, because during typer the
131-
ident should rest available for hyperlinking.*/
132-
This(tpe.cls).withPos(tree.pos)
133-
case _ => normalizeType(tree)
134-
}
135-
136-
137-
138-
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
139-
normalizeType {
140-
val qual = tree.qualifier
141-
qual.symbol.moduleClass.denot match {
142-
case pkg: PackageClassDenotation if !tree.symbol.maybeOwner.is(Package) =>
143-
cpy.Select(tree)(qual select pkg.packageObj.symbol, tree.name)
144-
case _ =>
145-
tree
146-
}
147-
}
148-
149-
override def transformSelectFromTypeTree(tree: SelectFromTypeTree)(implicit ctx: Context, info: TransformerInfo) =
150-
normalizeType(tree)
151-
152111
override def transformOther(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = tree match {
153112
case tree: Import => EmptyTree
154113
case tree: NamedArg => transform(tree.arg)
155-
case AppliedTypeTree(tycon, args) =>
156-
val tparams = tycon.tpe.typeSymbol.typeParams
157-
val bounds = tparams.map(tparam =>
158-
tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
159-
Checking.checkBounds(args, bounds, _.substDealias(tparams, _))
160-
normalizeType(tree)
161-
case tree =>
162-
normalizeType(tree)
114+
case tree => tree
163115
}
164116

165117
// invariants: all modules have companion objects

src/dotty/tools/dotc/transform/FullParameterization.scala

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Types._
66
import Contexts._
77
import Symbols._
88
import Decorators._
9+
import TypeUtils._
910
import StdNames.nme
1011
import NameOps._
1112
import ast._
@@ -128,14 +129,8 @@ trait FullParameterization {
128129
*/
129130
def memberSignature(info: Type)(implicit ctx: Context): Signature = info match {
130131
case info: PolyType => memberSignature(info.resultType)
131-
case info @ MethodType(nme.SELF :: Nil, _) =>
132-
val normalizedResultType = info.resultType match {
133-
case rtp: MethodType => rtp
134-
case rtp => ExprType(rtp)
135-
}
136-
normalizedResultType.signature
137-
case _ =>
138-
Signature.NotAMethod
132+
case info @ MethodType(nme.SELF :: Nil, _) => info.resultType.ensureMethodic.signature
133+
case _ => Signature.NotAMethod
139134
}
140135

141136
/** The type parameters (skolems) of the method definition `originalDef`,

src/dotty/tools/dotc/transform/LambdaLift.scala

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,18 +107,18 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
107107
* in `enclosure` or there is an intermediate class properly containing `enclosure`
108108
* in which `sym` is also free. Also, update `liftedOwner` of `enclosure` so
109109
* that `enclosure` can access `sym`, or its proxy in an intermediate class.
110-
* This means:
111-
*
110+
* This means:
111+
*
112112
* 1. If there is an intermediate class in which `sym` is free, `enclosure`
113-
* must be contained in that class (in order to access the `sym proxy stored
113+
* must be contained in that class (in order to access the `sym proxy stored
114114
* in the class).
115-
*
115+
*
116116
* 2. If there is no intermediate class, `enclosure` must be contained
117117
* in the class enclosing `sym`.
118-
*
118+
*
119119
* Return the closest enclosing intermediate class between `enclosure` and
120120
* the owner of sym, or NoSymbol if none exists.
121-
*
121+
*
122122
* pre: sym.owner.isTerm, (enclosure.isMethod || enclosure.isClass)
123123
*
124124
* The idea of `markFree` is illustrated with an example:
@@ -150,10 +150,10 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
150150
else {
151151
ctx.log(i"mark free: ${sym.showLocated} with owner ${sym.maybeOwner} marked free in $enclosure")
152152
ctx.debuglog(i"$enclosure != ${sym.enclosure}")
153-
val intermediate =
153+
val intermediate =
154154
if (enclosure.is(PackageClass)) enclosure
155-
else markFree(sym, enclosure.skipConstructor.enclosure)
156-
// `enclosure` might be a constructor, in which case we want the enclosure
155+
else markFree(sym, enclosure.skipConstructor.enclosure)
156+
// `enclosure` might be a constructor, in which case we want the enclosure
157157
// of the enclosing class, so skipConstructor is needed here.
158158
if (intermediate.exists) {
159159
narrowLiftedOwner(enclosure, intermediate)
@@ -394,12 +394,12 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
394394
val sym = tree.symbol
395395
tree.tpe match {
396396
case tpe @ TermRef(prefix, _) =>
397-
if (prefix eq NoPrefix)
397+
if (prefix eq NoPrefix)
398398
if (sym.enclosure != currentEnclosure && !sym.isStatic)
399399
(if (sym is Method) memberRef(sym) else proxyRef(sym)).withPos(tree.pos)
400400
else if (sym.owner.isClass) // sym was lifted out
401401
ref(sym).withPos(tree.pos)
402-
else
402+
else
403403
tree
404404
else if (!prefixIsElidable(tpe)) ref(tpe)
405405
else tree

src/dotty/tools/dotc/transform/MacroTransform.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,6 @@ abstract class MacroTransform extends Phase {
3838
ctx.fresh.setTree(tree).setOwner(owner)
3939
}
4040

41-
/** The current enclosing class
42-
* @pre We must be inside a class
43-
*/
44-
def currentClass(implicit ctx: Context): ClassSymbol = ctx.owner.enclosingClass.asClass
45-
4641
def transformStats(trees: List[Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
4742
def transformStat(stat: Tree): Tree = stat match {
4843
case _: Import | _: DefTree => transform(stat)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import ast.Trees._
6+
import Contexts._, Types._, Symbols._, Flags._, TypeUtils._, DenotTransformers._, StdNames._
7+
8+
/** For all parameter accessors
9+
*
10+
* val x: T = ...
11+
*
12+
* if
13+
* (1) x is forwarded in the supercall to a parameter that's also named `x`
14+
* (2) the superclass parameter accessor for `x` is accessible from the current class to
15+
* change the accessor to
16+
*
17+
* def x: T = super.x.asInstanceOf[T]
18+
*
19+
* Do the same also if there are intermediate inaccessible parameter accessor forwarders.
20+
* The aim of this transformation is to avoid redundant parameter accessor fields.
21+
*/
22+
class ParamForwarding(thisTransformer: DenotTransformer) {
23+
import ast.tpd._
24+
25+
def forwardParamAccessors(impl: Template)(implicit ctx: Context): Template = {
26+
def fwd(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
27+
val (superArgs, superParamNames) = impl.parents match {
28+
case superCall @ Apply(fn, args) :: _ =>
29+
fn.tpe.widen match {
30+
case MethodType(paramNames, _) => (args, paramNames)
31+
case _ => (Nil, Nil)
32+
}
33+
case _ => (Nil, Nil)
34+
}
35+
def inheritedAccessor(sym: Symbol): Symbol = {
36+
val candidate = sym.owner.asClass.superClass
37+
.info.decl(sym.name).suchThat(_ is (ParamAccessor, butNot = Mutable)).symbol
38+
if (candidate.isAccessibleFrom(currentClass.thisType, superAccess = true)) candidate
39+
else if (candidate is Method) inheritedAccessor(candidate)
40+
else NoSymbol
41+
}
42+
def forwardParamAccessor(stat: Tree): Tree = {
43+
stat match {
44+
case stat: ValDef =>
45+
val sym = stat.symbol.asTerm
46+
if (sym is (PrivateLocalParamAccessor, butNot = Mutable)) {
47+
val idx = superArgs.indexWhere(_.symbol == sym)
48+
if (idx >= 0 && superParamNames(idx) == stat.name) { // supercall to like-named parameter
49+
val alias = inheritedAccessor(sym)
50+
if (alias.exists) {
51+
def forwarder(implicit ctx: Context) = {
52+
sym.copySymDenotation(initFlags = sym.flags | Method, info = sym.info.ensureMethodic)
53+
.installAfter(thisTransformer)
54+
val superAcc =
55+
Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias)
56+
DefDef(sym, superAcc.ensureConforms(sym.info.widen))
57+
}
58+
return forwarder(ctx.withPhase(thisTransformer.next))
59+
}
60+
}
61+
}
62+
case _ =>
63+
}
64+
stat
65+
}
66+
stats map forwardParamAccessor
67+
}
68+
69+
cpy.Template(impl)(body = fwd(impl.body)(ctx.withPhase(thisTransformer)))
70+
}
71+
}

0 commit comments

Comments
 (0)