diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2016-02-01 14:13:23 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2016-02-01 14:13:23 +1000 |
commit | cc6fea6d30609b8879db1ecdbc288e4cdaa5b8d4 (patch) | |
tree | d2ebba9717ab1c172968f776c76eee827e62fbad /src | |
parent | d796f2c3a19a01cb4f08ca951014931b7d47b9bc (diff) | |
parent | 0f088022aac31f8ce9f174490c45f481db2faae9 (diff) | |
download | scala-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
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/reflect/quasiquotes/Parsers.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 57 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 32 |
3 files changed, 58 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 |