Skip to content

Transform/mixin #217

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 34 commits into from
Nov 10, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
31d2994
First version of mixin transform.
odersky Oct 31, 2014
7c5a3ff
Adapt GettersSetters to new Mixin scheme.
odersky Nov 1, 2014
0119ffd
Avoid getting confused because of Scala2 local suffixes
odersky Nov 1, 2014
43075bb
Improved version of mixin.
odersky Nov 1, 2014
97080a8
New option -Ydebug-owners
odersky Nov 3, 2014
b8b0682
Make cloneScope less forcefull.
odersky Nov 3, 2014
b98ed34
Fix problem in changeOwner
odersky Nov 3, 2014
a2f5581
Adaptation of Constructors to new mixin scheme.
odersky Nov 3, 2014
d287541
Adaptation of explicitOuter to trait initializers
odersky Nov 3, 2014
7194afe
Take supercalls into account for statement context
odersky Nov 4, 2014
e445000
Fixed redundancy in membersNeedAsSeenFrom
odersky Nov 4, 2014
6098546
Fixed typing of supertypes.
odersky Nov 4, 2014
3299df8
Fix of computeDenot.
odersky Nov 4, 2014
1fad643
Select operations in erasure should fix symbols in types.
odersky Nov 4, 2014
0d74e59
Superaccessors are methods
odersky Nov 5, 2014
211d46e
Cleanup of code for ExplicitOuter
odersky Nov 6, 2014
0f7934d
Methods always shwoDcl as `def`
odersky Nov 7, 2014
f618e47
Fixes to Unit handling in erasure
odersky Nov 8, 2014
c67d6cf
More systematic handling of Scala2LocalSuffix.
odersky Nov 8, 2014
e3a56c3
Accessor methods print as "method", not "val/var".
odersky Nov 8, 2014
4b5e630
Small polishings in docs and code.
odersky Nov 8, 2014
75c06fc
More robost handling of isSetter/isGetter
odersky Nov 8, 2014
0cd63ac
Adding test for Unit vars.
odersky Nov 8, 2014
fea26e1
New Mixin scheme.
odersky Nov 8, 2014
df0229e
Retract of optimization in computeDenot
odersky Nov 8, 2014
a8cd662
Fixed handling of ThisTypes in TypeErasure.
odersky Nov 8, 2014
0d0a37f
Better error message for adaptations of implicit methods
odersky Nov 8, 2014
383ba35
Reinstantiated full tests.
odersky Nov 8, 2014
0ad4dea
Fixed bug in treating Thickets in TreeTransform
odersky Nov 8, 2014
b07c30b
New functionality: changeOwnerAfter
odersky Nov 8, 2014
60803fa
Merge memoize with miniphases following it into one group.
odersky Nov 8, 2014
06c50af
Merge mixin with the group of miniphases following it.
odersky Nov 8, 2014
f2e3489
More docs and removing print statements
odersky Nov 9, 2014
83734e1
Generalize symbolic refs
odersky Nov 10, 2014
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
8 changes: 5 additions & 3 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,16 @@ class Compiler {
new TailRec),
List(new PatternMatcher,
new ExplicitOuter,
// new LazyValTranformContext().transformer, // disabled, awaiting fixes
new Splitter),
List(new ElimByName,
new InterceptedMethods,
new Literalize,
new GettersSetters),
new Getters,
new ResolveSuper),
List(new Erasure),
List(new CapturedVars,
List(new Mixin,
new Memoize, // TODO: Make LazyVals a part of this phase
new CapturedVars,
new Constructors),
List(new LambdaLift,
new Flatten,
Expand Down
16 changes: 12 additions & 4 deletions src/dotty/tools/dotc/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package core

import Symbols._, Types._, Contexts._, Flags._, Names._, StdNames._, Decorators._, Flags.JavaDefined
import dotc.transform.ExplicitOuter._
import typer.Mode
import util.DotClass

/** Erased types are:
Expand Down Expand Up @@ -89,7 +90,7 @@ object TypeErasure {

/** The current context with a phase no later than erasure */
private def erasureCtx(implicit ctx: Context) =
if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase) else ctx
if (ctx.erasedTypes) ctx.withPhase(ctx.erasurePhase).addMode(Mode.FutureDefsOK) else ctx

def erasure(tp: Type)(implicit ctx: Context): Type = scalaErasureFn(tp)(erasureCtx)
def semiErasure(tp: Type)(implicit ctx: Context): Type = semiErasureFn(tp)(erasureCtx)
Expand All @@ -107,6 +108,8 @@ object TypeErasure {
case tp: TermRef =>
assert(tp.symbol.exists, tp)
TermRef(erasedRef(tp.prefix), tp.symbol.asTerm)
case tp: ThisType =>
tp
case tp =>
erasure(tp)
}
Expand Down Expand Up @@ -141,7 +144,12 @@ object TypeErasure {
if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
else if (sym.isAbstractType) TypeAlias(WildcardType)
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
else eraseInfo(tp)(erasureCtx)
else eraseInfo(tp)(erasureCtx) match {
case einfo: MethodType if sym.isGetter && einfo.resultType.isRef(defn.UnitClass) =>
defn.BoxedUnitClass.typeRef
case einfo =>
einfo
}
}

def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
Expand Down Expand Up @@ -265,7 +273,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
case tp: TermRef =>
this(tp.widen)
case ThisType(_) =>
tp
this(tp.widen)
case SuperType(thistpe, supertpe) =>
SuperType(this(thistpe), this(supertpe))
case ExprType(rt) =>
Expand Down Expand Up @@ -319,7 +327,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
}

