Skip to content

Transform/super accessors #139

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

Closed
wants to merge 9 commits into from
Closed
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
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
List(new SuperAccessors),
List(new LazyValsCreateCompanionObjects,
new TailRec), //force separataion between lazyVals and LVCreateCO
List(new PatternMatcher,
Expand Down
3 changes: 3 additions & 0 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ object Trees {
type ThisTree[-T >: Untyped] <: DenotingTree[T]
override def denot(implicit ctx: Context) = tpe match {
case tpe: NamedType => tpe.denot
case ThisType(cls) => cls.denot
case _ => NoDenotation
}
}
Expand Down Expand Up @@ -1162,6 +1163,8 @@ object Trees {
cpy.Alternative(tree, transform(trees))
case UnApply(fun, implicits, patterns) =>
cpy.UnApply(tree, transform(fun), transform(implicits), transform(patterns))
case EmptyValDef =>
tree
case ValDef(mods, name, tpt, rhs) =>
cpy.ValDef(tree, mods, name, transform(tpt), transform(rhs))
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
Expand Down
19 changes: 16 additions & 3 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def DefDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): DefDef =
ta.assignType(DefDef(sym, Function.const(rhs) _), sym)

def DefDef(sym: TermSymbol, rhsFn: List[List[Tree]] => Tree)(implicit ctx: Context): DefDef = {
def DefDef(sym: TermSymbol, rhsFn: List[List[Tree]] => Tree)(implicit ctx: Context): DefDef =
polyDefDef(sym, Function.const(rhsFn))

def polyDefDef(sym: TermSymbol, rhsFn: List[Type] => List[List[Tree]] => Tree)(implicit ctx: Context): DefDef = {
val (tparams, mtp) = sym.info match {
case tp: PolyType =>
val tparams = ctx.newTypeParams(sym, tp.paramNames, EmptyFlags, tp.instantiateBounds)
Expand All @@ -200,11 +203,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case tp => (Nil, tp)
}
val (vparamss, rtp) = valueParamss(mtp)
val targs = tparams map (_.typeRef)
val argss = vparamss map (_ map (vparam => Ident(vparam.termRef)))
ta.assignType(
untpd.DefDef(
Modifiers(sym), sym.name, tparams map TypeDef,
vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhsFn(argss)), sym)
vparamss map (_ map (ValDef(_))), TypeTree(rtp), rhsFn(targs)(argss)), sym)
}

def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef =
Expand Down Expand Up @@ -381,7 +385,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
new TreeTypeMap(ownerMap = (sym => if (sym == from) to else sym)).apply(tree)

def appliedToTypes(targs: List[Type])(implicit ctx: Context): Tree =
if (targs.isEmpty) tree else TypeApply(tree, targs map (TypeTree(_)))
appliedToTypeTrees(targs map (TypeTree(_)))

def appliedToTypeTrees(targs: List[Tree])(implicit ctx: Context): Tree =
if (targs.isEmpty) tree else TypeApply(tree, targs)
}

