summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-02-05 11:53:43 +0100
committerEugene Burmako <xeno.by@gmail.com>2013-02-05 20:05:55 +0100
commitc9a0e36224b6eb2807bad0df2d5aa11bb05c8a32 (patch)
tree1d426346ba57ce6957403c232dacf1bf09635ff7 /src
parent570f4a46f663a8f55ce045bfde2d834bd4902f9c (diff)
downloadscala-c9a0e36224b6eb2807bad0df2d5aa11bb05c8a32.tar.gz
scala-c9a0e36224b6eb2807bad0df2d5aa11bb05c8a32.tar.bz2
scala-c9a0e36224b6eb2807bad0df2d5aa11bb05c8a32.zip
[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
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala18
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala62
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala20
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala1
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala22
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala396
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala2
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala1
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala7
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala3
13 files changed, 186 insertions, 372 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 <init> 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 <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,7 +226,7 @@ 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(
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 fa2913bee3..64c5b41638 100644
--- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -4,29 +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 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)
- * <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) { 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))
+ }
/** <p>Check that</p>
* <ul>
@@ -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: _*)