Skip to content

Refactor/super accessors #495

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 16 commits into from
Apr 28, 2015
Merged
Show file tree
Hide file tree
Changes from 15 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
10 changes: 4 additions & 6 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Contexts._
import Periods._
import Symbols._
import Scopes._
import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks, InstChecks}
import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks}
import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.transform._
Expand Down Expand Up @@ -38,11 +38,9 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
List(new InstChecks),
List(new FirstTransform,
new SyntheticMethods),
List(new SuperAccessors),
List(new Pickler), // Pickler needs to come last in a group since it should not pickle trees generated later
List(new PostTyper),
List(new Pickler),
List(new FirstTransform),
List(new RefChecks,
new ElimRepeated,
new NormalizeFlags,
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}

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

def PackageDef(pid: RefTree, stats: List[Tree])(implicit ctx: Context): PackageDef =
ta.assignType(untpd.PackageDef(pid, stats), pid)
Expand Down
4 changes: 4 additions & 0 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ object SymDenotations {
/** Does this denotation have an annotation matching the given class symbol? */
final def hasAnnotation(cls: Symbol)(implicit ctx: Context) =
dropOtherAnnotations(annotations, cls).nonEmpty

/** Apply transform `f` to all annotations of this denotation */
final def transformAnnotations(f: Annotation => Annotation)(implicit ctx: Context): Unit =
annotations = annotations.mapConserve(f)

/** Optionally, the annotation matching the given class symbol */
final def getAnnotation(cls: Symbol)(implicit ctx: Context): Option[Annotation] =
Expand Down
12 changes: 8 additions & 4 deletions src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ trait Symbols { this: Context =>
newSymbol(cls, nme.localDummyName(cls), EmptyFlags, NoType)

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

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

implicit def defn(implicit ctx: Context): Definitions = ctx.definitions

/** Makes all denotation operations available on symbols */
implicit def toDenot(sym: Symbol)(implicit ctx: Context): SymDenotation = sym.denot

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

/** The Definitions object */
def defn(implicit ctx: Context): Definitions = ctx.definitions

/** The current class */
def currentClass(implicit ctx: Context): ClassSymbol = ctx.owner.enclosingClass.asClass

var stubs: List[Symbol] = Nil // diagnostic
}
22 changes: 20 additions & 2 deletions src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -657,10 +657,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
}

def readIndexedStat(exprOwner: Symbol)(implicit ctx: Context): Tree = nextByte match {
case TYPEDEF | VALDEF | DEFDEF | IMPORT =>
case TYPEDEF | VALDEF | DEFDEF =>
readIndexedDef()
case IMPORT =>
???
readImport()
case PACKAGE =>
val start = currentAddr
processPackage { (pid, end) => implicit ctx =>
Expand All @@ -669,6 +669,24 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
case _ =>
readTerm()(ctx.withOwner(exprOwner))
}

def readImport()(implicit ctx: Context): Tree = {
readByte()
readEnd()
val expr = readTerm()
def readSelectors(): List[untpd.Tree] = nextByte match {
case RENAMED =>
readByte()
readEnd()
untpd.Pair(untpd.Ident(readName()), untpd.Ident(readName())) :: readSelectors()
case IMPORTED =>
readByte()
untpd.Ident(readName()) :: readSelectors()
case _ =>
Nil
}
Import(expr, readSelectors())
}

def readIndexedStats(exprOwner: Symbol, end: Addr)(implicit ctx: Context): List[Tree] =
until(end)(readIndexedStat(exprOwner))
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/printing/PlainPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
homogenize(tp) match {
case tp: TypeType =>
toTextRHS(tp)
case tp: TermRef if !tp.denotationIsCurrent || tp.symbol.is(Module) =>
case tp: TermRef if !tp.denotationIsCurrent || tp.symbol.is(Module) || tp.symbol.name.isImportName =>
toTextRef(tp) ~ ".type"
case tp: TermRef if tp.denot.isOverloaded =>
"<overloaded " ~ toTextRef(tp) ~ ">"
Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/transform/ExtensionMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
override def phaseName: String = "extmethods"

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

override def runsAfterGroupsOf = Set(classOf[FirstTransform]) // need companion objects to exist

override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: ClassDenotation if ref is ModuleClass =>
Expand Down
54 changes: 3 additions & 51 deletions src/dotty/tools/dotc/transform/FirstTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,13 @@ import StdNames._

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

override def phaseName = "firstTransform"

override def runsAfter = Set(classOf[typer.InstChecks])
// This phase makes annotations disappear in types, so InstChecks should
// run before so that it can get at all annotations.

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

Expand Down Expand Up @@ -101,10 +93,7 @@ class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer wi
case stat => stat
}

def skipJava(stats: List[Tree]): List[Tree] = // packages get a JavaDefined flag. Dont skip them
stats.filter(t => !(t.symbol is(Flags.JavaDefined, Flags.Package)))

addMissingCompanions(reorder(skipJava(stats)))
addMissingCompanions(reorder(stats))
}

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

private def normalizeType(tree: Tree)(implicit ctx: Context) =
if (tree.isType) TypeTree(tree.tpe).withPos(tree.pos) else tree

