diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-02-07 14:18:37 -0800 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2013-02-07 14:18:37 -0800 |
commit | 33608ffb282e3b844b28143d9f3588e57c20c7aa (patch) | |
tree | deff36c8e4253461a56d86d1ca5f93a02c657f40 /src | |
parent | db02585dafdc509de289177826df2eed8eb38326 (diff) | |
parent | 1f838edb02f6e5ced6641504a96cca3ec4c1fa7a (diff) | |
download | scala-33608ffb282e3b844b28143d9f3588e57c20c7aa.tar.gz scala-33608ffb282e3b844b28143d9f3588e57c20c7aa.tar.bz2 scala-33608ffb282e3b844b28143d9f3588e57c20c7aa.zip |
Merge pull request #2068 from scalamacros/ticket/7064
[nomaster] SI-7064 Reflection: forward compat for 2.10.1
Diffstat (limited to 'src')
27 files changed, 225 insertions, 425 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 49569f5e05..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.canHaveAttrs) () + 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/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/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index def1198dae..2ad762fd55 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.<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 } @@ -89,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 <init> as synthetic trees. @@ -124,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 = 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 = (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()))))) } } @@ -151,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)), @@ -164,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 -------------------------------------------------- @@ -337,8 +324,6 @@ trait Trees extends scala.reflect.internal.Trees { self: Global => else super.transform { tree match { - case tree if !tree.canHaveAttrs => - tree case tpt: TypeTree => if (tpt.original != null) transform(tpt.original) @@ -352,6 +337,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/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index c508e14343..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 @@ -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 ------------------------------------------- */ @@ -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,12 +2762,12 @@ 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! 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)) @@ -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 ac8ab493e0..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 <new parents { stats } * @param npos the position of the new * @param cpos the position of the anonymous class starting with parents */ - def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree], + def makeNew(parents: List[Tree], self: ValDef, stats: List[Tree], argss: List[List[Tree]], npos: Position, cpos: Position): Tree = if (parents.isEmpty) - makeNew(List(scalaAnyRefConstr), self, stats, npos, cpos) - else if (parents.tail.isEmpty && stats.isEmpty) { - // `Parsers.template` no longer differentiates tpts and their argss - // e.g. `C()` will be represented as a single tree Apply(Ident(C), Nil) - // instead of parents = Ident(C), argss = Nil as before - // this change works great for things that are actually templates - // but in this degenerate case we need to perform postprocessing - val app = treeInfo.dissectApplied(parents.head) - atPos(npos union cpos) { New(app.callee, app.argss) } - } else { + makeNew(List(scalaAnyRefConstr), self, stats, argss, npos, cpos) + else if (parents.tail.isEmpty && stats.isEmpty) + atPos(npos union cpos) { New(parents.head, argss) } + else { val x = tpnme.ANON_CLASS_NAME atPos(npos union cpos) { Block( @@ -232,12 +226,12 @@ abstract class TreeBuilder { atPos(cpos) { ClassDef( Modifiers(FINAL), x, Nil, - Template(parents, self, NoMods, ListOfNil, stats, cpos.focus)) + Template(parents, self, NoMods, ListOfNil, argss, stats, cpos.focus)) }), atPos(npos) { New( Ident(x) setPos npos.focus, - Nil) + ListOfNil) } ) } 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/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) diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index ec0797acb5..4891ef2fd1 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -511,6 +511,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { sym = closureClass, constrMods = Modifiers(0), vparamss = List(List(outerFieldDef)), + argss = ListOfNil, body = List(applyMethodDef), superPos = impl.pos) } diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 965063a724..e9f403aea0 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -277,7 +277,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( - List(ClassDef(anonClass, NoMods, ListOfNil, List(applyMethodDef), fun.pos)), + List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyMethodDef), fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } @@ -403,7 +403,7 @@ abstract class UnCurry extends InfoTransform localTyper.typedPos(fun.pos) { Block( - List(ClassDef(anonClass, NoMods, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)), + List(ClassDef(anonClass, NoMods, ListOfNil, ListOfNil, List(applyOrElseMethodDef, isDefinedAtMethodDef), fun.pos)), Typed(New(anonClass.tpe), TypeTree(fun.tpe))) } } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index fbf23968f0..4bf7f78167 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -184,18 +184,14 @@ trait ContextErrors { } def ParentTypesError(templ: Template, ex: TypeError) = { - templ.tpe = null - issueNormalTypeError(templ, ex.getMessage()) - setError(templ) + templ.tpe = null + issueNormalTypeError(templ, ex.getMessage()) } // additional parentTypes errors - def ConstrArgsInParentWhichIsTraitError(arg: Tree, parent: Symbol) = + def ConstrArgsInTraitParentTpeError(arg: Tree, parent: Symbol) = issueNormalTypeError(arg, parent + " is a trait; does not take constructor arguments") - def ConstrArgsInParentOfTraitError(arg: Tree, parent: Symbol) = - issueNormalTypeError(arg, "parents of traits may not have parameters") - def MissingTypeArgumentsParentTpeError(supertpt: Tree) = issueNormalTypeError(supertpt, "missing type arguments") @@ -1048,6 +1044,9 @@ trait ContextErrors { def MaxParametersCaseClassError(tree: Tree) = issueNormalTypeError(tree, "Implementation restriction: case classes cannot have more than " + definitions.MaxFunctionArity + " parameters.") + def InheritsItselfError(tree: Tree) = + issueNormalTypeError(tree, tree.tpe.typeSymbol+" inherits itself") + def MissingParameterOrValTypeError(vparam: Tree) = issueNormalTypeError(vparam, "missing parameter type") diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index c728185d4e..ab338447c9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -857,8 +857,13 @@ trait Namers extends MethodSynthesis { private def templateSig(templ: Template): Type = { val clazz = context.owner def checkParent(tpt: Tree): Type = { - if (tpt.tpe.isError) AnyRefClass.tpe - else tpt.tpe + val tp = tpt.tpe + val inheritsSelf = tp.typeSymbol == owner + if (inheritsSelf) + InheritsItselfError(tpt) + + if (inheritsSelf || tp.isError) AnyRefClass.tpe + else tp } val parents = typer.parentTypes(templ) map checkParent diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 20db479463..64c5b41638 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -4,31 +4,7 @@ package typechecker trait StdAttachments { self: Analyzer => - 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 SuperArgsAttachment(argss: List[List[Tree]]) - - /** Convenience method for `SuperArgsAttachment`. - * 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 } - - /** Determines whether the given tree has an associated SuperArgsAttachment. - */ - def hasSuperArgs(tree: Tree): Boolean = superArgs(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..f518712701 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.canHaveAttrs) { - tree.tpe = null - if (tree.hasSymbol) tree.symbol = NoSymbol - } + if (tree != EmptyTree) tree.tpe = null + if (tree.hasSymbol) tree.symbol = NoSymbol super.traverse(tree) } } @@ -1401,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)) { @@ -1502,243 +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 SuperArgsAttachment. - * 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) - * <the same three calls> - */ - 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) { - 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 SuperArgsAttachment(argss) - } - } - - /** 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. - * - * ***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) - * global.pendingSuperCall, - * 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`. - */ - private def typedPrimaryConstrBody(templ: Template)(actualSuperCall: => 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 global.pendingSuperCall => actualSuperCall - 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)(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)) + } /** <p>Check that</p> * <ul> @@ -2003,12 +1891,9 @@ 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) - 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") @@ -2016,21 +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, _)) - val primaryCtor = treeInfo.firstConstructor(body) - val primaryCtor1 = primaryCtor match { - case DefDef(_, _, _, _, _, Block(earlyVals :+ global.pendingSuperCall, unit)) => - val argss = superArgs(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 body = + if (isPastTyper || reporter.hasErrors) templ.body + else templ.body flatMap rewrappingWrapperTrees(namer.addDerivedTrees(Typer.this, _)) val body1 = typedStats(body, templ.symbol) @@ -2820,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 577aa087ea..69074e4c0c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -127,7 +127,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/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/api/Trees.scala b/src/reflect/scala/reflect/api/Trees.scala index cfa6315797..0937a93738 100644 --- a/src/reflect/scala/reflect/api/Trees.scala +++ b/src/reflect/scala/reflect/api/Trees.scala @@ -75,26 +75,11 @@ 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. - * - * @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 @@ -2420,15 +2405,6 @@ 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. @@ -2931,8 +2907,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/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) 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 f8c670827a..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.canHaveAttrs) () + 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 a8085a4c58..80d247c0ea 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) "<null>" else tree.tpe.toString, "}") } } @@ -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/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 a528a9ced8..5522c47cfa 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 canHaveAttrs = true /** 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 <empty>") + 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,23 +961,12 @@ trait Trees extends api.Trees { self: SymbolTable => def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree) - trait CannotHaveAttrs extends Tree { - override def canHaveAttrs = false - - private def unsupported(what: String, args: Any*) = - throw new UnsupportedOperationException(s"$what($args) inapplicable for "+self.toString) - + object emptyValDef extends ValDef(Modifiers(PRIVATE), nme.WILDCARD, TypeTree(NoType), EmptyTree) { + override def isEmpty = true 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 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 - def DefDef(sym: Symbol, mods: Modifiers, vparamss: List[List[ValDef]], rhs: Tree): DefDef = atPos(sym.pos) { assert(sym != NoSymbol) @@ -1039,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: _*) @@ -1122,7 +1114,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) 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) |