Skip to content

Transform/flatten #203

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 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
25a8937
Add echo method to printers.
odersky Oct 17, 2014
3fea947
Avoid hoisting local classes
odersky Oct 17, 2014
979fa47
More assertions in TreeChecker.
odersky Oct 17, 2014
8b38acb
Insert .package for package object references
odersky Oct 19, 2014
0f3a903
TreeTypeMap needs to map declarations of mapped classes
odersky Oct 19, 2014
1a81244
Fix to TreeTypeMap
odersky Oct 19, 2014
7167c22
Implement findMember for JavaArrays
odersky Oct 19, 2014
f590cb3
Rename flag Static -> JavaStatic
odersky Oct 21, 2014
e3b0fa2
Fix flatten problem in erasure
odersky Oct 21, 2014
04001be
Two fixes to avoid scanning package contents
odersky Oct 21, 2014
98deca5
Fix to enclosingClass
odersky Oct 21, 2014
138045c
Fixes to LambdaLift
odersky Oct 21, 2014
e7cc8a4
Added missing case for SuperTypes to TypeComparer
odersky Oct 22, 2014
8543737
SuperTypes are now promoted in Retyper; lambdaLift fails to Ycheck ot…
odersky Oct 22, 2014
651ff01
LambdaLift checks now explicitly for references to labels outside scope.
odersky Oct 22, 2014
a426e92
Fixes erasure of super
odersky Oct 24, 2014
17b78ba
Strenghten postCondition of firstTransform
odersky Oct 24, 2014
02afa11
Initialize lambda lift maps
odersky Oct 24, 2014
55715f1
Replace some idents by selects in LambdaLift
odersky Oct 24, 2014
4d370b6
Almost all tests pass -Ycheck:lambdLift
odersky Oct 24, 2014
3a25072
Add missing and double symbol checking to TreeChecker
odersky Oct 24, 2014
8b0f2d6
Enabled commented out tests
odersky Oct 24, 2014
a5878de
Fix pattern matcher double defining symbols used in type tests that a…
DarkDimius Oct 24, 2014
f459bf0
Fix PreserveSubPatBinders not storing subparts that are used only for…
DarkDimius Oct 24, 2014
70946d7
Better tests and bugfix for named args
odersky Oct 26, 2014
a3ef72b
Make LambdaLift diagnostics log messages instead of printing them dir…
odersky Oct 26, 2014
1070499
Dropped comment.
odersky Oct 27, 2014
46eb5ea
Fix treatment of by name functions
odersky Oct 27, 2014
474b2ae
Added a test for by name functions
odersky Oct 28, 2014
bae24fd
Made LambdaLift capable of having minitransforms run after it.
odersky Oct 28, 2014
f865d2a
New miniphase: Flatten
odersky Oct 28, 2014
048b484
Generalize lift behavior between Flatten and LambdaLift
odersky Oct 28, 2014
e6eb680
New phase: RestoreScopes
odersky Oct 29, 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
7 changes: 5 additions & 2 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,11 @@ class Compiler {
new Literalize,
new GettersSetters),
List(new Erasure),
List(new CapturedVars, new Constructors)/*,
List(new LambdaLift)*/
List(new CapturedVars,
new Constructors),
List(new LambdaLift,
new Flatten,
new RestoreScopes)
)

var runId = 1
Expand Down
15 changes: 0 additions & 15 deletions src/dotty/tools/dotc/Flatten.scala

This file was deleted.

19 changes: 16 additions & 3 deletions src/dotty/tools/dotc/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ object TypeErasure {
erasure(tp)
}

/** The erasure of a symbol's info. This is different of `erasure` in the way `ExprType`s are
* treated. `eraseInfo` maps them them to nullary method types, whereas `erasure` maps them
* to `Function0`.
*/
def eraseInfo(tp: Type)(implicit ctx: Context): Type = scalaErasureFn.eraseInfo(tp)(erasureCtx)

/** The erasure of a function result type. Differs from normal erasure in that
* Unit is kept instead of being mapped to BoxedUnit.
*/
Expand All @@ -135,7 +141,7 @@ 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 erase(tp)(erasureCtx)
else eraseInfo(tp)(erasureCtx)
}

