diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 32 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/Trees.scala | 25 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 73 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Scanners.scala | 36 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Tokens.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/AddInterfaces.scala | 17 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Constructors.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 15 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 13 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 112 | ||||
-rw-r--r-- | test/files/neg/patternalts.check | 4 | ||||
-rw-r--r-- | test/files/neg/patternalts.scala | 8 | ||||
-rw-r--r-- | test/files/run/colltest.check | 2 | ||||
-rw-r--r-- | test/files/run/colltest.scala | 2 |
16 files changed, 155 insertions, 202 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 89ad2c1ac9..e47183f146 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -120,6 +120,8 @@ abstract class TreeInfo { def isSelfConstrCall(tree: Tree): boolean = tree match { case Ident(nme.CONSTRUCTOR) => true + case Select(This(_), nme.CONSTRUCTOR) => + true case TypeApply(constr, _) => isSelfConstrCall(constr) case Apply(constr, _) => @@ -148,21 +150,27 @@ abstract class TreeInfo { /** The first constructor definitions in `stats' */ def firstConstructor(stats: List[Tree]): Tree = stats match { case List() => EmptyTree - case (constr @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _)) :: _ => constr + case (constr @ DefDef(_, name, _, _, _, _)) :: _ + if (name == nme.CONSTRUCTOR || name == nme.MIXIN_CONSTRUCTOR) => constr case _ :: stats1 => firstConstructor(stats1) } -/* - /** The super call that calls mixin `mix' in stats */ - def superCall(stats: List[Tree], mix: Name): Tree = stats match { - case scall @ Apply(Select(Super(_, mix1), name), List()) :: _ - if ((name == nme.CONSTRUCTOR || name == nme.MIXIN_CONSTRUCTOR) && mix1 == mix) => - scall - case _ :: stats1 => - superCall(stats1, name) - case _ => - assert(false, "no supercall to " + mix + " in " + stats) + + /** The reference to super in the body of a primary constructor */ + def superRef(tree: Tree): Tree = tree match { + case Block(stats, _) if !stats.isEmpty => superRef(stats.last) + case Apply(sr, _) => sr + case _ => EmptyTree } -*/ + + /** The value definitions marked PRESUPER in this statement sequence */ + def preSuperFields(stats: List[Tree]) = stats filter isPreSuper + + def isPreSuper(tree: Tree) = tree match { + case ValDef(mods, _, _, _) => mods hasFlag PRESUPER + case _ => false + } + + /** Is name a left-associative operator? */ def isLeftAssoc(operator: Name): boolean = operator.length > 0 && operator(operator.length - 1) != ':'; diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index b49018b377..c94ed6c94e 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -451,15 +451,22 @@ trait Trees requires Global { if (inIDE && vd.symbol != NoSymbol) ret.symbol = vd.symbol ret - })); - if (vparamss1.isEmpty || - !vparamss1.head.isEmpty && (vparamss1.head.head.mods.flags & IMPLICIT) != 0) - vparamss1 = List() :: vparamss1; - val superRef: Tree = Select(Super(nme.EMPTY.toTypeName, nme.EMPTY.toTypeName), nme.CONSTRUCTOR) - val superCall = posAssigner.atPos(parents.head.pos) { (superRef /: argss) (Apply) } - val constr: Tree = - DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), superCall) - Template(parents, List.flatten(vparamss) ::: constr :: body) + })) + val constrs = + if (constrMods hasFlag TRAIT) { + if (body forall treeInfo.isInterfaceMember) List() + else List( + DefDef(NoMods, nme.MIXIN_CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(), Literal(())))) + } else { + if (vparamss1.isEmpty || + !vparamss1.head.isEmpty && (vparamss1.head.head.mods.flags & IMPLICIT) != 0) + vparamss1 = List() :: vparamss1; + val superRef: Tree = Select(Super(nme.EMPTY.toTypeName, nme.EMPTY.toTypeName), nme.CONSTRUCTOR) + val superCall = posAssigner.atPos(parents.head.pos) { (superRef /: argss) (Apply) } + List( + DefDef(constrMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), Block(List(superCall), Literal(())))) + } + Template(parents, List.flatten(vparamss) ::: constrs ::: body) } /** Block of expressions (semicolon separated expressions) */ diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index b38ed20e1d..061aab47a9 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1057,10 +1057,9 @@ trait Parsers requires SyntaxAnalyzer { parents += annotType(false) } newLineOptWhenFollowedBy(LBRACE) - 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)) + val (self, stats) = if (in.token == LBRACE) templateBody() + else (emptyValDef, List()) + makeNew(parents.toList, self, stats, argss.toList) } canApply = false case _ => @@ -1076,17 +1075,6 @@ 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 { @@ -1907,7 +1895,7 @@ trait Parsers requires SyntaxAnalyzer { * | ConstrBlock */ def constrExpr(vparamss: List[List[ValDef]]): Tree = - if (in.token == LBRACE) constrBlock(vparamss) else selfInvocation(vparamss) + if (in.token == LBRACE) constrBlock(vparamss) else Block(List(selfInvocation(vparamss)), Literal()) /** SelfInvocation ::= this ArgumentExprs {ArgumentExprs} */ @@ -1932,7 +1920,7 @@ trait Parsers requires SyntaxAnalyzer { val stats = if (isStatSep) { in.nextToken(); blockStatSeq(statlist) } else statlist.toList accept(RBRACE) - makeBlock(stats) + Block(stats, Literal(())) } /** TypeDef ::= Id [TypeParamClause] `=' Type @@ -1999,9 +1987,8 @@ trait Parsers requires SyntaxAnalyzer { } val constrAnnots = annotations() val (constrMods, vparamss) = - if (mods.hasFlag(Flags.TRAIT)) (NoMods, List()) - else (accessModifierOpt(), - paramClauses(name, implicitClassViews, mods.hasFlag(Flags.CASE))) + if (mods.hasFlag(Flags.TRAIT)) (Modifiers(Flags.TRAIT), List()) + else (accessModifierOpt(), paramClauses(name, implicitClassViews, mods.hasFlag(Flags.CASE))) val thistpe = requiresTypeOpt() val (self0, template) = classTemplate(mods, name, constrMods withAnnotations constrAnnots, vparamss) @@ -2072,34 +2059,21 @@ trait Parsers requires SyntaxAnalyzer { } val ps = parents.toList newLineOptWhenFollowedBy(LBRACE) - val (self, body, superpos, superargss) = + val (self, body) = if (in.token == LBRACE) templateBody() - 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) + else { acceptEmptyTemplateBody("`{' expected"); (emptyValDef, List()) } + (self, atPos(pos) { Template(ps, constrMods, vparamss, argss.toList, body) }) } ////////// TEMPLATES //////////////////////////////////////////////////////////// /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ - def templateBody(): (ValDef, List[Tree], int, List[List[Tree]]) = { + def templateBody(): (ValDef, List[Tree]) = { accept(LBRACE) - val result @ (self, stats, superpos, superargss) = templateStatSeq() + val result @ (self, stats) = templateStatSeq() accept(RBRACE) - if (stats.isEmpty) (self, List(EmptyTree), Position.NOPOS, superargss) else result + if (stats.isEmpty) (self, List(EmptyTree)) else result } /** Refinement ::= [nl] `{' RefineStat {semi RefineStat} `}' @@ -2165,11 +2139,9 @@ trait Parsers requires SyntaxAnalyzer { * | super ArgumentExprs {ArgumentExprs} * | */ - def templateStatSeq(): (ValDef, List[Tree], int, List[List[Tree]]) = { + def templateStatSeq(): (ValDef, List[Tree]) = { var self: ValDef = emptyValDef - var stats = new ListBuffer[Tree] - var superpos = Position.NOPOS - val superargss = new ListBuffer[List[Tree]] + val stats = new ListBuffer[Tree] if (isExprIntro) { val first = expr(InTemplate) if (in.token == ARROW) { @@ -2189,25 +2161,12 @@ 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() } - 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 + (self, stats.toList) } /** 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 8eb785b38e..33f0c7db71 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -37,24 +37,12 @@ trait Scanners requires SyntaxAnalyzer { /** the base of a number */ var base: int = 0 - /** further lookahead tokens after this one */ - var following: TokenData = null - - def copyFrom(td: TokenData) { + 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 } } @@ -158,44 +146,34 @@ trait Scanners requires SyntaxAnalyzer { fetchToken() } else { this copyFrom next - if (next.following != null) { - next copyFrom next.following - next.following = null - } + next.token = EMPTY } if (token == CASE) { 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 pushFrom this + next copyFrom 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 fetchToken() if (token != ELSE) { - next pushFrom this + next copyFrom this this copyFrom prev } } if (afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) && (sepRegions.isEmpty || sepRegions.head == RBRACE)) { - next pushFrom this + next copyFrom this pos = in.lineStartPos if (settings.migrate.value) newNewLine = lastToken != RBRACE && token != EOF; token = if (in.lastBlankLinePos > lastPos) NEWLINES else NEWLINE diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala index 8044744e6c..0aed4e8eae 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala @@ -69,7 +69,6 @@ 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/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index a184a1a0b7..0179580e05 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)) { @@ -244,16 +245,18 @@ abstract class AddInterfaces extends InfoTransform { else if (needsImplMethod(tree.symbol)) implMethodDef(tree, tree.symbol) else EmptyTree - /** The mixin constructor definition + /** Add mixin constructor definition * def $init$(): Unit = () + * to `stats' unless there is already one. */ - private def mixinConstructorDef(clazz: Symbol): Tree = - DefDef(clazz.primaryConstructor, vparamss => Block(List(), Literal(()))) + private def addMixinConstructorDef(clazz: Symbol, stats: List[Tree]): List[Tree] = + if (treeInfo.firstConstructor(stats) != EmptyTree) stats + else DefDef(clazz.primaryConstructor, vparamss => Block(List(), Literal(()))) :: stats 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)) + Template(templ.parents, addMixinConstructorDef(clazz, templ.body map implMemberDef)) + .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/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 606a252b24..d9355bf24e 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -91,7 +91,8 @@ abstract class Constructors extends Transform { new ChangeOwnerTraverser(oldowner, constr.symbol)(tree)) def canBeMoved(tree: Tree) = tree match { - case ValDef(_, _, _, _) => !thisRefSeen + //todo: eliminate thisRefSeen + case ValDef(mods, _, _, _) => (mods hasFlag PRESUPER | PARAMACCESSOR) || !thisRefSeen case _ => false } diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 03eccb9b39..a9f5242508 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -91,10 +91,6 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter * </p> * </li> * <li> - * Add a mixin constructor <code>$init$</code> to all mixins except interfaces - * Leave all other types unchanged. todo: move to later - * </li> - * <li> * Make all super accessors and modules in traits non-private, mangling * their names. * </li> @@ -346,9 +342,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter if (sym.isClassConstructor) { rhs match { case Literal(_) => - // replace unit rhs () by empty block {()} - val rhs1 = Block(List(), rhs) setPos rhs.pos setType rhs.tpe - transform(copy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs1)) + Predef.error("unexpected case") //todo: remove case _ => val clazz = sym.owner val vparamss1 = diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 824e20a56e..20bc433c2f 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -348,16 +348,14 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { tree match { case DefDef(mods, name, tparams, vparamss, tpt, rhs) => withNeedLift(false) { - if (tree.symbol.isConstructor) { + if (tree.symbol.isClassConstructor) { atOwner(tree.symbol) { - val rhs1 = rhs match { + val rhs1 = (rhs: @unchecked) match { case Block(stat :: stats, expr) => copy.Block( rhs, withInConstructorFlag(INCONSTRUCTOR) { transform(stat) } :: transformTrees(stats), transform(expr)); - case _ => - withInConstructorFlag(INCONSTRUCTOR) { transform(rhs) } } copy.DefDef( tree, mods, name, transformAbsTypeDefs(tparams), diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 156700d590..6943c78226 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -230,10 +230,23 @@ trait Contexts requires Analyzer { val argContext = baseContext.makeNewScope(tree, owner) argContext.reportGeneralErrors = this.reportGeneralErrors argContext.reportAmbiguousErrors = this.reportAmbiguousErrors - for (val sym <- scope.toList) argContext.scope enter sym + def enterElems(c: Context) { + def enterLocalElems(e: ScopeEntry) { + if (e != null && e.owner == c.scope) { + enterLocalElems(e.next) + argContext.scope enter e.sym + } + } + if (c.owner.isTerm && !c.owner.isLocalDummy) { + enterElems(c.outer) + enterLocalElems(c.scope.elems) + } + } + enterElems(this) argContext } + //todo: remove def makeConstructorSuffixContext = { val c = make(tree) c.inConstructorSuffix = true diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index be5d2600d9..eafe154756 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -99,7 +99,7 @@ trait Namers requires Analyzer { innerNamerCache } - def primaryConstructorParamNamer: Namer = { + def primaryConstructorParamNamer: Namer = { //todo: can we merge this with SCCmode? val classContext = context.enclClass val outerContext = classContext.outer.outer val paramContext = outerContext.makeNewScope(outerContext.tree, outerContext.owner) @@ -661,22 +661,17 @@ trait Namers requires Analyzer { checkContractive(sym, result) case vdef @ ValDef(mods, _, tpt, rhs) => + val typer1 = typer.constrTyperIf(sym.hasFlag(PARAM | PRESUPER) && sym.owner.isConstructor) if (tpt.isEmpty) { if (rhs.isEmpty) { context.error(tpt.pos, "missing parameter type"); ErrorType } else { tpt.tpe = deconstIfNotFinal(sym, - typer.valDefRhsTyper(vdef).computeType(rhs, WildcardType)) + newTyper(typer1.context.make(vdef, sym)).computeType(rhs, WildcardType)) tpt.tpe } - } else { - val typer1 = - if (sym.hasFlag(PARAM) && sym.owner.isConstructor && !phase.erasedTypes) - newTyper(context.makeConstructorContext) - else typer; - typer1.typedType(tpt).tpe - } + } else typer1.typedType(tpt).tpe case tree @ AliasTypeDef(_, _, tparams, rhs) => new Namer(makeNewScope(context, tree, sym)).aliasTypeSig(sym, tparams, rhs) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 329eb344c6..60cfcac73f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -117,10 +117,17 @@ trait Typers requires Analyzer { */ val REGPATmode = 0x1000 - private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode | CONSTmode + /** The mode <code>ALTmode</code> is set when we are under a pattern alternative */ + val ALTmode = 0x2000 + + private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode | CONSTmode | ALTmode private def funMode(mode: int) = mode & (stickyModes | SCCmode) | FUNmode | POLYmode + private def argMode(fun: Tree, mode: int) = + if (treeInfo.isSelfConstrCall(fun) || treeInfo.isSuperConstrCall(fun)) mode | SCCmode + else mode + private var xxx = 10; class Typer(context0: Context) { import context0.unit @@ -182,7 +189,7 @@ trait Typers requires Analyzer { namerCache } - private var context = context0 + private[typechecker] var context = context0 def context1 = context /** Report a type error. @@ -420,12 +427,9 @@ 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 = + def constrTyperIf(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> @@ -561,7 +565,10 @@ trait Typers requires Analyzer { context.undetparams = List() inferExprInstance(tree, tparams, pt) adapt(tree, mode, pt) - } else typed(applyImplicitArgs(tree), mode, pt) + } else { + val typer1 = constrTyperIf(treeInfo.isSelfConstrCall(tree) || treeInfo.isSuperConstrCall(tree)) + typer1.typed(typer1.applyImplicitArgs(tree), mode, pt) + } case mt: MethodType if (((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) && (context.undetparams.isEmpty || (mode & POLYmode) != 0)) => @@ -758,7 +765,7 @@ trait Typers requires Analyzer { val constr = treeInfo.firstConstructor(templ.body) if (supertpt.tpe.symbol != firstParent) { constr match { - case DefDef(_, _, _, _, _, Apply(_, superargs)) => + case DefDef(_, _, _, _, _, Block(List(Apply(_, superargs)), _)) => if (!superargs.isEmpty) error(superargs.head.pos, firstParent+" is a trait; does not take constructor arguments") case _ => @@ -770,7 +777,7 @@ trait Typers requires Analyzer { constr match { case EmptyTree => error(supertpt.pos, "missing type arguments") - case DefDef(_, _, _, vparamss, _, Apply(_, superargs)) => + case DefDef(_, _, _, vparamss, _, Block(List(Apply(_, superargs)), _)) => val outercontext = context.outer supertpt = TypeTree( newTyper(makeNewScope(outercontext, constr, outercontext.owner)) @@ -1002,9 +1009,7 @@ trait Typers requires Analyzer { def typedValDef(vdef: ValDef): ValDef = { // attributes(vdef) val sym = vdef.symbol - val typer1 = if (sym.hasFlag(PARAM) && sym.owner.isConstructor) - newTyper(context.makeConstructorContext) - else this + val typer1 = constrTyperIf(sym.hasFlag(PARAM) && sym.owner.isConstructor) var tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) checkNonCyclic(vdef, tpt1) val rhs1 = @@ -1013,7 +1018,7 @@ trait Typers requires Analyzer { error(vdef.pos, "local variables must be initialized") vdef.rhs } else { - valDefRhsTyper(vdef).transformedOrTyped(vdef.rhs, tpt1.tpe) + newTyper(typer1.context.make(vdef, sym)).transformedOrTyped(vdef.rhs, tpt1.tpe) } copy.ValDef(vdef, vdef.mods, vdef.name, tpt1, checkDead(rhs1)) setType NoType } @@ -1035,8 +1040,8 @@ trait Typers requires Analyzer { if (args2.length != formals.length) assert(false, "mismatch " + clazz + " " + formals + " " + args2);//debug (superConstr, args1 ::: args2) - case Block(stats, expr) => - decompose(stats.head) + case Block(stats, expr) if !stats.isEmpty => + decompose(stats.last) case _ => (call, List()) } @@ -1086,24 +1091,7 @@ trait Typers requires Analyzer { * @return ... */ def typedDefDef(ddef: DefDef): DefDef = { -// attributes(ddef) - val meth = ddef.symbol - - def checkPrecedes(tree: Tree): unit = tree match { - case Block(stat :: _, _) => checkPrecedes(stat) - case Apply(fun, _) => - if (fun.symbol.isConstructor && - fun.symbol.owner == meth.owner && fun.symbol.pos >= meth.pos) - error(fun.pos, "called constructor's definition must precede calling constructor's definition") - case _ => - } - def typedSuperCall(tree: Tree, pt: Type): Tree = { - val result = typed(tree, EXPRmode | SCCmode, pt) - checkPrecedes(result) - result - } - reenterTypeParams(ddef.tparams) reenterValueParams(ddef.vparamss) val tparams1 = List.mapConserve(ddef.tparams)(typedAbsTypeDef) @@ -1115,33 +1103,24 @@ trait Typers requires Analyzer { var tpt1 = checkNoEscaping.locals(context.scope, WildcardType, checkNoEscaping.privates(meth, - typedType(ddef.tpt))) + typedType(ddef.tpt))) checkNonCyclic(ddef, tpt1) ddef.tpt.setType(tpt1.tpe) var rhs1 = if (ddef.name == nme.CONSTRUCTOR) { - if (!meth.hasFlag(SYNTHETIC) && - !(meth.owner.isClass || - meth.owner.isModuleClass || - meth.owner.isAnonymousClass || - meth.owner.isRefinementClass)) - error(ddef.pos, "constructor definition not allowed here "+meth.owner)//debug - val result = ddef.rhs match { - case block @ Block(stat :: stats, expr) => - // the following makes sure not to copy the tree if no subtrees have changed - val stat1 = typedSuperCall(stat, WildcardType) - val block1 = newTyper(context.makeConstructorSuffixContext) - .typedBlock(Block(stats, expr) setPos block.pos, EXPRmode, UnitClass.tpe) - val stats1 = if ((stat eq stat1) && (stats eq block1.stats)) block.stats - else stat1 :: block1.stats - copy.Block(block, stats1, block1.expr) setType block1.tpe - case _ => - typedSuperCall(ddef.rhs, UnitClass.tpe) - } - if (meth.isPrimaryConstructor && phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) - computeParamAliases(meth.owner, vparamss1, result) - result - } else transformedOrTyped(ddef.rhs, tpt1.tpe) + if (!meth.isPrimaryConstructor && + (!meth.owner.isClass || + meth.owner.isModuleClass || + meth.owner.isAnonymousClass || + meth.owner.isRefinementClass)) + error(ddef.pos, "constructor definition not allowed here") + typed(ddef.rhs) + } else { + transformedOrTyped(ddef.rhs, tpt1.tpe) + } + if (meth.isPrimaryConstructor && meth.isClassConstructor && + phase.id <= currentRun.typerPhase.id && !reporter.hasErrors) + computeParamAliases(meth.owner, vparamss1, rhs1) if (tpt1.tpe.symbol != AllClass && !context.returnsSeen) rhs1 = checkDead(rhs1) copy.DefDef(ddef, ddef.mods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType } @@ -1359,7 +1338,12 @@ trait Typers requires Analyzer { case _ => val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this else newTyper(context.make(stat, exprOwner)) - checkDead(localTyper.typed(stat)) + val result = checkDead(localTyper.typed(stat)) + if (treeInfo.isSelfConstrCall(stat) || treeInfo.isSuperConstrCall(stat)) + context.inConstructorSuffix = true + if (treeInfo.isSelfConstrCall(result) && result.symbol.pos >= exprOwner.enclMethod.pos) + error(stat.pos, "called constructor's definition must precede calling constructor's definition") + result } } def accesses(accessor: Symbol, accessed: Symbol) = @@ -1387,7 +1371,7 @@ trait Typers requires Analyzer { } def typedArg(arg: Tree, mode: int, newmode: int, pt: Type): Tree = - checkDead(exprTyper((mode & SCCmode) != 0).typed(arg, mode & stickyModes | newmode, pt)) + checkDead(constrTyperIf((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)) @@ -1448,7 +1432,7 @@ trait Typers requires Analyzer { case OverloadedType(pre, alts) => val undetparams = context.undetparams context.undetparams = List() - val args1 = typedArgs(args, mode) + val args1 = typedArgs(args, argMode(fun, mode)) context.undetparams = undetparams inferMethodAlternative(fun, context.undetparams, args1 map (.tpe.deconst), pt) typedApply(tree, adapt(fun, funMode(mode), WildcardType), args1, mode, pt) @@ -1466,7 +1450,7 @@ trait Typers requires Analyzer { val tparams = context.undetparams context.undetparams = List() if (tparams.isEmpty) { - val args2 = typedArgs(args1, mode, formals0, formals) + val args2 = typedArgs(args1, argMode(fun, mode), formals0, formals) def ifPatternSkipFormals(tp: Type) = tp match { case MethodType(_, rtp) if ((mode & PATTERNmode) != 0) => rtp case _ => tp @@ -1516,7 +1500,7 @@ trait Typers requires Analyzer { if (targ == WildcardType) tparam.tpe else targ) def typedArgToPoly(arg: Tree, formal: Type): Tree = { val lenientPt = formal.instantiateTypeParams(tparams, lenientTargs) - val arg1 = typedArg(arg, mode, POLYmode, lenientPt) + val arg1 = typedArg(arg, argMode(fun, mode), POLYmode, lenientPt) val argtparams = context.undetparams context.undetparams = List() if (!argtparams.isEmpty) { @@ -1710,7 +1694,7 @@ trait Typers requires Analyzer { * @param args ... * @return ... */ - def tryTypedArgs(args: List[Tree], other : TypeError) : List[Tree] = { + def tryTypedArgs(args: List[Tree], mode: int, other : TypeError) : List[Tree] = { val c = context.makeSilent(false) c.retyping = true try { @@ -1747,7 +1731,7 @@ trait Typers requires Analyzer { } if (errorInResult(fun) || (args exists errorInResult)) { val Select(qual, name) = fun - val args1 = tryTypedArgs(args, ex) + val args1 = tryTypedArgs(args, argMode(fun, mode), ex) val qual1 = if ((args1 ne null) && !pt.isError) { def templateArgType(arg: Tree) = @@ -2092,7 +2076,7 @@ trait Typers requires Analyzer { copy.Sequence(tree, elems1) setType pt case Alternative(alts) => - val alts1 = List.mapConserve(alts)(alt => typed(alt, mode, pt)) + val alts1 = List.mapConserve(alts)(alt => typed(alt, mode | ALTmode, pt)) copy.Alternative(tree, alts1) setType pt case Star(elem) => @@ -2125,6 +2109,8 @@ trait Typers requires Analyzer { "use backquotes `"+vble.name+"` if you mean to match against that value;\n" + "or rename the variable or use an explicit bind "+vble.name+"@_ to avoid this warning.") */ + if ((mode & ALTmode) != 0) + error(tree.pos, "illegal variable in pattern alternative") namer.enterInScope(vble) } val body1 = typed(body, mode, pt) diff --git a/test/files/neg/patternalts.check b/test/files/neg/patternalts.check new file mode 100644 index 0000000000..9bec9a001a --- /dev/null +++ b/test/files/neg/patternalts.check @@ -0,0 +1,4 @@ +patternalts.scala:3: error: illegal variable in pattern alternative + case List(x) | List() => Console.println(x) + ^ +one error found diff --git a/test/files/neg/patternalts.scala b/test/files/neg/patternalts.scala new file mode 100644 index 0000000000..091b6e51ad --- /dev/null +++ b/test/files/neg/patternalts.scala @@ -0,0 +1,8 @@ +object Test { + List(1) match { + case List(x) | List() => Console.println(x) + } + List(2) match { + case List(_: int) | List() => Console.println() + } +} diff --git a/test/files/run/colltest.check b/test/files/run/colltest.check index 868cc81ece..be930f06ce 100644 --- a/test/files/run/colltest.check +++ b/test/files/run/colltest.check @@ -1 +1 @@ -succeeded for 1000000 iterations. +succeeded for 10 iterations. diff --git a/test/files/run/colltest.scala b/test/files/run/colltest.scala index 024f2fb1f4..049c075fa1 100644 --- a/test/files/run/colltest.scala +++ b/test/files/run/colltest.scala @@ -1,6 +1,6 @@ import collection.mutable._ class TestSet(s0: Set[int], s1: Set[int]) { - val Iterations = 1000000 + val Iterations = 10 val Range = 100000 val testEachStep = false val Threshold = 20000 |