From 7bf0ecc8d2d92b352182d61095bf564253f813d3 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 00:38:50 +0100 Subject: [nomaster] doesn't touch NonemptyAttachments NonemptyAttachments in macro API used to be Attachments$NonemptyAttachments. However it's private, so noone outside scala.reflect.macros can access it, making it ineligible for the incompatibility criterion. --- src/reflect/scala/reflect/macros/Attachments.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala index eeb87fafcc..007df3b6e2 100644 --- a/src/reflect/scala/reflect/macros/Attachments.scala +++ b/src/reflect/scala/reflect/macros/Attachments.scala @@ -56,6 +56,8 @@ abstract class Attachments { self => // SI-7018: This used to be an inner class of `Attachments`, but that led to a memory leak in the // IDE via $outer pointers. +// Forward compatibility note: This class used to be Attachments$NonemptyAttachments. +// However it's private, therefore it transcends the compatibility policy for 2.10.x. private final class NonemptyAttachments[P >: Null](override val pos: P, override val all: Set[Any]) extends Attachments { type Pos = P def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all) -- cgit v1.2.3 From 1093ce0b7c0d5e78dbd4cacc5c90cb264298afb0 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 00:35:16 +0100 Subject: [nomaster] removes Tree.canHaveAttrs This forward compatibility fix is very easy. Have a new method in 2.10.1? Don't expose it in the public API, and you won't have any problems. --- src/reflect/scala/reflect/api/Trees.scala | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index cfa6315797..38835d0f77 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -84,17 +84,9 @@ trait Trees { self: Universe => * * Unfortunately `emptyValDef` is also considered to be `isEmpty`, but this is deemed to be * a conceptual mistake pending a fix in https://issues.scala-lang.org/browse/SI-6762. - * - * @see `canHaveAttrs` */ def isEmpty: Boolean - /** Can this tree carry attributes (i.e. symbols, types or positions)? - * Typically the answer is yes, except for the `EmptyTree` null object and - * two special singletons: `emptyValDef` and `pendingSuperCall`. - */ - def canHaveAttrs: Boolean - /** The canonical way to test if a Tree represents a term. */ def isTerm: Boolean -- cgit v1.2.3 From 0e0c8515ff52b0a2998f9a36840fb3c0a72c9f04 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 00:31:56 +0100 Subject: [nomaster] revives BuildUtils.emptyValDef That method was unnecessary in the first place, because we already had emptyValDef in scala.reflect.api.Trees: https://github.com/scala/scala/blob/v2.10.0/src/reflect/scala/reflect/api/Trees.scala#L2367. That's a rudiment from the times when we were unsure what to put into scala.reflect.base and what goes into scala.reflect.api. Unfortunately, it's not just a harmless extraneous method. Reifier v2.10.0 emits `u.build.emptyValDef` when it needs to reify `emptyValDef`. Therefore we need to restore it to be forward compatible. However we don't need to rollback the changes to the reifier v2.10.1, which now simply calls `u.emptyValDef`, because, as mentioned above, that `emptyValDef` was already there in v2.10.0. --- src/reflect/scala/reflect/api/BuildUtils.scala | 2 ++ src/reflect/scala/reflect/internal/BuildUtils.scala | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 8f256aa1f5..0c8e81a220 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -59,6 +59,8 @@ 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 diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index b1b0c5b60b..9f41f0336e 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -47,6 +47,8 @@ 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) -- cgit v1.2.3 From 4ef2a4971b62e0c7d4547de1096bec3231b918cb Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 11:24:42 +0100 Subject: [nomaster] Revert "s/SuperCallArgs/SuperArgs/" This reverts commit 2621918870e531b7a9bcccdf14bddea9b89804b2. --- .../scala/tools/nsc/typechecker/StdAttachments.scala | 12 ++++++------ src/compiler/scala/tools/nsc/typechecker/Typers.scala | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 20db479463..0a1d3bfa7a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -19,16 +19,16 @@ trait StdAttachments { * by `parentTypes`. This attachment coordinates `parentTypes` and `typedTemplate` and * allows them to complete the synthesis. */ - case class SuperArgsAttachment(argss: List[List[Tree]]) + case class SuperCallArgsAttachment(argss: List[List[Tree]]) - /** Convenience method for `SuperArgsAttachment`. + /** Convenience method for `SuperCallArgsAttachment`. * Compared with `MacroRuntimeAttachment` this attachment has different a usage pattern, * so it really benefits from a dedicated extractor. */ - def superArgs(tree: Tree): Option[List[List[Tree]]] = - tree.attachments.get[SuperArgsAttachment] collect { case SuperArgsAttachment(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 SuperArgsAttachment. + /** Determines whether the given tree has an associated SuperCallArgsAttachment. */ - def hasSuperArgs(tree: Tree): Boolean = superArgs(tree).nonEmpty + def hasSuperArgs(tree: Tree): Boolean = superCallArgs(tree).nonEmpty } \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 026c130a87..c7554801a0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1532,7 +1532,7 @@ trait Typers extends Modes with Adaptations with Tags { * * Returns a `TypeTree` representing a resolved parent type. * If the typechecked parent reference implies non-nullary and non-empty argument list, - * this argument list is attached to the returned value in SuperArgsAttachment. + * this argument list is attached to the returned value in SuperCallArgsAttachment. * The attachment is necessary for the subsequent typecheck to fixup a super constructor call * in the body of the primary constructor (see `typedTemplate` for details). * @@ -1598,7 +1598,7 @@ trait Typers extends Modes with Adaptations with Tags { // this is the place where we tell the typer what argss should be used for the super call // if argss are nullary or empty, then (see the docs for `typedPrimaryConstrBody`) // the super call dummy is already good enough, so we don't need to do anything - if (argssAreTrivial) supertpt else supertpt updateAttachment SuperArgsAttachment(argss) + if (argssAreTrivial) supertpt else supertpt updateAttachment SuperCallArgsAttachment(argss) } } @@ -2023,7 +2023,7 @@ trait Typers extends Modes with Adaptations with Tags { val primaryCtor = treeInfo.firstConstructor(body) val primaryCtor1 = primaryCtor match { case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) => - val argss = superArgs(parents1.head) getOrElse Nil + 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 -- cgit v1.2.3 From 4d7982b592fc2d4f75eb56b4a810c5d002d25866 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 11:24:58 +0100 Subject: [nomaster] Revert "more ListOfNil => Nil" This reverts commit bb9adfbd76af0a0281912fcef4bcaca409a7c9a3. --- src/compiler/scala/tools/nsc/ast/TreeGen.scala | 2 +- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 2 +- src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 2 +- src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 96146b7343..99b82d9746 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -58,7 +58,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) { // This can't be "Annotated(New(UncheckedClass), expr)" because annotations // are very picky about things and it crashes the compiler with "unexpected new". - Annotated(New(scalaDot(UncheckedClass.name), Nil), expr) + Annotated(New(scalaDot(UncheckedClass.name), ListOfNil), expr) } // if it's a Match, mark the selector unchecked; otherwise nothing. def mkUncheckedMatch(tree: Tree) = tree match { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index c508e14343..4b8136f725 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2103,7 +2103,7 @@ self => def annotationExpr(): Tree = atPos(in.offset) { val t = exprSimpleType() if (in.token == LPAREN) New(t, multipleArgumentExprs()) - else New(t, Nil) + else New(t, ListOfNil) } /* -------- PARAMETERS ------------------------------------------- */ diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index ac8ab493e0..e7dc0a47be 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -237,7 +237,7 @@ abstract class TreeBuilder { atPos(npos) { New( Ident(x) setPos npos.focus, - Nil) + ListOfNil) } ) } diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 050f7a8f95..43a8402fc7 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -551,7 +551,7 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { if (parentToken == AT && in.token == DEFAULT) { val annot = atPos(pos) { - New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), Nil) + New(Select(scalaDot(nme.runtime), tpnme.AnnotationDefaultATTR), ListOfNil) } mods1 = mods1 withAnnotations List(annot) skipTo(SEMI) -- cgit v1.2.3 From c7205317e1fa59430d2372c27c4d0858b05ffdfc Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 11:25:56 +0100 Subject: [nomaster] Revert "DummyTree => CannotHaveAttrs" This reverts commit 838cbe623c142b7005446793948097f679219fe3. Conflicts: src/reflect/scala/reflect/api/Trees.scala --- src/compiler/scala/tools/nsc/ast/Positions.scala | 2 +- src/compiler/scala/tools/nsc/ast/Trees.scala | 2 +- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 2 +- .../scala/tools/nsc/interactive/RangePositions.scala | 6 +++--- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 +- src/reflect/scala/reflect/api/Trees.scala | 10 +--------- src/reflect/scala/reflect/internal/Positions.scala | 2 +- src/reflect/scala/reflect/internal/Printers.scala | 2 +- src/reflect/scala/reflect/internal/Trees.scala | 15 ++++++++------- 9 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala index 49569f5e05..0503c5fb10 100644 --- a/src/compiler/scala/tools/nsc/ast/Positions.scala +++ b/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.canHaveAttrs) () + if (c.isDummy) () else if (c.pos == NoPosition) { reporter.warning(t.pos, " Positioned tree has unpositioned child in phase " + globalPhase) inform("parent: " + treeSymStatus(t)) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index def1198dae..4c725fd661 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -337,7 +337,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => else super.transform { tree match { - case tree if !tree.canHaveAttrs => + case tree if tree.isDummy => tree case tpt: TypeTree => if (tpt.original != null) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 4b8136f725..915a8bc49b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2764,7 +2764,7 @@ self => if (in.token == LBRACE) { // @S: pre template body cannot stub like post body can! val (self, body) = templateBody(isPre = true) - if (in.token == WITH && (self eq emptyValDef)) { + if (in.token == WITH && self.isEmpty) { val earlyDefs: List[Tree] = body flatMap { case vdef @ ValDef(mods, _, _, _) if !mods.isDeferred => List(copyValDef(vdef)(mods = mods | Flags.PRESUPER)) diff --git a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala index 64117bd8ee..b95f1fa7ca 100644 --- a/src/compiler/scala/tools/nsc/interactive/RangePositions.scala +++ b/src/compiler/scala/tools/nsc/interactive/RangePositions.scala @@ -144,7 +144,7 @@ self: scala.tools.nsc.Global => */ private def setChildrenPos(pos: Position, trees: List[Tree]): Unit = try { for (tree <- trees) { - if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) { + if (!tree.isEmpty && tree.pos == NoPosition) { val children = tree.children if (children.isEmpty) { tree setPos pos.focus @@ -165,7 +165,7 @@ self: scala.tools.nsc.Global => */ override def atPos[T <: Tree](pos: Position)(tree: T): T = { if (pos.isOpaqueRange) { - if (!tree.isEmpty && tree.canHaveAttrs && tree.pos == NoPosition) { + if (!tree.isEmpty && tree.pos == NoPosition) { tree.setPos(pos) val children = tree.children if (children.nonEmpty) { @@ -203,7 +203,7 @@ self: scala.tools.nsc.Global => def validate(tree: Tree, encltree: Tree): Unit = { - if (!tree.isEmpty && tree.canHaveAttrs) { + if (!tree.isEmpty) { if (settings.Yposdebug.value && (settings.verbose.value || settings.Yrangepos.value)) println("[%10s] %s".format("validate", treeStatus(tree, encltree))) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index c7554801a0..5ec4530287 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -53,7 +53,7 @@ trait Typers extends Modes with Adaptations with Tags { object UnTyper extends Traverser { override def traverse(tree: Tree) = { - if (tree.canHaveAttrs) { + if (!tree.isDummy) { tree.tpe = null if (tree.hasSymbol) tree.symbol = NoSymbol } diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 38835d0f77..869b92a104 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -75,15 +75,8 @@ trait Trees { self: Universe => def isDef: Boolean /** Is this tree one of the empty trees? - * * Empty trees are: the `EmptyTree` null object, `TypeTree` instances that don't carry a type * and the special `emptyValDef` singleton. - * - * In the compiler the `isEmpty` check and the derived `orElse` method are mostly used - * as a check for a tree being a null object (`EmptyTree` for term trees and empty TypeTree for type trees). - * - * Unfortunately `emptyValDef` is also considered to be `isEmpty`, but this is deemed to be - * a conceptual mistake pending a fix in https://issues.scala-lang.org/browse/SI-6762. */ def isEmpty: Boolean @@ -2923,8 +2916,7 @@ trait Trees { self: Universe => trees mapConserve (tree => transform(tree).asInstanceOf[TypeDef]) /** Transforms a `ValDef`. */ def transformValDef(tree: ValDef): ValDef = - if (tree eq emptyValDef) tree - else transform(tree).asInstanceOf[ValDef] + if (tree.isEmpty) tree else transform(tree).asInstanceOf[ValDef] /** Transforms a list of `ValDef` nodes. */ def transformValDefs(trees: List[ValDef]): List[ValDef] = trees mapConserve (transformValDef(_)) diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index f8c670827a..b65df0e70b 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/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.canHaveAttrs) () + 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? diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index a8085a4c58..6f834803c4 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -435,7 +435,7 @@ trait Printers extends api.Printers { self: SymbolTable => case tree => xprintTree(this, tree) } - if (printTypes && tree.isTerm && tree.canHaveAttrs) { + if (printTypes && tree.isTerm && !tree.isEmpty) { print("{", if (tree.tpe eq null) "" else tree.tpe.toString, "}") } } diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index a528a9ced8..e586ab4cad 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -36,7 +36,7 @@ trait Trees extends api.Trees { self: SymbolTable => def isDef = false def isEmpty = false - def canHaveAttrs = true + def isDummy = false /** The canonical way to test if a Tree represents a term. */ @@ -955,8 +955,9 @@ trait Trees extends api.Trees { self: SymbolTable => def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree) - trait CannotHaveAttrs extends Tree { - override def canHaveAttrs = false + trait DummyTree extends Tree { + override def isEmpty = true + override def isDummy = true private def unsupported(what: String, args: Any*) = throw new UnsupportedOperationException(s"$what($args) inapplicable for "+self.toString) @@ -968,9 +969,9 @@ trait Trees extends api.Trees { self: SymbolTable => override def tpe_=(t: Type) = if (t != NoType) unsupported("tpe_=", t) } - case object EmptyTree extends TermTree with CannotHaveAttrs { override def isEmpty = true; val asList = List(this) } - object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) with CannotHaveAttrs - object pendingSuperCall extends Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List()) with CannotHaveAttrs + 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) { @@ -1122,7 +1123,7 @@ trait Trees extends api.Trees { self: SymbolTable => traverse(annot); traverse(arg) case Template(parents, self, body) => traverseTrees(parents) - if (self ne emptyValDef) traverse(self) + if (!self.isEmpty) traverse(self) traverseStats(body, tree.symbol) case Block(stats, expr) => traverseTrees(stats); traverse(expr) -- cgit v1.2.3 From 570f4a46f663a8f55ce045bfde2d834bd4902f9c Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 11:51:24 +0100 Subject: [nomaster] Revert "introduces global.pendingSuperCall" This reverts commit 0ebf72b9498108e67c2133c6522c436af50a18e8. Conflicts: src/compiler/scala/tools/nsc/typechecker/Typers.scala src/reflect/scala/reflect/internal/Trees.scala --- .../scala/reflect/reify/codegen/GenTrees.scala | 4 +- .../scala/reflect/reify/codegen/GenUtils.scala | 3 + src/compiler/scala/tools/nsc/ast/Positions.scala | 2 +- src/compiler/scala/tools/nsc/ast/Trees.scala | 23 +++---- .../tools/nsc/typechecker/StdAttachments.scala | 12 ++-- .../scala/tools/nsc/typechecker/Typers.scala | 73 ++++++++++++++-------- src/reflect/scala/reflect/api/Trees.scala | 9 --- src/reflect/scala/reflect/internal/Importers.scala | 2 - src/reflect/scala/reflect/internal/Positions.scala | 2 +- src/reflect/scala/reflect/internal/Printers.scala | 4 +- src/reflect/scala/reflect/internal/StdNames.scala | 1 - src/reflect/scala/reflect/internal/Trees.scala | 26 +++----- test/files/neg/anyval-anyref-parent.check | 2 +- test/files/neg/names-defaults-neg.check | 2 +- test/files/neg/t5529.check | 5 +- test/files/run/t5064.check | 6 +- test/files/run/t5603.check | 4 +- test/files/run/t6288.check | 12 ++-- test/files/run/t6288b-jump-position.check | 6 +- 19 files changed, 98 insertions(+), 100 deletions(-) diff --git a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala index 31974b5b76..949f7f1799 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenTrees.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenTrees.scala @@ -45,9 +45,7 @@ trait GenTrees { case global.EmptyTree => reifyMirrorObject(EmptyTree) case global.emptyValDef => - mirrorSelect(nme.emptyValDef) - case global.pendingSuperCall => - mirrorSelect(nme.pendingSuperCall) + mirrorBuildSelect(nme.emptyValDef) case FreeDef(_, _, _, _, _) => reifyNestedFreeDef(tree) case FreeRef(_, _) => diff --git a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala index 21db93d8f5..49877b4286 100644 --- a/src/compiler/scala/reflect/reify/codegen/GenUtils.scala +++ b/src/compiler/scala/reflect/reify/codegen/GenUtils.scala @@ -34,6 +34,9 @@ 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) diff --git a/src/compiler/scala/tools/nsc/ast/Positions.scala b/src/compiler/scala/tools/nsc/ast/Positions.scala index 0503c5fb10..d8fb632f73 100644 --- a/src/compiler/scala/tools/nsc/ast/Positions.scala +++ b/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.isDummy) () + if ((c eq EmptyTree) || (c eq emptyValDef)) () else if (c.pos == NoPosition) { reporter.warning(t.pos, " Positioned tree has unpositioned child in phase " + globalPhase) inform("parent: " + treeSymStatus(t)) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 4c725fd661..2872b83d88 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -65,13 +65,6 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => // --- factory methods ---------------------------------------------------------- - /** Factory method for a primary constructor super call `super.(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 } @@ -124,12 +117,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 = 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 + 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 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`? @@ -337,8 +330,6 @@ 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) @@ -352,6 +343,8 @@ 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)) diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 0a1d3bfa7a..fa2913bee3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -21,14 +21,12 @@ trait StdAttachments { */ case class SuperCallArgsAttachment(argss: List[List[Tree]]) - /** Convenience method for `SuperCallArgsAttachment`. + /** Extractor for `SuperCallArgsAttachment`. * Compared with `MacroRuntimeAttachment` this attachment has different a usage pattern, * so it really benefits from a dedicated extractor. */ - 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 + object CarriesSuperCallArgs { + def unapply(tree: Tree): Option[List[List[Tree]]] = + tree.attachments.get[SuperCallArgsAttachment] collect { case SuperCallArgsAttachment(argss) => argss } + } } \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5ec4530287..45b151348b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -53,10 +53,8 @@ trait Typers extends Modes with Adaptations with Tags { object UnTyper extends Traverser { override def traverse(tree: Tree) = { - if (!tree.isDummy) { - tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol - } + if (tree != EmptyTree) tree.tpe = null + if (tree.hasSymbol) tree.symbol = NoSymbol super.traverse(tree) } } @@ -1584,7 +1582,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) { + typedPrimaryConstrBody(templ) { superRef => 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 @@ -1603,8 +1601,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, replaces the `pendingSuperCall` dummy with the result of `actualSuperCall`. - * `actualSuperCall` can return `EmptyTree`, in which case the dummy is replaced with a literal unit. + * 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. * * ***Return value and side effects*** * @@ -1629,14 +1627,34 @@ trait Typers extends Modes with Adaptations with Tags { * Block(List( * ValDef(NoMods, x, TypeTree(), 2) * ValDef(NoMods, y, TypeTree(), 4) - * global.pendingSuperCall, + * Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR)), List()), * Literal(Constant(()))) * - * 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`. + * 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. */ - private def typedPrimaryConstrBody(templ: Template)(actualSuperCall: => Tree): Tree = + private def typedPrimaryConstrBody(templ: Template)(superCallTransform: Tree => Tree): Tree = treeInfo.firstConstructor(templ.body) match { case ctor @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => val (preSuperStats, superCall) = { @@ -1644,7 +1662,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 global.pendingSuperCall => actualSuperCall + case Apply(superRef @ Select(Super(_, _), nme.CONSTRUCTOR), Nil) => superCallTransform(superRef) case EmptyTree => EmptyTree }) orElse cunit val cbody1 = treeCopy.Block(cbody, preSuperStats, superCall1) @@ -1724,7 +1742,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)(EmptyTree) + typedPrimaryConstrBody(templ)(superRef => EmptyTree) supertpts mapConserve (tpt => checkNoEscaping.privates(context.owner, tpt)) } catch { @@ -2007,8 +2025,6 @@ 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") @@ -2020,16 +2036,23 @@ 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, _)) - 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 + parents1.head match { + case CarriesSuperCallArgs(argss) => + if (clazz.isTrait) { + ConstrArgsInParentOfTraitError(parents1.head, clazz) + body + } else { + val pos = wrappingPos(parents1.head.pos, argss.flatten) + val primaryCtor = treeInfo.firstConstructor(templ.body) + val primaryCtor1 = (deriveDefDef(primaryCtor) { + case block @ Block(earlyVals :+ Apply(superRef, Nil), unit) => + 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 } - body mapConserve { case `primaryCtor` => primaryCtor1; case stat => stat } } val body1 = typedStats(body, templ.symbol) diff --git a/src/reflect/scala/reflect/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index 869b92a104..0937a93738 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -2405,15 +2405,6 @@ trait Trees { self: Universe => */ val emptyValDef: ValDef - /** An empty superclass constructor call corresponding to: - * super.() - * 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. diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala index 2f2b02975c..43902c1930 100644 --- a/src/reflect/scala/reflect/internal/Importers.scala +++ b/src/reflect/scala/reflect/internal/Importers.scala @@ -334,8 +334,6 @@ 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) => diff --git a/src/reflect/scala/reflect/internal/Positions.scala b/src/reflect/scala/reflect/internal/Positions.scala index b65df0e70b..faa161d6b1 100644 --- a/src/reflect/scala/reflect/internal/Positions.scala +++ b/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.isDummy) () + if (t eq EmptyTree) () else if (t.pos == NoPosition) { t.setPos(pos) super.traverse(t) // TODO: bug? shouldn't the traverse be outside of the if? diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala index 6f834803c4..80d247c0ea 100644 --- a/src/reflect/scala/reflect/internal/Printers.scala +++ b/src/reflect/scala/reflect/internal/Printers.scala @@ -542,10 +542,8 @@ trait Printers extends api.Printers { self: SymbolTable => print(")") case EmptyTree => print("EmptyTree") - case self.emptyValDef => + case emptyValDef: AnyRef if emptyValDef eq 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 diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index c870d8972d..5e7f5777b2 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -730,7 +730,6 @@ 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" diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index e586ab4cad..693b75fbbc 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -36,7 +36,6 @@ 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. */ @@ -229,6 +228,14 @@ 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 ") + override def isEmpty = true + } + abstract class MemberDef extends DefTree with MemberDefApi { def mods: Modifiers def keyword: String = this match { @@ -592,7 +599,6 @@ 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]) = @@ -955,24 +961,12 @@ trait Trees extends api.Trees { self: SymbolTable => def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree) - trait DummyTree extends Tree { + object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) { override def isEmpty = true - override def isDummy = true - - private def unsupported(what: String, args: Any*) = - throw new UnsupportedOperationException(s"$what($args) inapplicable for "+self.toString) - super.setPos(NoPosition) - override def setPos(pos: Position) = unsupported("setPos", pos) - - super.setType(NoType) - override def tpe_=(t: Type) = if (t != NoType) unsupported("tpe_=", t) + override def setPos(pos: Position) = { assert(false); this } } - 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) diff --git a/test/files/neg/anyval-anyref-parent.check b/test/files/neg/anyval-anyref-parent.check index 8c2aa36583..fe20e5de81 100644 --- a/test/files/neg/anyval-anyref-parent.check +++ b/test/files/neg/anyval-anyref-parent.check @@ -3,7 +3,7 @@ trait Foo2 extends AnyVal // fail ^ anyval-anyref-parent.scala:5: error: Any does not have a constructor class Bar1 extends Any // fail - ^ + ^ anyval-anyref-parent.scala:6: error: value class needs to have exactly one public val parameter class Bar2(x: Int) extends AnyVal // fail ^ diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index f6bd703e1f..ea7c323b74 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -100,7 +100,7 @@ Error occurred in an application involving default arguments. ^ names-defaults-neg.scala:86: error: module extending its companion class cannot use default constructor arguments object C extends C() - ^ + ^ names-defaults-neg.scala:90: error: deprecated parameter name x has to be distinct from any other parameter name (deprecated or not). def deprNam1(x: Int, @deprecatedName('x) y: String) = 0 ^ diff --git a/test/files/neg/t5529.check b/test/files/neg/t5529.check index da3f84e1ec..5d2175fa79 100644 --- a/test/files/neg/t5529.check +++ b/test/files/neg/t5529.check @@ -4,4 +4,7 @@ t5529.scala:12: error: File is already defined as class File t5529.scala:10: error: class type required but test.Test.File found sealed class Dir extends File { } ^ -two errors found +t5529.scala:10: error: test.Test.File does not have a constructor + sealed class Dir extends File { } + ^ +three errors found diff --git a/test/files/run/t5064.check b/test/files/run/t5064.check index 61ccfd16e7..077006abd9 100644 --- a/test/files/run/t5064.check +++ b/test/files/run/t5064.check @@ -1,6 +1,6 @@ -[53] T5064.super.() -[53] T5064.super. -[53] this +[12] T5064.super.() +[12] T5064.super. +[12] this [16:23] immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1})) [16:20] immutable.this.List.apply <16:20> immutable.this.List diff --git a/test/files/run/t5603.check b/test/files/run/t5603.check index 3b2eb55313..5127d3c1c7 100644 --- a/test/files/run/t5603.check +++ b/test/files/run/t5603.check @@ -12,7 +12,7 @@ [95:101] private[this] val i: [98:101]Int = _; <119:139>def ([95]i: [98]Int) = <119:139>{ <119:139>val nameElse = <134:139>"Bob"; - [NoPosition][NoPosition][NoPosition]super.(); + [94][94][94]super.(); [94]() }; [168:184]val name = [179:184]"avc"; @@ -20,7 +20,7 @@ }; [215:241]object Test extends [227:241][235:238]App { [227]def () = [227]{ - [NoPosition][NoPosition][NoPosition]super.(); + [227][227][227]super.(); [227]() }; [NoPosition] diff --git a/test/files/run/t6288.check b/test/files/run/t6288.check index 4895c2c007..e6467edc95 100644 --- a/test/files/run/t6288.check +++ b/test/files/run/t6288.check @@ -1,8 +1,8 @@ [[syntax trees at end of patmat]] // newSource1 [7]package [7] { [7]object Case3 extends [13][106]scala.AnyRef { - [106]def (): [13]Case3.type = [106]{ - [106][106][106]Case3.super.(); + [13]def (): [13]Case3.type = [13]{ + [13][13][13]Case3.super.(); [13]() }; [21]def unapply([29]z: [32]): [21]Option[Int] = [56][52][52]scala.Some.apply[[52]Int]([58]-1); @@ -24,8 +24,8 @@ } }; [113]object Case4 extends [119][217]scala.AnyRef { - [217]def (): [119]Case4.type = [217]{ - [217][217][217]Case4.super.(); + [119]def (): [119]Case4.type = [119]{ + [119][119][119]Case4.super.(); [119]() }; [127]def unapplySeq([138]z: [141]): [127]Option[List[Int]] = [167]scala.None; @@ -50,8 +50,8 @@ } }; [224]object Case5 extends [230][312]scala.AnyRef { - [312]def (): [230]Case5.type = [312]{ - [312][312][312]Case5.super.(); + [230]def (): [230]Case5.type = [230]{ + [230][230][230]Case5.super.(); [230]() }; [238]def unapply([246]z: [249]): [238]Boolean = [265]true; diff --git a/test/files/run/t6288b-jump-position.check b/test/files/run/t6288b-jump-position.check index ece88b18f0..83ba810958 100644 --- a/test/files/run/t6288b-jump-position.check +++ b/test/files/run/t6288b-jump-position.check @@ -65,9 +65,9 @@ object Case3 extends Object { blocks: [1] 1: - 12 THIS(Case3) - 12 CALL_METHOD java.lang.Object. (super()) - 12 RETURN(UNIT) + 1 THIS(Case3) + 1 CALL_METHOD java.lang.Object. (super()) + 1 RETURN(UNIT) } Exception handlers: -- cgit v1.2.3 From c9a0e36224b6eb2807bad0df2d5aa11bb05c8a32 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 11:53:43 +0100 Subject: [nomaster] Revert "refactors handling of parent types" This reverts commit 40063b0009d55ed527bf1625d99a168a8faa4124. Conflicts: src/compiler/scala/tools/nsc/ast/parser/Parsers.scala src/compiler/scala/tools/nsc/typechecker/Typers.scala --- src/compiler/scala/tools/nsc/ast/Trees.scala | 18 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 62 ++-- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 20 +- .../scala/tools/nsc/transform/Constructors.scala | 1 + .../scala/tools/nsc/transform/UnCurry.scala | 4 +- .../tools/nsc/typechecker/ContextErrors.scala | 13 +- .../scala/tools/nsc/typechecker/Namers.scala | 9 +- .../tools/nsc/typechecker/StdAttachments.scala | 22 -- .../scala/tools/nsc/typechecker/Typers.scala | 396 +++++++-------------- .../scala/tools/nsc/typechecker/Unapplies.scala | 2 +- .../scala/tools/reflect/ToolBoxFactory.scala | 1 + src/reflect/scala/reflect/internal/TreeInfo.scala | 7 - src/reflect/scala/reflect/internal/Trees.scala | 3 - test/files/neg/cyclics-import.check | 11 +- test/files/neg/protected-constructors.check | 5 +- test/files/neg/t2148.check | 2 +- test/files/neg/t409.check | 4 +- test/files/neg/t5696.check | 2 +- test/files/neg/t667.check | 4 +- test/files/neg/t877.check | 4 +- test/files/run/analyzerPlugins.check | 35 +- 21 files changed, 225 insertions(+), 400 deletions(-) diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 2872b83d88..2ad762fd55 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -82,7 +82,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * body * } */ - def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): Template = { + def Template(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): Template = { /* Add constructor to template */ // create parameters for as synthetic trees. @@ -117,16 +117,9 @@ 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 = (superRef /: argss) (Apply.apply) 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`? - atPos(wrappingPos(superPos, lvdefs)) ( + atPos(wrappingPos(superPos, lvdefs ::: argss.flatten)) ( DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(lvdefs ::: List(superCall), Literal(Constant()))))) } } @@ -144,10 +137,11 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => * @param constrMods the modifiers for the class constructor, i.e. as in `class C private (...)` * @param vparamss the value parameters -- if they have symbols they * should be owned by `sym` + * @param argss the supercall arguments * @param body the template statements without primary constructor * and value parameter fields. */ - def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position): ClassDef = { + def ClassDef(sym: Symbol, constrMods: Modifiers, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree], superPos: Position): ClassDef = { // "if they have symbols they should be owned by `sym`" assert( mforall(vparamss)(p => (p.symbol eq NoSymbol) || (p.symbol.owner == sym)), @@ -157,7 +151,7 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => ClassDef(sym, Template(sym.info.parents map TypeTree, if (sym.thisSym == sym || phase.erasedTypes) emptyValDef else ValDef(sym.thisSym), - constrMods, vparamss, body, superPos)) + constrMods, vparamss, argss, body, superPos)) } // --- subcomponents -------------------------------------------------- diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 915a8bc49b..6f79f639b9 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1559,9 +1559,9 @@ self => val nstart = in.skipToken() val npos = r2p(nstart, nstart, in.lastOffset) val tstart = in.offset - val (parents, self, stats) = template() + val (parents, argss, self, stats) = template(isTrait = false) val cpos = r2p(tstart, tstart, in.lastOffset max tstart) - makeNew(parents, self, stats, npos, cpos) + makeNew(parents, self, stats, argss, npos, cpos) case _ => syntaxErrorOrIncomplete("illegal start of simple expression", true) errorTermTree @@ -2739,17 +2739,20 @@ self => * TraitParents ::= AnnotType {with AnnotType} * }}} */ - def templateParents(): List[Tree] = { - val parents = new ListBuffer[Tree] - def readAppliedParent() = { - val start = in.offset - val parent = startAnnotType() - val argss = if (in.token == LPAREN) multipleArgumentExprs() else Nil - parents += atPos(start)((parent /: argss)(Apply.apply)) + def templateParents(isTrait: Boolean): (List[Tree], List[List[Tree]]) = { + val parents = new ListBuffer[Tree] += startAnnotType() + val argss = ( + // TODO: the insertion of ListOfNil here is where "new Foo" becomes + // indistinguishable from "new Foo()". + if (in.token == LPAREN && !isTrait) multipleArgumentExprs() + else ListOfNil + ) + + while (in.token == WITH) { + in.nextToken() + parents += startAnnotType() } - readAppliedParent() - while (in.token == WITH) { in.nextToken(); readAppliedParent() } - parents.toList + (parents.toList, argss) } /** {{{ @@ -2759,7 +2762,7 @@ self => * EarlyDef ::= Annotations Modifiers PatDef * }}} */ - def template(): (List[Tree], ValDef, List[Tree]) = { + def template(isTrait: Boolean): (List[Tree], List[List[Tree]], ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) { // @S: pre template body cannot stub like post body can! @@ -2776,16 +2779,16 @@ self => case _ => List() } in.nextToken() - val parents = templateParents() - val (self1, body1) = templateBodyOpt(parenMeansSyntaxError = false) - (parents, self1, earlyDefs ::: body1) + val (parents, argss) = templateParents(isTrait = isTrait) + val (self1, body1) = templateBodyOpt(traitParentSeen = isTrait) + (parents, argss, self1, earlyDefs ::: body1) } else { - (List(), self, body) + (List(), ListOfNil, self, body) } } else { - val parents = templateParents() - val (self, body) = templateBodyOpt(parenMeansSyntaxError = false) - (parents, self, body) + val (parents, argss) = templateParents(isTrait = isTrait) + val (self, body) = templateBodyOpt(traitParentSeen = isTrait) + (parents, argss, self, body) } } @@ -2799,15 +2802,15 @@ self => * }}} */ def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = { - val (parents0, self, body) = ( + val (parents0, argss, self, body) = ( if (in.token == EXTENDS || in.token == SUBTYPE && mods.isTrait) { in.nextToken() - template() + template(isTrait = mods.isTrait) } else { newLineOptWhenFollowedBy(LBRACE) - val (self, body) = templateBodyOpt(parenMeansSyntaxError = mods.isTrait || name.isTermName) - (List(), self, body) + val (self, body) = templateBodyOpt(traitParentSeen = false) + (List(), ListOfNil, self, body) } ) def anyrefParents() = { @@ -2829,7 +2832,7 @@ self => if (inScalaRootPackage && ScalaValueClassNames.contains(name)) Template(parents0, self, anyvalConstructor :: body) else - Template(anyrefParents, self, constrMods, vparamss, body, o2p(tstart)) + Template(anyrefParents, self, constrMods, vparamss, argss, body, o2p(tstart)) } } @@ -2844,15 +2847,14 @@ self => case (self, Nil) => (self, EmptyTree.asList) case result => result } - def templateBodyOpt(parenMeansSyntaxError: Boolean): (ValDef, List[Tree]) = { + def templateBodyOpt(traitParentSeen: Boolean): (ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) { templateBody(isPre = false) } else { - if (in.token == LPAREN) { - if (parenMeansSyntaxError) syntaxError(s"traits or objects may not have parameters", true) - else abort("unexpected opening parenthesis") - } + if (in.token == LPAREN) + syntaxError((if (traitParentSeen) "parents of traits" else "traits or objects")+ + " may not have parameters", true) (emptyValDef, List()) } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index e7dc0a47be..7969bb9c20 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -205,26 +205,20 @@ abstract class TreeBuilder { */ def makeAnonymousNew(stats: List[Tree]): Tree = { val stats1 = if (stats.isEmpty) List(Literal(Constant(()))) else stats - makeNew(Nil, emptyValDef, stats1, NoPosition, NoPosition) + makeNew(Nil, emptyValDef, stats1, ListOfNil, NoPosition, NoPosition) } /** Create positioned tree representing an object creation - import global._ - - /** Carries information necessary to expand the host tree. - * At times we need to store this info, because macro expansion can be delayed until its targs are inferred. - * After a macro application has been successfully expanded, this attachment is destroyed. - */ type UnaffiliatedMacroContext = scala.reflect.macros.runtime.Context type MacroContext = UnaffiliatedMacroContext { val universe: self.global.type } case class MacroRuntimeAttachment(delayed: Boolean, typerContext: Context, macroContext: Option[MacroContext]) - - /** After being synthesized by the parser, primary constructors aren't fully baked yet. - * A call to super in such constructors is just a fill-me-in-later dummy resolved later - * by `parentTypes`. This attachment coordinates `parentTypes` and `typedTemplate` and - * allows them to complete the synthesis. - */ - case class SuperCallArgsAttachment(argss: List[List[Tree]]) - - /** Extractor 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 } - } } \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 45b151348b..f518712701 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1399,6 +1399,13 @@ trait Typers extends Modes with Adaptations with Tags { if (member(qual, name) != NoSymbol) qual else adaptToMember(qual, HasMember(name)) + private def typePrimaryConstrBody(clazz : Symbol, cbody: Tree, tparams: List[Symbol], enclTparams: List[Symbol], vparamss: List[List[ValDef]]): Tree = { + // XXX: see about using the class's symbol.... + enclTparams foreach (sym => context.scope.enter(sym)) + namer.enterValueParams(vparamss) + typed(cbody) + } + private def validateNoCaseAncestor(clazz: Symbol) = { if (!phase.erasedTypes) { for (ancestor <- clazz.ancestors find (_.isCase)) { @@ -1500,263 +1507,126 @@ trait Typers extends Modes with Adaptations with Tags { unit.error(tparam.pos, "type parameter of value class may not be specialized") } - /** Typechecks a parent type reference. - * - * This typecheck is harder than it might look, because it should honor early - * definitions and also perform type argument inference with the help of super call - * arguments provided in `encodedtpt`. - * - * The method is called in batches (batch = 1 time per each parent type referenced), - * two batches per definition: once from namer, when entering a ClassDef or a ModuleDef - * and once from typer, when typechecking the definition. - * - * ***Arguments*** - * - * `encodedtpt` represents the parent type reference wrapped in an `Apply` node - * which indicates value arguments (i.e. type macro arguments or super constructor call arguments) - * If no value arguments are provided by the user, the `Apply` node is still - * there, but its `args` will be set to `Nil`. - * This argument is synthesized by `tools.nsc.ast.Parsers.templateParents`. - * - * `templ` is an enclosing template, which contains a primary constructor synthesized by the parser. - * Such a constructor is a DefDef which contains early initializers and maybe a super constructor call - * (I wrote "maybe" because trait constructors don't call super constructors). - * This argument is synthesized by `tools.nsc.ast.Trees.Template`. - * - * `inMixinPosition` indicates whether the reference is not the first in the - * list of parents (and therefore cannot be a class) or the opposite. - * - * ***Return value and side effects*** - * - * Returns a `TypeTree` representing a resolved parent type. - * If the typechecked parent reference implies non-nullary and non-empty argument list, - * this argument list is attached to the returned value in SuperCallArgsAttachment. - * The attachment is necessary for the subsequent typecheck to fixup a super constructor call - * in the body of the primary constructor (see `typedTemplate` for details). - * - * This method might invoke `typedPrimaryConstrBody`, hence it might cause the side effects - * described in the docs of that method. It might also attribute the Super(_, _) reference - * (if present) inside the primary constructor of `templ`. - * - * ***Example*** - * - * For the following definition: - * - * class D extends { - * val x = 2 - * val y = 4 - * } with B(x)(3) with C(y) with T - * - * this method will be called six times: - * - * (3 times from the namer) - * typedParentType(Apply(Apply(Ident(B), List(Ident(x))), List(3)), templ, inMixinPosition = false) - * typedParentType(Apply(Ident(C), List(Ident(y))), templ, inMixinPosition = true) - * typedParentType(Apply(Ident(T), List()), templ, inMixinPosition = true) - * - * (3 times from the typer) - * - */ - private def typedParentType(encodedtpt: Tree, templ: Template, inMixinPosition: Boolean): Tree = { - val app = treeInfo.dissectApplied(encodedtpt) - val (treeInfo.Applied(core, targs, argss), decodedtpt) = (app, app.callee) - val argssAreTrivial = argss == Nil || argss == ListOfNil - - // we cannot avoid cyclic references with `initialize` here, because when type macros arrive, - // we'll have to check the probe for isTypeMacro anyways. - // therefore I think it's reasonable to trade a more specific "inherits itself" error - // for a generic, yet understandable "cyclic reference" error - var probe = typedTypeConstructor(core.duplicate).tpe.typeSymbol - if (probe == null) probe = NoSymbol - probe.initialize - - if (probe.isTrait || inMixinPosition) { - if (!argssAreTrivial) { - if (probe.isTrait) ConstrArgsInParentWhichIsTraitError(encodedtpt, probe) - else () // a class in a mixin position - this warrants an error in `validateParentClasses` - // therefore here we do nothing, e.g. don't check that the # of ctor arguments - // matches the # of ctor parameters or stuff like that - } - typedType(decodedtpt) - } else { - var supertpt = typedTypeConstructor(decodedtpt) - val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else Nil - if (supertparams.nonEmpty) { - typedPrimaryConstrBody(templ) { superRef => - 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 - ctor setType supertpe // this is an essential hack, otherwise it will occasionally fail to typecheck - atPos(supertpt.pos.focus)(supercall) - } match { - case EmptyTree => MissingTypeArgumentsParentTpeError(supertpt) - case tpt => supertpt = TypeTree(tpt.tpe) setPos supertpt.pos.focus + def parentTypes(templ: Template): List[Tree] = + if (templ.parents.isEmpty) List(atPos(templ.pos)(TypeTree(AnyRefClass.tpe))) + else try { + val clazz = context.owner + // Normalize supertype and mixins so that supertype is always a class, not a trait. + var supertpt = typedTypeConstructor(templ.parents.head) + val firstParent = supertpt.tpe.typeSymbol + var mixins = templ.parents.tail map typedType + // If first parent is a trait, make it first mixin and add its superclass as first parent + while ((supertpt.tpe.typeSymbol ne null) && supertpt.tpe.typeSymbol.initialize.isTrait) { + val supertpt1 = typedType(supertpt) + if (!supertpt1.isErrorTyped) { + mixins = supertpt1 :: mixins + supertpt = TypeTree(supertpt1.tpe.firstParent) setPos supertpt.pos.focus } } - // this is the place where we tell the typer what argss should be used for the super call - // if argss are nullary or empty, then (see the docs for `typedPrimaryConstrBody`) - // the super call dummy is already good enough, so we don't need to do anything - if (argssAreTrivial) supertpt else supertpt updateAttachment SuperCallArgsAttachment(argss) - } - } - - /** 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. - * - * ***Return value and side effects*** - * - * If a super call is present in the primary constructor and is not erased by the transform, returns it typechecked. - * Otherwise (e.g. if the primary constructor is missing or the super call isn't there) returns `EmptyTree`. - * - * As a side effect, this method attributes the underlying fields of early vals. - * Early vals aren't typechecked anywhere else, so it's essential to call `typedPrimaryConstrBody` - * at least once per definition. It'd be great to disentangle this logic at some point. - * - * ***Example*** - * - * For the following definition: - * - * class D extends { - * val x = 2 - * val y = 4 - * } with B(x)(3) with C(y) with T - * - * the primary constructor of `templ` will be: - * - * Block(List( - * ValDef(NoMods, x, TypeTree(), 2) - * ValDef(NoMods, y, TypeTree(), 4) - * Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR)), List()), - * 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. - */ - private def typedPrimaryConstrBody(templ: Template)(superCallTransform: Tree => Tree): Tree = - treeInfo.firstConstructor(templ.body) match { - case ctor @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => - val (preSuperStats, superCall) = { - val (stats, rest) = cstats span (x => !treeInfo.isSuperConstrCall(x)) - (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 EmptyTree => EmptyTree - }) orElse cunit - val cbody1 = treeCopy.Block(cbody, preSuperStats, superCall1) - - val clazz = context.owner - assert(clazz != NoSymbol, templ) - val cscope = context.outer.makeNewScope(ctor, context.outer.owner) - val cbody2 = { // called both during completion AND typing. - val typer1 = newTyper(cscope) - // XXX: see about using the class's symbol.... - clazz.unsafeTypeParams foreach (sym => typer1.context.scope.enter(sym)) - typer1.namer.enterValueParams(vparamss map (_.map(_.duplicate))) - typer1.typed(cbody1) - } + if (supertpt.tpe.typeSymbol == AnyClass && firstParent.isTrait) + supertpt.tpe = AnyRefClass.tpe + + // Determine + // - supertparams: Missing type parameters from supertype + // - supertpe: Given supertype, polymorphic in supertparams + val supertparams = if (supertpt.hasSymbol) supertpt.symbol.typeParams else List() + var supertpe = supertpt.tpe + if (!supertparams.isEmpty) + supertpe = PolyType(supertparams, appliedType(supertpe, supertparams map (_.tpeHK))) + + // A method to replace a super reference by a New in a supercall + def transformSuperCall(scall: Tree): Tree = (scall: @unchecked) match { + case Apply(fn, args) => + treeCopy.Apply(scall, transformSuperCall(fn), args map (_.duplicate)) + case Select(Super(_, _), nme.CONSTRUCTOR) => + treeCopy.Select( + scall, + atPos(supertpt.pos.focus)(New(TypeTree(supertpe)) setType supertpe), + nme.CONSTRUCTOR) + } - val preSuperVals = treeInfo.preSuperFields(templ.body) - if (preSuperVals.isEmpty && preSuperStats.nonEmpty) - debugwarn("Wanted to zip empty presuper val list with " + preSuperStats) - else - map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) + treeInfo.firstConstructor(templ.body) match { + case constr @ DefDef(_, _, _, vparamss, _, cbody @ Block(cstats, cunit)) => + // Convert constructor body to block in environment and typecheck it + val (preSuperStats, superCall) = { + val (stats, rest) = cstats span (x => !treeInfo.isSuperConstrCall(x)) + (stats map (_.duplicate), if (rest.isEmpty) EmptyTree else rest.head.duplicate) + } + val cstats1 = if (superCall == EmptyTree) preSuperStats else preSuperStats :+ superCall + val cbody1 = treeCopy.Block(cbody, preSuperStats, superCall match { + case Apply(_, _) if supertparams.nonEmpty => transformSuperCall(superCall) + case _ => cunit.duplicate + }) + val outercontext = context.outer + + assert(clazz != NoSymbol, templ) + val cscope = outercontext.makeNewScope(constr, outercontext.owner) + val cbody2 = newTyper(cscope) // called both during completion AND typing. + .typePrimaryConstrBody(clazz, + cbody1, supertparams, clazz.unsafeTypeParams, vparamss map (_.map(_.duplicate))) + + superCall match { + case Apply(_, _) => + val treeInfo.Applied(_, _, argss) = superCall + val sarg = argss.flatten.headOption.getOrElse(EmptyTree) + if (sarg != EmptyTree && supertpe.typeSymbol != firstParent) + ConstrArgsInTraitParentTpeError(sarg, firstParent) + if (!supertparams.isEmpty) + supertpt = TypeTree(cbody2.tpe) setPos supertpt.pos.focus + case _ => + if (!supertparams.isEmpty) + MissingTypeArgumentsParentTpeError(supertpt) + } - if (superCall1 == cunit) EmptyTree else cbody2 - case _ => - EmptyTree - } + val preSuperVals = treeInfo.preSuperFields(templ.body) + if (preSuperVals.isEmpty && preSuperStats.nonEmpty) + debugwarn("Wanted to zip empty presuper val list with " + preSuperStats) + else + map2(preSuperStats, preSuperVals)((ldef, gdef) => gdef.tpt.tpe = ldef.symbol.tpe) - /** Makes sure that the first type tree in the list of parent types is always a class. - * If the first parent is a trait, prepend its supertype to the list until it's a class. - */ - private def normalizeFirstParent(parents: List[Tree]): List[Tree] = parents match { - case first :: rest if treeInfo.isTraitRef(first) => - def explode(supertpt: Tree, acc: List[Tree]): List[Tree] = { - if (treeInfo.isTraitRef(supertpt)) { - val supertpt1 = typedType(supertpt) - if (!supertpt1.isErrorTyped) { - val supersupertpt = TypeTree(supertpt1.tpe.firstParent) setPos supertpt.pos.focus - return explode(supersupertpt, supertpt1 :: acc) - } - } - if (supertpt.tpe.typeSymbol == AnyClass) supertpt.tpe = AnyRefClass.tpe - supertpt :: acc + case _ => + if (!supertparams.isEmpty) + MissingTypeArgumentsParentTpeError(supertpt) } - explode(first, Nil) ++ rest - case _ => parents - } +/* experimental: early types as type arguments + val hasEarlyTypes = templ.body exists (treeInfo.isEarlyTypeDef) + val earlyMap = new EarlyMap(clazz) + List.mapConserve(supertpt :: mixins){ tpt => + val tpt1 = checkNoEscaping.privates(clazz, tpt) + if (hasEarlyTypes) tpt1 else tpt1 setType earlyMap(tpt1.tpe) + } +*/ - /** Certain parents are added in the parser before it is known whether - * that class also declared them as parents. For instance, this is an - * error unless we take corrective action here: - * - * case class Foo() extends Serializable - * - * So we strip the duplicates before typer. - */ - private def fixDuplicateSyntheticParents(parents: List[Tree]): List[Tree] = parents match { - case Nil => Nil - case x :: xs => - val sym = x.symbol - x :: fixDuplicateSyntheticParents( - if (isPossibleSyntheticParent(sym)) xs filterNot (_.symbol == sym) - else xs - ) - } + //Console.println("parents("+clazz") = "+supertpt :: mixins);//DEBUG - def parentTypes(templ: Template): List[Tree] = templ.parents match { - case Nil => List(atPos(templ.pos)(TypeTree(AnyRefClass.tpe))) - case first :: rest => - try { - val supertpts = fixDuplicateSyntheticParents(normalizeFirstParent( - typedParentType(first, templ, inMixinPosition = false) +: - (rest map (typedParentType(_, templ, inMixinPosition = true))))) - - // if that is required to infer the targs of a super call - // typedParentType calls typedPrimaryConstrBody to do the inferring typecheck - // as a side effect, that typecheck also assigns types to the fields underlying early vals - // however if inference is not required, the typecheck doesn't happen - // 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) - - supertpts mapConserve (tpt => checkNoEscaping.privates(context.owner, tpt)) - } catch { - case ex: TypeError => - // fallback in case of cyclic errors - // @H none of the tests enter here but I couldn't rule it out - // upd. @E when a definitions inherits itself, we end up here - // because `typedParentType` triggers `initialize` for parent types symbols - log("Type error calculating parents in template " + templ) - log("Error: " + ex) - ParentTypesError(templ, ex) - List(TypeTree(AnyRefClass.tpe)) + // Certain parents are added in the parser before it is known whether + // that class also declared them as parents. For instance, this is an + // error unless we take corrective action here: + // + // case class Foo() extends Serializable + // + // So we strip the duplicates before typer. + def fixDuplicates(remaining: List[Tree]): List[Tree] = remaining match { + case Nil => Nil + case x :: xs => + val sym = x.symbol + x :: fixDuplicates( + if (isPossibleSyntheticParent(sym)) xs filterNot (_.symbol == sym) + else xs + ) } - } + + fixDuplicates(supertpt :: mixins) mapConserve (tpt => checkNoEscaping.privates(clazz, tpt)) + } + catch { + case ex: TypeError => + // fallback in case of cyclic errors + // @H none of the tests enter here but I couldn't rule it out + log("Type error calculating parents in template " + templ) + log("Error: " + ex) + ParentTypesError(templ, ex) + List(TypeTree(AnyRefClass.tpe)) + } /**

Check that

*
    @@ -2021,8 +1891,7 @@ trait Typers extends Modes with Adaptations with Tags { // the following is necessary for templates generated later assert(clazz.info.decls != EmptyScope, clazz) enterSyms(context.outer.make(templ, clazz, clazz.info.decls), templ.body) - if (!templ.isErrorTyped) // if `parentTypes` has invalidated the template, don't validate it anymore - validateParentClasses(parents1, selfType) + validateParentClasses(parents1, selfType) if (clazz.isCase) validateNoCaseAncestor(clazz) @@ -2032,28 +1901,9 @@ trait Typers extends Modes with Adaptations with Tags { if (!phase.erasedTypes && !clazz.info.resultType.isError) // @S: prevent crash for duplicated type members checkFinitary(clazz.info.resultType.asInstanceOf[ClassInfoType]) - val body = { - 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 pos = wrappingPos(parents1.head.pos, argss.flatten) - val primaryCtor = treeInfo.firstConstructor(templ.body) - val primaryCtor1 = (deriveDefDef(primaryCtor) { - case block @ Block(earlyVals :+ Apply(superRef, Nil), unit) => - 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 body = + if (isPastTyper || reporter.hasErrors) templ.body + else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _)) val body1 = typedStats(body, templ.symbol) @@ -2843,7 +2693,7 @@ trait Typers extends Modes with Adaptations with Tags { members foreach (m => anonClass.info.decls enter m.symbol) val typedBlock = typedPos(tree.pos, mode, pt) { - Block(ClassDef(anonClass, NoMods, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) + Block(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, members, tree.pos.focus), atPos(tree.pos.focus)(New(anonClass.tpe))) } if (typedBlock.isErrorTyped) typedBlock diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 8f607e9f67..fa4bb7188c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -126,7 +126,7 @@ trait Unapplies extends ast.TreeDSL ModuleDef( Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin), cdef.name.toTermName, - Template(parents, emptyValDef, NoMods, Nil, body, cdef.impl.pos.focus)) + Template(parents, emptyValDef, NoMods, Nil, ListOfNil, body, cdef.impl.pos.focus)) } private val caseMods = Modifiers(SYNTHETIC | CASE) diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala index 0125f1b189..95135b84e0 100644 --- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala +++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala @@ -230,6 +230,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf => emptyValDef, NoMods, List(), + List(List()), List(methdef), NoPosition)) trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value)) diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 98c1afb323..2cc848d458 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -342,9 +342,6 @@ abstract class TreeInfo { def preSuperFields(stats: List[Tree]): List[ValDef] = stats collect { case vd: ValDef if isEarlyValDef(vd) => vd } - def hasUntypedPreSuperFields(stats: List[Tree]): Boolean = - preSuperFields(stats) exists (_.tpt.isEmpty) - def isEarlyDef(tree: Tree) = tree match { case TypeDef(mods, _, _, _) => mods hasFlag PRESUPER case ValDef(mods, _, _, _) => mods hasFlag PRESUPER @@ -509,10 +506,6 @@ abstract class TreeInfo { def isSynthCaseSymbol(sym: Symbol) = sym hasAllFlags SYNTH_CASE_FLAGS def hasSynthCaseSymbol(t: Tree) = t.symbol != null && isSynthCaseSymbol(t.symbol) - def isTraitRef(tree: Tree): Boolean = { - val sym = if (tree.tpe != null) tree.tpe.typeSymbol else null - ((sym ne null) && sym.initialize.isTrait) - } /** Applications in Scala can have one of the following shapes: * diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala index 693b75fbbc..5522c47cfa 100644 --- a/src/reflect/scala/reflect/internal/Trees.scala +++ b/src/reflect/scala/reflect/internal/Trees.scala @@ -1034,9 +1034,6 @@ trait Trees extends api.Trees { self: SymbolTable => def New(tpe: Type, args: Tree*): Tree = ApplyConstructor(TypeTree(tpe), args.toList) - def New(tpe: Type, argss: List[List[Tree]]): Tree = - New(TypeTree(tpe), argss) - def New(sym: Symbol, args: Tree*): Tree = New(sym.tpe, args: _*) diff --git a/test/files/neg/cyclics-import.check b/test/files/neg/cyclics-import.check index be09fca374..ef355fab0a 100644 --- a/test/files/neg/cyclics-import.check +++ b/test/files/neg/cyclics-import.check @@ -3,4 +3,13 @@ Note: this is often due in part to a class depending on a definition nested with If applicable, you may wish to try moving some members into another object. import User.UserStatus._ ^ -one error found +cyclics-import.scala:12: error: not found: type Value + type UserStatus = Value + ^ +cyclics-import.scala:14: error: not found: value Value + val Active = Value("1") + ^ +cyclics-import.scala:15: error: not found: value Value + val Disabled = Value("2") + ^ +four errors found diff --git a/test/files/neg/protected-constructors.check b/test/files/neg/protected-constructors.check index e295917050..f137158ed6 100644 --- a/test/files/neg/protected-constructors.check +++ b/test/files/neg/protected-constructors.check @@ -19,4 +19,7 @@ protected-constructors.scala:15: error: class Foo3 in object Ding cannot be acce object Ding in package dingus where target is defined class Bar3 extends Ding.Foo3("abc") ^ -four errors found +protected-constructors.scala:15: error: too many arguments for constructor Object: ()Object + class Bar3 extends Ding.Foo3("abc") + ^ +5 errors found diff --git a/test/files/neg/t2148.check b/test/files/neg/t2148.check index 27b5dce507..5113b48e51 100644 --- a/test/files/neg/t2148.check +++ b/test/files/neg/t2148.check @@ -1,4 +1,4 @@ -t2148.scala:9: error: A is not a legal prefix for a constructor +t2148.scala:9: error: type A is not a stable prefix val b = new A with A#A1 ^ one error found diff --git a/test/files/neg/t409.check b/test/files/neg/t409.check index 0edc0d03cd..433d64d25d 100644 --- a/test/files/neg/t409.check +++ b/test/files/neg/t409.check @@ -1,4 +1,4 @@ -t409.scala:6: error: class Case1 needs to be a trait to be mixed in +t409.scala:6: error: traits or objects may not have parameters class Toto extends Expr with Case1(12); - ^ + ^ one error found diff --git a/test/files/neg/t5696.check b/test/files/neg/t5696.check index e0fb61b839..72b7781fc4 100644 --- a/test/files/neg/t5696.check +++ b/test/files/neg/t5696.check @@ -15,5 +15,5 @@ t5696.scala:38: error: too many argument lists for constructor invocation ^ t5696.scala:46: error: too many argument lists for constructor invocation object x extends G(1)(2) {} - ^ + ^ 6 errors found diff --git a/test/files/neg/t667.check b/test/files/neg/t667.check index e68c6dea00..d4367bc87b 100644 --- a/test/files/neg/t667.check +++ b/test/files/neg/t667.check @@ -1,4 +1,4 @@ -t667.scala:8: error: illegal cyclic reference involving class Ni +t667.scala:8: error: class Ni inherits itself class Ni extends super.Ni with Ni; - ^ + ^ one error found diff --git a/test/files/neg/t877.check b/test/files/neg/t877.check index c3d4ab6584..5f25bd439c 100644 --- a/test/files/neg/t877.check +++ b/test/files/neg/t877.check @@ -1,7 +1,7 @@ t877.scala:3: error: Invalid literal number trait Foo extends A(22A, Bug!) {} ^ -t877.scala:3: error: ')' expected but eof found. +t877.scala:3: error: parents of traits may not have parameters trait Foo extends A(22A, Bug!) {} - ^ + ^ two errors found diff --git a/test/files/run/analyzerPlugins.check b/test/files/run/analyzerPlugins.check index 8856fef5b3..7d8d181306 100644 --- a/test/files/run/analyzerPlugins.check +++ b/test/files/run/analyzerPlugins.check @@ -22,12 +22,12 @@ pluginsPt(?, Trees$Annotated) [7] pluginsPt(?, Trees$Apply) [8] pluginsPt(?, Trees$ApplyImplicitView) [2] pluginsPt(?, Trees$Assign) [7] -pluginsPt(?, Trees$Block) [4] +pluginsPt(?, Trees$Block) [7] pluginsPt(?, Trees$ClassDef) [2] pluginsPt(?, Trees$DefDef) [14] -pluginsPt(?, Trees$Ident) [51] +pluginsPt(?, Trees$Ident) [49] pluginsPt(?, Trees$If) [2] -pluginsPt(?, Trees$Literal) [16] +pluginsPt(?, Trees$Literal) [20] pluginsPt(?, Trees$New) [5] pluginsPt(?, Trees$PackageDef) [1] pluginsPt(?, Trees$Return) [1] @@ -37,9 +37,9 @@ pluginsPt(?, Trees$This) [20] pluginsPt(?, Trees$TypeApply) [3] pluginsPt(?, Trees$TypeBoundsTree) [2] pluginsPt(?, Trees$TypeDef) [1] -pluginsPt(?, Trees$TypeTree) [38] +pluginsPt(?, Trees$TypeTree) [37] pluginsPt(?, Trees$Typed) [1] -pluginsPt(?, Trees$ValDef) [21] +pluginsPt(?, Trees$ValDef) [23] pluginsPt(Any, Trees$Literal) [2] pluginsPt(Any, Trees$Typed) [1] pluginsPt(Array[Any], Trees$ArrayValue) [1] @@ -53,7 +53,7 @@ pluginsPt(Int @testAnn, Trees$Literal) [1] pluginsPt(Int, Trees$Apply) [1] pluginsPt(Int, Trees$Ident) [2] pluginsPt(Int, Trees$If) [1] -pluginsPt(Int, Trees$Literal) [5] +pluginsPt(Int, Trees$Literal) [6] pluginsPt(Int, Trees$Select) [3] pluginsPt(List, Trees$Apply) [1] pluginsPt(List[Any], Trees$Select) [1] @@ -82,8 +82,8 @@ pluginsTypeSig(value lub1, Trees$ValDef) [2] pluginsTypeSig(value lub2, Trees$ValDef) [2] pluginsTypeSig(value param, Trees$ValDef) [2] pluginsTypeSig(value str, Trees$ValDef) [1] -pluginsTypeSig(value x, Trees$ValDef) [4] -pluginsTypeSig(value y, Trees$ValDef) [4] +pluginsTypeSig(value x, Trees$ValDef) [5] +pluginsTypeSig(value y, Trees$ValDef) [5] pluginsTypeSig(variable count, Trees$ValDef) [3] pluginsTypeSigAccessor(value annotField) [1] pluginsTypeSigAccessor(value inferField) [1] @@ -110,7 +110,7 @@ pluginsTyped(, Trees$ClassDef) [2] pluginsTyped(, Trees$DefDef) [14] pluginsTyped(, Trees$PackageDef) [1] pluginsTyped(, Trees$TypeDef) [1] -pluginsTyped(, Trees$ValDef) [21] +pluginsTyped(, Trees$ValDef) [23] pluginsTyped(, Trees$Ident) [1] pluginsTyped(=> Boolean @testAnn, Trees$Select) [1] pluginsTyped(=> Double, Trees$Select) [4] @@ -124,7 +124,7 @@ pluginsTyped(A, Trees$TypeTree) [4] pluginsTyped(A.super.type, Trees$Super) [1] pluginsTyped(A.this.type, Trees$This) [11] pluginsTyped(Any, Trees$TypeTree) [1] -pluginsTyped(AnyRef, Trees$Select) [4] +pluginsTyped(AnyRef, Trees$Select) [2] pluginsTyped(Array[Any], Trees$ArrayValue) [1] pluginsTyped(Boolean @testAnn, Trees$Select) [1] pluginsTyped(Boolean @testAnn, Trees$TypeTree) [4] @@ -137,12 +137,12 @@ pluginsTyped(Int @testAnn, Trees$TypeTree) [2] pluginsTyped(Int @testAnn, Trees$Typed) [2] pluginsTyped(Int(0), Trees$Literal) [3] pluginsTyped(Int(1) @testAnn, Trees$Typed) [1] -pluginsTyped(Int(1), Trees$Literal) [8] +pluginsTyped(Int(1), Trees$Literal) [9] pluginsTyped(Int(2), Trees$Literal) [1] pluginsTyped(Int, Trees$Apply) [1] pluginsTyped(Int, Trees$Ident) [2] pluginsTyped(Int, Trees$If) [2] -pluginsTyped(Int, Trees$Select) [15] +pluginsTyped(Int, Trees$Select) [17] pluginsTyped(Int, Trees$TypeTree) [13] pluginsTyped(List, Trees$Apply) [1] pluginsTyped(List, Trees$Select) [1] @@ -160,27 +160,26 @@ pluginsTyped(String("huhu"), Trees$Literal) [1] pluginsTyped(String("str") @testAnn, Trees$Typed) [1] pluginsTyped(String("str"), Trees$Literal) [1] pluginsTyped(String("str"), Trees$Typed) [1] -pluginsTyped(String("two"), Trees$Literal) [2] +pluginsTyped(String("two"), Trees$Literal) [3] pluginsTyped(String, Trees$Apply) [2] pluginsTyped(String, Trees$Block) [2] pluginsTyped(String, Trees$Ident) [1] pluginsTyped(String, Trees$Select) [9] -pluginsTyped(String, Trees$TypeTree) [7] +pluginsTyped(String, Trees$TypeTree) [8] pluginsTyped(Unit, Trees$Apply) [2] pluginsTyped(Unit, Trees$Assign) [8] -pluginsTyped(Unit, Trees$Block) [4] +pluginsTyped(Unit, Trees$Block) [7] pluginsTyped(Unit, Trees$If) [1] -pluginsTyped(Unit, Trees$Literal) [5] +pluginsTyped(Unit, Trees$Literal) [8] pluginsTyped(Unit, Trees$TypeTree) [1] pluginsTyped([A](xs: A*)List[A], Trees$Select) [1] pluginsTyped([T <: Int]=> Int, Trees$Select) [1] pluginsTyped([T0 >: ? <: ?]()T0, Trees$Select) [1] pluginsTyped([T](xs: Array[T])scala.collection.mutable.WrappedArray[T], Trees$Select) [1] -pluginsTyped(annotation.type, Trees$Select) [4] +pluginsTyped(annotation.type, Trees$Select) [2] pluginsTyped(math.type, Trees$Select) [9] pluginsTyped(scala.annotation.Annotation, Trees$Apply) [1] pluginsTyped(scala.annotation.TypeConstraint, Trees$Select) [4] -pluginsTyped(scala.annotation.TypeConstraint, Trees$TypeTree) [2] pluginsTyped(scala.collection.immutable.List.type, Trees$Select) [2] pluginsTyped(scala.collection.immutable.StringOps, Trees$ApplyImplicitView) [2] pluginsTyped(scala.collection.mutable.WrappedArray[Any], Trees$Apply) [1] -- cgit v1.2.3 From 1f838edb02f6e5ced6641504a96cca3ec4c1fa7a Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 5 Feb 2013 12:09:06 +0100 Subject: [nomaster] verifies compat with 2.10.0 Makes sure that the compiler understands the 2.10.0 format of super constructor calls after the recent revert from the typemacro-compatible format. --- test/files/run/t7064-old-style-supercalls.check | 1 + test/files/run/t7064-old-style-supercalls.scala | 48 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 test/files/run/t7064-old-style-supercalls.check create mode 100644 test/files/run/t7064-old-style-supercalls.scala diff --git a/test/files/run/t7064-old-style-supercalls.check b/test/files/run/t7064-old-style-supercalls.check new file mode 100644 index 0000000000..0cfbf08886 --- /dev/null +++ b/test/files/run/t7064-old-style-supercalls.check @@ -0,0 +1 @@ +2 diff --git a/test/files/run/t7064-old-style-supercalls.scala b/test/files/run/t7064-old-style-supercalls.scala new file mode 100644 index 0000000000..cffa7b1888 --- /dev/null +++ b/test/files/run/t7064-old-style-supercalls.scala @@ -0,0 +1,48 @@ +import scala.reflect.runtime.universe._ +import Flag._ +import definitions._ +import scala.reflect.runtime.{currentMirror => cm} +import scala.tools.reflect.ToolBox +import scala.tools.reflect.Eval + +object Test extends App { + val PARAMACCESSOR = (1L << 29).asInstanceOf[FlagSet] + + // these trees can be acquired by running the following incantation: + // echo 'class C(val x: Int); class D extends C(2)' > foo.scala + // ./scalac -Xprint:parser -Yshow-trees-stringified -Yshow-trees-compact foo.scala + + val c = ClassDef( + Modifiers(), newTypeName("C"), List(), + Template( + List(Select(Ident(ScalaPackage), newTypeName("AnyRef"))), + emptyValDef, + List( + ValDef(Modifiers(PARAMACCESSOR), newTermName("x"), Ident(newTypeName("Int")), EmptyTree), + DefDef( + Modifiers(), + nme.CONSTRUCTOR, + List(), + List(List(ValDef(Modifiers(PARAM | PARAMACCESSOR), newTermName("x"), Ident(newTypeName("Int")), EmptyTree))), + TypeTree(), + Block( + List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), + Literal(Constant(()))))))) + val d = ClassDef( + Modifiers(), newTypeName("D"), List(), + Template( + List(Ident(newTypeName("C"))), + emptyValDef, + List( + DefDef( + Modifiers(), + nme.CONSTRUCTOR, + List(), + List(List()), + TypeTree(), + Block( + List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List(Literal(Constant(2))))), + Literal(Constant(()))))))) + val result = Select(Apply(Select(New(Ident(newTypeName("D"))), nme.CONSTRUCTOR), List()), newTermName("x")) + println(cm.mkToolBox().eval(Block(List(c, d), result))) +} \ No newline at end of file -- cgit v1.2.3