Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

introduces global.pendingSuperCall

Similarly to global.emptyValDef, which is a dummy that stands for an
empty self-type, this commit introduces global.pendingSuperCall, which
stands for a yet-to-be-filled-in call to a superclass constructor.

pendingSuperCall is emitted by Parsers.template, treated specially by
Typers.typedParentType and replaced with a real superclass ctor call
by Typers.typedTemplate.

To avoid copy/paste, this commit also factors out and unifies dumminess
of EmptyTree, emptyValDef and pendingSuperCall - they all don't have a
position and actively refuse to gain one, same story for tpe.
  • Loading branch information...
commit 0ebf72b9498108e67c2133c6522c436af50a18e8 1 parent 40063b0
@xeno-by xeno-by authored
View
4 src/compiler/scala/reflect/reify/codegen/GenTrees.scala
@@ -45,7 +45,9 @@ trait GenTrees {
case global.EmptyTree =>
reifyMirrorObject(EmptyTree)
case global.emptyValDef =>
- mirrorBuildSelect(nme.emptyValDef)
+ mirrorSelect(nme.emptyValDef)
+ case global.pendingSuperCall =>
+ mirrorSelect(nme.pendingSuperCall)
case FreeDef(_, _, _, _, _) =>
reifyNestedFreeDef(tree)
case FreeRef(_, _) =>
View
3  src/compiler/scala/reflect/reify/codegen/GenUtils.scala
@@ -34,9 +34,6 @@ trait GenUtils {
def mirrorSelect(name: String): Tree =
termPath(nme.UNIVERSE_PREFIX + name)
- def mirrorBuildSelect(name: String): Tree =
- termPath(nme.UNIVERSE_BUILD_PREFIX + name)
-
def mirrorMirrorSelect(name: String): Tree =
termPath(nme.MIRROR_PREFIX + name)
View
2  src/compiler/scala/tools/nsc/ast/Positions.scala
@@ -20,7 +20,7 @@ trait Positions extends scala.reflect.internal.Positions {
// When we prune due to encountering a position, traverse the
// pruned children so we can warn about those lacking positions.
t.children foreach { c =>
- if ((c eq EmptyTree) || (c eq emptyValDef)) ()
+ if (c.isDummy) ()
else if (c.pos == NoPosition) {
reporter.warning(t.pos, " Positioned tree has unpositioned child in phase " + globalPhase)
inform("parent: " + treeSymStatus(t))
View
23 src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -65,6 +65,13 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
// --- factory methods ----------------------------------------------------------
+ /** Factory method for a primary constructor super call `super.<init>(args_1)...(args_n)`
+ */
+ def PrimarySuperCall(argss: List[List[Tree]]): Tree = argss match {
+ case Nil => Apply(gen.mkSuperSelect, Nil)
+ case xs :: rest => rest.foldLeft(Apply(gen.mkSuperSelect, xs): Tree)(Apply.apply)
+ }
+
/** Generates a template with constructor corresponding to
*
* constrmods (vparams1_) ... (vparams_n) preSuper { presupers }
@@ -117,12 +124,12 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
if (vparamss1.isEmpty || !vparamss1.head.isEmpty && vparamss1.head.head.mods.isImplicit)
vparamss1 = List() :: vparamss1;
val superRef: Tree = atPos(superPos)(gen.mkSuperSelect)
- val superCall = Apply(superRef, Nil) // we can't know in advance which of the parents will end up as a superclass
- // this requires knowing which of the parents is a type macro and which is not
- // and that's something that cannot be found out before typer
- // (the type macros aren't in the trunk yet, but there is a plan for them to land there soon)
- // this means that we don't know what will be the arguments of the super call
- // therefore here we emit a dummy which gets populated when the template is named and typechecked
+ val superCall = pendingSuperCall // we can't know in advance which of the parents will end up as a superclass
+ // this requires knowing which of the parents is a type macro and which is not
+ // and that's something that cannot be found out before typer
+ // (the type macros aren't in the trunk yet, but there is a plan for them to land there soon)
+ // this means that we don't know what will be the arguments of the super call
+ // therefore here we emit a dummy which gets populated when the template is named and typechecked
List(
// TODO: previously this was `wrappingPos(superPos, lvdefs ::: argss.flatten)`
// is it going to be a problem that we can no longer include the `argss`?
@@ -330,6 +337,8 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
else
super.transform {
tree match {
+ case tree if tree.isDummy =>
+ tree
case tpt: TypeTree =>
if (tpt.original != null)
transform(tpt.original)
@@ -343,8 +352,6 @@ trait Trees extends scala.reflect.internal.Trees { self: Global =>
transform(fn)
case This(_) if tree.symbol != null && tree.symbol.isPackageClass =>
tree
- case EmptyTree =>
- tree
case _ =>
val dupl = tree.duplicate
if (tree.hasSymbol && (!localOnly || (locals contains tree.symbol)) && !(keepLabels && tree.symbol.isLabel))
View
12 src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -21,12 +21,14 @@ trait StdAttachments {
*/
case class SuperCallArgsAttachment(argss: List[List[Tree]])
- /** Extractor for `SuperCallArgsAttachment`.
+ /** Convenience method for `SuperCallArgsAttachment`.
* Compared with `MacroRuntimeAttachment` this attachment has different a usage pattern,
* so it really benefits from a dedicated extractor.
*/
- object CarriesSuperCallArgs {
- def unapply(tree: Tree): Option[List[List[Tree]]] =
- tree.attachments.get[SuperCallArgsAttachment] collect { case SuperCallArgsAttachment(argss) => argss }
- }
+ def superCallArgs(tree: Tree): Option[List[List[Tree]]] =
+ tree.attachments.get[SuperCallArgsAttachment] collect { case SuperCallArgsAttachment(argss) => argss }
+
+ /** Determines whether the given tree has an associated SuperCallArgsAttachment.
+ */
+ def hasSuperArgs(tree: Tree): Boolean = superCallArgs(tree).nonEmpty
}
View
103 src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -52,8 +52,10 @@ trait Typers extends Modes with Adaptations with Tags {
object UnTyper extends Traverser {
override def traverse(tree: Tree) = {
- if (tree != EmptyTree) tree.tpe = null
- if (tree.hasSymbol) tree.symbol = NoSymbol
+ if (!tree.isDummy) {
+ tree.tpe = null
+ if (tree.hasSymbol) tree.symbol = NoSymbol
+ }
super.traverse(tree)
}
}
@@ -1561,7 +1563,7 @@ trait Typers extends Modes with Adaptations with Tags {
var supertpt = typedTypeConstructor(decodedtpt)
val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else Nil
if (supertparams.nonEmpty) {
- typedPrimaryConstrBody(templ) { superRef =>
+ typedPrimaryConstrBody(templ) {
val supertpe = PolyType(supertparams, appliedType(supertpt.tpe, supertparams map (_.tpeHK)))
val supercall = New(supertpe, mmap(argss)(_.duplicate))
val treeInfo.Applied(Select(ctor, nme.CONSTRUCTOR), _, _) = supercall
@@ -1580,8 +1582,8 @@ trait Typers extends Modes with Adaptations with Tags {
}
/** Typechecks the mishmash of trees that happen to be stuffed into the primary constructor of a given template.
- * Before commencing the typecheck applies `superCallTransform` to a super call (if the latter exists).
- * The transform can return `EmptyTree`, in which case the super call is replaced with a literal unit.
+ * Before commencing the typecheck, replaces the `pendingSuperCall` dummy with the result of `actualSuperCall`.
+ * `actualSuperCall` can return `EmptyTree`, in which case the dummy is replaced with a literal unit.
*
* ***Return value and side effects***
*
@@ -1606,34 +1608,14 @@ trait Typers extends Modes with Adaptations with Tags {
* Block(List(
* ValDef(NoMods, x, TypeTree(), 2)
* ValDef(NoMods, y, TypeTree(), 4)
- * Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR)), List()),
+ * global.pendingSuperCall,
* Literal(Constant(())))
*
- * Note the Select(Super(_, _), nme.CONSTRUCTOR) part. This is the representation of
- * a fill-me-in-later supercall dummy. The argss are Nil, which encodes the fact
- * that supercall argss are unknown during parsing and need to be transplanted from one of the parent types.
- * Read more about why the argss are unknown in `tools.nsc.ast.Trees.Template`.
- *
- * The entire Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR)), List()) is a dummy,
- * and it's the one and only possible representation that can be emitted by parser.
- *
- * Despite of being unwieldy, this tree is quite convenient because:
- * * It works as is for the case when no processing is required (empty ctor args for the superclass)
- * * Stripping off the Apply produces a core that only needs rewrapping with applications of actual argss.
- *
- * For some time I was thinking of using just Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR)),
- * but that one required wrapping even if the superclass doesn't take any argss.
- *
- * Another option would be to introduce a singleton tree akin to `emptyValDef` and use it as a dummy.
- * Unfortunately this won't work out of the box, because the Super part is supposed to get attributed
- * during `typedPrimaryConstrBody`.
- *
- * We could introduce another attachment for that or change SuperCallArgsAttachment
- * to accommodate for the attributed Super, and then using the attached info to adjust the primary constructor
- * during typedTemplate. However, given the scope of necessary changes (beyond a few lines) and the fact that,
- * according to Martin, the whole thing is to be rewritten soon, I'd say we don't do the follow-up refactoring.
+ * Note the `pendingSuperCall` part. This is the representation of a fill-me-in-later supercall dummy,
+ * which encodes the fact that supercall argss are unknown during parsing and need to be transplanted
+ * from one of the parent types. Read more about why the argss are unknown in `tools.nsc.ast.Trees.Template`.
*/
- private def typedPrimaryConstrBody(templ: Template)(superCallTransform: Tree => Tree): Tree =
+ private def typedPrimaryConstrBody(templ: Template)(actualSuperCall: => Tree): Tree =
treeInfo.firstConstructor(templ.body) match {
case ctor @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) =>
val (preSuperStats, superCall) = {
@@ -1641,7 +1623,7 @@ trait Typers extends Modes with Adaptations with Tags {
(stats map (_.duplicate), if (rest.isEmpty) EmptyTree else rest.head.duplicate)
}
val superCall1 = (superCall match {
- case Apply(superRef @ Select(Super(_, _), nme.CONSTRUCTOR), Nil) => superCallTransform(superRef)
+ case global.pendingSuperCall => actualSuperCall
case EmptyTree => EmptyTree
}) orElse cunit
val cbody1 = treeCopy.Block(cbody, preSuperStats, superCall1)
@@ -1721,7 +1703,7 @@ trait Typers extends Modes with Adaptations with Tags {
// and therefore early fields have their type trees not assigned
// here we detect this situation and take preventive measures
if (treeInfo.hasUntypedPreSuperFields(templ.body))
- typedPrimaryConstrBody(templ)(superRef => EmptyTree)
+ typedPrimaryConstrBody(templ)(EmptyTree)
supertpts mapConserve (tpt => checkNoEscaping.privates(context.owner, tpt))
} catch {
@@ -1979,6 +1961,8 @@ trait Typers extends Modes with Adaptations with Tags {
validateParentClasses(parents1, selfType)
if (clazz.isCase)
validateNoCaseAncestor(clazz)
+ if (clazz.isTrait && hasSuperArgs(parents1.head))
+ ConstrArgsInParentOfTraitError(parents1.head, clazz)
if ((clazz isSubClass ClassfileAnnotationClass) && !clazz.owner.isPackageClass)
unit.error(clazz.pos, "inner classes cannot be classfile annotations")
@@ -1990,23 +1974,16 @@ trait Typers extends Modes with Adaptations with Tags {
val body =
if (isPastTyper || reporter.hasErrors) templ.body
else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _))
- parents1.head match {
- case CarriesSuperCallArgs(argss) =>
- if (clazz.isTrait) {
- ConstrArgsInParentOfTraitError(parents1.head, clazz)
- body
- } else {
- val primaryCtor = treeInfo.firstConstructor(templ.body)
- val primaryCtor1 = (deriveDefDef(primaryCtor) {
- case block @ Block(earlyVals :+ Apply(superRef, Nil), unit) =>
- val pos = wrappingPos(parents1.head.pos, argss.flatten)
- val superCall = atPos(pos)((superRef /: argss)(Apply.apply))
- Block(earlyVals :+ superCall, unit) setPos pos
- }) setPos pos
- body map { case `primaryCtor` => primaryCtor1; case stat => stat }
- }
- case _ => body
+ val primaryCtor = treeInfo.firstConstructor(body)
+ val primaryCtor1 = primaryCtor match {
+ case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) =>
+ val argss = superCallArgs(parents1.head) getOrElse Nil
+ val pos = wrappingPos(parents1.head.pos, argss.flatten)
+ val superCall = atPos(pos)(PrimarySuperCall(argss))
+ deriveDefDef(primaryCtor)(block => Block(earlyVals :+ superCall, unit) setPos pos) setPos pos
+ case _ => primaryCtor
}
+ body mapConserve { case `primaryCtor` => primaryCtor1; case stat => stat }
}
val body1 = typedStats(body, templ.symbol)
@@ -5752,21 +5729,21 @@ trait Typers extends Modes with Adaptations with Tags {
// enough to see those. See #3938
ConstructorPrefixError(tree, restpe)
} else {
- //@M fix for #2208
- // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef
- if (result.tpe.typeArgs.isEmpty) {
- // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) {
- // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not
- // designed to deal with the cycles in the scala package (ScalaObject extends
- // AnyRef, but the AnyRef type alias is entered after the scala package is
- // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
- // yet defined )
- // !!! TODO - revisit now that ScalaObject is gone.
- result setType(restpe)
- } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
- // during uncurry (after refchecks), all types are normalized
- result
- }
+ //@M fix for #2208
+ // if there are no type arguments, normalization does not bypass any checks, so perform it to get rid of AnyRef
+ if (result.tpe.typeArgs.isEmpty) {
+ // minimal check: if(result.tpe.typeSymbolDirect eq AnyRefClass) {
+ // must expand the fake AnyRef type alias, because bootstrapping (init in Definitions) is not
+ // designed to deal with the cycles in the scala package (ScalaObject extends
+ // AnyRef, but the AnyRef type alias is entered after the scala package is
+ // loaded and completed, so that ScalaObject is unpickled while AnyRef is not
+ // yet defined )
+ // !!! TODO - revisit now that ScalaObject is gone.
+ result setType(restpe)
+ } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208
+ // during uncurry (after refchecks), all types are normalized
+ result
+ }
}
}
View
2  src/reflect/scala/reflect/api/BuildUtils.scala
@@ -59,8 +59,6 @@ private[reflect] trait BuildUtils { self: Universe =>
def flagsFromBits(bits: Long): FlagSet
- def emptyValDef: ValDef
-
def This(sym: Symbol): Tree
def Select(qualifier: Tree, sym: Symbol): Select
View
9 src/reflect/scala/reflect/api/Trees.scala
@@ -2366,6 +2366,15 @@ trait Trees { self: Universe =>
*/
val emptyValDef: ValDef
+ /** An empty superclass constructor call corresponding to:
+ * super.<init>()
+ * This is used as a placeholder in the primary constructor body in class templates
+ * to denote the insertion point of a call to superclass constructor after the typechecker
+ * figures out the superclass of a given template.
+ * @group Trees
+ */
+ val pendingSuperCall: Apply
+
// ---------------------- factories ----------------------------------------------
/** A factory method for `ClassDef` nodes.
View
2  src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -47,8 +47,6 @@ trait BuildUtils { self: SymbolTable =>
def flagsFromBits(bits: Long): FlagSet = bits
- def emptyValDef: ValDef = self.emptyValDef
-
def This(sym: Symbol): Tree = self.This(sym)
def Select(qualifier: Tree, sym: Symbol): Select = self.Select(qualifier, sym)
View
2  src/reflect/scala/reflect/internal/Importers.scala
@@ -334,6 +334,8 @@ trait Importers extends api.Importers { self: SymbolTable =>
new ModuleDef(importModifiers(mods), importName(name).toTermName, importTemplate(impl))
case from.emptyValDef =>
emptyValDef
+ case from.pendingSuperCall =>
+ pendingSuperCall
case from.ValDef(mods, name, tpt, rhs) =>
new ValDef(importModifiers(mods), importName(name).toTermName, importTree(tpt), importTree(rhs))
case from.DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
View
2  src/reflect/scala/reflect/internal/Positions.scala
@@ -38,7 +38,7 @@ trait Positions extends api.Positions { self: SymbolTable =>
protected class DefaultPosAssigner extends PosAssigner {
var pos: Position = _
override def traverse(t: Tree) {
- if (t eq EmptyTree) ()
+ if (t.isDummy) ()
else if (t.pos == NoPosition) {
t.setPos(pos)
super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if?
View
4 src/reflect/scala/reflect/internal/Printers.scala
@@ -542,8 +542,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
print(")")
case EmptyTree =>
print("EmptyTree")
- case emptyValDef: AnyRef if emptyValDef eq self.emptyValDef =>
+ case self.emptyValDef =>
print("emptyValDef")
+ case self.pendingSuperCall =>
+ print("pendingSuperCall")
case tree: Tree =>
val hasSymbol = tree.hasSymbol && tree.symbol != NoSymbol
val isError = hasSymbol && tree.symbol.name.toString == nme.ERROR.toString
View
1  src/reflect/scala/reflect/internal/StdNames.scala
@@ -730,6 +730,7 @@ trait StdNames {
val null_ : NameType = "null"
val ofDim: NameType = "ofDim"
val origin: NameType = "origin"
+ val pendingSuperCall: NameType = "pendingSuperCall"
val prefix : NameType = "prefix"
val productArity: NameType = "productArity"
val productElement: NameType = "productElement"
View
20 src/reflect/scala/reflect/internal/Trees.scala
@@ -36,6 +36,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
def isDef = false
def isEmpty = false
+ def isDummy = false
/** The canonical way to test if a Tree represents a term.
*/
@@ -228,14 +229,6 @@ trait Trees extends api.Trees { self: SymbolTable =>
override def isDef = true
}
- case object EmptyTree extends TermTree {
- val asList = List(this)
- super.tpe_=(NoType)
- override def tpe_=(t: Type) =
- if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>")
- override def isEmpty = true
- }
-
abstract class MemberDef extends DefTree with MemberDefApi {
def mods: Modifiers
def keyword: String = this match {
@@ -599,6 +592,7 @@ trait Trees extends api.Trees { self: SymbolTable =>
case _: ApplyToImplicitArgs => new ApplyToImplicitArgs(fun, args)
case _: ApplyImplicitView => new ApplyImplicitView(fun, args)
// TODO: ApplyConstructor ???
+ case self.pendingSuperCall => self.pendingSuperCall
case _ => new Apply(fun, args)
}).copyAttrs(tree)
def ApplyDynamic(tree: Tree, qual: Tree, args: List[Tree]) =
@@ -961,12 +955,20 @@ trait Trees extends api.Trees { self: SymbolTable =>
def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree)
- object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) {
+ trait DummyTree extends Tree {
override def isEmpty = true
+ override def isDummy = true
super.setPos(NoPosition)
override def setPos(pos: Position) = { assert(false); this }
+ super.setType(NoType)
+ override def tpe_=(t: Type) =
+ if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for "+self.toString)
}
+ case object EmptyTree extends TermTree with DummyTree { val asList = List(this) }
+ object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) with DummyTree
+ object pendingSuperCall extends Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List()) with DummyTree
+
def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef =
atPos(sym.pos) {
assert(sym != NoSymbol)
View
4 test/files/run/t5603.check
@@ -12,7 +12,7 @@
[95:101]<paramaccessor> private[this] val i: [98:101]Int = _;
<119:139>def <init>([95]i: [98]Int) = <119:139>{
<119:139>val nameElse = <134:139>"Bob";
- [94][94][94]super.<init>();
+ [NoPosition][NoPosition][NoPosition]super.<init>();
[94]()
};
[168:184]val name = [179:184]"avc";
@@ -20,7 +20,7 @@
};
[215:241]object Test extends [227:241][235:238]App {
[227]def <init>() = [227]{
- [227][227][227]super.<init>();
+ [NoPosition][NoPosition][NoPosition]super.<init>();
[227]()
};
[NoPosition]<empty>
Please sign in to comment.
Something went wrong with that request. Please try again.