summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/build/genprod.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala166
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala8
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala4
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala14
8 files changed, 134 insertions, 70 deletions
diff --git a/src/build/genprod.scala b/src/build/genprod.scala
index ad38418e1b..70be325230 100644
--- a/src/build/genprod.scala
+++ b/src/build/genprod.scala
@@ -238,7 +238,7 @@ package scala
case class {tupleClassname(i)}{__typeArgs__}({ __fields__ }) {{
override def productPrefix = ""
-
+ override def toString() = scala.runtime.ScalaRunTime.caseFields.mkString("{", ", ", "}")
}}
</file>
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
index 3db2bd7673..4e1d73b53f 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
@@ -575,7 +575,7 @@ class MarkupParser(unit: CompilationUnit, s: Scanner, p: Parser, presWS: boolean
*/
def xScalaPatterns: List[Tree] = {
sync;
- val b = p.patterns();
+ val b = p.patterns(true);
if (/*s.*/token != RBRACE) {
reportSyntaxError(" expected end of Scala patterns");
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index f47ced301d..9fd03dedc0 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -300,6 +300,10 @@ trait Parsers requires SyntaxAnalyzer {
}
}
+ def checkSize(kind: String, size: int, max: int) {
+ if (size > max) syntaxError("too many "+kind+", maximum = "+max, false)
+ }
+
def checkAssoc(pos: int, op: Name, leftAssoc: boolean) =
if (treeInfo.isLeftAssoc(op) != leftAssoc)
syntaxError(
@@ -549,9 +553,10 @@ trait Parsers requires SyntaxAnalyzer {
val t0 = typ()
if (in.token == COMMA) {
in.nextToken()
- val ts = new ListBuffer[Tree] + t0 ++ types()
+ val ts = t0 :: types()
accept(RPAREN)
- atPos (accept(ARROW)) { makeFunctionTypeTree(ts.toList, typ()) }
+ checkSize("function arguments", ts.length, definitions.MaxFunctionArity)
+ atPos (accept(ARROW)) { makeFunctionTypeTree(ts, typ()) }
} else {
accept(RPAREN)
infixTypeRest(pos, t0, false, FirstOp)
@@ -574,7 +579,7 @@ trait Parsers requires SyntaxAnalyzer {
def infixTypeRest(pos: int, t0: Tree, isPattern: boolean, mode: int): Tree = {
val t = compoundTypeRest(pos, t0, isPattern)
if (isIdent && in.name != nme.STAR) {
- val opPos = in.pos
+ val opPos = in.currentPos
val leftAssoc = treeInfo.isLeftAssoc(in.name)
if (mode == LeftOp) checkAssoc(opPos, in.name, true)
else if (mode == RightOp) checkAssoc(opPos, in.name, false)
@@ -582,7 +587,7 @@ trait Parsers requires SyntaxAnalyzer {
newLineOptWhenFollowing(isTypeIntroToken)
def mkOp(t1: Tree) = atPos(opPos) { AppliedTypeTree(Ident(op.toTypeName), List(t, t1)) }
if (leftAssoc)
- infixTypeRest(in.pos, mkOp(compoundType(isPattern)), isPattern, LeftOp)
+ infixTypeRest(in.currentPos, mkOp(compoundType(isPattern)), isPattern, LeftOp)
else
mkOp(infixType(isPattern, RightOp))
} else t
@@ -610,11 +615,13 @@ trait Parsers requires SyntaxAnalyzer {
* | StableId
* | Path `.' type
* | `(' Type `)'
+ * | `{' [Type `,' Types] `}'
* | AttributeClauses SimpleType // if Xplugtypes enabled
- * SimpleTypePattern ::= SimpleTypePattern TypePatternArgs
+ * SimpleTypePattern ::= SimpleTypePattern1 [TypePatternArgs]
* SimpleTypePattern1 ::= SimpleTypePattern1 "#" Id
* | StableId
* | Path `.' type
+ * | `{' [ArgTypePattern `,' ArgTypePatterns] `}'
*/
def simpleType(isPattern: boolean): Tree = {
if(settings.Xplugtypes.value)
@@ -627,6 +634,17 @@ trait Parsers requires SyntaxAnalyzer {
val t = typ()
accept(RPAREN)
t
+ } else if (in.token == LBRACE) {
+ in.nextToken()
+ val ts = if (in.token == RBRACE) List()
+ else {
+ val t1 = argType(isPattern)
+ accept(COMMA)
+ t1 :: argTypes(isPattern)
+ }
+ checkSize("tuple elements", ts.length, definitions.MaxTupleArity)
+ accept(RBRACE)
+ makeTupleType(ts)
} else {
val r = path(false, true)
val x = r match {
@@ -637,38 +655,47 @@ trait Parsers requires SyntaxAnalyzer {
x
}
while (true) {
- if (in.token == HASH)
+ if (in.token == HASH) {
t = atPos(in.skipToken()) {
SelectFromTypeTree(t, ident().toTypeName)
}
- else if (in.token == LBRACKET)
+ } else if (in.token == LBRACKET) {
t = atPos(pos) { AppliedTypeTree(t, typeArgs(isPattern)) }
- else
+ if (isPattern) return t
+ } else
return t
}
null; //dummy
}
- /** TypeArgs ::= `[' TypeArg {`,' TypeArg} `]'
- * TypePatternArgs ::= '[' TypePatternArg {`,' TypePatternArg} `]'
+ /** TypeArgs ::= `[' ArgTypes `]'
+ * TypePatternArgs ::= '[' ArgTypePatterns `]'
*/
def typeArgs(isPattern: boolean): List[Tree] = {
accept(LBRACKET)
- val ts = new ListBuffer[Tree] + typeArg(isPattern)
+ val ts = argTypes(isPattern)
+ accept(RBRACKET)
+ ts
+ }
+
+ /** ArgTypes ::= ArgType {`,' ArgType}
+ * ArgTypePatterns ::= ArgTypePattern {`,' ArgTypePattern}
+ */
+ def argTypes(isPattern: boolean): List[Tree] = {
+ val ts = new ListBuffer[Tree] + argType(isPattern)
while (in.token == COMMA) {
in.nextToken()
- ts += typeArg(isPattern)
+ ts += argType(isPattern)
}
- accept(RBRACKET)
ts.toList
}
- /** TypeArg ::= Type
- * TypePatternArg ::= varid
+ /** ArgType ::= Type
+ * ArgTypePattern ::= varid
* | `_'
* | Type // for array elements only!
*/
- def typeArg(isPattern: boolean): Tree =
+ def argType(isPattern: boolean): Tree =
if (isPattern) {
if (in.token == USCORE)
atPos(in.skipToken()) { Bind(nme.WILDCARD.toTypeName, EmptyTree) }
@@ -736,6 +763,7 @@ trait Parsers requires SyntaxAnalyzer {
final val IsArgument = 1
final val IsInBlock = 2
+ final val ClosureOK = 4
/** Expr ::= (Bindings | Id) `=>' Expr
* | Expr1
@@ -758,20 +786,22 @@ trait Parsers requires SyntaxAnalyzer {
* Binding ::= Id [`:' Type]
*/
def expr(): Tree =
- liftingScope(exprImpl(0))
+ liftingScope(exprImpl(ClosureOK))
def blockStatExpr(): Tree = {
- liftingScope(exprImpl(IsInBlock))
+ liftingScope(exprImpl(IsInBlock | ClosureOK))
}
def argExpr(): Tree = {
- exprImpl(IsArgument)
+ exprImpl(IsArgument | ClosureOK)
}
def localExpr(): Tree = {
- exprImpl(0)
+ exprImpl(ClosureOK)
}
+ def expr1(): Tree = exprImpl(0)
+
private def exprImpl(mode: int): Tree = in.token match {
case IF =>
val pos = in.skipToken()
@@ -846,7 +876,7 @@ trait Parsers requires SyntaxAnalyzer {
liftingScope(makeClosure(simpleExpr()))
// Note: makeClosure does some special treatment of liftedGenerators
} else {
- syntaxError("identifier expected", true);
+ syntaxError("identifier expected", true)
errorTermTree
}
}
@@ -873,18 +903,10 @@ trait Parsers requires SyntaxAnalyzer {
syntaxError(in.currentPos, "`*' expected", true)
}
} else {
- t = atPos(pos) { Typed(t, if ((mode & IsInBlock) != 0) compoundType(false) else typ()) }
- if ((mode & IsInBlock) != 0 && in.token == COMMA) {
- val vdefs = new ListBuffer[ValDef]
- while (in.token == COMMA) {
- in.nextToken()
- vdefs += ValDef(Modifiers(Flags.PARAM), ident(), typedOpt(), EmptyTree)
- }
- if (in.token == ARROW) {
- t = atPos(in.skipToken()) {
- Function(convertToParams(t) ::: vdefs.toList, block())
- }
- } else syntaxError(in.currentPos, "`=>' expected", true)
+ t = atPos(pos) {
+ Typed(t, if ((mode & IsInBlock) != 0) compoundType(false) else typ())
+ // this does not correspond to syntax, but is necessary to
+ // accept closures. We should restrict closures to be between {...} only!
}
}
} else if (in.token == MATCH) {
@@ -895,7 +917,7 @@ trait Parsers requires SyntaxAnalyzer {
Match(t, cases): Tree
}
}
- if (in.token == ARROW) {
+ if ((mode & ClosureOK) != 0 && in.token == ARROW) {
t = atPos(in.skipToken()) {
Function(convertToParams(t), if ((mode & IsInBlock) != 0) block() else expr())
}
@@ -1064,20 +1086,23 @@ trait Parsers requires SyntaxAnalyzer {
}
}
- /** BlockExpr ::= `{' CaseClauses | Block `}'
+ /** BlockExpr ::= `{' CaseClauses | Block | Tuple `}'
*/
def blockExpr(): Tree = {
val res = atPos(accept(LBRACE)) {
if (in.token == CASE) makeVisitor(caseClauses())
- else block()
+ else blockOrTuple(true)
}
accept(RBRACE)
res
}
/** Block ::= BlockStatSeq
- */
- def block(): Tree = makeBlock(blockStatSeq(new ListBuffer[Tree]))
+ * Tuple ::= [Expr1 {`,' Expr1}]
+ */
+ def block(): Tree = blockOrTuple(false)
+ def blockOrTuple(tupleOK: boolean): Tree =
+ makeBlock(blockStatSeqOrTuple(tupleOK, new ListBuffer[Tree]))
/** CaseClauses ::= CaseClause {CaseClause}
*/
@@ -1126,12 +1151,13 @@ trait Parsers requires SyntaxAnalyzer {
//////// PATTERNS ////////////////////////////////////////////////////////////
- /** Patterns ::= SeqPattern { , SeqPattern } */
- def patterns(): List[Tree] = {
+ /** Patterns ::= Pattern { `,' Pattern } */
+ /** SeqPatterns ::= SeqPattern { `,' SeqPattern } */
+ def patterns(seqOK: boolean): List[Tree] = {
val ts = new ListBuffer[Tree]
- ts += pattern(true)
+ ts += pattern(seqOK)
while (in.token == COMMA) {
- in.nextToken(); ts += pattern(true)
+ in.nextToken(); ts += pattern(seqOK)
}
ts.toList
}
@@ -1227,14 +1253,16 @@ trait Parsers requires SyntaxAnalyzer {
* | `_'
* | literal
* | XmlPattern
- * | StableId [ `(' Patterns `)' ]
+ * | StableId [ `(' SeqPatterns `)' ]
* | `(' [Pattern] `)'
+ * | `{' [Pattern `,' Patterns] `}'
* SimpleSeqPattern ::= varid
* | `_'
* | literal
* | `<' xLiteralPattern
- * | StableId [TypePatternArgs] `(' Patterns `)' ]
- * | `(' Patterns `)'
+ * | StableId [TypePatternArgs] `(' SeqPatterns `)' ]
+ * | `{' [Pattern `,' Patterns] `}'
+ * | `(' SeqPatterns `)'
*/
def simplePattern(seqOK: boolean): Tree = in.token match {
case IDENTIFIER | BACKQUOTED_IDENT | THIS =>
@@ -1253,17 +1281,28 @@ trait Parsers requires SyntaxAnalyzer {
atPos(in.currentPos) {
val ts = typeArgs(true)
accept(LPAREN)
- val ps = if (in.token == RPAREN) List() else patterns()
+ val ps = if (in.token == RPAREN) List() else patterns(true)
accept(RPAREN)
Apply(TypeApply(convertToTypeId(t), ts), ps)
}
else */
if (in.token == LPAREN) {
atPos(in.skipToken()) {
- val ps = if (in.token == RPAREN) List() else patterns()
+ val ps = if (in.token == RPAREN) List() else patterns(true)
accept(RPAREN)
Apply(convertToTypeId(t), ps)
}
+ } else if (in.token == LBRACE) {
+ in.nextToken()
+ val ts = if (in.token == RBRACE) List()
+ else {
+ val p1 = pattern()
+ accept(COMMA)
+ p1 :: patterns(false)
+ }
+ checkSize("tuple elements", ts.length, definitions.MaxTupleArity)
+ accept(RBRACE)
+ makeTupleTerm(ts)
} else t
case USCORE =>
atPos(in.skipToken()) { Ident(nme.WILDCARD) }
@@ -1272,7 +1311,7 @@ trait Parsers requires SyntaxAnalyzer {
case LPAREN =>
val pos = in.skipToken()
val p =
- //if (false /*disabled, no regexp matching*/ && seqOK) atPos(pos) { makeSequence(patterns()) }
+ //if (false /*disabled, no regexp matching*/ && seqOK) atPos(pos) { makeSequence(patterns(true)) }
//else
if (in.token != RPAREN) pattern(false)
else Literal(()).setPos(pos)
@@ -1864,11 +1903,8 @@ trait Parsers requires SyntaxAnalyzer {
if (mods.hasFlag(Flags.CASE)) {
if (!vparamss.isEmpty) {
val argtypes: List[Tree] = vparamss.head map (.tpt.duplicate) //remove type annotation and you will get an interesting error message!!!
- val nargs = argtypes.length
- if (nargs <= definitions.MaxProductArity)
- parents += productConstr(argtypes)
- else
- unit.warning(in.currentPos, "can't have more than "+definitions.MaxProductArity+" case fields ")
+ checkSize("case class parameters", argtypes.length, definitions.MaxProductArity)
+ if (argtypes.length <= definitions.MaxProductArity) parents += productConstr(argtypes)
} else {
parents += productConstr(Nil)
}
@@ -2067,8 +2103,11 @@ trait Parsers requires SyntaxAnalyzer {
* | LocalModifiers TmplDef
* | Expr1
* |
+ * TupleExprs ::= ResultExpr "," ResultExprs
*/
- def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = {
+ def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] =
+ blockStatSeqOrTuple(false, stats)
+ def blockStatSeqOrTuple(tupleOK: boolean, stats: ListBuffer[Tree]): List[Tree] = {
def localDef(mods: Modifiers) = {
if (!(mods hasFlag ~Flags.IMPLICIT)) stats ++= defOrDcl(mods)
else stats += tmplDef(mods)
@@ -2079,12 +2118,27 @@ trait Parsers requires SyntaxAnalyzer {
if (in.token == RBRACE || in.token == CASE)
stats += Literal(()).setPos(in.currentPos)
}
- while ((in.token != RBRACE) && (in.token != EOF) && (in.token != CASE)) {
+ var last = false
+ while ((in.token != RBRACE) && (in.token != EOF) && (in.token != CASE) && !last) {
if (in.token == IMPORT) {
stats ++= importClause()
acceptStatSep()
} else if (isExprIntro) {
- stats += blockStatExpr()
+ val expr = blockStatExpr()
+ if (in.token == COMMA) {
+ val exprs = new ListBuffer[Tree] + expr
+ while (in.token == COMMA) {
+ in.nextToken()
+ exprs += expr1()
+ }
+ if (in.token == ARROW) {
+ val vdefs = exprs.toList flatMap convertToParams
+ checkSize("function arguments", vdefs.length, definitions.MaxFunctionArity)
+ stats += atPos(in.skipToken()) { Function(vdefs, block()) }
+ } else {
+ stats += makeTupleTerm(exprs.toList)
+ }
+ } else stats += expr
if (in.token != RBRACE && in.token != CASE) acceptStatSep()
} else if (isDefIntro) {
localDef(NoMods)
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index e98793f736..4060d8f619 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -94,12 +94,18 @@ abstract class TreeBuilder {
Apply(scalaDot(if (isType) newTypeName(tupString) else newTermName(tupString)), trees)
}
- private def makeTupleTerm(trees: List[Tree]): Tree = trees match {
+ def makeTupleTerm(trees: List[Tree]): Tree = trees match {
case List() => Literal(())
case List(tree) => tree
case _ => makeTuple(trees, false)
}
+ def makeTupleType(trees: List[Tree]): Tree = trees match {
+ case List() => scalaUnitConstr
+ case List(tree) => tree
+ case _ => AppliedTypeTree(scalaDot(newTypeName("Tuple" + trees.length)), trees)
+ }
+
/** If tree is a variable pattern, return Some("its name and type").
* Otherwise return none */
private def matchVarPattern(tree: Tree): Option[Pair[Name, Tree]] = tree match {
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 78354d92f2..809da82ee5 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -98,7 +98,7 @@ trait Definitions requires SymbolTable {
var RepeatedParamClass: Symbol = _
var ByNameParamClass: Symbol = _
- val MaxTupleArity = 9
+ val MaxTupleArity = 9 //todo: lift to 22
val TupleClass: Array[Symbol] = new Array(MaxTupleArity + 1)
def tupleField(n: Int, j: Int) = getMember(TupleClass(n), "_" + j)
def isTupleType(tp: Type): Boolean = tp match {
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 6207e93ee0..5cc54503ab 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -1,4 +1,4 @@
- /* NSC -- new Scala compiler
+/* NSC -- new Scala compiler
* Copyright 2005-2006 LAMP/EPFL
* @author Martin Odersky
*/
@@ -960,6 +960,8 @@ trait Types requires SymbolTable {
return "=> " + args(0).toString()
if (isFunctionType(this))
return args.init.mkString("(", ", ", ")") + " => " + args.last
+ if (isTupleType(this))
+ return args.mkString("{", ", ", "}")
}
val str = (pre.prefixString + sym.nameString +
(if (args.isEmpty) "" else args.mkString("[", ",", "]")))
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 70996371b8..b205c38f55 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -391,7 +391,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter
else Select(This(currentClass), outerField(currentClass))
localTyper.typed {
atPos(currentClass.pos) {
- DefDef(outerAcc, vparamss => rhs)
+ DefDef(outerAcc, {vparamss => rhs})
}
}
}
@@ -413,7 +413,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter
val rhs = ExplicitOuterTransformer.this.transform(path)
localTyper.typed {
atPos(currentClass.pos) {
- DefDef(outerAcc, vparamss => rhs)
+ DefDef(outerAcc, {vparamss=>rhs})
}
}
}
@@ -560,7 +560,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter
if(settings.Xkilloption.value) {
//Console.println("vparamss"+vparamss)
- val nvparamss = vparamss.map { x => super.transformValDefs(x) /*x.map { y => transform(y) if(wasOptionRef(y.tpe)) y.setType(getOptionArg(y.tpe)) */}
+ val nvparamss = vparamss.map { x => super.transformValDefs(x) }
//Console.println("nvparamss"+nvparamss)
val ntpt = if(wasOptionRef(tpt.tpe)) TypeTree(getOptionArg(tpt.tpe)) else tpt
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 75a0229869..aa6f5148f8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1664,13 +1664,15 @@ trait Typers requires Analyzer {
if (!sym.exists) {
if (settings.debug.value) Console.err.println("qual = "+qual+":"+qual.tpe+"\nSymbol="+qual.tpe.symbol+"\nsymbol-info = "+qual.tpe.symbol.info+"\nscope-id = "+qual.tpe.symbol.info.decls.hashCode()+"\nmembers = "+qual.tpe.members+"\nname = "+name+"\nfound = "+sym+"\nowner = "+context.enclClass.owner)
if (!qual.tpe.widen.isErroneous) {
- if (false && (context.unit eq null)) assert(false, "("+qual+":"+qual.tpe+")."+name)
error(tree.pos,
- decode(name)+" is not a member of "+qual.tpe.widen +
- (if ((context.unit ne null) && Position.line(context.unit.source, qual.pos) <
- Position.line(context.unit.source, tree.pos))
- "\npossible cause: maybe a semicolon is missing before `"+decode(name)+"'?"
- else ""))
+ if (name == nme.CONSTRUCTOR)
+ qual.tpe.widen+" does not have a constructor"
+ else
+ decode(name)+" is not a member of "+qual.tpe.widen +
+ (if ((context.unit ne null) && Position.line(context.unit.source, qual.pos) <
+ Position.line(context.unit.source, tree.pos))
+ "\npossible cause: maybe a semicolon is missing before `"+decode(name)+"'?"
+ else ""))
}
setError(tree)
} else {