implicit class ListOfTreeDecorator(val xs: List[tpd.Tree]) extends AnyVal {
Expand Down Expand Up @@ -451,6 +458,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def mkAnd(tree1: Tree, tree2: Tree)(implicit ctx: Context) =
Apply(Select(tree1, defn.Boolean_and), tree2 :: Nil)

def mkAsInstanceOf(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
TypeApply(Select(tree, defn.Any_asInstanceOf), TypeTree(pt) :: Nil)

def ensureConforms(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
if (tree.tpe <:< pt) tree else mkAsInstanceOf(tree, pt)

// ensure that constructors are fully applied?
// ensure that normal methods are fully applied?

Expand Down
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ object Denotations {
final def signature(implicit ctx: Context): Signature = {
if (isType) Signature.NotAMethod // don't force info if this is a type SymDenotation
else info match {
case info: SignedType =>
case info: MethodicType =>
try info.signature
catch { // !!! DEBUG
case ex: Throwable =>
Expand Down Expand Up @@ -574,6 +574,7 @@ object Denotations {
/** Install this denotation to be the result of the given denotation transformer.
* This is the implementation of the same-named method in SymDenotations.
* It's placed here because it needs access to private fields of SingleDenotation.
* @pre Can only be called in `phase.next`.
*/
protected def installAfter(phase: DenotTransformer)(implicit ctx: Context): Unit = {
val targetId = phase.next.id
Expand Down
17 changes: 14 additions & 3 deletions src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,16 @@ object Flags {
}

/** The list of non-empty names of flags that are set in this FlagSet */
def flagStrings: Seq[String] =
(2 to MaxFlag).flatMap(flagString)
def flagStrings: Seq[String] = {
val rawStrings = (2 to MaxFlag).flatMap(flagString)
if (this is Local)
rawStrings.filter(_ != "<local>").map {
case "private" => "private[this]"
case "protected" => "protected[this]"
case str => str
}
else rawStrings
}

/** The string representation of this flag set */
override def toString = flagStrings.mkString(" ")
Expand Down Expand Up @@ -405,7 +413,10 @@ object Flags {

/** Flags representing modifiers that can appear in trees */
final val ModifierFlags =
SourceModifierFlags | Trait | Module | Param | Synthetic | Package
SourceModifierFlags | Module | Param | Synthetic | Package | Local
// | Trait is subsumed by commonFlags(Lazy) from SourceModifierFlags

assert(ModifierFlags.isTermFlags && ModifierFlags.isTypeFlags)

/** Flags representing access rights */
final val AccessFlags = Private | Protected | Local
Expand Down
21 changes: 13 additions & 8 deletions src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ object NameOps {
}
}

object SuperAccessorName {
val pre = nme.SUPER_PREFIX
def apply(name: TermName): TermName = pre ++ name
def unapply(name: TermName): Option[TermName] =
if (name startsWith pre) Some(name.drop(pre.length).asTermName) else None
}

implicit class NameDecorator[N <: Name](val name: N) extends AnyVal {
import nme._

Expand All @@ -59,7 +66,6 @@ object NameOps {
def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX
def isLoopHeaderLabel = (name startsWith WHILE_PREFIX) || (name startsWith DO_WHILE_PREFIX)
def isProtectedAccessorName = name startsWith PROTECTED_PREFIX
def isSuperAccessorName = name startsWith SUPER_PREFIX
def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER
def isSetterName = name endsWith SETTER_SUFFIX
def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_SEPARATOR)
Expand Down Expand Up @@ -126,6 +132,9 @@ object NameOps {
if (flags is (ModuleClass, butNot = Package)) name.asTypeName.moduleClassName.asInstanceOf[N]
else name

/** The superaccessor for method with given name */
def superName: TermName = (nme.SUPER_PREFIX ++ name).toTermName

/** The expanded name of `name` relative to this class `base` with given `separator`
*/
def expandedName(base: Symbol, separator: Name = nme.EXPAND_SEPARATOR)(implicit ctx: Context): N = {
Expand Down Expand Up @@ -247,17 +256,13 @@ object NameOps {
else -1
}

/** The name of a super-accessor */
def superAccessorName: TermName =
SUPER_PREFIX ++ name

/** The name of an accessor for protected symbols. */
def protectedAccessorName: TermName =
PROTECTED_PREFIX ++ name
PROTECTED_PREFIX ++ name.unexpandedName()

/** The name of a setter for protected symbols. Used for inherited Java fields. */
def protectedSetterName(name: Name): TermName =
PROTECTED_SET_PREFIX ++ name
def protectedSetterName: TermName =
PROTECTED_SET_PREFIX ++ name.unexpandedName()

def moduleVarName: TermName =
name ++ MODULE_VAR_SUFFIX
Expand Down
9 changes: 5 additions & 4 deletions src/dotty/tools/dotc/core/Scopes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import SymDenotations._
import printing.Texts._
import printing.Printer
import util.common._
import util.DotClass
import SymDenotations.NoDenotation
import collection.mutable.ListBuffer

Expand Down Expand Up @@ -55,7 +56,7 @@ object Scopes {
* or to delete them. These methods are provided by subclass
* MutableScope.
*/
abstract class Scope extends printing.Showable with Iterable[Symbol] {
abstract class Scope extends DotClass with printing.Showable with Iterable[Symbol] {

/** The last scope-entry from which all others are reachable via `prev` */
private[dotc] def lastEntry: ScopeEntry
Expand All @@ -77,8 +78,8 @@ object Scopes {
*/
def iterator: Iterator[Symbol] = toList.iterator

/** Returns a new scope with the same content as this one. */
def cloneScope(implicit ctx: Context): Scope
/** Returns a new mutable scope with the same content as this one. */
def cloneScope(implicit ctx: Context): MutableScope

/** Is the scope empty? */
override def isEmpty: Boolean = lastEntry eq null
Expand Down Expand Up @@ -354,7 +355,7 @@ object Scopes {
override def size = 0
override def nestingLevel = 0
override def toList = Nil
override def cloneScope(implicit ctx: Context): Scope = this
override def cloneScope(implicit ctx: Context): MutableScope = unsupported("cloneScope")
override def lookupEntry(name: Name)(implicit ctx: Context): ScopeEntry = null
override def lookupNextEntry(entry: ScopeEntry)(implicit ctx: Context): ScopeEntry = null
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Signature.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object Signature {
* a type different from PolyType, MethodType, or ExprType.
*/
val NotAMethod = Signature(List(), EmptyTypeName)

/** The signature of an overloaded denotation.
*/
val OverloadedSignature = Signature(List(tpnme.OVERLOADED), EmptyTypeName)
Expand Down
45 changes: 41 additions & 4 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,14 @@ object SymDenotations {
/** Is this a user defined "def" method? Excluded are accessors. */
final def isSourceMethod(implicit ctx: Context) = this is (Method, butNot = Accessor)

/** This this a method in a value class that is implemented as an extension method? */
final def isMethodWithExtension(implicit ctx: Context) =
isSourceMethod &&
owner.isDerivedValueClass &&
!isConstructor &&
!is(SuperAccessor) &&
!is(Macro)

/** Is this a setter? */
final def isGetter(implicit ctx: Context) = (this is Accessor) && !originalName.isSetterName

Expand Down Expand Up @@ -447,7 +455,7 @@ object SymDenotations {
def accessWithin(boundary: Symbol) =
ctx.owner.isContainedIn(boundary) &&
(!(this is JavaDefined) || // disregard package nesting for Java
ctx.owner.enclosingPackage == boundary.enclosingPackage)
ctx.owner.enclosingPackageClass == boundary.enclosingPackageClass)

/** Are we within definition of linked class of `boundary`? */
def accessWithinLinked(boundary: Symbol) = {
Expand Down Expand Up @@ -572,6 +580,12 @@ object SymDenotations {
NoSymbol
}

/** The field accessed by this getter or setter */
def accessedField(implicit ctx: Context): Symbol = {
val fieldName = if (isSetter) name.asTermName.setterToGetter else name
owner.info.decl(fieldName).suchThat(d => !(d is Method)).symbol
}

/** The chain of owners of this denotation, starting with the denoting symbol itself */
final def ownersIterator(implicit ctx: Context) = new Iterator[Symbol] {
private[this] var current = symbol
Expand Down Expand Up @@ -624,8 +638,8 @@ object SymDenotations {
}

/** The package class containing this denotation */
final def enclosingPackage(implicit ctx: Context): Symbol =
if (this is PackageClass) symbol else owner.enclosingPackage
final def enclosingPackageClass(implicit ctx: Context): Symbol =
if (this is PackageClass) symbol else owner.enclosingPackageClass

/** The module object with the same (term-) name as this class or module class,
* and which is also defined in the same scope and compilation unit.
Expand Down Expand Up @@ -747,7 +761,6 @@ object SymDenotations {
loop(base.info.baseClasses.dropWhile(owner != _).tail)
}


/** A a member of class `base` is incomplete if
* (1) it is declared deferred or
* (2) it is abstract override and its super symbol in `base` is
Expand Down Expand Up @@ -895,6 +908,15 @@ object SymDenotations {
case _ => Nil
}

/** The symbol of the superclass, NoSymbol if no superclass exists */
def superClass(implicit ctx: Context): Symbol = classParents match {
case parent :: _ =>
val cls = parent.classSymbol
if (cls is Trait) NoSymbol else cls
case _ =>
NoSymbol
}

/** The denotation is fully completed: all attributes are fully defined.
* ClassDenotations compiled from source are first completed, then fully completed.
* @see Namer#ClassCompleter
Expand Down Expand Up @@ -1292,6 +1314,21 @@ object SymDenotations {
def underlyingOfValueClass: Type = ???

def valueClassUnbox: Symbol = ???

/** If this class has the same `decls` scope reference in `phase` and
* `phase.next`, install a new denotation with a cloned scope in `phase.next`.
* @pre Can only be called in `phase.next`.
*/
def ensureFreshScopeAfter(phase: DenotTransformer)(implicit ctx: Context): Unit = {
assert(ctx.phaseId == phase.next.id)
val prevCtx = ctx.withPhase(phase)
val ClassInfo(pre, _, ps, decls, selfInfo) = classInfo
if (classInfo(prevCtx).decls eq decls) {
copySymDenotation(
info = ClassInfo(pre, classSymbol, ps, decls.cloneScope, selfInfo),
initFlags = this.flags &~ Frozen).installAfter(phase)
}
}
}

/** The denotation of a package class.
Expand Down
12 changes: 12 additions & 0 deletions src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import printing.Printer
import Types._
import Annotations._
import util.Positions._
import DenotTransformers._
import StdNames._
import NameOps._
import ast.tpd.{TreeTypeMap, Tree}
Expand Down Expand Up @@ -372,6 +373,17 @@ object Symbols {
this
}

/** Enter this symbol in its class owner after given `phase`. Create a fresh
* denotation for its owner class if the class has not yet already one
* that starts being valid after `phase`.
* @pre Symbol is a class member
*/
def enteredAfter(phase: DenotTransformer)(implicit ctx: Context): this.type = {
val nextCtx = ctx.withPhase(phase.next)
this.owner.asClass.ensureFreshScopeAfter(phase)(nextCtx)
entered(nextCtx)
}

/** This symbol, if it exists, otherwise the result of evaluating `that` */
def orElse(that: => Symbol)(implicit ctx: Context) =
if (this.exists) this else that
Expand Down
Loading