def eraseInfo(tp: Type)(implicit ctx: Context) = tp match {
case ExprType(rt) => MethodType(Nil, Nil, erasure(rt))
case ExprType(rt) => MethodType(Nil, Nil, eraseResult(rt))
case tp => erasure(tp)
}

Expand Down
29 changes: 25 additions & 4 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import transform.SymUtils._
import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._
import Denotations._, Decorators._
import Denotations._, Decorators._, DenotTransformers._
import config.Printers._
import typer.Mode
import collection.mutable
Expand Down Expand Up @@ -39,8 +39,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def This(cls: ClassSymbol)(implicit ctx: Context): This =
untpd.This(cls.name).withType(cls.thisType)

def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean)(implicit ctx: Context): Super =
ta.assignType(untpd.Super(qual, mix), qual, inConstrCall)
def Super(qual: Tree, mix: TypeName, inConstrCall: Boolean, mixinClass: Symbol = NoSymbol)(implicit ctx: Context): Super =
ta.assignType(untpd.Super(qual, mix), qual, inConstrCall, mixinClass)

def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply =
ta.assignType(untpd.Apply(fn, args), fn, args)
Expand Down Expand Up @@ -527,7 +527,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
*/
def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree = {
def loop(from: Symbol, froms: List[Symbol], tos: List[Symbol]): ThisTree = {
if (from.isWeakOwner) loop(from.owner, from :: froms, to :: tos)
if (from.isWeakOwner && !from.owner.isClass)
loop(from.owner, from :: froms, to :: tos)
else {
//println(i"change owner ${from :: froms}%, % ==> $tos of $tree")
new TreeTypeMap(oldOwners = from :: froms, newOwners = tos).apply(tree)
Expand All @@ -536,6 +537,26 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
loop(from, Nil, to :: Nil)
}

/** After phase `trans`, set the owner of every definition in this tree that was formerly
* owner by `from` to `to`.
*/
def changeOwnerAfter(from: Symbol, to: Symbol, trans: DenotTransformer)(implicit ctx: Context): ThisTree = {
assert(ctx.phase == trans.next)
val traverser = new TreeTraverser {
def traverse(tree: Tree) = tree match {
case tree: DefTree =>
val sym = tree.symbol
if (sym.denot(ctx.withPhase(trans)).owner == from)
sym.copySymDenotation(owner = to).installAfter(trans)
if (sym.isWeakOwner) traverseChildren(tree)
case _ =>
traverseChildren(tree)
}
}
traverser.traverse(tree)
tree
}

def select(name: Name)(implicit ctx: Context): Select =
Select(tree, name)

Expand Down
5 changes: 3 additions & 2 deletions src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ class ScalaSettings extends Settings.SettingGroup {
val Xdce = BooleanSetting("-Ydead-code", "Perform dead code elimination.")
val debug = BooleanSetting("-Ydebug", "Increase the quantity of debugging output.")
val debugNames = BooleanSetting("-YdebugNames", "Show name-space indicators when printing names")
val debugTrace = BooleanSetting("-YdebugTrace", "Trace core operations")
val debugFlags = BooleanSetting("-YdebugFlags", "Print all flags of definitions")
val debugTrace = BooleanSetting("-Ydebug-trace", "Trace core operations")
val debugFlags = BooleanSetting("-Ydebug-flags", "Print all flags of definitions")
val debugOwners = BooleanSetting("-Ydebug-owners", "Print all owners of definitions (requires -Yprint-syms)")
//val doc = BooleanSetting ("-Ydoc", "Generate documentation")
val termConflict = ChoiceSetting("-Yresolve-term-conflict", "strategy", "Resolve term conflicts", List("package", "object", "error"), "error")
val inline = BooleanSetting("-Yinline", "Perform inlining when possible.")
Expand Down
13 changes: 9 additions & 4 deletions src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -297,16 +297,21 @@ object Contexts {
def thisCallArgContext: Context = {
assert(owner.isClassConstructor)
val constrCtx = outersIterator.dropWhile(_.outer.owner == owner).next
var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
classCtx.superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
}

/** The super= or this-call context with given owner and locals. */
private def superOrThisCallContext(owner: Symbol, locals: Scope): FreshContext = {
assert(isClassDefContext)
outer.fresh.setOwner(owner).setScope(locals).setMode(ctx.mode | Mode.InSuperCall)
var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
classCtx.outer.fresh.setOwner(owner).setScope(locals).setMode(classCtx.mode | Mode.InSuperCall)
}

/** The context of expression `expr` seen as a member of a statement sequence */
def exprContext(stat: Tree[_ >: Untyped], exprOwner: Symbol) =
if (exprOwner == this.owner) this
else if (untpd.isSuperConstrCall(stat) && this.owner.isClass) superCallContext
else ctx.fresh.setOwner(exprOwner)

/** The current source file; will be derived from current
* compilation unit.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ object Denotations {
def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass

/** The denotation that has a type matching `targetType` when seen
/** The alternative of this denotation that has a type matching `targetType` when seen
* as a member of type `site`, `NoDenotation` if none exists.
*/
def matchingDenotation(site: Type, targetType: Type)(implicit ctx: Context): SingleDenotation =
Expand Down
24 changes: 10 additions & 14 deletions src/dotty/tools/dotc/core/NameOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ object NameOps {
}
}

object SuperAccessorName {
val pre = nme.SUPER_PREFIX
class PrefixNameExtractor(pre: TermName) {
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
}

object SuperAccessorName extends PrefixNameExtractor(nme.SUPER_PREFIX)
object InitializerName extends PrefixNameExtractor(nme.INITIALIZER_PREFIX)

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

Expand All @@ -68,14 +70,13 @@ object NameOps {
def isProtectedAccessorName = name startsWith PROTECTED_PREFIX
def isReplWrapperName = name containsSlice INTERPRETER_IMPORT_WRAPPER
def isSetterName = name endsWith SETTER_SUFFIX
def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_PREFIX)
def isSingletonName = name endsWith SINGLETON_SUFFIX
def isModuleClassName = name endsWith MODULE_SUFFIX
def isImportName = name startsWith IMPORT
def isFieldName = name endsWith LOCAL_SUFFIX
def isInheritedName = name.length > 0 && name.head == '(' && name.startsWith(nme.INHERITED)
def isDefaultGetterName = name.isTermName && name.asTermName.defaultGetterIndex >= 0

def isScala2LocalSuffix = name.endsWith(" ")
def isModuleVarName(name: Name): Boolean =
name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX

Expand Down Expand Up @@ -224,9 +225,6 @@ object NameOps {
implicit class TermNameDecorator(val name: TermName) extends AnyVal {
import nme._

def traitSetterName: TermName =
nme.TRAIT_SETTER_PREFIX ++ setterName

def setterName: TermName =
if (name.isFieldName) name.fieldToGetter.setterName
else name ++ SETTER_SUFFIX
Expand All @@ -240,13 +238,8 @@ object NameOps {
else name ++ LOCAL_SUFFIX

private def setterToGetter: TermName = {
val p = name.indexOfSlice(TRAIT_SETTER_PREFIX)
if (p >= 0)
(name drop (p + TRAIT_SETTER_PREFIX.length)).asTermName.getterName
else {
assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
name.take(name.length - SETTER_SUFFIX.length).asTermName
}
assert(name.endsWith(SETTER_SUFFIX), name + " is referenced as a setter but has wrong name format")
name.take(name.length - SETTER_SUFFIX.length).asTermName
}

def fieldToGetter: TermName = {
Expand Down Expand Up @@ -283,6 +276,9 @@ object NameOps {
-1
}

def stripScala2LocalSuffix: TermName =
if (name.isScala2LocalSuffix) name.init.asTermName else name

/** The name of an accessor for protected symbols. */
def protectedAccessorName: TermName =
PROTECTED_PREFIX ++ name.unexpandedName()
Expand Down
31 changes: 25 additions & 6 deletions src/dotty/tools/dotc/core/Scopes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import printing.Printer
import util.common._
import util.DotClass
import SymDenotations.NoDenotation
import collection.mutable.ListBuffer
import collection.mutable

object Scopes {

Expand Down Expand Up @@ -172,12 +172,27 @@ object Scopes {
*/
private var elemsCache: List[Symbol] = null

def cloneScope(implicit ctx: Context): MutableScope = newScopeWith(this.toList: _*)
/** Clone scope, taking care not to force the denotations of any symbols in the scope.
*/
def cloneScope(implicit ctx: Context): MutableScope = {
val entries = new mutable.ArrayBuffer[ScopeEntry]
var e = lastEntry
while ((e ne null) && e.owner == this) {
entries += e
e = e.prev
}
val scope = newScope
for (i <- entries.length - 1 to 0 by -1) {
val e = entries(i)
scope.newScopeEntry(e.name, e.sym)
}
scope
}

/** create and enter a scope entry */
protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry = {
/** create and enter a scope entry with given name and symbol */
protected def newScopeEntry(name: Name, sym: Symbol)(implicit ctx: Context): ScopeEntry = {
ensureCapacity(if (hashTable ne null) hashTable.length else MinHash)
val e = new ScopeEntry(sym.name, sym, this)
val e = new ScopeEntry(name, sym, this)
e.prev = lastEntry
lastEntry = e
if (hashTable ne null) enterInHash(e)
Expand All @@ -186,6 +201,10 @@ object Scopes {
e
}

/** create and enter a scope entry */
protected def newScopeEntry(sym: Symbol)(implicit ctx: Context): ScopeEntry =
newScopeEntry(sym.name, sym)

private def enterInHash(e: ScopeEntry)(implicit ctx: Context): Unit = {
val idx = e.name.hashCode & (hashTable.length - 1)
e.tail = hashTable(idx)
Expand Down Expand Up @@ -325,7 +344,7 @@ object Scopes {
}

override def implicitDecls(implicit ctx: Context): List[TermRef] = {
var irefs = new ListBuffer[TermRef]
var irefs = new mutable.ListBuffer[TermRef]
var e = lastEntry
while (e ne null) {
if (e.sym is Implicit) {
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ object StdNames {
val SINGLETON_SUFFIX: N = ".type"
val SPECIALIZED_SUFFIX: N = "$sp"
val SUPER_PREFIX: N = "super$"
val TRAIT_SETTER_PREFIX: N = "_setter_$"
val WHILE_PREFIX: N = "while$"
val DEFAULT_EXCEPTION_NAME: N = "ex$"
val DEFAULT_EXCEPTION_NAME: N = "ex$"
val INITIALIZER_PREFIX: N = "initial$"

// value types (and AnyRef) are all used as terms as well
// as (at least) arguments to the @specialize annotation.
Expand Down
10 changes: 7 additions & 3 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,14 @@ object SymDenotations {
final def isSourceMethod(implicit ctx: Context) = this is (Method, butNot = Accessor)

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

/** Is this a setter? */
final def isSetter(implicit ctx: Context) = (this is Accessor) && originalName.isSetterName
final def isSetter(implicit ctx: Context) =
(this is Accessor) &&
originalName.isSetterName &&
info.firstParamTypes.nonEmpty // to avoid being fooled by var x_= : Unit = ...

/** is this the constructor of a class? */
final def isClassConstructor = name == nme.CONSTRUCTOR
Expand Down Expand Up @@ -560,7 +564,7 @@ object SymDenotations {
def membersNeedAsSeenFrom(pre: Type)(implicit ctx: Context) =
!( this.isTerm
|| this.isStaticOwner
|| ctx.erasedTypes && symbol != defn.ArrayClass
|| ctx.erasedTypes
|| (pre eq NoPrefix) || (pre eq thisType)
)

Expand Down
Loading