Skip to content

Commit 75ff20b

Browse files
committed
fix(scala#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.
1 parent 5fc2ef9 commit 75ff20b

File tree

5 files changed

+40
-3
lines changed

5 files changed

+40
-3
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4005,13 +4005,17 @@ object Parsers {
40054005
def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) {
40064006
var mods1 = addMod(mods, givenMod)
40074007
val nameStart = in.offset
4008-
val name = if isIdent && followingIsGivenSig() then ident() else EmptyTermName
40094008

4009+
val givenSigPart =
4010+
if isIdent && followingIsGivenSig() then Some(ident())
4011+
else if followingIsGivenSig() then Some(EmptyTermName)
4012+
else None
4013+
val name = givenSigPart.getOrElse(EmptyTermName)
40104014
val gdef =
40114015
val tparams = typeParamClauseOpt(ParamOwner.Given)
40124016
newLineOpt()
40134017
val vparamss =
4014-
if in.token == LPAREN && in.lookahead.isIdent(nme.using)
4018+
if in.token == LPAREN && givenSigPart.nonEmpty
40154019
then termParamClauses(ParamOwner.Given)
40164020
else Nil
40174021
newLinesOpt()

tests/neg/i19402.check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg/i19402.scala:9:12 ----------------------------------------------------------------------------------
2+
9 | given bar(foo: Foo): Bar = Bar(foo) // error
3+
| ^^^
4+
| `using` expected

tests/neg/i19402.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
object Example {
2+
3+
class Bar(foo: Foo)
4+
5+
class Foo
6+
7+
given Foo = Foo()
8+
9+
given bar(foo: Foo): Bar = Bar(foo) // error
10+
11+
}

tests/neg/i8150.check

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
-- Error: tests/neg/i8150.scala:3:16 -----------------------------------------------------------------------------------
2+
3 |type T = {given A with A} // error
3+
| ^^^^^^^^^^^^^^
4+
| refinement cannot be `given`
5+
-- [E040] Syntax Error: tests/neg/i8150.scala:4:23 ---------------------------------------------------------------------
6+
4 |type T = {given(using a: A) as B} // error // error
7+
| ^
8+
| an identifier expected, but ':' found
9+
-- [E040] Syntax Error: tests/neg/i8150.scala:4:28 ---------------------------------------------------------------------
10+
4 |type T = {given(using a: A) as B} // error // error
11+
| ^^
12+
| 'with' expected, but identifier found
13+
-- [E040] Syntax Error: tests/neg/i8150.scala:5:8 ----------------------------------------------------------------------
14+
5 |// error
15+
| ^
16+
| '}' expected, but eof found

tests/neg/i8150.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
trait A
22
trait B
3-
type T = {given(using a: A) as B} // error: refinement cannot be `given`
3+
type T = {given A with A} // error
4+
type T = {given(using a: A) as B} // error // error
5+
// error

0 commit comments

Comments
 (0)