From b0fe13505faf7c93093b4e9dc2813259e2f70094 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Sun, 23 Feb 2014 02:37:09 -0800 Subject: SI-8325 Accept infix star type outside patterns This is a follow-up to SI-5702 which enabled use of `*` in infix notation in patterns. Most of the work is in distinguishing infix from a sequence pattern. Also, do not take backticked star as the repeated parameter marker in postfix position. That is, `Int``*``` is not `Int*` -- I hope double-tick renders as tick. There is not a special use case except that backticks mean "I am an identifier, as is, and not a keyword." --- .../scala/tools/nsc/ast/parser/Parsers.scala | 30 +++++++++++++++------- test/files/neg/t8325-b.check | 10 ++++++++ test/files/neg/t8325-b.scala | 4 +++ test/files/neg/t8325-c.check | 7 +++++ test/files/neg/t8325-c.scala | 4 +++ test/files/neg/t8325.check | 15 +++++++++++ test/files/neg/t8325.scala | 11 ++++++++ test/files/pos/t8325.scala | 9 +++++++ 8 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 test/files/neg/t8325-b.check create mode 100644 test/files/neg/t8325-b.scala create mode 100644 test/files/neg/t8325-c.check create mode 100644 test/files/neg/t8325-c.scala create mode 100644 test/files/neg/t8325.check create mode 100644 test/files/neg/t8325.scala create mode 100644 test/files/pos/t8325.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 9e631febee..ffc45b21ea 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -654,9 +654,10 @@ self => def isIdentExcept(except: Name) = isIdent && in.name != except def isIdentOf(name: Name) = isIdent && in.name == name - def isUnaryOp = isIdent && raw.isUnary(in.name) - def isRawStar = isIdent && in.name == raw.STAR - def isRawBar = isIdent && in.name == raw.BAR + def isUnaryOp = isIdent && raw.isUnary(in.name) + def isRawStar = isRawIdent && in.name == raw.STAR + def isRawBar = isRawIdent && in.name == raw.BAR + def isRawIdent = in.token == IDENTIFIER def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw @@ -1001,19 +1002,30 @@ self => } def infixTypeRest(t: Tree, mode: InfixMode.Value): Tree = { - if (isIdent && in.name != nme.STAR) { - val opOffset = in.offset + // Detect postfix star for repeated args. + // Only RPAREN can follow, but accept COMMA and EQUALS for error's sake. + // Take RBRACE as a paren typo. + def checkRepeatedParam = if (isRawStar) { + lookingAhead (in.token match { + case RPAREN | COMMA | EQUALS | RBRACE => t + case _ => EmptyTree + }) + } else EmptyTree + def asInfix = { + val opOffset = in.offset val leftAssoc = treeInfo.isLeftAssoc(in.name) - if (mode != InfixMode.FirstOp) checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp) - val op = identForType() - val tycon = atPos(opOffset) { Ident(op) } + if (mode != InfixMode.FirstOp) + checkAssoc(opOffset, in.name, leftAssoc = mode == InfixMode.LeftOp) + val tycon = atPos(opOffset) { Ident(identForType()) } newLineOptWhenFollowing(isTypeIntroToken) def mkOp(t1: Tree) = atPos(t.pos.start, opOffset) { AppliedTypeTree(tycon, List(t, t1)) } if (leftAssoc) infixTypeRest(mkOp(compoundType()), InfixMode.LeftOp) else mkOp(infixType(InfixMode.RightOp)) - } else t + } + if (isIdent) checkRepeatedParam orElse asInfix + else t } /** {{{ diff --git a/test/files/neg/t8325-b.check b/test/files/neg/t8325-b.check new file mode 100644 index 0000000000..ec80826dc0 --- /dev/null +++ b/test/files/neg/t8325-b.check @@ -0,0 +1,10 @@ +t8325-b.scala:3: error: Unmatched closing brace '}' ignored here + def k(is: Int*} = ??? + ^ +t8325-b.scala:3: error: ';' expected but '=' found. + def k(is: Int*} = ??? + ^ +t8325-b.scala:4: error: eof expected but '}' found. +} +^ +three errors found diff --git a/test/files/neg/t8325-b.scala b/test/files/neg/t8325-b.scala new file mode 100644 index 0000000000..6ac78708bb --- /dev/null +++ b/test/files/neg/t8325-b.scala @@ -0,0 +1,4 @@ + +trait Test { + def k(is: Int*} = ??? +} diff --git a/test/files/neg/t8325-c.check b/test/files/neg/t8325-c.check new file mode 100644 index 0000000000..51ea4988a6 --- /dev/null +++ b/test/files/neg/t8325-c.check @@ -0,0 +1,7 @@ +t8325-c.scala:3: error: identifier expected but ')' found. + def k(xx: Int`*`) = ??? + ^ +t8325-c.scala:4: error: ')' expected but '}' found. +} +^ +two errors found diff --git a/test/files/neg/t8325-c.scala b/test/files/neg/t8325-c.scala new file mode 100644 index 0000000000..076202df3f --- /dev/null +++ b/test/files/neg/t8325-c.scala @@ -0,0 +1,4 @@ + +trait Test { + def k(xx: Int`*`) = ??? +} diff --git a/test/files/neg/t8325.check b/test/files/neg/t8325.check new file mode 100644 index 0000000000..175a0db415 --- /dev/null +++ b/test/files/neg/t8325.check @@ -0,0 +1,15 @@ +t8325.scala:5: error: *-parameter must come last + def f(is: Int*, s: String) = ??? + ^ +t8325.scala:7: error: *-parameter must come last + def h(is: Int * String *, s: String) = ??? + ^ +t8325.scala:10: error: type mismatch; + found : Int(5) + required: Int* + def j(is: Int* = 5) = ??? + ^ +t8325.scala:10: error: a parameter section with a `*'-parameter is not allowed to have default arguments + def j(is: Int* = 5) = ??? + ^ +four errors found diff --git a/test/files/neg/t8325.scala b/test/files/neg/t8325.scala new file mode 100644 index 0000000000..3813797e83 --- /dev/null +++ b/test/files/neg/t8325.scala @@ -0,0 +1,11 @@ + +trait Test { + type OK[A,B] = A Tuple2 B + type *[A,B] = A Tuple2 B + def f(is: Int*, s: String) = ??? + def g(is: Int * String, s: String) = ??? // OK + def h(is: Int * String *, s: String) = ??? + // won't recover from following + //def i(is: Int OK) = ??? //error: identifier expected but ')' found. + def j(is: Int* = 5) = ??? +} diff --git a/test/files/pos/t8325.scala b/test/files/pos/t8325.scala new file mode 100644 index 0000000000..af33ee7bb3 --- /dev/null +++ b/test/files/pos/t8325.scala @@ -0,0 +1,9 @@ + +trait Test { + type +[A, B] = (A, B) + type *[A, B] = (A, B) + + type X[A, B] = A + B + type Y[A, B] = A * B + type Z[A, B] = A `*` B +} -- cgit v1.2.3