def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
Expand Down Expand Up @@ -258,10 +264,12 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
else this(parent)
case tp: TermRef =>
this(tp.widen)
case ThisType(_) | SuperType(_, _) =>
case ThisType(_) =>
tp
case SuperType(thistpe, supertpe) =>
SuperType(this(thistpe), this(supertpe))
case ExprType(rt) =>
MethodType(Nil, Nil, this(rt))
defn.FunctionClass(0).typeRef
case tp: TypeProxy =>
this(tp.underlying)
case AndType(tp1, tp2) =>
Expand Down Expand Up @@ -310,6 +318,11 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
else JavaArrayType(this(elemtp))
}

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

private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type =
unsupported("eraseDerivedValueClass")

Expand Down
35 changes: 25 additions & 10 deletions src/dotty/tools/dotc/ast/TreeTypeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,13 @@ final class TreeTypeMap(

override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = treeMap(tree) match {
case impl @ Template(constr, parents, self, body) =>
val tmap = withMappedSyms(impl.symbol :: impl.constr.symbol :: Nil)
val parents1 = parents mapconserve transform
val (_, constr1 :: self1 :: Nil) = transformDefs(constr :: self :: Nil)
val body1 = tmap.transformStats(body)
updateDecls(constr :: body, constr1 :: body1)
val tmap = withMappedSyms(localSyms(impl :: self :: Nil))
cpy.Template(impl)(
constr1.asInstanceOf[DefDef], parents1, self1.asInstanceOf[ValDef], body1)
.withType(tmap.mapType(impl.tpe))
constr = tmap.transformSub(constr),
parents = parents mapconserve transform,
self = tmap.transformSub(self),
body = body mapconserve tmap.transform
).withType(tmap.mapType(impl.tpe))
case tree1 =>
tree1.withType(mapType(tree1.tpe)) match {
case id: Ident if tpd.needsSelect(id.tpe) =>
Expand Down Expand Up @@ -160,8 +159,24 @@ final class TreeTypeMap(
* and return a treemap that contains the substitution
* between original and mapped symbols.
*/
def withMappedSyms(syms: List[Symbol]): TreeTypeMap = {
val mapped = ctx.mapSymbols(syms, this)
withSubstitution(syms, mapped)
def withMappedSyms(syms: List[Symbol], mapAlways: Boolean = false): TreeTypeMap =
withMappedSyms(syms, ctx.mapSymbols(syms, this, mapAlways))

/** The tree map with the substitution between originals `syms`
* and mapped symbols `mapped`. Also goes into mapped classes
* and substitutes their declarations.
*/
def withMappedSyms(syms: List[Symbol], mapped: List[Symbol]): TreeTypeMap = {
val symsChanged = syms ne mapped
val substMap = withSubstitution(syms, mapped)
val fullMap = (substMap /: mapped.filter(_.isClass)) { (tmap, cls) =>
val origDcls = cls.decls.toList
val mappedDcls = ctx.mapSymbols(origDcls, tmap)
val tmap1 = tmap.withMappedSyms(origDcls, mappedDcls)
if (symsChanged) (origDcls, mappedDcls).zipped.foreach(cls.asClass.replace)
tmap1
}
if (symsChanged || (fullMap eq substMap)) fullMap
else withMappedSyms(syms, mapAlways = true)
}
}
7 changes: 7 additions & 0 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,11 @@ object Trees {
s
}

/** If this is a thicket, gerform `op` on each of its trees
* otherwise, perform `op` ion tree itself.
*/
def foreachInThicket(op: Tree[T] => Unit): Unit = op(this)

override def toText(printer: Printer) = printer.toText(this)

override def hashCode(): Int = System.identityHashCode(this)
Expand Down Expand Up @@ -809,6 +814,8 @@ object Trees {
val newTrees = trees.map(_.withPos(pos))
new Thicket[T](newTrees).asInstanceOf[this.type]
}
override def foreachInThicket(op: Tree[T] => Unit): Unit =
trees foreach (_.foreachInThicket(op))
}

class EmptyValDef[T >: Untyped] extends ValDef[T](
Expand Down
7 changes: 7 additions & 0 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols.
import Denotations._, Decorators._
import config.Printers._
import typer.Mode
import collection.mutable
import typer.ErrorReporting._

import scala.annotation.tailrec
Expand Down Expand Up @@ -620,6 +621,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
acc(false, tree)
}

def filterSubTrees(f: Tree => Boolean): List[Tree] = {
val buf = new mutable.ListBuffer[Tree]
foreachSubTree { tree => if (f(tree)) buf += tree }
buf.toList
}
}

implicit class ListOfTreeDecorator(val xs: List[tpd.Tree]) extends AnyVal {
Expand Down
2 changes: 2 additions & 0 deletions src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ object Printers {

class Printer {
def println(msg: => String): Unit = System.out.println(msg)
def echo[T](msg: => String, value: T): T = { println(msg + value); value }
}

object noPrinter extends Printer {
override def println(msg: => String): Unit = ()
override def echo[T](msg: => String, value: T): T = value
}

val default: Printer = new Printer
Expand Down
5 changes: 5 additions & 0 deletions src/dotty/tools/dotc/core/Decorators.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ object Decorators {
else x1 :: xs1
}

def foldRightBN[U](z: => U)(op: (T, => U) => U): U = xs match {
case Nil => z
case x :: xs1 => op(x, xs1.foldRightBN(z)(op))
}

final def hasSameLengthAs[U](ys: List[U]): Boolean = {
@tailrec def loop(xs: List[T], ys: List[U]): Boolean =
if (xs.isEmpty) ys.isEmpty
Expand Down
14 changes: 8 additions & 6 deletions src/dotty/tools/dotc/core/Flags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,9 @@ object Flags {
final val JavaDefined = commonFlag(30, "<java>")

/** Symbol is implemented as a Java static */
final val Static = commonFlag(31, "<static>")
final val JavaStatic = commonFlag(31, "<static>")
final val JavaStaticTerm = JavaStatic.toTermFlags
final val JavaStaticType = JavaStatic.toTypeFlags

/** Variable is accessed from nested function. */
final val Captured = termFlag(32, "<captured>")
Expand Down Expand Up @@ -421,7 +423,7 @@ object Flags {
/** Flags representing source modifiers */
final val SourceModifierFlags =
commonFlags(Private, Protected, Abstract, Final,
Sealed, Case, Implicit, Override, AbsOverride, Lazy, Static)
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic)

/** Flags representing modifiers that can appear in trees */
final val ModifierFlags =
Expand All @@ -436,7 +438,7 @@ object Flags {
/** Flags guaranteed to be set upon symbol creation */
final val FromStartFlags =
AccessFlags | Module | Package | Deferred | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon |
InSuperCall | Touched | Static | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
InSuperCall | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
CaseAccessorOrTypeArgument | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent |
SelfNameOrImplClass

Expand Down Expand Up @@ -473,7 +475,7 @@ object Flags {
*/
final val RetainedModuleValAndClassFlags: FlagSet =
AccessFlags | Package | Case |
Synthetic | ExpandedName | JavaDefined | Static | Artifact |
Synthetic | ExpandedName | JavaDefined | JavaStatic | Artifact |
Erroneous | Lifted | MixedIn | Specialized

/** Flags that can apply to a module val */
Expand All @@ -487,7 +489,7 @@ object Flags {

/** Packages and package classes always have these flags set */
final val PackageCreationFlags =
Module | Package | Final | JavaDefined | Static
Module | Package | Final | JavaDefined

/** These flags are pickled */
final val PickledFlags = flagRange(FirstFlag, FirstNotPickledFlag)
Expand Down Expand Up @@ -562,7 +564,7 @@ object Flags {
final val ProtectedLocal = allOf(Protected, Local)

/** Java symbol which is `protected` and `static` */
final val StaticProtected = allOf(JavaDefined, Protected, Static)
final val StaticProtected = allOf(JavaDefined, Protected, JavaStatic)

final val AbstractFinal = allOf(Abstract, Final)
final val AbstractSealed = allOf(Abstract, Sealed)
Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/core/Scopes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ object Scopes {
if (e.sym == prev) e.sym = replacement
e = lookupNextEntry(e)
}
elemsCache = null
}

/** Lookup a symbol entry matching given name.
Expand Down
18 changes: 12 additions & 6 deletions src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ object SymDenotations {

/** Is this denotation static (i.e. with no outer instance)? */
final def isStatic(implicit ctx: Context) =
(this is Static) || this.exists && owner.isStaticOwner
(this is JavaStatic) || this.exists && owner.isStaticOwner

/** Is this a package class or module class that defines static symbols? */
final def isStaticOwner(implicit ctx: Context): Boolean =
Expand Down Expand Up @@ -666,10 +666,16 @@ object SymDenotations {
* for these definitions.
*/
final def enclosingClass(implicit ctx: Context): Symbol = {
def enclClass(d: SymDenotation): Symbol =
if (d.isClass || !d.exists) d.symbol else enclClass(d.owner)
val cls = enclClass(this)
if (this is InSuperCall) cls.owner.enclosingClass else cls
def enclClass(sym: Symbol, skip: Boolean): Symbol = {
def newSkip = sym.is(InSuperCall) || sym.is(JavaStaticTerm)
if (!sym.exists)
NoSymbol
else if (sym.isClass)
if (skip) enclClass(sym.owner, newSkip) else sym
else
enclClass(sym.owner, skip || newSkip)
}
enclClass(symbol, false)
}

final def isEffectivelyFinal(implicit ctx: Context): Boolean = {
Expand Down Expand Up @@ -976,7 +982,7 @@ object SymDenotations {
/** The type parameters of this class */
override final def typeParams(implicit ctx: Context): List[TypeSymbol] = {
def computeTypeParams = {
if (ctx.erasedTypes && (symbol ne defn.ArrayClass)) Nil
if (ctx.erasedTypes || is(Module)) Nil // fast return for modules to avoid scanning package decls
else if (this ne initial) initial.asSymDenotation.typeParams
else decls.filter(sym =>
(sym is TypeParam) && sym.owner == symbol).asInstanceOf[List[TypeSymbol]]
Expand Down
6 changes: 3 additions & 3 deletions src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,10 @@ trait Symbols { this: Context =>
* Cross symbol references are brought over from originals to copies.
* Do not copy any symbols if all attributes of all symbols stay the same.
*/
def mapSymbols(originals: List[Symbol], ttmap: TreeTypeMap) =
if (originals forall (sym =>
def mapSymbols(originals: List[Symbol], ttmap: TreeTypeMap, mapAlways: Boolean = false): List[Symbol] =
if (originals.forall(sym =>
(ttmap.mapType(sym.info) eq sym.info) &&
!(ttmap.oldOwners contains sym.owner)))
!(ttmap.oldOwners contains sym.owner)) && !mapAlways)
originals
else {
val copies: List[Symbol] = for (original <- originals) yield
Expand Down
8 changes: 8 additions & 0 deletions src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,14 @@ class TypeComparer(initctx: Context) extends DotClass {
case _ =>
secondTry(tp1, tp2)
}
case tp2: SuperType =>
tp1 match {
case tp1: SuperType =>
isSubType(tp1.thistpe, tp2.thistpe) &&
isSameType(tp1.supertpe, tp2.supertpe)
case _ =>
secondTry(tp1, tp2)
}
case AndType(tp21, tp22) =>
isSubType(tp1, tp21) && isSubType(tp1, tp22)
case ErrorType =>
Expand Down
4 changes: 4 additions & 0 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ object Types {
tp.tp1.derivesFrom(cls) || tp.tp2.derivesFrom(cls)
case tp: OrType =>
tp.tp1.derivesFrom(cls) && tp.tp2.derivesFrom(cls)
case tp: JavaArrayType =>
cls == defn.ObjectClass
case _ =>
false
}
Expand Down Expand Up @@ -408,6 +410,8 @@ object Types {
goAnd(l, r)
case OrType(l, r) =>
goOr(l, r)
case tp: JavaArrayType =>
defn.ObjectType.findMember(name, pre, excluded)
case ErrorType =>
ctx.newErrorSymbol(pre.classSymbol orElse defn.RootClass, name)
case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ object ClassfileConstants {
case JAVA_ACC_PROTECTED => Protected
case JAVA_ACC_FINAL => Final
case JAVA_ACC_SYNTHETIC => Synthetic
case JAVA_ACC_STATIC => Static
case JAVA_ACC_STATIC => JavaStatic
case JAVA_ACC_ABSTRACT => if (isAnnotation) EmptyFlags else if (isClass) Abstract else Deferred
case JAVA_ACC_INTERFACE => if (isAnnotation) EmptyFlags else JavaInterface
case _ => EmptyFlags
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/pickling/PickleBuffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ object PickleBuffer {
JAVA -> JavaDefined,
SYNTHETIC -> Synthetic,
STABLE -> Stable,
STATIC -> Static,
STATIC -> JavaStatic,
CASEACCESSOR -> CaseAccessor,
DEFAULTPARAM -> (DefaultParameterized, Trait),
BRIDGE -> Bridge,
Expand Down
Loading