summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-02-01 14:13:23 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-02-01 14:13:23 +1000
commitcc6fea6d30609b8879db1ecdbc288e4cdaa5b8d4 (patch)
treed2ebba9717ab1c172968f776c76eee827e62fbad
parentd796f2c3a19a01cb4f08ca951014931b7d47b9bc (diff)
parent0f088022aac31f8ce9f174490c45f481db2faae9 (diff)
downloadscala-cc6fea6d30609b8879db1ecdbc288e4cdaa5b8d4.tar.gz
scala-cc6fea6d30609b8879db1ecdbc288e4cdaa5b8d4.tar.bz2
scala-cc6fea6d30609b8879db1ecdbc288e4cdaa5b8d4.zip
Merge pull request #4927 from szeiger/issue/9572
SI-9572 Check for illegal tuple sizes in the parser
-rw-r--r--src/compiler/scala/reflect/quasiquotes/Parsers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala57
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala32
-rw-r--r--test/files/neg/t9572.check7
-rw-r--r--test/files/neg/t9572.scala6
5 files changed, 71 insertions, 35 deletions
diff --git a/src/compiler/scala/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/reflect/quasiquotes/Parsers.scala
index 97ec7dbfc3..108ad0bc2e 100644
--- a/src/compiler/scala/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/reflect/quasiquotes/Parsers.scala
@@ -59,6 +59,10 @@ trait Parsers { self: Quasiquotes =>
override implicit lazy val fresh: FreshNameCreator = new FreshNameCreator(nme.QUASIQUOTE_PREFIX)
+ // Do not check for tuple arity. The placeholders can support arbitrary tuple sizes.
+ override def makeSafeTupleTerm(trees: List[Tree], offset: Offset): Tree = treeBuilder.makeTupleTerm(trees)
+ override def makeSafeTupleType(trees: List[Tree], offset: Offset): Tree = treeBuilder.makeTupleType(trees)
+
override val treeBuilder = new ParserTreeBuilder {
override implicit def fresh: FreshNameCreator = parser.fresh
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 4494a8ac8d..c04d305f9e 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -766,7 +766,58 @@ self =>
@inline final def caseSeparated[T](part: => T): List[T] = tokenSeparated(CASE, sepFirst = true, part)
def readAnnots(part: => Tree): List[Tree] = tokenSeparated(AT, sepFirst = true, part)
-/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
+ /** Create a tuple type Tree. If the arity is not supported, a syntax error is emitted. */
+ def makeSafeTupleType(elems: List[Tree], offset: Offset) = {
+ if (checkTupleSize(elems, offset)) makeTupleType(elems)
+ else makeTupleType(Nil) // create a dummy node; makeTupleType(elems) would fail
+ }
+
+ /** Create a tuple term Tree. If the arity is not supported, a syntax error is emitted. */
+ def makeSafeTupleTerm(elems: List[Tree], offset: Offset) = {
+ checkTupleSize(elems, offset)
+ makeTupleTerm(elems)
+ }
+
+ private[this] def checkTupleSize(elems: List[Tree], offset: Offset): Boolean =
+ if (elems.lengthCompare(definitions.MaxTupleArity) > 0) {
+ syntaxError(offset, "too many elements for tuple: "+elems.length+", allowed: "+definitions.MaxTupleArity, skipIt = false)
+ false
+ } else true
+
+ /** Strip the artifitial `Parens` node to create a tuple term Tree. */
+ def stripParens(t: Tree) = t match {
+ case Parens(ts) => atPos(t.pos) { makeSafeTupleTerm(ts, t.pos.point) }
+ case _ => t
+ }
+
+ /** Create tree representing (unencoded) binary operation expression or pattern. */
+ def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = {
+ require(isExpr || targs.isEmpty || targs.exists(_.isErroneous), s"Incompatible args to makeBinop: !isExpr but targs=$targs")
+
+ def mkSelection(t: Tree) = {
+ def sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode))
+ if (targs.isEmpty) sel else atPos(left.pos)(TypeApply(sel, targs))
+ }
+ def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args
+ val arguments = right match {
+ case Parens(args) => mkNamed(args)
+ case _ => List(right)
+ }
+ if (isExpr) {
+ if (treeInfo.isLeftAssoc(op)) {
+ Apply(mkSelection(left), arguments)
+ } else {
+ val x = freshTermName()
+ Block(
+ List(ValDef(Modifiers(symtab.Flags.SYNTHETIC | symtab.Flags.ARTIFACT), x, TypeTree(), stripParens(left))),
+ Apply(mkSelection(right), List(Ident(x))))
+ }
+ } else {
+ Apply(Ident(op.encode), stripParens(left) :: arguments)
+ }
+ }
+
+ /* --------- OPERAND/OPERATOR STACK --------------------------------------- */
/** Modes for infix types. */
object InfixMode extends Enumeration {
@@ -870,7 +921,7 @@ self =>
atPos(start, in.skipToken()) { makeFunctionTypeTree(ts, typ()) }
else {
ts foreach checkNotByNameOrVarargs
- val tuple = atPos(start) { makeTupleType(ts) }
+ val tuple = atPos(start) { makeSafeTupleType(ts, start) }
infixTypeRest(
compoundTypeRest(
annotTypeRest(
@@ -937,7 +988,7 @@ self =>
def simpleType(): Tree = {
val start = in.offset
simpleTypeRest(in.token match {
- case LPAREN => atPos(start)(makeTupleType(inParens(types())))
+ case LPAREN => atPos(start)(makeSafeTupleType(inParens(types()), start))
case USCORE => wildcardType(in.skipToken())
case _ =>
path(thisOK = false, typeOK = true) match {
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 6e5a3f6ef7..cc9e39f430 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -43,44 +43,12 @@ abstract class TreeBuilder {
def makeTupleType(elems: List[Tree]) = gen.mkTupleType(elems)
- def stripParens(t: Tree) = t match {
- case Parens(ts) => atPos(t.pos) { makeTupleTerm(ts) }
- case _ => t
- }
-
def makeAnnotated(t: Tree, annot: Tree): Tree =
atPos(annot.pos union t.pos)(Annotated(annot, t))
def makeSelfDef(name: TermName, tpt: Tree): ValDef =
ValDef(Modifiers(PRIVATE), name, tpt, EmptyTree)
- /** Create tree representing (unencoded) binary operation expression or pattern. */
- def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = {
- require(isExpr || targs.isEmpty || targs.exists(_.isErroneous), s"Incompatible args to makeBinop: !isExpr but targs=$targs")
-
- def mkSelection(t: Tree) = {
- def sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode))
- if (targs.isEmpty) sel else atPos(left.pos)(TypeApply(sel, targs))
- }
- def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args
- val arguments = right match {
- case Parens(args) => mkNamed(args)
- case _ => List(right)
- }
- if (isExpr) {
- if (treeInfo.isLeftAssoc(op)) {
- Apply(mkSelection(left), arguments)
- } else {
- val x = freshTermName()
- Block(
- List(ValDef(Modifiers(SYNTHETIC | ARTIFACT), x, TypeTree(), stripParens(left))),
- Apply(mkSelection(right), List(Ident(x))))
- }
- } else {
- Apply(Ident(op.encode), stripParens(left) :: arguments)
- }
- }
-
/** Tree for `od op`, start is start0 if od.pos is borked. */
def makePostfixSelect(start0: Int, end: Int, od: Tree, op: Name): Tree = {
val start = if (od.pos.isDefined) od.pos.start else start0
diff --git a/test/files/neg/t9572.check b/test/files/neg/t9572.check
new file mode 100644
index 0000000000..b95bd015cf
--- /dev/null
+++ b/test/files/neg/t9572.check
@@ -0,0 +1,7 @@
+t9572.scala:3: error: too many elements for tuple: 23, allowed: 22
+ val term23 = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
+ ^
+t9572.scala:5: error: too many elements for tuple: 23, allowed: 22
+ val type23: (Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int) = null
+ ^
+two errors found
diff --git a/test/files/neg/t9572.scala b/test/files/neg/t9572.scala
new file mode 100644
index 0000000000..32b2db320e
--- /dev/null
+++ b/test/files/neg/t9572.scala
@@ -0,0 +1,6 @@
+class T9572 {
+ val term22 = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
+ val term23 = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
+ val type22: (Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int) = null
+ val type23: (Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int,Int) = null
+}