override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = tree.tpe match {
case tpe: ThisType =>
/*
A this reference hide in a self ident, and be subsequently missed
when deciding on whether outer accessors are needed and computing outer paths.
We do this normalization directly after Typer, because during typer the
ident should rest available for hyperlinking.*/
This(tpe.cls).withPos(tree.pos)
case _ => normalizeType(tree)
}



override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
normalizeType {
val qual = tree.qualifier
qual.symbol.moduleClass.denot match {
case pkg: PackageClassDenotation if !tree.symbol.maybeOwner.is(Package) =>
cpy.Select(tree)(qual select pkg.packageObj.symbol, tree.name)
case _ =>
tree
}
}

override def transformSelectFromTypeTree(tree: SelectFromTypeTree)(implicit ctx: Context, info: TransformerInfo) =
normalizeType(tree)

override def transformOther(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = tree match {
case tree: Import => EmptyTree
case tree: NamedArg => transform(tree.arg)
case AppliedTypeTree(tycon, args) =>
val tparams = tycon.tpe.typeSymbol.typeParams
val bounds = tparams.map(tparam =>
tparam.info.asSeenFrom(tycon.tpe.normalizedPrefix, tparam.owner.owner).bounds)
Checking.checkBounds(args, bounds, _.substDealias(tparams, _))
normalizeType(tree)
case tree =>
normalizeType(tree)
case tree => tree
}

// invariants: all modules have companion objects
Expand Down
11 changes: 3 additions & 8 deletions src/dotty/tools/dotc/transform/FullParameterization.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Types._
import Contexts._
import Symbols._
import Decorators._
import TypeUtils._
import StdNames.nme
import NameOps._
import ast._
Expand Down Expand Up @@ -128,14 +129,8 @@ trait FullParameterization {
*/
def memberSignature(info: Type)(implicit ctx: Context): Signature = info match {
case info: PolyType => memberSignature(info.resultType)
case info @ MethodType(nme.SELF :: Nil, _) =>
val normalizedResultType = info.resultType match {
case rtp: MethodType => rtp
case rtp => ExprType(rtp)
}
normalizedResultType.signature
case _ =>
Signature.NotAMethod
case info @ MethodType(nme.SELF :: Nil, _) => info.resultType.ensureMethodic.signature
case _ => Signature.NotAMethod
}

/** The type parameters (skolems) of the method definition `originalDef`,
Expand Down
5 changes: 0 additions & 5 deletions src/dotty/tools/dotc/transform/MacroTransform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ abstract class MacroTransform extends Phase {
ctx.fresh.setTree(tree).setOwner(owner)
}

/** The current enclosing class
* @pre We must be inside a class
*/
def currentClass(implicit ctx: Context): ClassSymbol = ctx.owner.enclosingClass.asClass

def transformStats(trees: List[Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
def transformStat(stat: Tree): Tree = stat match {
case _: Import | _: DefTree => transform(stat)
Expand Down
71 changes: 71 additions & 0 deletions src/dotty/tools/dotc/transform/ParamForwarding.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package dotty.tools.dotc
package transform

import core._
import ast.Trees._
import Contexts._, Types._, Symbols._, Flags._, TypeUtils._, DenotTransformers._, StdNames._

/** For all parameter accessors
*
* val x: T = ...
*
* if
* (1) x is forwarded in the supercall to a parameter that's also named `x`
* (2) the superclass parameter accessor for `x` is accessible from the current class to
* change the accessor to
*
* def x: T = super.x.asInstanceOf[T]
*
* Do the same also if there are intermediate inaccessible parameter accessor forwarders.
* The aim of this transformation is to avoid redundant parameter accessor fields.
*/
class ParamForwarding(thisTransformer: DenotTransformer) {
import ast.tpd._

def forwardParamAccessors(impl: Template)(implicit ctx: Context): Template = {
def fwd(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
val (superArgs, superParamNames) = impl.parents match {
case superCall @ Apply(fn, args) :: _ =>
fn.tpe.widen match {
case MethodType(paramNames, _) => (args, paramNames)
case _ => (Nil, Nil)
}
case _ => (Nil, Nil)
}
def inheritedAccessor(sym: Symbol): Symbol = {
val candidate = sym.owner.asClass.superClass
.info.decl(sym.name).suchThat(_ is (ParamAccessor, butNot = Mutable)).symbol
if (candidate.isAccessibleFrom(currentClass.thisType, superAccess = true)) candidate
else if (candidate is Method) inheritedAccessor(candidate)
else NoSymbol
}
def forwardParamAccessor(stat: Tree): Tree = {
stat match {
case stat: ValDef =>
val sym = stat.symbol.asTerm
if (sym is (PrivateLocalParamAccessor, butNot = Mutable)) {
val idx = superArgs.indexWhere(_.symbol == sym)
if (idx >= 0 && superParamNames(idx) == stat.name) { // supercall to like-named parameter
val alias = inheritedAccessor(sym)
if (alias.exists) {
def forwarder(implicit ctx: Context) = {
sym.copySymDenotation(initFlags = sym.flags | Method, info = sym.info.ensureMethodic)
.installAfter(thisTransformer)
val superAcc =
Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias)
DefDef(sym, superAcc.ensureConforms(sym.info.widen))
}
return forwarder(ctx.withPhase(thisTransformer.next))
}
}
}
case _ =>
}
stat
}
stats map forwardParamAccessor
}

cpy.Template(impl)(body = fwd(impl.body)(ctx.withPhase(thisTransformer)))
}
}
Loading