From 75ff20be0e87c6d95fec93893371122b0414cf19 Mon Sep 17 00:00:00 2001 From: i10416 Date: Sat, 20 Jan 2024 22:37:48 +0900 Subject: [PATCH] fix(#19402): error message for missing using in given params `given`-s can't have non-implicit arguments, but when users forget adding a `using` modifier to given parameters, it showed unfriendly error message; "only classes can have declared but undefined members". The `termParamClauses` parser is aware of the owner of parameters and it raises a syntax error when parameters in given definition do not have `using` modifier with clear reason, but `in.token == LPAREN && in.lookahead.isIdent(nme.using)` in Parsers.scala was too strict to delegate parameter clause handling to `termParamClauses`. Note: This change requires tests/neg/i8150.check to be updated because the original test starts failing due to the syntax error rather than "refinement cannot be `given`" error. `type T = {given A with A}` in i8150.check confirms that a valid given definition in RHS of type alias still raises the original error; "refinement cannot be `given`" error. --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 8 ++++++-- tests/neg/i19402.check | 4 ++++ tests/neg/i19402.scala | 11 +++++++++++ tests/neg/i8150.check | 16 ++++++++++++++++ tests/neg/i8150.scala | 4 +++- 5 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 tests/neg/i19402.check create mode 100644 tests/neg/i19402.scala create mode 100644 tests/neg/i8150.check diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 18294a28b4a1..e15e95392b67 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -4005,13 +4005,17 @@ object Parsers { def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) { var mods1 = addMod(mods, givenMod) val nameStart = in.offset - val name = if isIdent && followingIsGivenSig() then ident() else EmptyTermName + val givenSigPart = + if isIdent && followingIsGivenSig() then Some(ident()) + else if followingIsGivenSig() then Some(EmptyTermName) + else None + val name = givenSigPart.getOrElse(EmptyTermName) val gdef = val tparams = typeParamClauseOpt(ParamOwner.Given) newLineOpt() val vparamss = - if in.token == LPAREN && in.lookahead.isIdent(nme.using) + if in.token == LPAREN && givenSigPart.nonEmpty then termParamClauses(ParamOwner.Given) else Nil newLinesOpt() diff --git a/tests/neg/i19402.check b/tests/neg/i19402.check new file mode 100644 index 000000000000..0792f82a627c --- /dev/null +++ b/tests/neg/i19402.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/i19402.scala:9:12 ---------------------------------------------------------------------------------- +9 | given bar(foo: Foo): Bar = Bar(foo) // error + | ^^^ + | `using` expected diff --git a/tests/neg/i19402.scala b/tests/neg/i19402.scala new file mode 100644 index 000000000000..112a70d9d188 --- /dev/null +++ b/tests/neg/i19402.scala @@ -0,0 +1,11 @@ +object Example { + + class Bar(foo: Foo) + + class Foo + + given Foo = Foo() + + given bar(foo: Foo): Bar = Bar(foo) // error + +} diff --git a/tests/neg/i8150.check b/tests/neg/i8150.check new file mode 100644 index 000000000000..373dc6a74355 --- /dev/null +++ b/tests/neg/i8150.check @@ -0,0 +1,16 @@ +-- Error: tests/neg/i8150.scala:3:16 ----------------------------------------------------------------------------------- +3 |type T = {given A with A} // error + | ^^^^^^^^^^^^^^ + | refinement cannot be `given` +-- [E040] Syntax Error: tests/neg/i8150.scala:4:23 --------------------------------------------------------------------- +4 |type T = {given(using a: A) as B} // error // error + | ^ + | an identifier expected, but ':' found +-- [E040] Syntax Error: tests/neg/i8150.scala:4:28 --------------------------------------------------------------------- +4 |type T = {given(using a: A) as B} // error // error + | ^^ + | 'with' expected, but identifier found +-- [E040] Syntax Error: tests/neg/i8150.scala:5:8 ---------------------------------------------------------------------- +5 |// error + | ^ + | '}' expected, but eof found diff --git a/tests/neg/i8150.scala b/tests/neg/i8150.scala index 2f0505c6265a..7266b359944e 100644 --- a/tests/neg/i8150.scala +++ b/tests/neg/i8150.scala @@ -1,3 +1,5 @@ trait A trait B -type T = {given(using a: A) as B} // error: refinement cannot be `given` \ No newline at end of file +type T = {given A with A} // error +type T = {given(using a: A) as B} // error // error +// error \ No newline at end of file