diff options
Diffstat (limited to 'src')
10 files changed, 135 insertions, 74 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index a2da40d399..e516fa86a3 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -17,7 +17,7 @@ trait Trees requires Global { //statistics var nodeCount = 0 - case class Modifiers(flags: int, privateWithin: Name, annotations: List[Annotation]) { + case class Modifiers(flags: long, privateWithin: Name, annotations: List[Annotation]) { def isCovariant = hasFlag(COVARIANT ) def isContravariant = hasFlag(CONTRAVARIANT) def isPrivate = hasFlag(PRIVATE ) @@ -34,18 +34,18 @@ trait Trees requires Global { def isTrait = hasFlag(TRAIT ) def isImplicit = hasFlag(IMPLICIT ) def isPublic = !isPrivate && !isProtected - def hasFlag(flag: int) = (flag & flags) != 0 - def & (flag: Int): Modifiers = { + def hasFlag(flag: long) = (flag & flags) != 0 + def & (flag: long): Modifiers = { val flags1 = flags & flag if (flags1 == flags) this else Modifiers(flags1, privateWithin, annotations) } - def &~ (flag: Int): Modifiers = { + def &~ (flag: long): Modifiers = { val flags1 = flags & (~flag) if (flags1 == flags) this else Modifiers(flags1, privateWithin, annotations) } - def | (flag: int): Modifiers = { + def | (flag: long): Modifiers = { val flags1 = flags | flag if (flags1 == flags) this else Modifiers(flags1, privateWithin, annotations) @@ -55,9 +55,8 @@ trait Trees requires Global { else Modifiers(flags, privateWithin, annotations ::: annots) } - def Modifiers(flags: int, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List()) - def Modifiers(flags: int): Modifiers = Modifiers(flags, nme.EMPTY.toTypeName) - def Modifiers(flags: long): Modifiers = Modifiers(flags.asInstanceOf[int]) + def Modifiers(flags: long, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List()) + def Modifiers(flags: long): Modifiers = Modifiers(flags, nme.EMPTY.toTypeName) val NoMods = Modifiers(0) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 0517e50624..863d489667 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1057,9 +1057,10 @@ trait Parsers requires SyntaxAnalyzer { parents += annotType(false) } newLineOptWhenFollowedBy(LBRACE) - val (self, stats) = if (in.token == LBRACE) templateBody() - else (emptyValDef, List()) - makeNew(parents.toList, self, stats, argss.toList) + val (self, stats, superpos, superargss) = + if (in.token == LBRACE) templateBody() + else (emptyValDef, List(), Position.NOPOS, List(List())) + makeNew(parents.toList, self, stats, superArgs(superpos, argss.toList, superargss)) } canApply = false case _ => @@ -1075,6 +1076,17 @@ trait Parsers requires SyntaxAnalyzer { simpleExprRest(t, canApply) } + private def isEmpty(argss: List[List[Tree]]) = argss.head.isEmpty && argss.tail.isEmpty + + private def superArgs(pos: int, extargss: List[List[Tree]], superargss: List[List[Tree]]) = { + var argss = extargss + if (isEmpty(argss)) + argss = superargss + else if (!isEmpty(superargss)) + syntaxError(pos, "super call arguments are specified twice; once here and once in a subsequent super call", false) + argss + } + def simpleExprRest(t: Tree, canApply: boolean): Tree = { if (canApply) newLineOptWhenFollowedBy(LBRACE) in.token match { @@ -1150,10 +1162,19 @@ trait Parsers requires SyntaxAnalyzer { * | Expr */ def enumerators(): List[Enumerator] = { + val newStyle = in.token != VAL val enums = new ListBuffer[Enumerator] + generator(false) while (isStatSep) { in.nextToken() - enums += (if (in.token == VAL) generator(true) else Filter(expr())) + enums += { + if (newStyle) { + if (in.token == IF) { in.nextToken(); Filter(expr()) } + else generator(true) + } else { + if (in.token == VAL) generator(true) + else Filter(expr()) + } + } } enums.toList } @@ -2040,25 +2061,34 @@ trait Parsers requires SyntaxAnalyzer { } val ps = parents.toList newLineOptWhenFollowedBy(LBRACE) - val (self, body) = + val (self, body, superpos, superargss) = if (in.token == LBRACE) templateBody() - else { acceptEmptyTemplateBody("`{' expected"); (emptyValDef, List()) } - (self, - atPos(pos) { - if (!mods.hasFlag(Flags.TRAIT)) Template(ps, constrMods, vparamss, argss.toList, body) - else Template(ps, body) - }) + else { + acceptEmptyTemplateBody("`{' expected") + (emptyValDef, List(), Position.NOPOS, List(List())) + } + val argumentss = superArgs(pos, argss.toList, superargss) + val impl = atPos(pos) { + if (mods.hasFlag(Flags.TRAIT)) { + if (!isEmpty(argumentss)) + syntaxError(superpos, "traits cannot have supercall arguments", false) + Template(ps, body) + } else { + Template(ps, constrMods, vparamss, argumentss, body) + } + } + (self, impl) } ////////// TEMPLATES //////////////////////////////////////////////////////////// /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ - def templateBody(): (ValDef, List[Tree]) = { + def templateBody(): (ValDef, List[Tree], int, List[List[Tree]]) = { accept(LBRACE) - val result @ (self, stats) = templateStatSeq() + val result @ (self, stats, superpos, superargss) = templateStatSeq() accept(RBRACE) - if (stats.isEmpty) (self, List(EmptyTree)) else result + if (stats.isEmpty) (self, List(EmptyTree), Position.NOPOS, superargss) else result } /** Refinement ::= [nl] `{' RefineStat {semi RefineStat} `}' @@ -2124,9 +2154,11 @@ trait Parsers requires SyntaxAnalyzer { * | super ArgumentExprs {ArgumentExprs} * | */ - def templateStatSeq(): (ValDef, List[Tree]) = { + def templateStatSeq(): (ValDef, List[Tree], int, List[List[Tree]]) = { var self: ValDef = emptyValDef - val stats = new ListBuffer[Tree] + var stats = new ListBuffer[Tree] + var superpos = Position.NOPOS + val superargss = new ListBuffer[List[Tree]] if (isExprIntro) { val first = expr(InTemplate) if (in.token == ARROW) { @@ -2146,12 +2178,25 @@ trait Parsers requires SyntaxAnalyzer { } else if (isDefIntro || isModifier || in.token == LBRACKET /*todo: remove */ || in.token == AT) { val annots = annotations() stats ++ joinComment(defOrDcl(modifiers() withAnnotations annots)) + } else if (in.token == SUPERCALL) { + superpos = in.skipToken() + stats = new ListBuffer[Tree] ++ (stats.toList map markPreSuper) + while (in.token == LPAREN) { superargss += argumentExprs() } } else if (!isStatSep) { syntaxErrorOrIncomplete("illegal start of definition", true) } if (in.token != RBRACE && in.token != EOF) acceptStatSep() } - (self, stats.toList) + if (!superargss.hasNext) superargss += List() + (self, stats.toList, superpos, superargss.toList) + } + + private def markPreSuper(stat: Tree): Tree = stat match { + case ValDef(mods, name, tpt, rhs) => + copy.ValDef(stat, mods | Flags.PRESUPER, name, tpt, rhs) + case _ => + syntaxError(stat.pos, "only value definitions may precede super call", false) + stat } /** RefineStatSeq ::= RefineStat {semi RefineStat} diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 080c83f49c..8eb785b38e 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -37,12 +37,24 @@ trait Scanners requires SyntaxAnalyzer { /** the base of a number */ var base: int = 0 - def copyFrom(td: TokenData) = { + /** further lookahead tokens after this one */ + var following: TokenData = null + + def copyFrom(td: TokenData) { this.token = td.token this.pos = td.pos this.lastPos = td.lastPos this.name = td.name this.base = td.base + td.token = EMPTY + } + + def pushFrom(td: TokenData) { + if (token != EMPTY) { + following = new TokenData + following copyFrom this + } + this copyFrom td } } @@ -145,42 +157,45 @@ trait Scanners requires SyntaxAnalyzer { if (next.token == EMPTY) { fetchToken() } else { - this.copyFrom(next) - next.token = EMPTY + this copyFrom next + if (next.following != null) { + next copyFrom next.following + next.following = null + } } if (token == CASE) { - prev.copyFrom(this) + prev copyFrom this fetchToken() if (token == CLASS) { + this copyFrom prev token = CASECLASS - lastPos = prev.lastPos } else if (token == OBJECT) { + this copyFrom prev token = CASEOBJECT - lastPos = prev.lastPos } else { - next.copyFrom(this) - this.copyFrom(prev) + next pushFrom this + this copyFrom prev } + } else if (token == SUPER && next.token == EMPTY) { + prev copyFrom this + fetchToken() + val isSuperCall = token == LPAREN + next pushFrom this + this copyFrom prev + if (isSuperCall) token = SUPERCALL } else if (token == SEMI) { - prev.copyFrom(this) + prev copyFrom this fetchToken() if (token != ELSE) { - next.copyFrom(this) - this.copyFrom(prev) + next pushFrom this + this copyFrom prev } - } else if (token == IDENTIFIER && name == nme.MIXINkw) { //todo: remove eventually - prev.copyFrom(this) - fetchToken() - if (token == CLASS) - unit.warning(prev.pos, "`mixin' is no longer a reserved word; you should use `trait' instead of `mixin class'"); - next.copyFrom(this) - this.copyFrom(prev) } if (afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) && (sepRegions.isEmpty || sepRegions.head == RBRACE)) { - next.copyFrom(this) + next pushFrom this pos = in.lineStartPos if (settings.migrate.value) newNewLine = lastToken != RBRACE && token != EOF; token = if (in.lastBlankLinePos > lastPos) NEWLINES else NEWLINE @@ -273,7 +288,7 @@ trait Scanners requires SyntaxAnalyzer { return case '`' => in.next - getStringLit('`', IDENTIFIER) + getStringLit('`', BACKQUOTED_IDENT) return case '\"' => in.next @@ -569,7 +584,6 @@ trait Scanners requires SyntaxAnalyzer { } private def getStringLit(delimiter: char, litType: int): unit = { - assert((litType==STRINGLIT) || (litType==IDENTIFIER)) while (in.ch != delimiter && (in.isUnicode || in.ch != CR && in.ch != LF && in.ch != SU)) { getlitch() } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 0aed4e8eae..8044744e6c 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -69,6 +69,7 @@ object Tokens { final val RETURN = 57 final val MATCH = 58 final val REQUIRES = 59 + final val SUPERCALL = 60 /** special symbols */ final val COMMA = 61 diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index 16b64b9aef..2566e687b0 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -67,6 +67,7 @@ object Flags { final val EXPANDEDNAME = 0x1000000000L // name has been expanded with class suffix final val IMPLCLASS = 0x2000000000L // symbol is an implementation class + final val PRESUPER = 0x2000000000L // value is evaluated before super call final val TRANS_FLAG = 0x4000000000L // transient flag guaranteed to be reset // after each phase. @@ -156,7 +157,7 @@ object Flags { else if (flag == LIFTED ) "<lifted>" else if (flag == MIXEDIN ) "<mixedin>" else if (flag == EXPANDEDNAME) "<expandedname>" - else if (flag == IMPLCLASS ) "<implclass>" + else if (flag == IMPLCLASS ) "<implclass/presuper>" else if (flag == TRANS_FLAG ) "<trans-flag>" else if (flag == LOCKED ) "<locked>" else flag.asInstanceOf[int] match { diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index b1235c9c94..3de9399779 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -129,8 +129,9 @@ abstract class AddInterfaces extends InfoTransform { */ private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = { val decls = newScope - decls enter (implClass.newMethod(implClass.pos, nme.MIXIN_CONSTRUCTOR) - setInfo MethodType(List(), UnitClass.tpe)) + if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol) + decls enter (implClass.newMethod(implClass.pos, nme.MIXIN_CONSTRUCTOR) + setInfo MethodType(List(), UnitClass.tpe)) for (val sym <- ifaceDecls.elements) { if (isInterfaceMember(sym)) { if (needsImplMethod(sym)) { @@ -252,8 +253,10 @@ abstract class AddInterfaces extends InfoTransform { private def implTemplate(clazz: Symbol, templ: Template): Template = atPos(templ.pos) { val templ1 = atPos(templ.pos) { - Template(templ.parents, mixinConstructorDef(clazz) :: (templ.body map implMemberDef)) - .setSymbol(clazz.newLocalDummy(templ.pos)) + var ibody = templ.body map implMemberDef + if (!(ibody exists (stat => stat.isDef && stat.symbol.isMixinConstructor))) + ibody = mixinConstructorDef(clazz) :: ibody + Template(templ.parents, ibody) setSymbol clazz.newLocalDummy(templ.pos) } new ChangeOwnerTraverser(templ.symbol.owner, clazz)( new ChangeOwnerTraverser(templ.symbol, templ1.symbol)(templ1)) diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 705bdaaedf..03eccb9b39 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -230,14 +230,6 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter * 1a. A class which is not a trait gets an outer field. * </p> * </li> - * <li> <!-- 2 --> - * A mixin which is not also an interface gets a mixin constructor - * (@see mixinConstructorDef) - * </li> - * <li> <!-- 3 --> - * Constructor bodies are augmented by calls to supermixin constructors - * (@see addMixinConstructorCalls) - * </li> * <li> <!-- 4 --> * A constructor of a non-trait inner class gets an outer parameter. * </li> @@ -311,9 +303,6 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter */ def mixinOuterAccessorDef(mixinClass: Symbol): Tree = { val outerAcc = outerAccessor(mixinClass).overridingSymbol(currentClass) - if (outerAcc == NoSymbol) - Console.println("cc " + currentClass + ":" + currentClass.info.decls + - " at " + phase)//debug assert(outerAcc != NoSymbol) val path = if (mixinClass.owner.isTerm) gen.mkAttributedThis(mixinClass.owner.enclClass) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 407c50caf1..eece1dabd0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -228,6 +228,8 @@ trait Contexts requires Analyzer { while (baseContext.tree.isInstanceOf[Template]) baseContext = baseContext.outer val argContext = baseContext.makeNewScope(tree, owner) + argContext.reportGeneralErrors = this.reportGeneralErrors + argContext.reportAmbiguousErrors = this.reportAmbiguousErrors for (val sym <- scope.toList) argContext.scope enter sym argContext } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index f843059872..c41a30de7e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -56,7 +56,7 @@ trait Namers requires Analyzer { sym } - def updatePosFlags(sym: Symbol, pos: PositionType, flags: int): Symbol = { + def updatePosFlags(sym: Symbol, pos: PositionType, flags: long): Symbol = { if (settings.debug.value) log("overwriting " + sym) val lockedFlag = sym.flags & LOCKED sym.reset(NoType) @@ -144,7 +144,7 @@ trait Namers requires Analyzer { if (context.owner.isConstructor && !context.inConstructorSuffix) INCONSTRUCTOR else 0l - private def enterClassSymbol(pos: PositionType, flags: int, name: Name): Symbol = { + private def enterClassSymbol(pos: PositionType, flags: long, name: Name): Symbol = { var c: Symbol = context.scope.lookup(name) if (c.isType && !currentRun.compiles(c) && context.scope == c.owner.info.decls) { updatePosFlags(c, pos, flags) @@ -166,7 +166,7 @@ trait Namers requires Analyzer { c } - private def enterModuleSymbol(pos: PositionType, flags: int, name: Name): Symbol = { + private def enterModuleSymbol(pos: PositionType, flags: long, name: Name): Symbol = { var m: Symbol = context.scope.lookup(name) if (m.isModule && !m.isPackage && !currentRun.compiles(m) && (context.scope == m.owner.info.decls)) { @@ -186,7 +186,7 @@ trait Namers requires Analyzer { m } - private def enterCaseFactorySymbol(pos: PositionType, flags: int, name: Name): Symbol = { + private def enterCaseFactorySymbol(pos: PositionType, flags: long, name: Name): Symbol = { var m: Symbol = context.scope.lookup(name) if (m.isTerm && !m.isPackage && !currentRun.compiles(m) && context.scope == m.owner.info.decls) { updatePosFlags(m, pos, flags) @@ -608,13 +608,14 @@ trait Namers requires Analyzer { new Namer(makeNewScope(context, tree, sym)).methodSig(tparams, vparamss, tpt, rhs); checkContractive(sym, result) - case ValDef(_, _, tpt, rhs) => + case vdef @ ValDef(mods, _, tpt, rhs) => if (tpt.isEmpty) { if (rhs.isEmpty) { context.error(tpt.pos, "missing parameter type"); ErrorType } else { - tpt.tpe = deconstIfNotFinal(sym, newTyper(context.make(tree, sym)).computeType(rhs, WildcardType)); + tpt.tpe = deconstIfNotFinal(sym, + typer.valDefRhsTyper(vdef).computeType(rhs, WildcardType)) tpt.tpe } } else { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 084ed5df2e..b54d378eb7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -416,6 +416,15 @@ trait Typers requires Analyzer { } } + /** The typer for an expression, depending on where we are. If we are before a superclass + * call, this is a typer over a constructor context; otherwise it is the current typer. + */ + def exprTyper(inConstr: boolean): Typer = + if (inConstr) newTyper(context.makeConstructorContext) else this + + def valDefRhsTyper(vdef: ValDef): Typer = + newTyper(context.make(vdef, vdef.symbol)).exprTyper(vdef.mods hasFlag PRESUPER) + /** <p> * Post-process an identifier or selection node, performing the following: * </p> @@ -994,7 +1003,7 @@ trait Typers requires Analyzer { error(vdef.pos, "local variables must be initialized") vdef.rhs } else { - newTyper(context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt1.tpe) + valDefRhsTyper(vdef).transformedOrTyped(vdef.rhs, tpt1.tpe) } copy.ValDef(vdef, vdef.mods, vdef.name, tpt1, checkDead(rhs1)) setType NoType } @@ -1365,11 +1374,8 @@ trait Typers requires Analyzer { checkNoDoubleDefs(List.mapConserve(stats)(typedStat)) } - def typedArg(arg: Tree, mode: int, newmode: int, pt: Type): Tree = { - val argTyper = if ((mode & SCCmode) != 0) newTyper(context.makeConstructorContext) - else this - checkDead(argTyper.typed(arg, mode & stickyModes | newmode, pt)) - } + def typedArg(arg: Tree, mode: int, newmode: int, pt: Type): Tree = + checkDead(exprTyper((mode & SCCmode) != 0).typed(arg, mode & stickyModes | newmode, pt)) def typedArgs(args: List[Tree], mode: int) = List.mapConserve(args)(arg => typedArg(arg, mode, 0, WildcardType)) |