aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala10
-rw-r--r--src/dotty/tools/dotc/ElimLocals.scala13
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala81
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala3
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala177
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala36
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala12
-rw-r--r--src/dotty/tools/dotc/core/DenotTransformers.scala8
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala59
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala36
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala21
-rw-r--r--src/dotty/tools/dotc/core/Periods.scala7
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala18
-rw-r--r--src/dotty/tools/dotc/core/Scopes.scala9
-rw-r--r--src/dotty/tools/dotc/core/Signature.scala2
-rw-r--r--src/dotty/tools/dotc/core/Substituters.scala6
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala88
-rw-r--r--src/dotty/tools/dotc/core/SymbolLoaders.scala6
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala34
-rw-r--r--src/dotty/tools/dotc/core/Types.scala57
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala20
-rw-r--r--src/dotty/tools/dotc/core/pickling/UnPickler.scala16
-rw-r--r--src/dotty/tools/dotc/core/transform/Erasure.scala2
-rw-r--r--src/dotty/tools/dotc/printing/PlainPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala28
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala3
-rw-r--r--src/dotty/tools/dotc/transform/Companions.scala67
-rw-r--r--src/dotty/tools/dotc/transform/Constructors.scala3
-rw-r--r--src/dotty/tools/dotc/transform/CreateCompanionObjects.scala53
-rw-r--r--src/dotty/tools/dotc/transform/ElimRepeated.scala61
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala21
-rw-r--r--src/dotty/tools/dotc/transform/ExtensionMethods.scala188
-rw-r--r--src/dotty/tools/dotc/transform/FullParameterization.scala225
-rw-r--r--src/dotty/tools/dotc/transform/InterceptedMethods.scala11
-rw-r--r--src/dotty/tools/dotc/transform/LazyVals.scala53
-rw-r--r--src/dotty/tools/dotc/transform/Literalize.scala65
-rw-r--r--src/dotty/tools/dotc/transform/MacroTransform.scala76
-rw-r--r--src/dotty/tools/dotc/transform/Nullarify.scala4
-rw-r--r--src/dotty/tools/dotc/transform/PostTyperTransformers.scala62
-rw-r--r--src/dotty/tools/dotc/transform/Splitter.scala4
-rw-r--r--src/dotty/tools/dotc/transform/SuperAccessors.scala557
-rw-r--r--src/dotty/tools/dotc/transform/TailRec.scala2
-rw-r--r--src/dotty/tools/dotc/transform/TreeTransform.scala14
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala4
-rw-r--r--src/dotty/tools/dotc/transform/TypeUtils.scala23
-rw-r--r--src/dotty/tools/dotc/transform/ValueClasses.scala36
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala7
-rw-r--r--src/dotty/tools/dotc/typer/ErrorReporting.scala2
-rw-r--r--src/dotty/tools/dotc/typer/EtaExpansion.scala4
-rw-r--r--src/dotty/tools/dotc/typer/ImportInfo.scala2
-rw-r--r--src/dotty/tools/dotc/typer/ReTyper.scala15
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala15
53 files changed, 1937 insertions, 393 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index a4a8fbbc8..95f74e290 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -11,7 +11,6 @@ import reporting.ConsoleReporter
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.transform._
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer}
-import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
import dotty.tools.dotc.core.Denotations.SingleDenotation
@@ -20,14 +19,17 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
- List(new LazyValsCreateCompanionObjects,
- new TailRec), //force separataion between lazyVals and LVCreateCO
+ List(new Companions, new ElimRepeated /*, new ElimLocals*/),
+ List(new SuperAccessors),
+ List(new ExtensionMethods),
+ List(new TailRec),
List(new PatternMatcher,
new LazyValTranformContext().transformer,
new Splitter),
List(new Nullarify,
new TypeTestsCasts,
- new InterceptedMethods),
+ new InterceptedMethods,
+ new Literalize),
List(new Erasure),
List(new UncurryTreeTransform
/* , new Constructors */)
diff --git a/src/dotty/tools/dotc/ElimLocals.scala b/src/dotty/tools/dotc/ElimLocals.scala
new file mode 100644
index 000000000..878783ffc
--- /dev/null
+++ b/src/dotty/tools/dotc/ElimLocals.scala
@@ -0,0 +1,13 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
+import DenotTransformers._
+
+/** Widens all private[this] and protected[this] qualifiers to just private/protected */
+abstract class ElimLocals extends TreeTransform with InfoTransformer { thisTransformer =>
+
+ // TODO complete
+
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index 734963ea3..1354f7375 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -282,41 +282,46 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped]
trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
- /** Is tree a definition that has no side effects when
- * evaluated as part of a block after the first time?
+ /** The purity level of this statement.
+ * @return pure if statement has no side effects
+ * idempotent if running the statement a second time has no side effects
+ * impure otherwise
*/
- def isIdempotentDef(tree: tpd.Tree)(implicit ctx: Context): Boolean = unsplice(tree) match {
+ private def statPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
case EmptyTree
| TypeDef(_, _, _)
| Import(_, _)
| DefDef(_, _, _, _, _, _) =>
- true
+ Pure
case ValDef(mods, _, _, rhs) =>
- !(mods is Mutable) && isIdempotentExpr(rhs)
+ if (mods is Mutable) Impure else exprPurity(rhs)
case _ =>
- false
+ Impure
}
- /** Is tree an expression which can be inlined without affecting program semantics?
+ /** The purity level of this expression.
+ * @return pure if expression has no side effects
+ * idempotent if running the expression a second time has no side effects
+ * impure otherwise
*
- * Note that this is not called "isExprPure" since purity (lack of side-effects)
- * is not the litmus test. References to modules and lazy vals are side-effecting,
- * both because side-effecting code may be executed and because the first reference
- * takes a different code path than all to follow; but they are safe to inline
- * because the expression result from evaluating them is always the same.
+ * Note that purity and idempotency are different. References to modules and lazy
+ * vals are impure (side-effecting) both because side-effecting code may be executed and because the first reference
+ * takes a different code path than all to follow; but they are idempotent
+ * because running the expression a second time gives the cached result.
*/
- def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context): Boolean = unsplice(tree) match {
+ private def exprPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
case EmptyTree
| This(_)
| Super(_, _)
| Literal(_) =>
- true
+ Pure
case Ident(_) =>
- isIdempotentRef(tree)
+ refPurity(tree)
case Select(qual, _) =>
- isIdempotentRef(tree) && isIdempotentExpr(qual)
+ refPurity(tree).min(
+ if (tree.symbol.is(Inline)) Pure else exprPurity(qual))
case TypeApply(fn, _) =>
- isIdempotentExpr(fn)
+ exprPurity(fn)
/*
* Not sure we'll need that. Comment out until we find out
case Apply(Select(free @ Ident(_), nme.apply), _) if free.symbol.name endsWith nme.REIFY_FREE_VALUE_SUFFIX =>
@@ -326,21 +331,36 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case Apply(fn, Nil) =>
// Note: After uncurry, field accesses are represented as Apply(getter, Nil),
// so an Apply can also be pure.
- // However, before typing, applications of nullary functional values are also
- // Apply(function, Nil) trees. To prevent them from being treated as pure,
- // we check that the callee is a method.
- // The callee might also be a Block, which has a null symbol, so we guard against that (SI-7185)
- fn.symbol != null && (fn.symbol is (Method, butNot = Lazy)) && isIdempotentExpr(fn)
+ if (fn.symbol is Stable) exprPurity(fn) else Impure
case Typed(expr, _) =>
- isIdempotentExpr(expr)
+ exprPurity(expr)
case Block(stats, expr) =>
- (stats forall isIdempotentDef) && isIdempotentExpr(expr)
+ (exprPurity(expr) /: stats.map(statPurity))(_ min _)
case _ =>
- false
+ Impure
}
+ def isPureExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) == Pure
+ def isIdempotentExpr(tree: tpd.Tree)(implicit ctx: Context) = exprPurity(tree) >= Idempotent
+
+ /** The purity level of this reference.
+ * @return
+ * pure if reference is (nonlazy and stable) or to a parameterized function
+ * idempotent if reference is lazy and stable
+ * impure otherwise
+ * @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
+ * flags set.
+ */
+ private def refPurity(tree: tpd.Tree)(implicit ctx: Context): PurityLevel =
+ if (!tree.tpe.widen.isParameterless) Pure
+ else if (!tree.symbol.is(Stable)) Impure
+ else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
+ else Pure
+
+ def isPureRef(tree: tpd.Tree)(implicit ctx: Context) =
+ refPurity(tree) == Pure
def isIdempotentRef(tree: tpd.Tree)(implicit ctx: Context) =
- tree.symbol.isStable || !tree.tpe.widen.isParameterless
+ refPurity(tree) >= Idempotent
/** Is symbol potentially a getter of a mutable variable?
*/
@@ -456,6 +476,15 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case nil =>
Nil
}
+
+ private class PurityLevel(val x: Int) {
+ def >= (that: PurityLevel) = x >= that.x
+ def min(that: PurityLevel) = new PurityLevel(x min that.x)
+ }
+
+ private val Pure = new PurityLevel(2)
+ private val Idempotent = new PurityLevel(1)
+ private val Impure = new PurityLevel(0)
}
/** a Match(Typed(_, tpt), _) must be translated into a switch if isSwitchAnnotation(tpt.tpe)
diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index dfd69c03c..8a36fee3a 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -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
}
}
@@ -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) =>
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 3b240ad2c..fecfefd37 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -4,7 +4,7 @@ package ast
import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
-import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
+import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._
import CheckTrees._, Denotations._, Decorators._
import config.Printers._
import typer.ErrorReporting._
@@ -25,17 +25,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Select(qualifier: Tree, name: Name)(implicit ctx: Context): Select =
ta.assignType(untpd.Select(qualifier, name), qualifier)
- def Select(qualifier: Tree, tp: NamedType)(implicit ctx: Context): Select =
- untpd.Select(qualifier, tp.name).withType(tp)
-
- def Select(qualifier: Tree, sym: Symbol)(implicit ctx: Context): Select =
- untpd.Select(qualifier, sym.name).withType(
- TermRef.withSig(qualifier.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(qualifier.tpe)))
-
- def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context) =
- untpd.SelectWithSig(qualifier, name, sig)
- .withType(TermRef.withSig(qualifier.tpe, name.asTermName, sig))
-
def SelectFromTypeTree(qualifier: Tree, name: Name)(implicit ctx: Context): SelectFromTypeTree =
ta.assignType(untpd.SelectFromTypeTree(qualifier, name), qualifier)
@@ -182,7 +171,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)
@@ -200,11 +192,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case tp => (Nil, tp)
}
val (vparamss, rtp) = valueParamss(mtp)
- val argss = vparamss map (_ map (vparam => Ident(vparam.termRef)))
+ val targs = tparams map (_.typeRef)
+ val argss = vparamss.nestedMap(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.nestedMap(ValDef(_)), TypeTree(rtp), rhsFn(targs)(argss)), sym)
}
def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef =
@@ -258,9 +251,9 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
/** A tree representing the same reference as the given type */
def ref(tp: NamedType)(implicit ctx: Context): NameTree =
- if (tp.symbol.isStatic) Ident(tp)
+ if (tp.symbol.isStatic || tp.prefix == NoPrefix) Ident(tp)
else tp.prefix match {
- case pre: TermRef => Select(ref(pre), tp)
+ case pre: TermRef => ref(pre).select(tp)
case pre => SelectFromTypeTree(TypeTree(pre), tp)
} // no checks necessary
@@ -283,12 +276,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
/** new C(args), calling given constructor `constr` of C */
def New(tp: Type, constr: TermSymbol, args: List[Tree])(implicit ctx: Context): Apply = {
val targs = tp.argTypes
- Apply(
- Select(
- New(tp withoutArgs targs),
- TermRef.withSig(tp.normalizedPrefix, constr))
- .appliedToTypes(targs),
- args)
+ New(tp withoutArgs targs)
+ .select(TermRef.withSig(tp.normalizedPrefix, constr))
+ .appliedToTypes(targs)
+ .appliedToArgs(args)
}
/** An object def
@@ -380,34 +371,95 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree =
new TreeTypeMap(ownerMap = (sym => if (sym == from) to else sym)).apply(tree)
+ def select(name: Name)(implicit ctx: Context): Select =
+ Select(tree, name)
+
+ def select(tp: NamedType)(implicit ctx: Context): Select =
+ untpd.Select(tree, tp.name).withType(tp)
+
+ def select(sym: Symbol)(implicit ctx: Context): Select =
+ untpd.Select(tree, sym.name).withType(
+ TermRef.withSig(tree.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(tree.tpe)))
+
+ def selectWithSig(name: Name, sig: Signature)(implicit ctx: Context) =
+ untpd.SelectWithSig(tree, name, sig)
+ .withType(TermRef.withSig(tree.tpe, name.asTermName, sig))
+
+ def appliedTo(arg: Tree)(implicit ctx: Context): Tree =
+ appliedToArgs(arg :: Nil)
+
+ def appliedTo(arg: Tree, args: Tree*)(implicit ctx: Context): Tree =
+ appliedToArgs(arg :: args.toList)
+
+ def appliedToArgs(args: List[Tree])(implicit ctx: Context): Apply =
+ Apply(tree, args)
+
+ def appliedToArgss(argss: List[List[Tree]])(implicit ctx: Context): Tree =
+ ((tree: Tree) /: argss)(Apply(_, _))
+
+ def appliedToNone(implicit ctx: Context): Apply = appliedToArgs(Nil)
+
+ def appliedToType(targ: Type)(implicit ctx: Context): Tree =
+ appliedToTypes(targ :: Nil)
+
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 {
def tpes: List[Type] = xs map (_.tpe)
}
- class TreeTypeMap(val typeMap: TypeMap = IdentityTypeMap, val ownerMap: Symbol => Symbol = identity _)(implicit ctx: Context) extends TreeMap {
- override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = super.transform {
- tree.withType(typeMap(tree.tpe)) match {
- case bind: tpd.Bind =>
- val sym = bind.symbol
- val newOwner = ownerMap(sym.owner)
- val newInfo = typeMap(sym.info)
- if ((newOwner ne sym.owner) || (newInfo ne sym.info))
- bind.withType(sym.copy(owner = newOwner, info = newInfo).namedType)
- else
- bind
+ /** A map that applies three functions together to a tree and makes sure
+ * they are coordinated so that the result is well-typed. The functions are
+ * @param typeMap A function from Type to type that gets applied to the
+ * type of every tree node and to all locally defined symbols
+ * @param ownerMap A function that translates owners of top-level local symbols
+ * defined in the mapped tree.
+ * @param treeMap A transformer that translates all encountered subtrees in
+ * prefix traversal order.
+ */
+ final class TreeTypeMap(
+ val typeMap: Type => Type = IdentityTypeMap,
+ val ownerMap: Symbol => Symbol = identity _,
+ val treeMap: Tree => Tree = identity _)(implicit ctx: Context) extends TreeMap {
+
+ override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = {
+ val tree1 = treeMap(tree)
+ tree1.withType(typeMap(tree1.tpe)) match {
+ case ddef @ DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ val (tmap1, tparams1) = transformDefs(ddef.tparams)
+ val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss)
+ cpy.DefDef(ddef, mods, name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(rhs))
+ case blk @ Block(stats, expr) =>
+ val (tmap1, stats1) = transformDefs(stats)
+ cpy.Block(blk, stats1, tmap1.transform(expr))
+ case cdef @ CaseDef(pat, guard, rhs) =>
+ val tmap = withMappedSyms(patVars(pat))
+ cpy.CaseDef(cdef, tmap.transform(pat), tmap.transform(guard), tmap.transform(rhs))
case tree1 =>
- tree1
+ super.transform(tree1)
}
}
- override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context) = {
- val locals = ta.localSyms(trees)
- val mapped = ctx.mapSymbols(locals, typeMap, ownerMap)
- if (locals eq mapped) super.transform(trees)
- else withSubstitution(locals, mapped).transform(trees)
+
+ override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context) =
+ transformDefs(trees)._2
+
+ private def transformDefs[TT <: tpd.Tree](trees: List[TT])(implicit ctx: Context): (TreeTypeMap, List[TT]) = {
+ val tmap = withMappedSyms(ta.localSyms(trees))
+ (tmap, tmap.transformSub(trees))
+ }
+
+ private def transformVParamss(vparamss: List[List[ValDef]]): (TreeTypeMap, List[List[ValDef]]) = vparamss match {
+ case vparams :: rest =>
+ val (tmap1, vparams1) = transformDefs(vparams)
+ val (tmap2, vparamss2) = tmap1.transformVParamss(rest)
+ (tmap2, vparams1 :: vparamss2)
+ case nil =>
+ (this, vparamss)
}
def apply[ThisTree <: tpd.Tree](tree: ThisTree): ThisTree = transform(tree).asInstanceOf[ThisTree]
@@ -418,10 +470,35 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}
/** The current tree map composed with a substitution [from -> to] */
- def withSubstitution(from: List[Symbol], to: List[Symbol]) =
- new TreeTypeMap(
- typeMap andThen ((tp: Type) => tp.substSym(from, to)),
- ownerMap andThen (from zip to).toMap)
+ def withSubstitution(from: List[Symbol], to: List[Symbol]): TreeTypeMap =
+ if (from eq to) this
+ else new TreeTypeMap(
+ typeMap andThen (_.substSym(from, to)),
+ ownerMap andThen { sym =>
+ val idx = from.indexOf(sym)
+ if (idx >= 0) to(idx) else sym
+ },
+ treeMap)
+
+ /** Apply `typeMap` and `ownerMap` to given symbols `syms`
+ * and return a treemap that contains the substitution
+ * between original and mapped symbols.
+ */
+ def withMappedSyms(syms: List[Symbol]): TreeTypeMap = {
+ val mapped = ctx.mapSymbols(syms, typeMap, ownerMap)
+ withSubstitution(syms, mapped)
+ }
+ }
+
+ /** The variables defined by a pattern, in reverse order of their appearance. */
+ def patVars(tree: Tree)(implicit ctx: Context): List[Symbol] = {
+ val acc = new TreeAccumulator[List[Symbol]] {
+ def apply(syms: List[Symbol], tree: Tree) = tree match {
+ case Bind(_, body) => apply(tree.symbol :: syms, body)
+ case _ => foldOver(syms, tree)
+ }
+ }
+ acc(Nil, tree)
}
// convert a numeric with a toXXX method
@@ -429,7 +506,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
val mname = ("to" + numericCls.name).toTermName
val conversion = tree.tpe member mname
if (conversion.symbol.exists)
- ensureApplied(Select(tree, conversion.symbol.termRef))
+ ensureApplied(tree.select(conversion.symbol.termRef))
else if (tree.tpe.widen isRef numericCls)
tree
else {
@@ -449,7 +526,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def runtimeCall(name: TermName, args: List[Tree])(implicit ctx: Context): Tree = ???
def mkAnd(tree1: Tree, tree2: Tree)(implicit ctx: Context) =
- Apply(Select(tree1, defn.Boolean_and), tree2 :: Nil)
+ tree1.select(defn.Boolean_and).appliedTo(tree2)
+
+ def mkAsInstanceOf(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
+ tree.select(defn.Any_asInstanceOf).appliedToType(pt)
+
+ 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?
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index 155ea87e0..cd7b46896 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -143,7 +143,7 @@ object Decorators {
* 2) Lists can be formatted using the desired separator between two `%` signs,
* eg `i"myList = (${myList}%, %)"`
*/
- implicit class InfoString(val sc: StringContext) extends AnyVal {
+ implicit class StringInterpolators(val sc: StringContext) extends AnyVal {
def i(args: Any*)(implicit ctx: Context): String = {
@@ -166,7 +166,39 @@ object Decorators {
val (args1, suffixes1) = (args, suffixes).zipped.map(treatArg(_, _)).unzip
new StringContext(prefix :: suffixes1.toList: _*).s(args1: _*)
}
- }
+ /** Lifted from scala.reflect.internal.util
+ * A safe combination of [[scala.collection.immutable.StringLike#stripMargin]]
+ * and [[scala.StringContext#raw]].
+ *
+ * The margin of each line is defined by whitespace leading up to a '|' character.
+ * This margin is stripped '''before''' the arguments are interpolated into to string.
+ *
+ * String escape sequences are '''not''' processed; this interpolater is designed to
+ * be used with triple quoted Strings.
+ *
+ * {{{
+ * scala> val foo = "f|o|o"
+ * foo: String = f|o|o
+ * scala> sm"""|${foo}
+ * |"""
+ * res0: String =
+ * "f|o|o
+ * "
+ * }}}
+ */
+ final def sm(args: Any*): String = {
+ def isLineBreak(c: Char) = c == '\n' || c == '\f' // compatible with StringLike#isLineBreak
+ def stripTrailingPart(s: String) = {
+ val (pre, post) = s.span(c => !isLineBreak(c))
+ pre + post.stripMargin
+ }
+ val stripped: List[String] = sc.parts.toList match {
+ case head :: tail => head.stripMargin :: (tail map stripTrailingPart)
+ case Nil => Nil
+ }
+ new StringContext(stripped: _*).raw(args: _*)
+ }
+ }
}
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 5e335e240..594f0c013 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -37,7 +37,7 @@ class Definitions {
scope.enter(newSymbol(cls, name, flags, TypeBounds.empty))
private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) =
- newTypeField(cls, name, flags | TypeParamCreationFlags, scope)
+ newTypeField(cls, name, flags | ClassTypeParamCreationFlags, scope)
private def newSyntheticTypeParam(cls: ClassSymbol, scope: MutableScope, paramFlags: FlagSet, suffix: String = "T0") =
newTypeParam(cls, suffix.toTypeName.expandedName(cls), ExpandedName | paramFlags, scope)
@@ -409,20 +409,20 @@ class Definitions {
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
- def isTupleType(tp: Type) = {
+ def isTupleType(tp: Type)(implicit ctx: Context) = {
val arity = tp.dealias.argInfos.length
arity <= MaxTupleArity && (tp isRef TupleClass(arity))
}
- def isProductSubType(tp: Type) =
+ def isProductSubType(tp: Type)(implicit ctx: Context) =
(tp derivesFrom ProductClass) && tp.baseClasses.exists(ProductClasses contains _)
- def isFunctionType(tp: Type) = {
+ def isFunctionType(tp: Type)(implicit ctx: Context) = {
val arity = functionArity(tp)
0 <= arity && arity <= MaxFunctionArity && (tp isRef FunctionClass(arity))
}
- def functionArity(tp: Type) = tp.dealias.argInfos.length - 1
+ def functionArity(tp: Type)(implicit ctx: Context) = tp.dealias.argInfos.length - 1
// ----- LambdaXYZ traits ------------------------------------------
@@ -544,7 +544,7 @@ class Definitions {
val BooleanEnc = 17
val UnitEnc = 19
- def isValueSubClass(cls1: Symbol, cls2: Symbol) =
+ def isValueSubClass(cls1: Symbol, cls2: Symbol)(implicit ctx: Context) =
valueClassEnc(cls2) % valueClassEnc(cls1) == 0
// ----- Initialization ---------------------------------------------------
diff --git a/src/dotty/tools/dotc/core/DenotTransformers.scala b/src/dotty/tools/dotc/core/DenotTransformers.scala
index 6daa028fc..e052a07ea 100644
--- a/src/dotty/tools/dotc/core/DenotTransformers.scala
+++ b/src/dotty/tools/dotc/core/DenotTransformers.scala
@@ -46,4 +46,12 @@ object DenotTransformers {
}
}
}
+
+ /** A `DenotTransformer` trait that has the identity as its `transform` method.
+ * You might want to inherit from this trait so that new denotations can be
+ * installed using `installAfter` and `enteredAfter` at the end of the phase.
+ */
+ trait IdentityDenotTransformer extends DenotTransformer {
+ def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref
+ }
}
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 264f9aa46..43fff62ec 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -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 =>
@@ -494,7 +494,8 @@ object Denotations {
} while (d ne denot)
initial.syncWithParents
case _ =>
- staleSymbolError
+ if (coveredInterval.containsPhaseId(ctx.phaseId)) staleSymbolError
+ else NoDenotation
}
/** Produce a denotation that is valid for the given context.
@@ -512,7 +513,13 @@ object Denotations {
def current(implicit ctx: Context): SingleDenotation = {
val currentPeriod = ctx.period
val valid = myValidFor
- assert(valid.code > 0)
+ if (valid.code <= 0) {
+ // can happen if we sit on a stale denotation which has been replaced
+ // wholesale by an installAfter; in this case, proceed to the next
+ // denotation and try again.
+ if (validFor == Nowhere && nextInRun.validFor != Nowhere) return nextInRun.current
+ assert(false)
+ }
if (valid.runId != currentPeriod.runId) bringForward.current
else {
@@ -551,6 +558,7 @@ object Denotations {
cur = next
}
cur.validFor = Period(currentPeriod.runId, startPid, transformer.lastPhaseId)
+ //printPeriods(cur)
//println(s"new denot: $cur, valid for ${cur.validFor}")
}
cur.current // multiple transformations could be required
@@ -563,23 +571,28 @@ object Denotations {
//println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
cur = cur.nextInRun
cnt += 1
- assert(cnt <= MaxPossiblePhaseId, s"seems to be a loop in Denotations for $this, currentPeriod = $currentPeriod")
+ assert(cnt <= MaxPossiblePhaseId, demandOutsideDefinedMsg)
}
cur
}
-
}
}
+ private def demandOutsideDefinedMsg(implicit ctx: Context): String =
+ s"demanding denotation of $this at phase ${ctx.phase}(${ctx.phaseId}) outside defined interval: defined periods are${definedPeriodsString}"
+
/** 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
assert(ctx.phaseId == targetId,
s"denotation update for $this called in phase ${ctx.phase}, expected was ${phase.next}")
val current = symbol.current
+ // println(s"installing $this after $phase/${phase.id}, valid = ${current.validFor}")
+ // printPeriods(current)
this.nextInRun = current.nextInRun
this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId)
if (current.validFor.firstPhaseId == targetId) {
@@ -587,12 +600,14 @@ object Denotations {
var prev = current
while (prev.nextInRun ne current) prev = prev.nextInRun
prev.nextInRun = this
+ current.validFor = Nowhere
}
else {
// insert this denotation after current
current.validFor = Period(ctx.runId, current.validFor.firstPhaseId, targetId - 1)
current.nextInRun = this
}
+ // printPeriods(this)
}
def staleSymbolError(implicit ctx: Context) = {
@@ -604,6 +619,22 @@ object Denotations {
throw new StaleSymbol(msg)
}
+ /** The period (interval of phases) for which there exists
+ * a valid denotation in this flock.
+ */
+ def coveredInterval(implicit ctx: Context): Period = {
+ var cur = this
+ var cnt = 0
+ var interval = validFor
+ do {
+ cur = cur.nextInRun
+ cnt += 1
+ assert(cnt <= MaxPossiblePhaseId, demandOutsideDefinedMsg)
+ interval |= cur.validFor
+ } while (cur ne this)
+ interval
+ }
+
/** For ClassDenotations only:
* If caches influenced by parent classes are still valid, the denotation
* itself, otherwise a freshly initialized copy.
@@ -614,10 +645,24 @@ object Denotations {
if (symbol == NoSymbol) symbol.toString
else s"<SingleDenotation of type $infoOrCompleter>"
+
+ def definedPeriodsString: String = {
+ var sb = new StringBuilder()
+ var cur = this
+ var cnt = 0
+ do {
+ sb.append(" " + cur.validFor)
+ cur = cur.nextInRun
+ cnt += 1
+ if (cnt > MaxPossiblePhaseId) { sb.append(" ..."); cur = this }
+ } while (cur ne this)
+ sb.toString
+ }
+
// ------ PreDenotation ops ----------------------------------------------
final def first = this
- final def toDenot(pre: Type)(implicit ctx: Context) = this
+ final def toDenot(pre: Type)(implicit ctx: Context): Denotation = this
final def containsSym(sym: Symbol): Boolean = hasUniqueSym && (symbol eq sym)
final def containsSig(sig: Signature)(implicit ctx: Context) =
exists && (signature matches sig)
@@ -764,7 +809,7 @@ object Denotations {
else DenotUnion(this, that)
}
- case class DenotUnion(denots1: PreDenotation, denots2: PreDenotation) extends PreDenotation {
+ final case class DenotUnion(denots1: PreDenotation, denots2: PreDenotation) extends PreDenotation {
assert(denots1.exists && denots2.exists, s"Union of non-existing denotations ($denots1) and ($denots2)")
def exists = true
def first = denots1.first
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 40da7525d..c467a553f 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -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(" ")
@@ -316,8 +324,8 @@ object Flags {
/** Symbol is initialized to the default value, e.g. var x: T = _ */
final val DefaultInit = termFlag(29, "<defaultinit>")
- /** Symbol is a macro */
- final val Macro = commonFlag(30, "<macro>")
+ /** Symbol is inlined */
+ final val Inline = commonFlag(30, "inline")
/** Symbol is defined by a Java class */
final val JavaDefined = commonFlag(31, "<java>")
@@ -387,14 +395,17 @@ object Flags {
/** A definition that's initialized before the super call (Scala 2.x only) */
final val Scala2PreSuper = termFlag(58, "<presuper>")
+ /** A macro (Scala 2.x only) */
+ final val Macro = commonFlag(59, "<macro>")
+
/** A method that is known to have inherited default parameters */
- final val InheritedDefaultParams = termFlag(59, "<inherited-default-param>")
+ final val InheritedDefaultParams = termFlag(60, "<inherited-default-param>")
- /** A method that is known to no default parameters */
- final val NoDefaultParams = termFlag(60, "<no-default-param>")
+ /** A method that is known to have no default parameters */
+ final val NoDefaultParams = termFlag(61, "<no-default-param>")
/** A denotation that is valid in all run-ids */
- final val Permanent = commonFlag(61, "<permanent>")
+ final val Permanent = commonFlag(62, "<permanent>")
// --------- Combined Flag Sets and Conjunctions ----------------------
@@ -405,7 +416,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
@@ -438,8 +452,8 @@ object Flags {
/** The flags of the self symbol */
final val SelfSymFlags = Private | Local | Deferred
- /** The flags of a type parameter */
- final val TypeParamCreationFlags = TypeParam | Deferred | Protected | Local
+ /** The flags of a class type parameter */
+ final def ClassTypeParamCreationFlags = TypeParam | Deferred | Protected | Local
/** Flags that can apply to both a module val and a module class, except those that
* are added at creation anyway
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index 5bdafcf8a..404a0844a 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -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._
@@ -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)
@@ -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 = {
@@ -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
diff --git a/src/dotty/tools/dotc/core/Periods.scala b/src/dotty/tools/dotc/core/Periods.scala
index 4ab04fad0..e0d9e3b5d 100644
--- a/src/dotty/tools/dotc/core/Periods.scala
+++ b/src/dotty/tools/dotc/core/Periods.scala
@@ -67,6 +67,8 @@ object Periods {
/** The first phase of this period */
def firstPhaseId = lastPhaseId - (code & PhaseMask)
+ def containsPhaseId(id: PhaseId) = firstPhaseId <= id && id <= lastPhaseId
+
/** Does this period contain given period? */
def contains(that: Period): Boolean = {
// Let this = (r1, l1, d1), that = (r2, l2, d2)
@@ -106,6 +108,11 @@ object Periods {
else
Nowhere
+ def | (that: Period): Period =
+ Period(this.runId,
+ this.firstPhaseId min that.firstPhaseId,
+ this.lastPhaseId max that.lastPhaseId)
+
override def toString = s"Period($firstPhaseId..$lastPhaseId, run = $runId)"
}
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index 7bc5f3052..aabde4cf9 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -9,7 +9,6 @@ import Denotations._
import config.Printers._
import scala.collection.mutable.{ListBuffer, ArrayBuffer}
import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, TreeTransform}
-import dotty.tools.dotc.transform.PostTyperTransformers.PostTyperTransformer
import dotty.tools.dotc.transform.TreeTransforms
import TreeTransforms.Separator
import Periods._
@@ -72,12 +71,10 @@ object Phases {
/** Squash TreeTransform's beloning to same sublist to a single TreeTransformer
* Each TreeTransform gets own period,
* whereas a combined TreeTransformer gets period equal to union of periods of it's TreeTransforms
- * first TreeTransformer emitted is PostTyperTransformer that simplifies trees, see it's documentation
*/
private def squashPhases(phasess: List[List[Phase]]): Array[Phase] = {
val squashedPhases = ListBuffer[Phase]()
var prevPhases: Set[String] = Set.empty
- var postTyperEmmited = false
var i = 0
while (i < phasess.length) {
if (phasess(i).length > 1) {
@@ -95,17 +92,10 @@ object Phases {
}
}
val transforms = phasess(i).asInstanceOf[List[TreeTransform]]
- val block =
- if (!postTyperEmmited) {
- postTyperEmmited = true
- new PostTyperTransformer {
- override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}")
- override def transformations: Array[TreeTransform] = transforms.toArray
- }
- } else new TreeTransformer {
- override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}")
- override def transformations: Array[TreeTransform] = transforms.toArray
- }
+ val block = new TreeTransformer {
+ override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}")
+ override def transformations: Array[TreeTransform] = transforms.toArray
+ }
squashedPhases += block
prevPhases ++= phasess(i).map(_.name)
block.init(this, phasess(i).head.id, phasess(i).last.id)
diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala
index 367713d11..919e35a7e 100644
--- a/src/dotty/tools/dotc/core/Scopes.scala
+++ b/src/dotty/tools/dotc/core/Scopes.scala
@@ -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
@@ -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
@@ -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
@@ -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
}
diff --git a/src/dotty/tools/dotc/core/Signature.scala b/src/dotty/tools/dotc/core/Signature.scala
index eb85fbb99..22d038d11 100644
--- a/src/dotty/tools/dotc/core/Signature.scala
+++ b/src/dotty/tools/dotc/core/Signature.scala
@@ -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)
diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala
index 1b96de47e..3d14317cb 100644
--- a/src/dotty/tools/dotc/core/Substituters.scala
+++ b/src/dotty/tools/dotc/core/Substituters.scala
@@ -205,7 +205,11 @@ trait Substituters { this: Context =>
final class SubstMap(from: List[Symbol], to: List[Type]) extends DeepTypeMap {
def apply(tp: Type): Type = subst(tp, from, to, this)
}
-
+/* not needed yet
+ final class SubstDealiasMap(from: List[Symbol], to: List[Type]) extends SubstMap(from, to) {
+ override def apply(tp: Type): Type = subst(tp.dealias, from, to, this)
+ }
+*/
final class SubstSymMap(from: List[Symbol], to: List[Symbol]) extends DeepTypeMap {
def apply(tp: Type): Type = substSym(tp, from, to, this)
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 802762045..b0a09baf0 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -83,6 +83,9 @@ object SymDenotations {
/** The owner of the symbol; overridden in NoDenotation */
def owner: Symbol = ownerIfExists
+ /** Same as owner, except returns NoSymbol for NoSymbol */
+ def maybeOwner: Symbol = if (exists) owner else NoSymbol
+
/** The flag set */
final def flags(implicit ctx: Context): FlagSet = { ensureCompleted(); myFlags }
@@ -212,6 +215,14 @@ object SymDenotations {
final def addAnnotation(annot: Annotation): Unit =
annotations = annot :: myAnnotations
+ /** Remove annotation with given class from this denotation */
+ final def removeAnnotation(cls: Symbol)(implicit ctx: Context): Unit =
+ annotations = myAnnotations.filterNot(_ matches cls)
+
+ /** Copy all annotations from given symbol by adding them to this symbol */
+ final def addAnnotations(from: Symbol)(implicit ctx: Context): Unit =
+ from.annotations.foreach(addAnnotation)
+
@tailrec
private def dropOtherAnnotations(anns: List[Annotation], cls: Symbol)(implicit ctx: Context): List[Annotation] = anns match {
case ann :: rest => if (ann matches cls) anns else dropOtherAnnotations(rest, cls)
@@ -321,6 +332,12 @@ object SymDenotations {
final def isAnonymousClass(implicit ctx: Context): Boolean =
initial.asSymDenotation.name startsWith tpnme.ANON_CLASS
+ /** Is symbol a primitive value class? */
+ def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains symbol
+
+ /** Is symbol a phantom class for which no runtime representation exists? */
+ def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains symbol
+
/** Is this symbol a class representing a refinement? These classes
* are used only temporarily in Typer and Unpickler as an intermediate
* step for creating Refinement types.
@@ -447,7 +464,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) = {
@@ -572,6 +589,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
@@ -624,8 +647,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.
@@ -747,7 +770,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
@@ -809,6 +831,11 @@ object SymDenotations {
else if (this is Contravariant) -1
else 0
+ /** The flags to be used for a type parameter owned by this symbol.
+ * Overridden by ClassDenotation.
+ */
+ def typeParamCreationFlags: FlagSet = TypeParam
+
override def toString = {
val kindString =
if (myFlags is ModuleClass) "module class"
@@ -848,6 +875,22 @@ object SymDenotations {
/** Install this denotation as the result of the given denotation transformer. */
override def installAfter(phase: DenotTransformer)(implicit ctx: Context): Unit =
super.installAfter(phase)
+
+ /** Remove private modifier from symbol's definition. If this symbol
+ * is not a constructor nor a static module, rename it by expanding its name to avoid name clashes
+ * @param base the fully qualified name of this class will be appended if name expansion is needed
+ */
+ final def makeNotPrivateAfter(base: Symbol, phase: DenotTransformer)(implicit ctx: Context): Unit = {
+ if (this.is(Private)) {
+ val newName =
+ if (this.is(Module) && isStatic || isClassConstructor) name
+ else {
+ if (this.is(Module)) moduleClass.makeNotPrivateAfter(base, phase)
+ name.expandedName(base)
+ }
+ copySymDenotation(name = newName, initFlags = flags &~ Private).installAfter(phase)
+ }
+ }
}
/** The contents of a class definition during a period
@@ -895,6 +938,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
@@ -938,6 +990,7 @@ object SymDenotations {
mySuperClassBits = null
myMemberFingerPrint = FingerPrint.unknown
myMemberCache = null
+ myMemberCachePeriod = Nowhere
memberNamesCache = SimpleMap.Empty
}
@@ -1036,6 +1089,8 @@ object SymDenotations {
(symbol eq defn.NothingClass) ||
(symbol eq defn.NullClass) && (base ne defn.NothingClass))
+ final override def typeParamCreationFlags = ClassTypeParamCreationFlags
+
private[this] var myMemberFingerPrint: FingerPrint = FingerPrint.unknown
private def computeMemberFingerPrint(implicit ctx: Context): FingerPrint = {
@@ -1070,9 +1125,13 @@ object SymDenotations {
}
private[this] var myMemberCache: LRUCache[Name, PreDenotation] = null
+ private[this] var myMemberCachePeriod: Period = Nowhere
- private def memberCache: LRUCache[Name, PreDenotation] = {
- if (myMemberCache == null) myMemberCache = new LRUCache
+ private def memberCache(implicit ctx: Context): LRUCache[Name, PreDenotation] = {
+ if (myMemberCachePeriod != ctx.period) {
+ myMemberCache = new LRUCache
+ myMemberCachePeriod = ctx.period
+ }
myMemberCache
}
@@ -1289,9 +1348,20 @@ object SymDenotations {
decls.denotsNamed(cname).first.symbol
}
- 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.
diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala
index bebad60cc..886c728b7 100644
--- a/src/dotty/tools/dotc/core/SymbolLoaders.scala
+++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala
@@ -12,7 +12,7 @@ import scala.compat.Platform.currentTime
import dotty.tools.io.{ ClassPath, AbstractFile }
import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, util.Positions._, Names._
import StdNames._, NameOps._
-import Decorators.StringDecorator
+import Decorators.{StringDecorator, StringInterpolators}
import pickling.ClassfileParser
object SymbolLoaders {
@@ -69,8 +69,8 @@ class SymbolLoaders {
// require yjp.jar at runtime. See SI-2089.
if (ctx.settings.termConflict.isDefault)
throw new TypeError(
- s"""$owner contains object and package with same name: $pname
- |one of them needs to be removed from classpath""".stripMargin)
+ sm"""$owner contains object and package with same name: $pname
+ |one of them needs to be removed from classpath""")
else if (ctx.settings.termConflict.value == "package") {
ctx.warning(
s"Resolving package/object name conflict in favor of package ${preExisting.fullName}. The object will be inaccessible.")
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 26553ddff..1767d7c0c 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -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}
@@ -250,7 +251,7 @@ trait Symbols { this: Context =>
val tparams = tparamBuf.toList
val bounds = boundsFn(trefBuf.toList)
for ((name, tparam, bound) <- (names, tparams, bounds).zipped)
- tparam.denot = SymDenotation(tparam, owner, name, flags | TypeParamCreationFlags, bound)
+ tparam.denot = SymDenotation(tparam, owner, name, flags | owner.typeParamCreationFlags, bound)
tparams
}
@@ -260,16 +261,14 @@ trait Symbols { this: Context =>
newSymbol(owner, name, SyntheticArtifact,
if (name.isTypeName) TypeAlias(ErrorType) else ErrorType)
- type OwnerMap = Symbol => Symbol
-
/** Map given symbols, subjecting all types to given type map and owner map.
* 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],
- typeMap: TypeMap = IdentityTypeMap,
- ownerMap: OwnerMap = identity)
+ typeMap: Type => Type = IdentityTypeMap,
+ ownerMap: Symbol => Symbol = identity)
=
if (originals forall (sym =>
(typeMap(sym.info) eq sym.info) && (ownerMap(sym.owner) eq sym.owner)))
@@ -358,6 +357,10 @@ object Symbols {
final def asType(implicit ctx: Context): TypeSymbol = { assert(isType, s"isType called on not-a-Type $this"); asInstanceOf[TypeSymbol] }
final def asClass: ClassSymbol = asInstanceOf[ClassSymbol]
+ /** Special cased here, because it may be used on naked symbols in substituters */
+ final def isStatic(implicit ctx: Context): Boolean =
+ lastDenot != null && denot.isStatic
+
/** A unique, densely packed integer tag for each class symbol, -1
* for all other symbols. To save memory, this method
* should be called only if class is a super class of some other class.
@@ -372,6 +375,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
@@ -381,14 +395,8 @@ object Symbols {
/** Is this symbol a user-defined value class? */
final def isDerivedValueClass(implicit ctx: Context): Boolean =
- false && // value classes are not supported yet
- isClass && denot.derivesFrom(defn.AnyValClass) && !isPrimitiveValueClass
-
- /** Is symbol a primitive value class? */
- def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains this
-
- /** Is symbol a phantom class for which no runtime representation exists? */
- def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains this
+ false // will migrate to ValueClasses.isDerivedValueClass;
+ // unsupported value class code will continue to use this stub while it exists
/** The current name of this symbol */
final def name(implicit ctx: Context): ThisName = denot.name.asInstanceOf[ThisName]
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 4885b30d8..289515ae1 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -813,11 +813,15 @@ object Types {
if (from1.isEmpty) ctx.subst1(this, from.head, to.head, null)
else {
val from2 = from1.tail
- if (from2.isEmpty) ctx.subst2(this, from.head, to.head, from.tail.head, to.tail.head, null)
+ if (from2.isEmpty) ctx.subst2(this, from.head, to.head, from1.head, to.tail.head, null)
else ctx.subst(this, from, to, null)
}
}
+/* Not needed yet:
+ final def substDealias(from: List[Symbol], to: List[Type])(implicit ctx: Context): Type =
+ new ctx.SubstDealiasMap(from, to).apply(this)
+*/
/** Substitute all types of the form `PolyParam(from, N)` by
* `PolyParam(to, N)`.
*/
@@ -1602,17 +1606,22 @@ object Types {
// and therefore two different poly types would never be equal.
/** A trait that mixes in functionality for signature caching */
- trait SignedType extends Type {
+ trait MethodicType extends Type {
private[this] var mySignature: Signature = _
private[this] var mySignatureRunId: Int = NoRunId
protected def computeSignature(implicit ctx: Context): Signature
- protected def resultSignature(implicit ctx: Context) = resultType match {
- case rtp: SignedType => rtp.signature
+ protected def resultSignature(implicit ctx: Context) = try resultType match {
+ case rtp: MethodicType => rtp.signature
case tp => Signature(tp, isJava = false)
}
+ catch {
+ case ex: AssertionError =>
+ println(i"failure while taking result signture of $resultType")
+ throw ex
+ }
final override def signature(implicit ctx: Context): Signature = {
if (ctx.runId != mySignatureRunId) {
@@ -1623,7 +1632,7 @@ object Types {
}
}
- trait MethodOrPoly extends SignedType
+ trait MethodOrPoly extends MethodicType
abstract case class MethodType(paramNames: List[TermName], paramTypes: List[Type])
(resultTypeExp: MethodType => Type)
@@ -1717,6 +1726,8 @@ object Types {
def apply(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType
def apply(paramNames: List[TermName], paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
apply(paramNames, paramTypes)(_ => resultType)
+ def apply(paramTypes: List[Type])(resultTypeExp: MethodType => Type)(implicit ctx: Context): MethodType =
+ apply(nme.syntheticParamNames(paramTypes.length), paramTypes)(resultTypeExp)
def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType)
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
@@ -1748,7 +1759,7 @@ object Types {
}
abstract case class ExprType(override val resultType: Type)
- extends CachedProxyType with TermType with SignedType {
+ extends CachedProxyType with TermType with MethodicType {
override def underlying(implicit ctx: Context): Type = resultType
protected def computeSignature(implicit ctx: Context): Signature = resultSignature
def derivedExprType(resultType: Type)(implicit ctx: Context) =
@@ -2019,19 +2030,31 @@ object Types {
decls: Scope,
selfInfo: DotClass /* should be: Type | Symbol */) extends CachedGroundType with TypeType {
- def selfType(implicit ctx: Context): Type = selfInfo match {
- case NoType =>
- if (selfTypeCache == null) selfTypeCache = computeSelfType(cls.typeRef, cls.typeParams)
- selfTypeCache
- case tp: Type => tp
- case self: Symbol => self.info
+ /** The self type of a class is the conjunction of
+ * - the explicit self type if given (or the info of a given self symbol), and
+ * - the fully applied reference to the class itself.
+ */
+ def selfType(implicit ctx: Context): Type = {
+ if (selfTypeCache == null) {
+ def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams)
+ selfTypeCache = selfInfo match {
+ case NoType =>
+ fullRef
+ case tp: Type =>
+ if (cls is Module) tp else AndType(tp, fullRef)
+ case self: Symbol =>
+ assert(!(cls is Module))
+ AndType(self.info, fullRef)
+ }
+ }
+ selfTypeCache
}
private var selfTypeCache: Type = null
- private def computeSelfType(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = tparams match {
+ private def fullyAppliedRef(base: Type, tparams: List[TypeSymbol])(implicit ctx: Context): Type = tparams match {
case tparam :: tparams1 =>
- computeSelfType(
+ fullyAppliedRef(
RefinedType(base, tparam.name, TypeRef(cls.thisType, tparam).toBounds(tparam)),
tparams1)
case nil =>
@@ -2077,8 +2100,8 @@ object Types {
if (prefix eq this.prefix) this
else ClassInfo(prefix, cls, classParents, decls, selfInfo)
- def derivedClassInfo(prefix: Type = this.prefix, classParents: List[TypeRef] = classParents, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) =
- if ((prefix eq this.prefix) && (classParents eq this.classParents) && (selfInfo eq this.selfInfo)) this
+ def derivedClassInfo(prefix: Type = this.prefix, classParents: List[TypeRef] = classParents, decls: Scope = this.decls, selfInfo: DotClass = this.selfInfo)(implicit ctx: Context) =
+ if ((prefix eq this.prefix) && (classParents eq this.classParents) && (decls eq this.decls) && (selfInfo eq this.selfInfo)) this
else ClassInfo(prefix, cls, classParents, decls, selfInfo)
override def computeHash = doHash(cls, prefix)
@@ -2431,7 +2454,7 @@ object Types {
case self: Type => this(self)
case _ => tp.self
}
- tp.derivedClassInfo(prefix1, parents1, self1)
+ tp.derivedClassInfo(prefix1, parents1, tp.decls, self1)
}
}
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index 0ed301732..59658c9c1 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -48,8 +48,8 @@ class ClassfileParser(
case e: RuntimeException =>
if (ctx.debug) e.printStackTrace()
throw new IOException(
- s"""class file $classfile is broken, reading aborted with $e.getClass
- |${Option(e.getMessage).getOrElse("")}""".stripMargin)
+ sm"""class file $classfile is broken, reading aborted with $e.getClass
+ |${Option(e.getMessage).getOrElse("")}""")
}
private def parseHeader(): Unit = {
@@ -353,7 +353,7 @@ class ClassfileParser(
val tpname = subName(':'.==).toTypeName
val expname = if (owner.isClass) tpname.expandedName(owner) else tpname
val s = ctx.newSymbol(
- owner, expname, Flags.TypeParamCreationFlags,
+ owner, expname, owner.typeParamCreationFlags,
typeParamCompleter(index), coord = indexCoord(index))
if (owner.isClass) owner.asClass.enter(s, owner.decls)
tparams = tparams + (tpname -> s)
@@ -702,12 +702,12 @@ class ClassfileParser(
getMember(owner, innerName.toTypeName)
}
assert(result ne NoSymbol,
- s"""failure to resolve inner class:
- |externalName = $externalName,
- |outerName = $outerName,
- |innerName = $innerName
- |owner.fullName = owner.showFullName
- |while parsing ${classfile}""".stripMargin)
+ sm"""failure to resolve inner class:
+ |externalName = $externalName,
+ |outerName = $outerName,
+ |innerName = $innerName
+ |owner.fullName = owner.showFullName
+ |while parsing ${classfile}""")
result
case None =>
@@ -752,7 +752,7 @@ class ClassfileParser(
private def setPrivateWithin(denot: SymDenotation, jflags: Int)(implicit ctx: Context): Unit = {
if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PUBLIC)) == 0)
- denot.privateWithin = denot.enclosingPackage
+ denot.privateWithin = denot.enclosingPackageClass
}
private def isPrivate(flags: Int) = (flags & JAVA_ACC_PRIVATE) != 0
diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
index dd26b20df..36b2c99bf 100644
--- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala
+++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala
@@ -53,10 +53,10 @@ object UnPickler {
val result = restpe.parameterizeWith(tparams)
for ((msg, pos) <- err)
ctx.warning(
- s"""$msg
- |originally parsed type : ${tp.show}
- |will be approximated by: ${result.show}.
- |Proceed at own risk.""".stripMargin)
+ sm"""$msg
+ |originally parsed type : ${tp.show}
+ |will be approximated by: ${result.show}.
+ |Proceed at own risk.""")
result
}
else
@@ -161,8 +161,8 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
protected def errorBadSignature(msg: String, original: Option[RuntimeException] = None)(implicit ctx: Context) = {
val ex = new BadSignature(
- s"""error reading Scala signature of $classRoot from $source:
- |error occured at position $readIndex: $msg""".stripMargin)
+ sm"""error reading Scala signature of $classRoot from $source:
+ |error occured at position $readIndex: $msg""")
/*if (debug)*/ original.getOrElse(ex).printStackTrace() // !!! DEBUG
throw ex
}
@@ -453,7 +453,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
var flags1 = flags
if (flags is TypeParam) {
name1 = name1.expandedName(owner)
- flags1 |= TypeParamCreationFlags | ExpandedName
+ flags1 |= owner.typeParamCreationFlags | ExpandedName
}
ctx.newSymbol(owner, name1, flags1, localMemberUnpickler, coord = start)
case CLASSsym =>
@@ -1080,7 +1080,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot:
setSym()
val qualifier = readTreeRef()
val selector = readNameRef()
- Select(qualifier, symbol.namedType)
+ qualifier.select(symbol.namedType)
case IDENTtree =>
setSymName()
Ident(symbol.namedType)
diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala
index da14f72d1..e35cdd128 100644
--- a/src/dotty/tools/dotc/core/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/core/transform/Erasure.scala
@@ -146,7 +146,7 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard
if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil
else if (cls eq defn.ArrayClass) defn.ObjectClass.typeRef :: Nil
else removeLaterObjects(classParents.mapConserve(eraseTypeRef))
- tp.derivedClassInfo(this(pre), parents, this(tp.selfType))
+ tp.derivedClassInfo(this(pre), parents, decls, this(tp.selfType))
case NoType | NoPrefix | ErrorType =>
tp
case tp: WildcardType if wildcardOK =>
diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 3a322648a..ec4a4db88 100644
--- a/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -319,6 +319,8 @@ class PlainPrinter(_ctx: Context) extends Printer {
case _ => ""
}
+ def annotsText(sym: Symbol): Text = Text(sym.annotations.map(toText))
+
def dclText(sym: Symbol): Text =
(toTextFlags(sym) ~~ keyString(sym) ~~
(varianceString(sym) ~ nameString(sym)) ~ toTextRHS(sym.unforcedInfo)).close
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 385b407b5..acba22afe 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -15,7 +15,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
override protected def recursionLimitExceeded() = {}
- protected val PrintableFlags = (SourceModifierFlags | Label | Module).toCommonFlags
+ protected val PrintableFlags = (SourceModifierFlags | Label | Module | Local).toCommonFlags
/** The closest enclosing DefDef, TypeDef, or ClassDef node */
private var currentOwner: untpd.Tree = untpd.EmptyTree
@@ -194,6 +194,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
case _ => toTextGlobal(arg)
}
+ def dclTextOr(treeText: => Text) =
+ if (ctx.isAfterTyper(ctx.phase) && tree.symbol != null && tree.symbol.exists)
+ annotsText(tree.symbol) ~~ dclText(tree.symbol)
+ else treeText
+
import untpd._
var txt: Text = tree match {
@@ -283,19 +288,24 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
"(" ~ toTextGlobal(patterns, ", ") ~ ")" ~
("(" ~ toTextGlobal(implicits, ", ") ~ ")" provided implicits.nonEmpty)
case ValDef(mods, name, tpt, rhs) =>
- modText(mods, if (mods is Mutable) "var" else "val") ~~ toText(name) ~
- optAscription(tpt) ~ optText(rhs)(" = " ~ _)
+ dclTextOr {
+ modText(mods, if (mods is Mutable) "var" else "val") ~~ toText(name) ~
+ optAscription(tpt)
+ } ~ optText(rhs)(" = " ~ _)
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
atOwner(tree) {
- val first = modText(mods, "def") ~~ toText(name) ~ tparamsText(tparams)
- addVparamssText(first, vparamss) ~ optAscription(tpt) ~ optText(rhs)(" = " ~ _)
+ dclTextOr {
+ val first = modText(mods, "def") ~~ toText(name) ~ tparamsText(tparams)
+ addVparamssText(first, vparamss) ~ optAscription(tpt)
+ } ~ optText(rhs)(" = " ~ _)
}
case tree @ TypeDef(mods, name, rhs) =>
atOwner(tree) {
- def typeDefText(rhsText: Text) = {
- val rhsText1 = if (tree.hasType) toText(tree.symbol.info) else rhsText
- modText(mods, "type") ~~ toText(name) ~ tparamsText(tree.tparams) ~ rhsText1
- }
+ def typeDefText(rhsText: Text) =
+ dclTextOr {
+ val rhsText1 = if (tree.hasType) toText(tree.symbol.info) else rhsText
+ modText(mods, "type") ~~ toText(name) ~ tparamsText(tree.tparams) ~ rhsText1
+ }
rhs match {
case impl: Template =>
modText(mods, if (mods is Trait) "trait" else "class") ~~ toText(name) ~ toText(impl) ~
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index 82b0a1158..7f0c88bc5 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -93,6 +93,9 @@ trait Reporting { this: Context =>
reporter.report(new Error(msg, pos))
}
+ def restrictionError(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
+ error(s"Implementation restriction: $msg", pos)
+
def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit =
reporter.incomplete(new Error(msg, pos))(ctx)
diff --git a/src/dotty/tools/dotc/transform/Companions.scala b/src/dotty/tools/dotc/transform/Companions.scala
new file mode 100644
index 000000000..0e31b511d
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/Companions.scala
@@ -0,0 +1,67 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Names._
+import TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
+import ast.Trees.flatten
+import Flags._
+import Contexts.Context
+import Symbols._
+import scala.collection.mutable
+import DenotTransformers._
+import Names.Name
+import NameOps._
+
+
+/** A transformer that provides a convenient way to create companion objects
+ */
+class Companions extends TreeTransform with IdentityDenotTransformer { thisTransformer =>
+ import ast.tpd._
+
+ override def name = "companions"
+
+ /** Reorder statements so that module classes always come after their companion classes, add missing companion classes */
+ private def reorderAndComplete(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
+ val moduleClassDefs, singleClassDefs = mutable.Map[Name, Tree]()
+
+ def reorder(stats: List[Tree]): List[Tree] = stats match {
+ case (stat: TypeDef) :: stats1 if stat.symbol.isClass =>
+ if (stat.symbol is Flags.Module) {
+ moduleClassDefs += (stat.name -> stat)
+ singleClassDefs -= stat.name.stripModuleClassSuffix
+ val stats1r = reorder(stats1)
+ if (moduleClassDefs contains stat.name) stat :: stats1r else stats1r
+ } else {
+ def stats1r = reorder(stats1)
+ val normalized = moduleClassDefs remove stat.name.moduleClassName match {
+ case Some(mcdef) =>
+ mcdef :: stats1r
+ case None =>
+ singleClassDefs += (stat.name -> stat)
+ stats1r
+ }
+ stat :: normalized
+ }
+ case stat :: stats1 => stat :: reorder(stats1)
+ case Nil => Nil
+ }
+
+ def newCompanion(name: TermName): Thicket = {
+ val modul = ctx.newCompleteModuleSymbol(ctx.owner, name, Synthetic, Synthetic,
+ defn.ObjectClass.typeRef :: Nil, Scopes.newScope)
+ if (ctx.owner.isClass) modul.enteredAfter(thisTransformer)
+ ModuleDef(modul, Nil)
+ }
+
+ def addMissingCompanions(stats: List[Tree]): List[Tree] = stats map {
+ case stat: TypeDef if singleClassDefs contains stat.name =>
+ Thicket(stat :: newCompanion(stat.name.toTermName).trees)
+ case stat => stat
+ }
+ addMissingCompanions(reorder(stats))
+ }
+
+ override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] =
+ ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisTransformer.next)))
+}
diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala
index bc9d6ea61..4bef41d8f 100644
--- a/src/dotty/tools/dotc/transform/Constructors.scala
+++ b/src/dotty/tools/dotc/transform/Constructors.scala
@@ -17,7 +17,8 @@ class Constructors extends TreeTransform {
val claz = tree.symbol.enclosingClass.asClass
val zuper = claz.info.parents.head.typeSymbol
cpy.DefDef(tree, tree.mods, tree.name, tree.tparams, tree.vparamss, tree.tpt, rhs = {
- val parentCall = Apply(Select(Super(This(claz), tpnme.EMPTY, true), zuper.primaryConstructor), Nil)
+ val parentCall =
+ Super(This(claz), tpnme.EMPTY, true).select(zuper.primaryConstructor).appliedToNone
if(tree.rhs.isEmpty) parentCall
else Block(List(parentCall), tree.rhs)
diff --git a/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala b/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
deleted file mode 100644
index b1cc8ea52..000000000
--- a/src/dotty/tools/dotc/transform/CreateCompanionObjects.scala
+++ /dev/null
@@ -1,53 +0,0 @@
-package dotty.tools.dotc.transform
-
-import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
-import dotty.tools.dotc.ast.tpd
-import dotty.tools.dotc.core.Contexts.Context
-import scala.collection.mutable.ListBuffer
-import dotty.tools.dotc.core.{Scopes, Flags}
-import dotty.tools.dotc.core.Symbols.NoSymbol
-import scala.annotation.tailrec
-import dotty.tools.dotc.core._
-import Symbols._
-import scala.Some
-import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer}
-import dotty.tools.dotc.ast.tpd
-import dotty.tools.dotc.core.Contexts.Context
-import scala.collection.mutable
-import dotty.tools.dotc.core.Names.Name
-import NameOps._
-
-/** A transformer that provides a convenient way to create companion objects
- */
-abstract class CreateCompanionObjects extends TreeTransform {
-
- import tpd._
-
- /** Given class definition should return true if companion object creation should be enforced
- */
- def predicate(cls: TypeDef)(implicit ctx: Context): Boolean
-
- override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[tpd.Tree] = {
- @tailrec
- def transformStats0(trees: List[Tree], acc: ListBuffer[Tree]): List[Tree] = {
- trees match {
- case Nil => acc.toList
- case (claz: TypeDef) :: stats if claz.symbol.isClass && !(claz.symbol is Flags.Module) => {
- val moduleExists = !(claz.symbol.companionModule eq NoSymbol)
- if (moduleExists || !predicate(claz)) transformStats0(stats, acc += claz)
- else {
- val moduleSymbol = ctx.newCompleteModuleSymbol(claz.symbol.owner, claz.name.toTermName, Flags.Synthetic, Flags.Synthetic, List(defn.ObjectClass.typeRef), Scopes.newScope)
- if (moduleSymbol.owner.isClass) moduleSymbol.entered
- val companion = tpd.ModuleDef(moduleSymbol, List(EmptyTree)).withPos(claz.pos)
- acc += claz
- acc += companion
- transformStats0(stats, acc)
- }
- }
- case stat :: stats => transformStats0(stats, acc += stat)
- }
- }
-
- transformStats0(trees, ListBuffer())
- }
-}
diff --git a/src/dotty/tools/dotc/transform/ElimRepeated.scala b/src/dotty/tools/dotc/transform/ElimRepeated.scala
new file mode 100644
index 000000000..a362aee07
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ElimRepeated.scala
@@ -0,0 +1,61 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Names._
+import Types._
+import TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
+import ast.Trees.flatten
+import Flags._
+import Contexts.Context
+import Symbols._
+import Denotations._, SymDenotations._
+import Decorators.StringInterpolators
+import scala.collection.mutable
+import DenotTransformers._
+import Names.Name
+import NameOps._
+import TypeUtils._
+
+/** A transformer that removes repeated parameters (T*) from all types, replacing
+ * them with Seq types.
+ */
+class ElimRepeated extends TreeTransform with InfoTransformer { thisTransformer =>
+ import ast.tpd._
+
+ override def name = "elimrepeated"
+
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
+ elimRepeated(tp)
+
+ private def elimRepeated(tp: Type)(implicit ctx: Context): Type = tp.stripTypeVar match {
+ case tp @ MethodType(paramNames, paramTypes) =>
+ val resultType1 = elimRepeated(tp.resultType)
+ val paramTypes1 =
+ if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) {
+ paramTypes.init :+
+ paramTypes.last.translateParameterized(defn.RepeatedParamClass, defn.SeqClass)
+ }
+ else paramTypes
+ tp.derivedMethodType(paramNames, paramTypes1, resultType1)
+ case tp: PolyType =>
+ tp.derivedPolyType(tp.paramNames, tp.paramBounds, elimRepeated(tp.resultType))
+ case tp =>
+ tp
+ }
+
+ def transformTypeOfTree(tree: Tree)(implicit ctx: Context): Tree =
+ tree.withType(elimRepeated(tree.tpe))
+
+ override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
+ transformTypeOfTree(tree)
+
+ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
+ transformTypeOfTree(tree)
+
+ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ transformTypeOfTree(tree)
+
+ override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ transformTypeOfTree(tree)
+}
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index e56132057..35742ac8c 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -22,6 +22,7 @@ import dotty.tools.dotc.ast.{Trees, tpd, untpd}
import ast.Trees._
import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.Flags
+import ValueClasses._
class Erasure extends Phase with DenotTransformer {
@@ -85,12 +86,12 @@ object Erasure {
def isPrimitiveValueType(tpe: Type)(implicit ctx: Context): Boolean = tpe.classSymbol.isPrimitiveValueClass
def constant(tree: Tree, const: Tree)(implicit ctx: Context) =
- if (isIdempotentExpr(tree)) Block(tree :: Nil, const) else const
+ if (isPureExpr(tree)) Block(tree :: Nil, const) else const
final def box(tree: Tree, target: => String = "")(implicit ctx: Context): Tree = ctx.traceIndented(i"boxing ${tree.showSummary}: ${tree.tpe} into $target") {
tree.tpe.widen match {
case ErasedValueType(clazz, _) =>
- New(clazz.typeRef, cast(tree, clazz.underlyingOfValueClass) :: Nil) // todo: use adaptToType?
+ New(clazz.typeRef, cast(tree, underlyingOfValueClass(clazz)) :: Nil) // todo: use adaptToType?
case tp =>
val cls = tp.classSymbol
if (cls eq defn.UnitClass) constant(tree, ref(defn.BoxedUnit_UNIT))
@@ -98,7 +99,7 @@ object Erasure {
else {
assert(cls ne defn.ArrayClass)
val arg = safelyRemovableUnboxArg(tree)
- if (arg.isEmpty) Apply(ref(boxMethod(cls.asClass)), tree :: Nil)
+ if (arg.isEmpty) ref(boxMethod(cls.asClass)).appliedTo(tree)
else {
ctx.log(s"boxing an unbox: ${tree.symbol} -> ${arg.tpe}")
arg
@@ -116,14 +117,16 @@ object Erasure {
// via the unboxed type would yield a NPE (see SI-5866)
unbox(tree, underlying)
else
- Apply(Select(adaptToType(tree, clazz.typeRef), clazz.valueClassUnbox), Nil)
+ adaptToType(tree, clazz.typeRef)
+ .select(valueClassUnbox(clazz))
+ .appliedToNone
cast(tree1, pt)
case _ =>
val cls = pt.classSymbol
if (cls eq defn.UnitClass) constant(tree, Literal(Constant(())))
else {
assert(cls ne defn.ArrayClass)
- Apply(ref(unboxMethod(cls.asClass)), tree :: Nil)
+ ref(unboxMethod(cls.asClass)).appliedTo(tree)
}
}
}
@@ -139,7 +142,7 @@ object Erasure {
cast(runtimeCall(nme.toObjectArray, tree :: Nil), pt)
case _ =>
ctx.log(s"casting from ${tree.showSummary}: ${tree.tpe.show} to ${pt.show}")
- TypeApply(Select(tree, defn.Any_asInstanceOf), TypeTree(pt) :: Nil)
+ mkAsInstanceOf(tree, pt)
}
/** Adaptation of an expression `e` to an expected type `PT`, applying the following
@@ -267,7 +270,7 @@ object Erasure {
override def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context) =
EmptyTree
- override def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[tpd.Tree] = {
+ override def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = {
val statsFlatten = Trees.flatten(stats)
val stats1 = super.typedStats(statsFlatten, exprOwner)
@@ -343,7 +346,7 @@ object Erasure {
bridge.entered // this should be safe, as we're executing in context of next phase
ctx.debuglog(s"generating bridge from ${newDef.symbol} to $bridge")
- val sel: Tree = tpd.Select(This(newDef.symbol.owner.asClass), newDef.symbol.termRef)
+ val sel: Tree = This(newDef.symbol.owner.asClass).select(newDef.symbol.termRef)
val resultType = bridge.info.widen.resultType
tpd.DefDef(bridge, { paramss: List[List[tpd.Tree]] =>
@@ -363,4 +366,4 @@ object Erasure {
if (tree.isEmpty) tree else adaptToType(tree, pt)
}
}
-} \ No newline at end of file
+}
diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
new file mode 100644
index 000000000..ba5b9fab6
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
@@ -0,0 +1,188 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2013 LAMP/EPFL
+ * @author Martin Odersky
+ */
+package dotty.tools.dotc
+package transform
+
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
+import ValueClasses._
+import dotty.tools.dotc.ast.{Trees, tpd}
+import scala.collection.{ mutable, immutable }
+import mutable.ListBuffer
+import core._
+import Phases.Phase
+import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
+import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._
+import TypeUtils._
+import util.Positions._
+import Decorators._
+
+/**
+ * Perform Step 1 in the inline classes SIP: Creates extension methods for all
+ * methods in a value class, except parameter or super accessors, or constructors.
+ */
+class ExtensionMethods extends MacroTransform with DenotTransformer with FullParameterization { thisTransformer =>
+
+ import tpd._
+
+ /** the following two members override abstract members in Transform */
+ val name: String = "extmethods"
+
+ override def runsAfter: Set[String] = Set("elimrepeated") // TODO: add tailrec
+
+ override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
+ case ref: ClassDenotation if ref is ModuleClass =>
+ ref.linkedClass match {
+ case origClass: ClassSymbol if isDerivedValueClass(origClass) =>
+ val cinfo = ref.classInfo
+ val decls1 = cinfo.decls.cloneScope
+ ctx.atPhase(thisTransformer.next) { implicit ctx =>
+ for (decl <- origClass.classInfo.decls) {
+ if (isMethodWithExtension(decl))
+ decls1.enter(createExtensionMethod(decl, ref.symbol))
+ }
+ }
+ if (decls1.isEmpty) ref
+ else ref.copySymDenotation(info = cinfo.derivedClassInfo(decls = decls1))
+ case _ =>
+ ref
+ }
+ case ref: SymDenotation
+ if isMethodWithExtension(ref) && ref.hasAnnotation(defn.TailrecAnnotationClass) =>
+ val ref1 = ref.copySymDenotation()
+ ref1.removeAnnotation(defn.TailrecAnnotationClass)
+ ref1
+ case _ =>
+ ref
+ }
+
+ def newTransformer(implicit ctx: Context): Transformer = new Extender
+
+ override def transformPhase(implicit ctx: Context): Phase = thisTransformer.next
+
+ protected def rewiredTarget(target: Symbol, derived: Symbol)(implicit ctx: Context): Symbol =
+ if (isMethodWithExtension(target) &&
+ target.owner.linkedClass == derived.owner) extensionMethod(target)
+ else NoSymbol
+
+ /** Generate stream of possible names for the extension version of given instance method `imeth`.
+ * If the method is not overloaded, this stream consists of just "imeth$extension".
+ * If the method is overloaded, the stream has as first element "imeth$extenionX", where X is the
+ * index of imeth in the sequence of overloaded alternatives with the same name. This choice will
+ * always be picked as the name of the generated extension method.
+ * After this first choice, all other possible indices in the range of 0 until the number
+ * of overloaded alternatives are returned. The secondary choices are used to find a matching method
+ * in `extensionMethod` if the first name has the wrong type. We thereby gain a level of insensitivity
+ * of how overloaded types are ordered between phases and picklings.
+ */
+ private def extensionNames(imeth: Symbol)(implicit ctx: Context): Stream[Name] = {
+ val decl = imeth.owner.info.decl(imeth.name)
+
+ /** No longer needed for Dotty, as we are more disciplined with scopes now.
+ // Bridge generation is done at phase `erasure`, but new scopes are only generated
+ // for the phase after that. So bridges are visible in earlier phases.
+ //
+ // `info.member(imeth.name)` filters these out, but we need to use `decl`
+ // to restrict ourselves to members defined in the current class, so we
+ // must do the filtering here.
+ val declTypeNoBridge = decl.filter(sym => !sym.isBridge).tpe
+ */
+ decl match {
+ case decl: MultiDenotation =>
+ val alts = decl.alternatives
+ val index = alts indexOf imeth.denot
+ assert(index >= 0, alts+" does not contain "+imeth)
+ def altName(index: Int) = (imeth.name+"$extension"+index).toTermName
+ altName(index) #:: ((0 until alts.length).toStream filter (index != _) map altName)
+ case decl =>
+ assert(decl.exists, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls)
+ Stream((imeth.name+"$extension").toTermName)
+ }
+ }
+
+ /** Return the extension method that corresponds to given instance method `meth`. */
+ def extensionMethod(imeth: Symbol)(implicit ctx: Context): TermSymbol =
+ ctx.atPhase(thisTransformer.next) { implicit ctx =>
+ // FIXME use toStatic instead?
+ val companionInfo = imeth.owner.companionModule.info
+ val candidates = extensionNames(imeth) map (companionInfo.decl(_).symbol) filter (_.exists)
+ val matching = candidates filter (c => memberSignature(c.info) == imeth.signature)
+ assert(matching.nonEmpty,
+ sm"""|no extension method found for:
+ |
+ | $imeth:${imeth.info.show} with signature ${imeth.signature}
+ |
+ | Candidates:
+ |
+ | ${candidates.map(c => c.name + ":" + c.info.show).mkString("\n")}
+ |
+ | Candidates (signatures normalized):
+ |
+ | ${candidates.map(c => c.name + ":" + c.info.signature + ":" + memberSignature(c.info)).mkString("\n")}
+ |
+ | Eligible Names: ${extensionNames(imeth).mkString(",")}""")
+ matching.head.asTerm
+ }
+
+ private def createExtensionMethod(imeth: Symbol, staticClass: Symbol)(implicit ctx: Context): TermSymbol = {
+ assert(ctx.phase == thisTransformer.next)
+ val extensionName = extensionNames(imeth).head.toTermName
+ val extensionMeth = ctx.newSymbol(staticClass, extensionName,
+ imeth.flags | Final &~ (Override | Protected | AbsOverride),
+ fullyParameterizedType(imeth.info, imeth.owner.asClass),
+ privateWithin = imeth.privateWithin, coord = imeth.coord)
+ extensionMeth.addAnnotations(from = imeth)(ctx.withPhase(thisTransformer))
+ // need to change phase to add tailrec annotation which gets removed from original method in the same phase.
+ extensionMeth
+ }
+
+ class Extender extends Transformer {
+ private val extensionDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]()
+
+ def checkNonCyclic(pos: Position, seen: Set[Symbol], clazz: ClassSymbol)(implicit ctx: Context): Unit =
+ if (seen contains clazz)
+ ctx.error("value class may not unbox to itself", pos)
+ else {
+ val unboxed = underlyingOfValueClass(clazz).typeSymbol
+ if (isDerivedValueClass(unboxed)) checkNonCyclic(pos, seen + clazz, unboxed.asClass)
+ }
+
+ override def transform(tree: Tree)(implicit ctx: Context): Tree = {
+ tree match {
+ case tree: Template =>
+ if (isDerivedValueClass(ctx.owner)) {
+ /* This is currently redundant since value classes may not
+ wrap over other value classes anyway.
+ checkNonCyclic(ctx.owner.pos, Set(), ctx.owner) */
+ extensionDefs(ctx.owner.linkedClass) = new mutable.ListBuffer[Tree]
+ ctx.owner.primaryConstructor.makeNotPrivateAfter(NoSymbol, thisTransformer)
+ // SI-7859 make param accessors accessible so the erasure can generate unbox operations.
+ val paramAccessors = ctx.owner.info.decls.filter(_.is(TermParamAccessor))
+ paramAccessors.foreach(_.makeNotPrivateAfter(ctx.owner, thisTransformer))
+ super.transform(tree)
+ } else if (ctx.owner.isStaticOwner) {
+ val tree1 @ Template(constr, parents, selfType, body) = super.transform(tree)
+ extensionDefs remove tree1.symbol.owner match {
+ case Some(defns) if defns.nonEmpty =>
+ cpy.Template(tree1, constr, parents, selfType, body ++ defns)
+ case _ =>
+ tree1
+ }
+ } else tree
+ case ddef: DefDef if isMethodWithExtension(tree.symbol) =>
+ val origMeth = tree.symbol
+ val origClass = ctx.owner.asClass
+ val staticClass = origClass.linkedClass
+ assert(staticClass.exists, s"$origClass lacks companion, ${origClass.owner.definedPeriodsString} ${origClass.owner.info.decls} ${origClass.owner.info.decls}")
+ val extensionMeth = extensionMethod(origMeth)
+ ctx.log(s"Value class $origClass spawns extension method.\n Old: ${origMeth.showDcl}\n New: ${extensionMeth.showDcl}")
+ extensionDefs(staticClass) += fullyParameterizedDef(extensionMeth, ddef)
+ cpy.DefDef(tree, ddef.mods, ddef.name, ddef.tparams, ddef.vparamss, ddef.tpt,
+ forwarder(extensionMeth, ddef))
+ case _ =>
+ super.transform(tree)
+ }
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/FullParameterization.scala b/src/dotty/tools/dotc/transform/FullParameterization.scala
new file mode 100644
index 000000000..fea0482a0
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/FullParameterization.scala
@@ -0,0 +1,225 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Types._
+import Contexts._
+import Symbols._
+import Decorators._
+import StdNames.nme
+import NameOps._
+import ast._
+import ast.Trees._
+
+/** Provides methods to produce fully parameterized versions of instance methods,
+ * where the `this` of the enclosing class is abstracted out in an extra leading
+ * `$this` parameter and type parameters of the class become additional type
+ * parameters of the fully parameterized method.
+ *
+ * Example usage scenarios are:
+ *
+ * - extension methods of value classes
+ * - implementations of trait methods
+ * - static protected accessors
+ * - local methods produced by tailrec transform
+ *
+ * Note that the methods lift out type parameters of the class containing
+ * the instance method, but not type parameters of enclosing classes. The
+ * fully instantiated method therefore needs to be put in a scope "close"
+ * to the original method, i.e. they need to share the same outer pointer.
+ * Examples of legal positions are: in the companion object, or as a local
+ * method inside the original method.
+ *
+ * Note: The scheme does not handle yet methods where type parameter bounds
+ * depend on value parameters of the enclosing class, as in:
+ *
+ * class C(val a: String) extends AnyVal {
+ * def foo[U <: a.type]: Unit = ...
+ * }
+ *
+ * The expansion of method `foo` would lead to
+ *
+ * def foo$extension[U <: $this.a.type]($this: C): Unit = ...
+ *
+ * which is not typable. Not clear yet what to do. Maybe allow PolyTypes
+ * to follow method parameters and translate to the following:
+ *
+ * def foo$extension($this: C)[U <: $this.a.type]: Unit = ...
+ *
+ * @see class-dependent-extension-method.scala in pending/pos.
+ */
+trait FullParameterization {
+
+ import tpd._
+
+ /** If references to original symbol `referenced` from within fully parameterized method
+ * `derived` should be rewired to some fully parameterized method, the rewiring target symbol,
+ * otherwise NoSymbol.
+ */
+ protected def rewiredTarget(referenced: Symbol, derived: Symbol)(implicit ctx: Context): Symbol
+
+ /** If references to some original symbol from given tree node within fully parameterized method
+ * `derived` should be rewired to some fully parameterized method, the rewiring target symbol,
+ * otherwise NoSymbol. By default implemented as
+ *
+ * rewiredTarget(tree.symbol, derived)
+ *
+ * but can be overridden.
+ */
+ protected def rewiredTarget(tree: Tree, derived: Symbol)(implicit ctx: Context): Symbol =
+ rewiredTarget(tree.symbol, derived)
+
+ /** Converts the type `info` of a member of class `clazz` to a method type that
+ * takes the `this` of the class and any type parameters of the class
+ * as additional parameters. Example:
+ *
+ * class Foo[+A <: AnyRef](val xs: List[A]) extends AnyVal {
+ * def baz[B >: A](x: B): List[B] = ...
+ * }
+ *
+ * leads to:
+ *
+ * object Foo {
+ * def extension$baz[B >: A <: Any, A >: Nothing <: AnyRef]($this: Foo[A])(x: B): List[B]
+ * }
+ *
+ * If a self type is present, $this has this self type as its type.
+ */
+ def fullyParameterizedType(info: Type, clazz: ClassSymbol)(implicit ctx: Context): Type = {
+ val (mtparamCount, origResult) = info match {
+ case info @ PolyType(mtnames) => (mtnames.length, info.resultType)
+ case info: ExprType => (0, info.resultType)
+ case _ => (0, info)
+ }
+ val ctparams = clazz.typeParams
+ val ctnames = ctparams.map(_.name.unexpandedName())
+
+ /** The method result type */
+ def resultType(mapClassParams: Type => Type) = {
+ val thisParamType = mapClassParams(clazz.classInfo.selfType)
+ MethodType(nme.SELF :: Nil, thisParamType :: Nil)(mt =>
+ mapClassParams(origResult).substThis(clazz, MethodParam(mt, 0)))
+ }
+
+ /** Replace class type parameters by the added type parameters of the polytype `pt` */
+ def mapClassParams(tp: Type, pt: PolyType): Type = {
+ val classParamsRange = (mtparamCount until mtparamCount + ctparams.length).toList
+ tp.subst(clazz.typeParams, classParamsRange map (PolyParam(pt, _)))
+ }
+
+ /** The bounds for the added type paraneters of the polytype `pt` */
+ def mappedClassBounds(pt: PolyType): List[TypeBounds] =
+ ctparams.map(tparam => mapClassParams(tparam.info, pt).bounds)
+
+ info match {
+ case info @ PolyType(mtnames) =>
+ PolyType(mtnames ++ ctnames)(
+ pt => (info.paramBounds ++ mappedClassBounds(pt))
+ .mapConserve(_.subst(info, pt).bounds),
+ pt => resultType(mapClassParams(_, pt)).subst(info, pt))
+ case _ =>
+ if (ctparams.isEmpty) resultType(identity)
+ else PolyType(ctnames)(mappedClassBounds, pt => resultType(mapClassParams(_, pt)))
+ }
+ }
+
+ /** Assuming `info` is a result of a `fullyParameterizedType` call, the signature of the
+ * original method type `X` such that `info = fullyParameterizedType(X, ...)`.
+ */
+ 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
+ }
+
+ /** The type parameters (skolems) of the method definition `originalDef`,
+ * followed by the class parameters of its enclosing class.
+ */
+ private def allInstanceTypeParams(originalDef: DefDef)(implicit ctx: Context): List[Symbol] =
+ originalDef.tparams.map(_.symbol) ::: originalDef.symbol.owner.typeParams
+
+ /** Given an instance method definition `originalDef`, return a
+ * fully parameterized method definition derived from `originalDef`, which
+ * has `derived` as symbol and `fullyParameterizedType(originalDef.symbol.info)`
+ * as info.
+ */
+ def fullyParameterizedDef(derived: TermSymbol, originalDef: DefDef)(implicit ctx: Context): Tree =
+ polyDefDef(derived, trefs => vrefss => {
+ val origMeth = originalDef.symbol
+ val origClass = origMeth.owner.asClass
+ val origTParams = allInstanceTypeParams(originalDef)
+ val origVParams = originalDef.vparamss.flatten map (_.symbol)
+ val thisRef :: argRefs = vrefss.flatten
+
+ /** If tree should be rewired, the rewired tree, otherwise EmptyTree.
+ * @param targs Any type arguments passed to the rewired tree.
+ */
+ def rewireTree(tree: Tree, targs: List[Tree])(implicit ctx: Context): Tree = {
+ def rewireCall(thisArg: Tree): Tree = {
+ val rewired = rewiredTarget(tree, derived)
+ if (rewired.exists) {
+ val base = thisArg.tpe.baseTypeWithArgs(origClass)
+ assert(base.exists)
+ ref(rewired.termRef)
+ .appliedToTypeTrees(targs ++ base.argInfos.map(TypeTree(_)))
+ .appliedTo(thisArg)
+ } else EmptyTree
+ }
+ tree match {
+ case Ident(_) => rewireCall(thisRef)
+ case Select(qual, _) => rewireCall(qual)
+ case tree @ TypeApply(fn, targs1) =>
+ assert(targs.isEmpty)
+ rewireTree(fn, targs1)
+ case _ => EmptyTree
+ }
+ }
+
+ /** Type rewiring is needed because a previous reference to an instance
+ * method might still persist in the types of enclosing nodes. Example:
+ *
+ * if (true) this.imeth else this.imeth
+ *
+ * is rewritten to
+ *
+ * if (true) xmeth($this) else xmeth($this)
+ *
+ * but the type `this.imeth` still persists as the result type of the `if`,
+ * because it is kept by the `cpy` operation of the tree transformer.
+ * It needs to be rewritten to the common result type of `imeth` and `xmeth`.
+ */
+ def rewireType(tpe: Type) = tpe match {
+ case tpe: TermRef if rewiredTarget(tpe.symbol, derived).exists => tpe.widen
+ case _ => tpe
+ }
+
+ new TreeTypeMap(
+ typeMap = rewireType(_)
+ .subst(origTParams, trefs)
+ .subst(origVParams, argRefs.map(_.tpe))
+ .substThis(origClass, thisRef.tpe),
+ ownerMap = (sym => if (sym eq origMeth) derived else sym),
+ treeMap = {
+ case tree: This if tree.symbol == origClass => thisRef
+ case tree => rewireTree(tree, Nil) orElse tree
+ }).transform(originalDef.rhs)
+ })
+
+ /** A forwarder expression which calls `derived`, passing along
+ * - the type parameters and enclosing class parameters of `originalDef`,
+ * - the `this` of the enclosing class,
+ * - the value parameters of the original method `originalDef`.
+ */
+ def forwarder(derived: TermSymbol, originalDef: DefDef)(implicit ctx: Context): Tree =
+ ref(derived.termRef)
+ .appliedToTypes(allInstanceTypeParams(originalDef).map(_.typeRef))
+ .appliedTo(This(originalDef.symbol.owner.asClass))
+ .appliedToArgss(originalDef.vparamss.nestedMap(vparam => ref(vparam.symbol)))
+ .withPos(originalDef.rhs.pos)
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
index f5fed6fda..6dd66ec75 100644
--- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala
+++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
@@ -91,9 +91,8 @@ class InterceptedMethods extends TreeTransform {
def alt2 = defn.ScalaRuntimeModule.info.member(nme.hash_)
.suchThat(_.info.firstParamTypes.head.typeSymbol == defn.AnyClass)
- if (defn.ScalaNumericValueClasses contains s) {
- tpd.Apply(Ident(alt1.termRef), List(tree))
- } else tpd.Apply(Ident(alt2.termRef), List(tree))
+ Ident((if (defn.ScalaNumericValueClasses contains s) alt1 else alt2).termRef)
+ .appliedTo(tree)
}
}
@@ -111,9 +110,9 @@ class InterceptedMethods extends TreeTransform {
PoundPoundValue(qual)
} else if (Any_comparisons contains tree.fun.symbol.asTerm) {
if (tree.fun.symbol eq defn.Any_==) {
- Apply(Select(qual, defn.Any_equals), tree.args)
+ qual.select(defn.Any_equals).appliedToArgs(tree.args)
} else if (tree.fun.symbol eq defn.Any_!=) {
- Select(Apply(Select(qual, defn.Any_equals), tree.args), defn.Boolean_!)
+ qual.select(defn.Any_equals).appliedToArgs(tree.args).select(defn.Boolean_!)
} else unknown
} /* else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
// todo: this is needed to support value classes
@@ -130,7 +129,7 @@ class InterceptedMethods extends TreeTransform {
// we get a primitive form of _getClass trying to target a boxed value
// so we need replace that method name with Object_getClass to get correct behavior.
// See SI-5568.
- Apply(Select(qual, defn.Any_getClass), Nil)
+ qual.select(defn.Any_getClass).appliedToNone
} else {
unknown
}
diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala
index fe6c3e2e4..75dc10ce4 100644
--- a/src/dotty/tools/dotc/transform/LazyVals.scala
+++ b/src/dotty/tools/dotc/transform/LazyVals.scala
@@ -7,6 +7,7 @@ import Contexts._
import Symbols._
import Decorators._
import NameOps._
+import StdNames.nme
import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransformer, TreeTransform}
import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.{untpd, tpd}
@@ -19,25 +20,6 @@ import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.SymDenotations.SymDenotation
import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
-
-class LazyValsCreateCompanionObjects extends CreateCompanionObjects {
- import tpd._
-
-
- override def name: String = "lazyValsModules"
-
- /** Companion classes are required to hold offsets for volatile lazy vals */
- override def predicate(forClass: tpd.TypeDef)(implicit ctx: Context): Boolean = {
- (!(forClass.symbol is Flags.Module)) && forClass.rhs.isInstanceOf[Template] && {
- val body = forClass.rhs.asInstanceOf[Template].body
- body.exists {
- case x: ValDef =>
- (x.mods is Flags.Lazy) && x.symbol.hasAnnotation(defn.VolatileAnnot)
- case _ => false
- }
- }
- }
-}
class LazyValTranformContext {
import tpd._
@@ -67,7 +49,7 @@ class LazyValTranformContext {
/** List of names of phases that should have finished their processing of all compilation units
* before this phase starts */
- override def runsAfterGroupsOf: Set[String] = Set("lazyValsModules")
+
/** List of names of phases that should have finished their processing of all compilation units
* before this phase starts */
@@ -144,9 +126,11 @@ class LazyValTranformContext {
val holderSymbol = ctx.newSymbol(x.symbol.owner, holderName, containerFlags, holderImpl.typeRef, coord = x.symbol.coord)
val holderTree = ValDef(holderSymbol, New(holderImpl.typeRef, List(valueInitter)))
- val methodBody =
- if(holderType != "LazyRef") Select(Ident(holderSymbol.termRef), "value".toTermName)
- else TypeApply(Select(Select(Ident(holderSymbol.termRef), "value".toTermName), defn.Any_asInstanceOf), List(TypeTree(tpe)))
+ val methodBody = {
+ val prefix = ref(holderSymbol).select("value".toTermName)
+ if (holderType != "LazyRef") prefix
+ else prefix.select(defn.Any_asInstanceOf).appliedToType(tpe)
+ }
val methodTree = DefDef(x.symbol.asTerm, methodBody)
ctx.debuglog(s"found a lazy val ${x.show},\n rewrote with ${holderTree.show}")
Thicket(holderTree, methodTree)
@@ -160,7 +144,7 @@ class LazyValTranformContext {
* flag = true
* target
* }
- * }
+ * }`
*/
def mkNonThreadSafeDef(target: Symbol, flag: Symbol, rhs: Tree)(implicit ctx: Context) = {
@@ -181,7 +165,7 @@ class LazyValTranformContext {
* }
*/
def mkDefNonThreadSafeNonNullable(target: Symbol, rhs: Tree)(implicit ctx: Context) = {
- val cond = Apply(Select(Ident(target.termRef), "eq".toTermName), List(Literal(Constant(null))))
+ val cond = Ident(target.termRef).select(nme.eq).appliedTo(Literal(Constant(null)))
val exp = Ident(target.termRef)
val setTarget = Assign(exp, rhs)
val init = Block(List(setTarget), exp)
@@ -255,6 +239,7 @@ class LazyValTranformContext {
* }
* result
* }
+ * FIXME: Don't use strings with toTermName, use predefined names instead.
*/
def mkThreadSafeDef(methodSymbol: TermSymbol, claz: ClassSymbol, ord: Int, target: Symbol, rhs: Tree, tp: Types.Type, offset: Tree, getFlag: Tree, stateMask: Tree, casFlag: Tree, setFlagState: Tree, waitOnLock: Tree)(implicit ctx: Context) = {
val initState = Literal(Constants.Constant(0))
@@ -281,16 +266,16 @@ class LazyValTranformContext {
val handler = Closure(handlerSymbol, {
args =>
val exception = args.head.head
- val complete = Apply(setFlagState, List(thiz, offset, initState, Literal(Constant(ord))))
+ val complete = setFlagState.appliedTo(thiz, offset, initState, Literal(Constant(ord)))
Block(List(complete), Throw(exception))
})
val compute = Assign(Ident(resultSymbol.termRef), rhs)
val tr = Try(compute, handler, EmptyTree)
val assign = Assign(Ident(target.termRef), Ident(resultSymbol.termRef))
- val complete = Apply(setFlagState, List(thiz, offset, computedState, Literal(Constant(ord))))
+ val complete = setFlagState.appliedTo(thiz, offset, computedState, Literal(Constant(ord)))
val noRetry = Assign(Ident(retrySymbol.termRef), Literal(Constants.Constant(false)))
- val body = If(Apply(casFlag, List(thiz, offset, Ident(flagSymbol.termRef), computeState, Literal(Constant(ord)))),
+ val body = If(casFlag.appliedTo(thiz, offset, Ident(flagSymbol.termRef), computeState, Literal(Constant(ord))),
Block(tr :: assign :: complete :: noRetry :: Nil, Literal(Constant(()))),
Literal(Constant(())))
@@ -298,12 +283,12 @@ class LazyValTranformContext {
}
val waitFirst = {
- val wait = Apply(waitOnLock, List(thiz, offset, Ident(flagSymbol.termRef), Literal(Constant(ord))))
+ val wait = waitOnLock.appliedTo(thiz, offset, Ident(flagSymbol.termRef), Literal(Constant(ord)))
CaseDef(computeState, EmptyTree, wait)
}
val waitSecond = {
- val wait = Apply(waitOnLock, List(thiz, offset, Ident(flagSymbol.termRef), Literal(Constant(ord))))
+ val wait = waitOnLock.appliedTo(thiz, offset, Ident(flagSymbol.termRef), Literal(Constant(ord)))
CaseDef(notifyState, EmptyTree, wait)
}
@@ -314,10 +299,10 @@ class LazyValTranformContext {
CaseDef(computedState, EmptyTree, body)
}
- val cases = Match(Apply(stateMask, List(Ident(flagSymbol.termRef), Literal(Constant(ord)))),
+ val cases = Match(stateMask.appliedTo(Ident(flagSymbol.termRef), Literal(Constant(ord))),
List(compute, waitFirst, waitSecond, computed)) //todo: annotate with @switch
- val whileBody = Block(List(Assign(Ident(flagSymbol.termRef), Apply(getFlag, List(thiz, offset)))), cases)
+ val whileBody = Block(List(Assign(Ident(flagSymbol.termRef), getFlag.appliedTo(thiz, offset))), cases)
val cycle = untpd.WhileDo(whileCond, whileBody).withTypeUnchecked(defn.UnitType)
DefDef(methodSymbol, Block(resultDef :: retryDef :: flagDef :: cycle :: Nil, Ident(resultSymbol.termRef)))
}
@@ -353,7 +338,7 @@ class LazyValTranformContext {
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType)
addSym(claz, flagSymbol)
flag = ValDef(flagSymbol, Literal(Constants.Constant(0L)))
- val offsetTree = ValDef(offsetSymbol, Apply(getOffset, List(thiz, Literal(Constant(flagName.toString)))))
+ val offsetTree = ValDef(offsetSymbol, getOffset.appliedTo(thiz, Literal(Constant(flagName.toString))))
info.defs = offsetTree :: info.defs
}
@@ -363,7 +348,7 @@ class LazyValTranformContext {
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType)
addSym(claz, flagSymbol)
flag = ValDef(flagSymbol, Literal(Constants.Constant(0L)))
- val offsetTree = ValDef(offsetSymbol, Apply(getOffset, List(thiz, Literal(Constant(flagName.toString)))))
+ val offsetTree = ValDef(offsetSymbol, getOffset.appliedTo(thiz, Literal(Constant(flagName.toString))))
appendOffsetDefs += (companion.name.moduleClassName -> new OffsetInfo(List(offsetTree), ord))
}
diff --git a/src/dotty/tools/dotc/transform/Literalize.scala b/src/dotty/tools/dotc/transform/Literalize.scala
new file mode 100644
index 000000000..14ce8fd05
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/Literalize.scala
@@ -0,0 +1,65 @@
+package dotty.tools.dotc
+package transform
+
+import TreeTransforms._
+import core.DenotTransformers._
+import core.Symbols._
+import core.Contexts._
+import core.Types._
+import core.Flags._
+import core.Decorators._
+import core.StdNames.nme
+import ast.Trees._
+
+/** This phase rewrites idempotent expressions with constant types to Literals.
+ * The constant types are eliminated by erasure, so we need to keep
+ * the info about constantness in the trees.
+ */
+class Literalize extends TreeTransform {
+ import ast.tpd._
+
+ override def name: String = "literalize"
+
+ /** Note: Demanding idempotency instead of purity is strictly speaking too loose.
+ * Example
+ *
+ * object O { final val x = 42; println("43") }
+ * O.x
+ *
+ * Strictly speaking we can't replace `O.x` with `42`. But this would make
+ * most expressions non-constant. Maybe we can change the spec to accept this
+ * kind of eliding behavior. Or else enforce true purity in the compiler.
+ * The choice will be affected by what we will do with `inline` and with
+ * Singleton type bounds (see SIP 23). Presumably
+ *
+ * object O1 { val x: Singleton = 42; println("43") }
+ * object O2 { inline val x = 42; println("43") }
+ *
+ * should behave differently.
+ *
+ * O1.x should have the same effect as { println("43"; 42 }
+ *
+ * whereas
+ *
+ * O2.x = 42
+ *
+ * Revisit this issue once we have implemented `inline`. Then we can demand
+ * purity of the prefix unless the selection goes to an inline val.
+ */
+ def literalize(tree: Tree)(implicit ctx: Context): Tree = tree.tpe match {
+ case ConstantType(value) if isIdempotentExpr(tree) => Literal(value)
+ case _ => tree
+ }
+
+ override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+
+ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+
+ override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+
+ override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ literalize(tree)
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/MacroTransform.scala b/src/dotty/tools/dotc/transform/MacroTransform.scala
new file mode 100644
index 000000000..0ee92bccd
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/MacroTransform.scala
@@ -0,0 +1,76 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import typer._
+import Phases._
+import ast.Trees._
+import Contexts._
+import Symbols._
+import Flags.PackageVal
+import Decorators._
+
+/** A base class for transforms.
+ * A transform contains a compiler phase which applies a tree transformer.
+ */
+abstract class MacroTransform extends Phase {
+
+ import ast.tpd._
+
+ override def run(implicit ctx: Context): Unit = {
+ val unit = ctx.compilationUnit
+ unit.tpdTree = newTransformer.transform(unit.tpdTree)(ctx.withPhase(transformPhase))
+ }
+
+ protected def newTransformer(implicit ctx: Context): Transformer
+
+ /** The phase in which the transformation should be run.
+ * By default this is the phase given by the this macro transformer,
+ * but it could be overridden to be the phase following that one.
+ */
+ protected def transformPhase(implicit ctx: Context): Phase = this
+
+ class Transformer extends TreeMap {
+
+ protected def localCtx(tree: Tree)(implicit ctx: Context) = {
+ val sym = tree.symbol
+ val owner = if (sym is PackageVal) sym.moduleClass else sym
+ 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] = {
+ val exprCtx = ctx.withOwner(exprOwner)
+ def transformStat(stat: Tree): Tree = stat match {
+ case _: Import | _: DefTree => transform(stat)
+ case Thicket(stats) => cpy.Thicket(stat, stats mapConserve transformStat)
+ case _ => transform(stat)(exprCtx)
+ }
+ flatten(trees.mapconserve(transformStat(_)))
+ }
+
+ override def transform(tree: Tree)(implicit ctx: Context): Tree = {
+ tree match {
+ case EmptyValDef =>
+ tree
+ case _: PackageDef | _: MemberDef =>
+ super.transform(tree)(localCtx(tree))
+ case Template(constr, parents, self, body) =>
+ cpy.Template(tree,
+ transformSub(constr),
+ transform(parents),
+ transformSelf(self),
+ transformStats(body, tree.symbol))
+ case _ =>
+ super.transform(tree)
+ }
+ }
+
+ def transformSelf(vd: ValDef)(implicit ctx: Context) =
+ cpy.ValDef(vd, vd.mods, vd.name, transform(vd.tpt), vd.rhs)
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/Nullarify.scala b/src/dotty/tools/dotc/transform/Nullarify.scala
index 664b4bee1..8d967cc1a 100644
--- a/src/dotty/tools/dotc/transform/Nullarify.scala
+++ b/src/dotty/tools/dotc/transform/Nullarify.scala
@@ -85,11 +85,11 @@ class Nullarify extends TreeTransform with InfoTransformer {
def result(implicit ctx: Context) = {
tp1.widen match {
case MethodType(Nil, _) if origType.widenExpr.isInstanceOf[ValueType] =>
- Apply(tree1, Nil)
+ tree1.appliedToNone
case _ =>
origType match {
case _: ExprType => // it's a by-name parameter
- Apply(Select(tree1, defn.Function0_apply), Nil)
+ tree1.select(defn.Function0_apply).appliedToNone
case _ =>
tree1
}
diff --git a/src/dotty/tools/dotc/transform/PostTyperTransformers.scala b/src/dotty/tools/dotc/transform/PostTyperTransformers.scala
deleted file mode 100644
index 25f122cf5..000000000
--- a/src/dotty/tools/dotc/transform/PostTyperTransformers.scala
+++ /dev/null
@@ -1,62 +0,0 @@
-package dotty.tools.dotc.transform
-
-import dotty.tools.dotc.core._
-import Symbols._
-import scala.Some
-import dotty.tools.dotc.transform.TreeTransforms.{NXTransformations, TransformerInfo, TreeTransform, TreeTransformer}
-import dotty.tools.dotc.ast.tpd
-import dotty.tools.dotc.core.Contexts.Context
-import scala.collection.mutable
-import dotty.tools.dotc.core.Names.Name
-import NameOps._
-
-object PostTyperTransformers {
-
- import tpd._
-
-
- /** A trait that's assumed by the transformers that run right after typer.
- * Ensures that trees are normalized when seen by other transforms. This means:
- * (1) All module class definitions appear after their companion class definitions
- * (2) There are no import clauses or named arguments
- * (3) All trees designating types are instances of TypeTree
- */
- abstract class PostTyperTransformer extends TreeTransformer {
-
- /** Reorder statements so that module classes always come after their companion classes, add missing companion classes */
- def reorder(stats: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = {
- val moduleClassDefs = mutable.Map[Name, Tree]()
- def reorder0(stats: List[Tree]): List[Tree] = {
- stats match {
- case (stat: TypeDef) :: stats1 if stat.symbol.isClass =>
- if (stat.symbol is Flags.Module) {
- moduleClassDefs += (stat.name -> stat)
- val stats1r = reorder0(stats1)
- if (moduleClassDefs contains stat.name) stat :: stats1r else stats1r
- }
- else {
- val mclsName = stat.name.moduleClassName
- moduleClassDefs remove mclsName match {
- case Some(mcdef) => stat :: mcdef :: reorder0(stats1)
- case None => stat :: reorder0(stats1)
- }
- }
- case stat :: stats1 => stat :: reorder0(stats1)
- case Nil => Nil
- }
- }
- reorder0(stats)
- }
-
- override def transformStats(trees: List[tpd.Tree], exprOwner: Symbol, info: TransformerInfo, current: Int)(implicit ctx: Context): List[tpd.Tree] =
- super.transformStats(reorder(trees)(ctx, info), exprOwner, info, current)
-
- override def transform(tree: tpd.Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): tpd.Tree = tree match {
- case tree: Import => EmptyTree
- case tree: NamedArg => super.transform(tree.arg, info, cur)
- case tree: TypeTree => super.transform(tree, info, cur)
- case tree => super.transform(if (tree.isType) TypeTree(tree.tpe) else tree, info, cur)
- }
- }
-
-} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/Splitter.scala b/src/dotty/tools/dotc/transform/Splitter.scala
index 978a9cce4..745919f3a 100644
--- a/src/dotty/tools/dotc/transform/Splitter.scala
+++ b/src/dotty/tools/dotc/transform/Splitter.scala
@@ -80,12 +80,12 @@ class Splitter extends TreeTransform {
else {
def choose(qual: Tree, syms: List[Symbol]): Tree = {
def testOrCast(which: Symbol, mbr: Symbol) =
- TypeApply(Select(qual, which), TypeTree(mbr.owner.typeRef) :: Nil)
+ qual.select(which).appliedToType(mbr.owner.typeRef)
def select(sym: Symbol) = {
val qual1 =
if (qual.tpe derivesFrom sym.owner) qual
else testOrCast(defn.Any_asInstanceOf, sym)
- Select(qual1, sym) withPos tree.pos
+ qual1.select(sym).withPos(tree.pos)
}
syms match {
case Nil =>
diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala
new file mode 100644
index 000000000..52306956e
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala
@@ -0,0 +1,557 @@
+package dotty.tools.dotc
+package transform
+
+import dotty.tools.dotc.transform.TreeTransforms.{TransformerInfo, TreeTransform, TreeTransformer}
+import dotty.tools.dotc.ast.{Trees, tpd}
+import scala.collection.{ mutable, immutable }
+import ValueClasses._
+import mutable.ListBuffer
+import scala.annotation.tailrec
+import core._
+import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
+import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._
+import util.Positions._
+import Decorators._
+import Symbols._
+
+/** This phase performs the following functions, each of which could be split out in a
+ * mini-phase:
+ *
+ * (1) Adds super accessors for all super calls that either
+ * appear in a trait or have as a target a member of some outer class.
+ *
+ * (2) Converts parameter fields that have the same name as a corresponding
+ * public parameter field in a superclass to a forwarder to the superclass
+ * field (corresponding = super class field is initialized with subclass field)
+ *
+ * (3) Adds protected accessors if the access to the protected member happens
+ * in a class which is not a subclass of the member's owner.
+ *
+ * (4) Finally, the phase used to mangle the names of class-members which are
+ * private up to an enclosing non-package class, in order to avoid overriding conflicts.
+ * This is currently disabled, and class-qualified private is deprecated.
+ *
+ * It also checks that:
+ *
+ * (1) Symbols accessed from super are not abstract, or are overridden by
+ * an abstract override.
+ *
+ * (2) If a symbol accessed accessed from super is defined in a real class (not a trait),
+ * there are no abstract members which override this member in Java's rules
+ * (see SI-4989; such an access would lead to illegal bytecode)
+ *
+ * (3) Super calls do not go to some synthetic members of Any (see isDisallowed)
+ *
+ * (4) Super calls do not go to synthetic field accessors
+ *
+ * (5) A class and its companion object do not both define a class or module with the
+ * same name.
+ *
+ * TODO: Rename phase to "Accessors" because it handles more than just super accessors
+ */
+class SuperAccessors extends MacroTransform with IdentityDenotTransformer { thisTransformer =>
+
+ import tpd._
+
+ /** the following two members override abstract members in Transform */
+ val name: String = "superaccessors"
+
+ protected def newTransformer(implicit ctx: Context): Transformer =
+ new SuperAccTransformer
+
+ class SuperAccTransformer extends Transformer {
+
+ /** validCurrentOwner arrives undocumented, but I reverse engineer it to be
+ * a flag for needsProtectedAccessor which is false while transforming either
+ * a by-name argument block or a closure. This excludes them from being
+ * considered able to access protected members via subclassing (why?) which in turn
+ * increases the frequency with which needsProtectedAccessor will be true.
+ */
+ private var validCurrentOwner = true
+
+ private val accDefs = mutable.Map[Symbol, ListBuffer[Tree]]()
+
+ private def storeAccessorDefinition(clazz: Symbol, tree: Tree) = {
+ val buf = accDefs.getOrElse(clazz, sys.error("no acc def buf for "+clazz))
+ buf += tree
+ }
+
+ private def ensureMethodic(tpe: Type)(implicit ctx: Context) = tpe match {
+ case tpe: MethodicType => tpe
+ case _ => ExprType(tpe)
+ }
+
+ private def ensureAccessor(sel: Select)(implicit ctx: Context) = {
+ val Select(qual, name) = sel
+ val sym = sel.symbol
+ val clazz = qual.symbol.asClass
+ val supername = name.superName
+
+ val superAcc = clazz.info.decl(supername).suchThat(_.signature == sym.signature).symbol orElse {
+ ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz")
+ val acc = ctx.newSymbol(
+ clazz, supername, SuperAccessor | Private | Artifact,
+ ensureMethodic(sel.tpe.widenSingleton), coord = sym.coord).enteredAfter(thisTransformer)
+ // Diagnostic for SI-7091
+ if (!accDefs.contains(clazz))
+ ctx.error(s"Internal error: unable to store accessor definition in ${clazz}. clazz.hasPackageFlag=${clazz is Package}. Accessor required for ${sel} (${sel.show})", sel.pos)
+ else storeAccessorDefinition(clazz, DefDef(acc, EmptyTree))
+ acc
+ }
+
+ This(clazz).select(superAcc).withPos(sel.pos)
+ }
+
+ private def transformArgs(formals: List[Type], args: List[Tree])(implicit ctx: Context) =
+ args.zipWithConserve(formals) {(arg, formal) =>
+ formal match {
+ case _: ExprType => withInvalidOwner(transform(arg))
+ case _ => transform(arg)
+ }
+ }
+
+ /** Check that a class and its companion object to not both define
+ * a class or module with same name
+ */
+ private def checkCompanionNameClashes(cls: ClassSymbol)(implicit ctx: Context): Unit =
+ if (!(cls.owner is ModuleClass)) {
+ val other = cls.owner.linkedClass.info.decl(cls.name)
+ if (other.symbol.isClass)
+ ctx.error(s"name clash: ${cls.owner} defines $cls" + "\n" +
+ s"and its companion ${cls.owner.companionModule} also defines $other",
+ cls.pos)
+ }
+
+ /** Expand all declarations in this class which are private within a class.
+ * Note: It's not sure whether this is the right way. Persumably, we expand
+ * qualified privates to prvent them from overriding or be overridden by
+ * symbols that are defined in classes where the qualified private is not
+ * visible. But it seems a bit dubiuous to do this between type checking
+ * and refchecks.
+ */
+ def expandQualifiedPrivates(cls: ClassSymbol)(implicit ctx: Context) = {
+ val decls = cls.info.decls
+ val decls1: MutableScope = newScope
+ def needsExpansion(sym: Symbol) =
+ sym.privateWithin.isClass &&
+ !(sym is Protected) &&
+ !(sym.privateWithin is ModuleClass) &&
+ !(sym is ExpandedName) &&
+ !sym.isConstructor
+ val nextCtx = ctx.withPhase(thisTransformer.next)
+ for (s <- decls) {
+ // !!! hacky to do this by mutation; would be better to do with an infotransformer
+ // !!! also, why is this done before pickling?
+ if (needsExpansion(s)) {
+ ctx.deprecationWarning(s"private qualified with a class has been deprecated, use package enclosing ${s.privateWithin} instead", s.pos)
+ /* disabled for now
+ decls.asInstanceOf[MutableScope].unlink(s)
+ s.copySymDenotation(name = s.name.expandedName(s.privateWithin))
+ .installAfter(thisTransformer)
+ decls1.enter(s)(nextCtx)
+ ctx.log(i"Expanded ${s.name}, ${s.name(nextCtx)}, sym")
+ */
+ }
+ }
+ /* Disabled for now:
+ if (decls1.nonEmpty) {
+ for (s <- decls)
+ if (!needsExpansion(s)) decls1.enter(s)(nextCtx)
+ val ClassInfo(pre, _, ps, _, selfInfo) = cls.classInfo
+ cls.copySymDenotation(info = ClassInfo(pre, cls, ps, decls1, selfInfo))
+ .installAfter(thisTransformer)
+ }
+ */
+ }
+
+ private def transformSuperSelect(sel: Select)(implicit ctx: Context): Tree = {
+ val Select(sup @ Super(_, mix), name) = sel
+ val sym = sel.symbol
+ assert(sup.symbol.exists, s"missing symbol in $sel: ${sup.tpe}")
+ val clazz = sup.symbol.asClass
+
+ if (sym is Deferred) {
+ val member = sym.overridingSymbol(clazz)
+ if (mix != tpnme.EMPTY ||
+ !member.exists ||
+ !(member is AbsOverride) && member.isIncompleteIn(clazz))
+ ctx.error(
+ i"${sym.showLocated} is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override'",
+ sel.pos)
+ }
+ else if (mix == tpnme.EMPTY && !(sym.owner is Trait))
+ // SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract.
+ for (intermediateClass <- clazz.info.baseClasses.tail.takeWhile(_ != sym.owner)) {
+ val overriding = sym.overridingSymbol(intermediateClass)
+ if ((overriding is (Deferred, butNot = AbsOverride)) && !(overriding.owner is Trait))
+ ctx.error(
+ s"${sym.showLocated} cannot be directly accessed from ${clazz} because ${overriding.owner} redeclares it as abstract",
+ sel.pos)
+
+ }
+ if (name.isTermName && mix == tpnme.EMPTY &&
+ ((clazz is Trait) || clazz != ctx.owner.enclosingClass || !validCurrentOwner))
+ ensureAccessor(sel)(ctx.withPhase(thisTransformer.next))
+ else sel
+ }
+
+ // Disallow some super.XX calls targeting Any methods which would
+ // otherwise lead to either a compiler crash or runtime failure.
+ private def isDisallowed(sym: Symbol)(implicit ctx: Context) = {
+ val d = defn
+ import d._
+ (sym eq Any_isInstanceOf) ||
+ (sym eq Any_asInstanceOf) ||
+ (sym eq Any_==) ||
+ (sym eq Any_!=) ||
+ (sym eq Any_##)
+ }
+
+ override def transform(tree: Tree)(implicit ctx: Context): Tree = {
+ val sym = tree.symbol
+
+ def mayNeedProtectedAccessor(sel: Select, targs: List[Tree], goToSuper: Boolean) =
+ if (sym.exists && needsProtectedAccessor(sym, tree.pos)) {
+ ctx.debuglog("Adding protected accessor for " + tree)
+ transform(makeAccessor(sel, targs))
+ }
+ else if (goToSuper) super.transform(tree)
+ else tree
+
+ try tree match {
+ // Don't transform patterns or strange trees will reach the matcher (ticket #4062)
+ // TODO Drop once this runs after pattern matcher
+ case CaseDef(pat, guard, body) =>
+ cpy.CaseDef(tree, pat, transform(guard), transform(body))
+
+ case TypeDef(_, _, impl: Template) =>
+ val cls = sym.asClass
+ checkCompanionNameClashes(cls)
+ expandQualifiedPrivates(cls)
+ super.transform(tree)
+
+ case impl: Template =>
+
+ /** 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.
+ */
+ def forwardParamAccessors(stats: List[Tree]): 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 = ensureMethodic(sym.info))
+ .installAfter(thisTransformer)
+ val superAcc =
+ Super(This(currentClass), tpnme.EMPTY, inConstrCall = false).select(alias)
+ DefDef(sym, ensureConforms(superAcc, sym.info.widen))
+ }
+ return forwarder(ctx.withPhase(thisTransformer.next))
+ }
+ }
+ }
+ case _ =>
+ }
+ stat
+ }
+ stats map forwardParamAccessor
+ }
+
+ def transformTemplate = {
+ val ownStats = new ListBuffer[Tree]
+ accDefs(currentClass) = ownStats
+ val body1 = forwardParamAccessors(transformStats(impl.body, tree.symbol))
+ accDefs -= currentClass
+ ownStats ++= body1
+ cpy.Template(tree, impl.constr, impl.parents, impl.self, body1)
+ }
+ transformTemplate
+
+ case TypeApply(sel @ Select(This(_), name), args) =>
+ mayNeedProtectedAccessor(sel, args, goToSuper = false)
+
+ case sel @ Select(qual, name) =>
+ def transformSelect = {
+
+ qual match {
+ case This(_) =>
+ // warn if they are selecting a private[this] member which
+ // also exists in a superclass, because they may be surprised
+ // to find out that a constructor parameter will shadow a
+ // field. See SI-4762.
+ /* to be added
+ if (settings.lint) {
+ if (sym.isPrivateLocal && sym.paramss.isEmpty) {
+ qual.symbol.ancestors foreach { parent =>
+ parent.info.decls filterNot (x => x.isPrivate || x.isLocalToThis) foreach { m2 =>
+ if (sym.name == m2.name && m2.isGetter && m2.accessed.isMutable) {
+ unit.warning(sel.pos,
+ sym.accessString + " " + sym.fullLocationString + " shadows mutable " + m2.name
+ + " inherited from " + m2.owner + ". Changes to " + m2.name + " will not be visible within "
+ + sym.owner + " - you may want to give them distinct names.")
+ }
+ }
+ }
+ }
+ }
+ */
+
+ /*
+ * A trait which extends a class and accesses a protected member
+ * of that class cannot implement the necessary accessor method
+ * because its implementation is in an implementation class (e.g.
+ * Foo$class) which inherits nothing, and jvm access restrictions
+ * require the call site to be in an actual subclass. So non-trait
+ * classes inspect their ancestors for any such situations and
+ * generate the accessors. See SI-2296.
+ */
+ // FIXME - this should be unified with needsProtectedAccessor, but some
+ // subtlety which presently eludes me is foiling my attempts.
+ val shouldEnsureAccessor = (
+ (currentClass is Trait)
+ && (sym is Protected)
+ && sym.enclosingClass != currentClass
+ && !(sym.owner is PackageClass) // SI-7091 no accessor needed package owned (ie, top level) symbols
+ && !(sym.owner is Trait)
+ && sym.owner.enclosingPackageClass != currentClass.enclosingPackageClass
+ && qual.symbol.info.member(sym.name).exists
+ && !needsProtectedAccessor(sym, tree.pos))
+ if (shouldEnsureAccessor) {
+ ctx.log("Ensuring accessor for call to protected " + sym.showLocated + " from " + currentClass)
+ ensureAccessor(sel)
+ } else
+ mayNeedProtectedAccessor(sel, Nil, goToSuper = false)
+
+ case Super(_, mix) =>
+ if ((sym.isTerm) && !(sym is Method) || (sym is Accessor)) {
+ ctx.error(s"super may be not be used on ${sym.accessedField orElse sym}", tree.pos)
+ } else if (isDisallowed(sym)) {
+ ctx.error(s"super not allowed here: use this.${name.decode} instead", tree.pos)
+ }
+ transformSuperSelect(sel)
+
+ case _ =>
+ mayNeedProtectedAccessor(sel, Nil, goToSuper = true)
+ }
+ }
+ transformSelect
+
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ val rhs1 = if (isMethodWithExtension(sym)) withInvalidOwner(transform(rhs)) else transform(rhs)
+ cpy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs1)
+
+ case TypeApply(sel @ Select(qual, name), args) =>
+ mayNeedProtectedAccessor(sel, args, goToSuper = true)
+
+ case Assign(lhs @ Select(qual, name), rhs) =>
+ def transformAssign = {
+ if ((lhs.symbol is Mutable) &&
+ (lhs.symbol is JavaDefined) &&
+ needsProtectedAccessor(lhs.symbol, tree.pos)) {
+ ctx.debuglog("Adding protected setter for " + tree)
+ val setter = makeSetter(lhs)
+ ctx.debuglog("Replaced " + tree + " with " + setter)
+ transform(Apply(setter, qual :: rhs :: Nil))
+ } else
+ super.transform(tree)
+ }
+ transformAssign
+
+ case Apply(fn, args) =>
+ val MethodType(_, formals) = fn.tpe.widen
+ cpy.Apply(tree, transform(fn), transformArgs(formals, args))
+
+ case _ =>
+ super.transform(tree)
+ }
+ catch {
+ case ex : AssertionError =>
+ if (sym != null && sym != NoSymbol)
+ Console.println("TRANSFORM: " + tree.symbol.sourceFile)
+
+ Console.println("TREE: " + tree)
+ throw ex
+ }
+ }
+
+ private def withInvalidOwner[A](trans: => A): A = {
+ val saved = validCurrentOwner
+ validCurrentOwner = false
+ try trans
+ finally validCurrentOwner = saved
+ }
+
+ /** Add a protected accessor, if needed, and return a tree that calls
+ * the accessor and returns the same member. The result is already
+ * typed.
+ * TODO why is targs needed? It looks like we can do without.
+ */
+ private def makeAccessor(tree: Select, targs: List[Tree])(implicit ctx: Context): Tree = {
+ val Select(qual, _) = tree
+ val sym = tree.symbol.asTerm
+ val clazz = hostForAccessorOf(sym, currentClass)
+ assert(clazz.exists, sym)
+ ctx.debuglog("Decided for host class: " + clazz)
+
+ val accName = sym.name.protectedAccessorName
+
+ // if the result type depends on the this type of an enclosing class, the accessor
+ // has to take an object of exactly this type, otherwise it's more general
+ val receiverType = if (isThisType(sym.info.finalResultType)) clazz.thisType else clazz.classInfo.selfType
+ val accType = {
+ def accTypeOf(tpe: Type): Type = tpe match {
+ case tpe: PolyType =>
+ tpe.derivedPolyType(tpe.paramNames, tpe.paramBounds, accTypeOf(tpe.resultType))
+ case _ =>
+ MethodType(receiverType :: Nil)(mt => tpe.substThis(sym.owner.asClass, MethodParam(mt, 0)))
+ }
+ accTypeOf(sym.info)
+ }
+ val protectedAccessor = clazz.info.decl(accName).suchThat(_.signature == accType.signature).symbol orElse {
+ val newAcc = ctx.newSymbol(
+ clazz, accName, Artifact, accType, coord = tree.pos).enteredAfter(thisTransformer)
+ val code = polyDefDef(newAcc, trefs => vrefss => {
+ val (receiver :: _) :: tail = vrefss
+ val base = receiver.select(sym).appliedToTypes(trefs)
+ (base /: vrefss)(Apply(_, _))
+ })
+ ctx.debuglog("created protected accessor: " + code)
+ storeAccessorDefinition(clazz, code)
+ newAcc
+ }
+ val res = This(clazz)
+ .select(protectedAccessor)
+ .appliedToTypeTrees(targs)
+ .appliedTo(qual)
+ .withPos(tree.pos)
+ ctx.debuglog(s"Replaced $tree with $res")
+ res
+ }
+
+ /** Add an accessor for field, if needed, and return a selection tree for it .
+ * The result is not typed.
+ */
+ private def makeSetter(tree: Select)(implicit ctx: Context): Tree = {
+ val field = tree.symbol.asTerm
+ val clazz = hostForAccessorOf(field, currentClass)
+ assert(clazz.exists, field)
+ ctx.debuglog("Decided for host class: " + clazz)
+
+ val accName = field.name.protectedSetterName
+ val accType = MethodType(clazz.classInfo.selfType :: field.info :: Nil, defn.UnitType)
+ val protectedAccessor = clazz.info.decl(accName).symbol orElse {
+ val newAcc = ctx.newSymbol(
+ clazz, accName, Artifact, accType, coord = tree.pos).enteredAfter(thisTransformer)
+ val code = DefDef(newAcc, vrefss => {
+ val (receiver :: value :: Nil) :: Nil = vrefss
+ Assign(receiver.select(field), value).withPos(tree.pos)
+ })
+ ctx.debuglog("created protected setter: " + code)
+ storeAccessorDefinition(clazz, code)
+ newAcc
+ }
+ This(clazz).select(protectedAccessor).withPos(tree.pos)
+ }
+
+ /** Does `sym` need an accessor when accessed from `currentClass`?
+ * A special case arises for classes with explicit self-types. If the
+ * self type is a Java class, and a protected accessor is needed, we issue
+ * an error. If the self type is a Scala class, we don't add an accessor.
+ * An accessor is not needed if the access boundary is larger than the
+ * enclosing package, since that translates to 'public' on the host sys.
+ * (as Java has no real package nesting).
+ *
+ * If the access happens inside a 'trait', access is more problematic since
+ * the implementation code is moved to an '$class' class which does not
+ * inherit anything. Since we can't (yet) add accessors for 'required'
+ * classes, this has to be signaled as error.
+ * FIXME Need to better understand this logic
+ */
+ private def needsProtectedAccessor(sym: Symbol, pos: Position)(implicit ctx: Context): Boolean = {
+ val clazz = currentClass
+ val host = hostForAccessorOf(sym, clazz)
+ val selfType = host.classInfo.selfType
+ def accessibleThroughSubclassing =
+ validCurrentOwner && (selfType <:< sym.owner.typeRef) && !clazz.is(Trait)
+
+ val isCandidate = (
+ sym.is(Protected)
+ && sym.is(JavaDefined)
+ && !sym.effectiveOwner.is(Package)
+ && !accessibleThroughSubclassing
+ && (sym.enclosingPackageClass != currentClass.enclosingPackageClass)
+ && (sym.enclosingPackageClass == sym.accessBoundary(sym.enclosingPackageClass))
+ )
+ def isSelfType = !(host.typeRef <:< selfType) && {
+ if (selfType.typeSymbol.is(JavaDefined))
+ ctx.restrictionError(s"cannot accesses protected $sym from within $clazz with self type $selfType", pos)
+ true
+ }
+ def isJavaProtected = host.is(Trait) && sym.is(JavaDefined) && {
+ ctx.restrictionError(
+ s"""$clazz accesses protected $sym inside a concrete trait method.
+ |Add an accessor in a class extending ${sym.enclosingClass} as a workaround.""".stripMargin,
+ pos
+ )
+ true
+ }
+ isCandidate && !host.is(Package) && !isSelfType && !isJavaProtected
+ }
+
+ /** Return the innermost enclosing class C of referencingClass for which either
+ * of the following holds:
+ * - C is a subclass of sym.owner or
+ * - C is declared in the same package as sym's owner
+ */
+ private def hostForAccessorOf(sym: Symbol, referencingClass: ClassSymbol)(implicit ctx: Context): ClassSymbol =
+ if (referencingClass.derivesFrom(sym.owner)
+ || referencingClass.classInfo.selfType <:< sym.owner.typeRef
+ || referencingClass.enclosingPackageClass == sym.owner.enclosingPackageClass) {
+ assert(referencingClass.isClass, referencingClass)
+ referencingClass
+ }
+ else if(referencingClass.owner.enclosingClass.exists)
+ hostForAccessorOf(sym, referencingClass.owner.enclosingClass.asClass)
+ else
+ referencingClass
+
+ /** Is 'tpe' the type of a member of an enclosing class? */
+ private def isThisType(tpe: Type)(implicit ctx: Context): Boolean = tpe match {
+ case ThisType(cls) => !cls.is(PackageClass)
+ case tpe: TypeProxy => isThisType(tpe.underlying)
+ case _ => false
+ }
+ }
+}
diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala
index cd0643a6e..a2278e72f 100644
--- a/src/dotty/tools/dotc/transform/TailRec.scala
+++ b/src/dotty/tools/dotc/transform/TailRec.scala
@@ -329,7 +329,7 @@ class TailRec extends TreeTransform with DenotTransformer {
val newDenot = d.copySymDenotation(initFlags = sym.flags &~ Flags.Local)
newDenot.installAfter(TailRec.this)
}
- Select(thiz, sym)
+ thiz.select(sym)
case _ => tree
}
}
diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala
index 347762678..8e7c4f6d0 100644
--- a/src/dotty/tools/dotc/transform/TreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/TreeTransform.scala
@@ -5,6 +5,7 @@ import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Contexts.Context
import dotty.tools.dotc.core.Phases.Phase
import dotty.tools.dotc.core.Symbols.Symbol
+import dotty.tools.dotc.core.Flags.PackageVal
import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.core.Decorators._
import scala.annotation.tailrec
@@ -883,7 +884,12 @@ object TreeTransforms {
}
} else tree
- def localContext(owner: Symbol)(implicit ctx: Context) = ctx.fresh.setOwner(owner)
+ // TODO merge with localCtx in MacroTransform
+ // Generally: If we will keep MacroTransform, merge common behavior with TreeTransform
+ def localContext(sym: Symbol)(implicit ctx: Context) = {
+ val owner = if (sym is PackageVal) sym.moduleClass else sym
+ ctx.fresh.setOwner(owner)
+ }
final private[TreeTransforms] def transformNamed(tree: NameTree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree =
tree match {
@@ -1124,8 +1130,12 @@ object TreeTransforms {
val stats = transformStats(tree.stats, tree.symbol, mutatedInfo, cur)(nestedCtx)
goPackageDef(cpy.PackageDef(tree, pid, stats), mutatedInfo.nx.nxTransPackageDef(cur))
}
+ case tree: Import => EmptyTree
+ case tree: NamedArg => transform(tree.arg, info, cur)
case Thicket(trees) => cpy.Thicket(tree, transformTrees(trees, info, cur))
- case tree => tree
+ case tree =>
+ if (tree.isType) transform(TypeTree(tree.tpe).withPos(tree.pos), info, cur)
+ else tree
}
def transform(tree: Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree = ctx.traceIndented(s"transforming ${tree.show} at ${ctx.phase}", transforms, show = true) {
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index 5f65ee414..b209f7647 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -34,7 +34,7 @@ class TypeTestsCasts extends TreeTransform {
def isPrimitive(tp: Type) = tp.classSymbol.isPrimitiveValueClass
def derivedTree(qual1: Tree, sym: Symbol, tp: Type) =
- cpy.TypeApply(tree, Select(qual1, sym) withPos qual.pos, List(TypeTree(tp)))
+ cpy.TypeApply(tree, qual1.select(sym).withPos(qual.pos), List(TypeTree(tp)))
def qualCls = qual.tpe.classSymbol
@@ -49,7 +49,7 @@ class TypeTestsCasts extends TreeTransform {
else argType.dealias match {
case _: SingletonType =>
val cmpOp = if (argType derivesFrom defn.AnyValClass) defn.Any_equals else defn.Object_eq
- Apply(Select(expr, cmpOp), singleton(argType) :: Nil)
+ expr.select(cmpOp).appliedTo(singleton(argType))
case AndType(tp1, tp2) =>
evalOnce(expr) { fun =>
val erased1 = transformIsInstanceOf(fun, tp1)
diff --git a/src/dotty/tools/dotc/transform/TypeUtils.scala b/src/dotty/tools/dotc/transform/TypeUtils.scala
new file mode 100644
index 000000000..f11bb980a
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/TypeUtils.scala
@@ -0,0 +1,23 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Types._
+import Contexts._
+import Symbols._
+import Decorators._
+import StdNames.nme
+import NameOps._
+import language.implicitConversions
+
+object TypeUtils {
+ implicit def decorateTypeUtils(tpe: Type): TypeUtils = new TypeUtils(tpe)
+}
+
+/** A decorator that provides methods for type transformations
+ * that are needed in the transofmer pipeline (not needed right now)
+ */
+class TypeUtils(val self: Type) extends AnyVal {
+ import TypeUtils._
+
+} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/transform/ValueClasses.scala b/src/dotty/tools/dotc/transform/ValueClasses.scala
new file mode 100644
index 000000000..c5cf44552
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ValueClasses.scala
@@ -0,0 +1,36 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import Types._
+import Symbols._
+import SymDenotations._
+import Contexts._
+import Flags._
+
+/** Methods that apply to user-defined value classes */
+object ValueClasses {
+
+ def isDerivedValueClass(d: SymDenotation)(implicit ctx: Context) =
+ d.isClass && d.derivesFrom(defn.AnyValClass) && !d.isPrimitiveValueClass
+
+ def isMethodWithExtension(d: SymDenotation)(implicit ctx: Context) =
+ d.isSourceMethod &&
+ isDerivedValueClass(d.owner) &&
+ !d.isConstructor &&
+ !d.is(SuperAccessor) &&
+ !d.is(Macro)
+
+ /** The member that of a derived value class that unboxes it. */
+ def valueClassUnbox(d: ClassDenotation)(implicit ctx: Context): Symbol =
+ // (info.decl(nme.unbox)).orElse(...) uncomment once we accept unbox methods
+ d.classInfo.decls
+ .find(d => d.isTerm && d.symbol.is(ParamAccessor))
+ .map(_.symbol)
+ .getOrElse(NoSymbol)
+
+ /** The unboxed type that underlies a derived value class */
+ def underlyingOfValueClass(d: ClassDenotation)(implicit ctx: Context): Type =
+ valueClassUnbox(d).info.resultType
+
+}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 91f4ce9a5..242985b57 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -735,9 +735,9 @@ trait Applications extends Compatibility { self: Typer =>
onMethod(tp, isApplicable(_, args, resultType))
private def onMethod(tp: Type, p: TermRef => Boolean)(implicit ctx: Context): Boolean = tp match {
- case methRef: TermRef if methRef.widenSingleton.isInstanceOf[SignedType] =>
+ case methRef: TermRef if methRef.widenSingleton.isInstanceOf[MethodicType] =>
p(methRef)
- case mt: SignedType =>
+ case mt: MethodicType =>
p(mt.narrow)
case _ =>
tp.member(nme.apply).hasAltWith(d => p(TermRef(tp, nme.apply, d)))
@@ -767,8 +767,7 @@ trait Applications extends Compatibility { self: Typer =>
*/
def isAsSpecific(alt1: TermRef, tp1: Type, alt2: TermRef, tp2: Type): Boolean = ctx.traceIndented(i"isAsSpecific $tp1 $tp2", overload) { tp1 match {
case tp1: PolyType =>
- def bounds(tparamRefs: List[TypeRef]) = tp1.paramBounds map (_.substParams(tp1, tparamRefs))
- val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, bounds)
+ val tparams = ctx.newTypeParams(alt1.symbol, tp1.paramNames, EmptyFlags, tp1.instantiateBounds)
isAsSpecific(alt1, tp1.instantiate(tparams map (_.typeRef)), alt2, tp2)
case tp1: MethodType =>
def repeatedToSingle(tp: Type) = if (tp.isRepeatedParam) tp.argTypesHi.head else tp
diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala
index 0b016769b..89e73013f 100644
--- a/src/dotty/tools/dotc/typer/ErrorReporting.scala
+++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala
@@ -127,7 +127,7 @@ object ErrorReporting {
case _ => true
}
- val s = new InfoString(sc).i(args : _*)
+ val s = new StringInterpolators(sc).i(args : _*)
if (args.forall(isSensical(_))) s else nonSensicalStartTag + s + nonSensicalEndTag
}
}
diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala
index 110dc6152..69b512416 100644
--- a/src/dotty/tools/dotc/typer/EtaExpansion.scala
+++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -21,7 +21,7 @@ object EtaExpansion {
import tpd._
private def lift(defs: mutable.ListBuffer[Tree], expr: Tree, prefix: String = "")(implicit ctx: Context): Tree =
- if (isIdempotentExpr(expr)) expr
+ if (isPureExpr(expr)) expr
else {
val name = ctx.freshName(prefix).toTermName
val sym = ctx.newSymbol(ctx.owner, name, EmptyFlags, expr.tpe.widen, coord = positionCoord(expr.pos))
@@ -83,7 +83,7 @@ object EtaExpansion {
cpy.Apply(tree, liftApp(defs, fn), liftArgs(defs, fn.tpe, args))
case TypeApply(fn, targs) =>
cpy.TypeApply(tree, liftApp(defs, fn), targs)
- case Select(pre, name) if tpd.isIdempotentRef(tree) =>
+ case Select(pre, name) if isPureRef(tree) =>
cpy.Select(tree, liftApp(defs, pre), name)
case Block(stats, expr) =>
liftApp(defs ++= stats, expr)
diff --git a/src/dotty/tools/dotc/typer/ImportInfo.scala b/src/dotty/tools/dotc/typer/ImportInfo.scala
index 9fbd07102..18e5db209 100644
--- a/src/dotty/tools/dotc/typer/ImportInfo.scala
+++ b/src/dotty/tools/dotc/typer/ImportInfo.scala
@@ -7,7 +7,7 @@ import ast.Trees._
import core._
import util.SimpleMap
import Symbols._, Names._, Denotations._, Types._, Contexts._, StdNames._, Flags._
-import Decorators.InfoString
+import Decorators.StringInterpolators
object ImportInfo {
/** The import info for a root import from given symbol `sym` */
diff --git a/src/dotty/tools/dotc/typer/ReTyper.scala b/src/dotty/tools/dotc/typer/ReTyper.scala
index 76817fd16..6adfa3052 100644
--- a/src/dotty/tools/dotc/typer/ReTyper.scala
+++ b/src/dotty/tools/dotc/typer/ReTyper.scala
@@ -1,10 +1,11 @@
package dotty.tools.dotc
package typer
-import core.Contexts._
-import core.Types._
-import core.Symbols._
-import core.Decorators._
+import core._
+import Contexts._
+import Types._
+import Symbols._
+import Decorators._
import typer.ProtoTypes._
import ast.{tpd, untpd}
import ast.Trees._
@@ -59,4 +60,10 @@ class ReTyper extends Typer {
override def localTyper(sym: Symbol) = this
override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx
+
+ override def tryInsertApplyOrImplicit(tree: Tree, pt: ProtoType)(fallBack: (Tree, TyperState) => Tree)(implicit ctx: Context): Tree =
+ fallBack(tree, ctx.typerState)
+
+ override def addTypedModifiersAnnotations(mods: untpd.Modifiers, sym: Symbol)(implicit ctx: Context): Modifiers =
+ typedModifiers(mods, sym)
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 48c263085..ae56df82f 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -279,7 +279,7 @@ trait TypeAssigner {
def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = {
val ownType =
if (ctx.erasedTypes) defn.SeqType
- else defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes))
+ else defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes).widen)
tree.withType(ownType)
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index c01cf714f..6dc9a49b1 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -744,9 +744,14 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
assignType(cpy.Alternative(tree, trees1), trees1)
}
+ def addTypedModifiersAnnotations(mods: untpd.Modifiers, sym: Symbol)(implicit ctx: Context): Modifiers = {
+ val mods1 = typedModifiers(mods, sym)
+ for (tree <- mods1.annotations) sym.addAnnotation(Annotation(tree))
+ mods1
+ }
+
def typedModifiers(mods: untpd.Modifiers, sym: Symbol)(implicit ctx: Context): Modifiers = track("typedModifiers") {
val annotations1 = mods.annotations mapconserve typedAnnotation
- for (tree <- annotations1) sym.addAnnotation(Annotation(tree))
if (annotations1 eq mods.annotations) mods.asInstanceOf[Modifiers]
else Modifiers(mods.flags, mods.privateWithin, annotations1)
}
@@ -757,7 +762,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context) = track("typedValDef") {
val ValDef(mods, name, tpt, rhs) = vdef
- val mods1 = typedModifiers(mods, sym)
+ val mods1 = addTypedModifiersAnnotations(mods, sym)
val tpt1 = typedType(tpt)
val rhs1 = rhs match {
case Ident(nme.WILDCARD) => rhs withType tpt1.tpe
@@ -768,7 +773,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = track("typedDefDef") {
val DefDef(mods, name, tparams, vparamss, tpt, rhs) = ddef
- val mods1 = typedModifiers(mods, sym)
+ val mods1 = addTypedModifiersAnnotations(mods, sym)
val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef])
val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef])
if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1)
@@ -780,7 +785,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): Tree = track("typedTypeDef") {
val TypeDef(mods, name, rhs) = tdef
- val mods1 = typedModifiers(mods, sym)
+ val mods1 = addTypedModifiersAnnotations(mods, sym)
val _ = typedType(rhs) // unused, typecheck only to remove from typedTree
assignType(cpy.TypeDef(tdef, mods1, name, TypeTree(sym.info)), sym)
}
@@ -807,7 +812,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
val TypeDef(mods, name, impl @ Template(constr, parents, self, body)) = cdef
- val mods1 = typedModifiers(mods, cls)
+ val mods1 = addTypedModifiersAnnotations(mods, cls)
val constr1 = typed(constr).asInstanceOf[DefDef]
val parents1 = ensureConstrCall(ensureFirstIsClass(
parents mapconserve typedParent, cdef.pos.toSynthetic))