diff --git a/spec/06-expressions.md b/spec/06-expressions.md index 924d69b2ca03..f316d9a33846 100644 --- a/spec/06-expressions.md +++ b/spec/06-expressions.md @@ -240,6 +240,7 @@ depending on whether `B` is mixed in with class `Root` or `A`. ```ebnf SimpleExpr ::= SimpleExpr1 ArgumentExprs ArgumentExprs ::= ‘(’ [Exprs] ‘)’ + | ‘(’ ‘using’ Exprs ‘)’ | ‘(’ [Exprs ‘,’] PostfixExpr ‘:’ ‘_’ ‘*’ ‘)’ | [nl] BlockExpr Exprs ::= Expr {‘,’ Expr} @@ -328,6 +329,9 @@ sum(List(1, 2, 3, 4)) would not typecheck. +An argument list may begin with the soft keyword `using` to facilitate cross-compilation with Scala 3. +The keyword is ignored. + ### Named and Default Arguments If an application is to use named arguments ´p = e´ or default diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 2291a141d124..659c3c6558cb 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1916,6 +1916,7 @@ self => /** {{{ * ArgumentExprs ::= `(` [Exprs] `)` + * | `(` `using` Exprs `)` * | [nl] BlockExpr * }}} */ @@ -1924,9 +1925,15 @@ self => if (isIdent) treeInfo.assignmentToMaybeNamedArg(expr()) else expr() ) in.token match { - case LBRACE => List(blockExpr()) - case LPAREN => inParens(if (in.token == RPAREN) Nil else args()) - case _ => Nil + case LBRACE => List(blockExpr()) + case LPAREN => inParens { + in.token match { + case RPAREN => Nil + case IDENTIFIER if in.name == nme.using && lookingAhead(isExprIntro) => in.nextToken() ; args() + case _ => args() + } + } + case _ => Nil } } /** A succession of argument lists. */ diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index da5888601479..d2b3df3b762d 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -684,6 +684,7 @@ trait StdNames { // Scala 3 soft keywords val infix: NameType = nameType("infix") val open: NameType = nameType("open") + val using: NameType = nameType("using") // Compiler utilized names diff --git a/test/files/neg/i15552.check b/test/files/neg/i15552.check new file mode 100644 index 000000000000..849f2936c7a1 --- /dev/null +++ b/test/files/neg/i15552.check @@ -0,0 +1,7 @@ +i15552.scala:4: error: not found: value g + def f() = g(42)(using ctx) // error: no g + ^ +i15552.scala:22: error: not found: value using + def f() = g(using) // error: no using, does not actually suggest Using + ^ +2 errors diff --git a/test/files/neg/i15552.scala b/test/files/neg/i15552.scala new file mode 100644 index 000000000000..e9363222d038 --- /dev/null +++ b/test/files/neg/i15552.scala @@ -0,0 +1,40 @@ +// scalac: -Werror +class C { + val ctx: C = new C() + def f() = g(42)(using ctx) // error: no g +} + +class Innocent { + val using = 42 + def g(i: Int) = i + def f() = g(using) +} + +class Malicious { + val using = 42 + def g(i: Int) = i + def f() = g(using using) +} + +class Suggest { + import scala.util._ + def g(i: Int) = i + def f() = g(using) // error: no using, does not actually suggest Using +} + +class Fancy { + def g(i: Int) = i + def f() = g(using if (true) 42 else 17) +} + +/* +was: + +i15552.scala:4: error: not found: value g + def f() = g(42)(using ctx) + ^ +i15552.scala:4: error: not found: value using + def f() = g(42)(using ctx) + ^ +i15552.scala:4: error: postfix operator ctx needs to be enabled + */