Skip to content

Commit 33e6ca1

Browse files
committed
Detect illegal refinements in Parser
1 parent cb93ee7 commit 33e6ca1

File tree

6 files changed

+37
-14
lines changed

6 files changed

+37
-14
lines changed

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,22 +2422,35 @@ object Parsers {
24222422
(self, if (stats.isEmpty) List(EmptyTree) else stats.toList)
24232423
}
24242424

2425-
/** RefineStatSeq ::= RefineStat {semi RefineStat}
2426-
* RefineStat ::= Dcl
2427-
* |
2428-
* (in reality we admit Defs and filter them out afterwards)
2425+
/** RefineStatSeq ::= RefineStat {semi RefineStat}
2426+
* RefineStat ::= ‘val’ VarDcl
2427+
* | ‘def’ DefDcl
2428+
* | ‘type’ {nl} TypeDcl
2429+
* (in reality we admit Defs and vars and filter them out afterwards in `checkLegal`)
24292430
*/
24302431
def refineStatSeq(): List[Tree] = {
24312432
val stats = new ListBuffer[Tree]
2433+
def checkLegal(tree: Tree): List[Tree] = {
2434+
val isLegal = tree match {
2435+
case tree: ValDef => tree.rhs.isEmpty && !tree.mods.flags.is(Mutable)
2436+
case tree: DefDef => tree.rhs.isEmpty
2437+
case tree: TypeDef => true
2438+
case _ => false
2439+
}
2440+
if (isLegal) tree :: Nil
2441+
else {
2442+
syntaxError("illegal refinement", tree.pos)
2443+
Nil
2444+
}
2445+
}
24322446
while (!isStatSeqEnd) {
2433-
if (isDclIntro) {
2434-
stats += defOrDcl(in.offset, Modifiers())
2435-
} else if (!isStatSep) {
2447+
if (isDclIntro)
2448+
stats ++= checkLegal(defOrDcl(in.offset, Modifiers()))
2449+
else if (!isStatSep)
24362450
syntaxErrorOrIncomplete(
24372451
"illegal start of declaration" +
24382452
(if (inFunReturnType) " (possible cause: missing `=' in front of current method body)"
24392453
else ""))
2440-
}
24412454
acceptStatSepUnlessAtEnd()
24422455
}
24432456
stats.toList

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ class Typer extends Namer
11941194
val refineCls = createSymbol(refineClsDef).asClass
11951195
val TypeDef(_, impl: Template) = typed(refineClsDef)
11961196
val refinements1 = impl.body
1197-
assert(tree.refinements.length == refinements1.length, s"${tree.refinements} != $refinements1")
1197+
assert(tree.refinements.hasSameLengthAs(refinements1), i"${tree.refinements}%, % > $refinements1%, %")
11981198
val seen = mutable.Set[Symbol]()
11991199
for (refinement <- refinements1) { // TODO: get clarity whether we want to enforce these conditions
12001200
typr.println(s"adding refinement $refinement")

docs/docs/internals/syntax.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ ParamValueType ::= Type [‘*’]
147147
TypeArgs ::= ‘[’ ArgTypes ‘]’ ts
148148
NamedTypeArg ::= id ‘=’ Type NamedArg(id, t)
149149
NamedTypeArgs ::= ‘[’ NamedTypeArg {‘,’ NamedTypeArg} ‘]’ nts
150-
Refinement ::= ‘{’ [Dcl] {semi [Dcl]} ‘}’ ds
150+
Refinement ::= ‘{’ [RefineDcl] {semi [RefineDcl]} ‘}’ ds
151151
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] | INT TypeBoundsTree(lo, hi)
152152
TypeParamBounds ::= TypeBounds {‘<%’ Type} {‘:’ Type} ContextBounds(typeBounds, tps)
153153
```
@@ -299,12 +299,12 @@ ImportSelector ::= id [‘=>’ id | ‘=>’ ‘_’]
299299

300300
### Declarations and Definitions
301301
```ebnf
302-
Dcl ::= ‘val’ ValDcl
303-
| ‘var’ VarDcl
302+
RefineDcl ::= ‘val’ VarDcl
304303
| ‘def’ DefDcl
305304
| ‘type’ {nl} TypeDcl
306305
| INT
307-
306+
Dcl ::= RefineDcl
307+
| ‘var’ VarDcl
308308
ValDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
309309
VarDcl ::= ids ‘:’ Type PatDef(_, ids, tpe, EmptyTree)
310310
DefDcl ::= DefSig [‘:’ Type] DefDef(_, name, tparams, vparamss, tpe, EmptyTree)

tests/neg/illegal-refinements.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait x0 {
2+
3+
type T = String { val x: Int = 1 } // error: illegal refinement
4+
type U = String { def x(): Int = 1 } // error: illegal refinement
5+
type V = String { var x: Int } // error: illegal refinement
6+
7+
}

tests/neg/parser-stability-5.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait x0 {
2+
x1 : { // error
3+
var x2 // error // error

tests/neg/structural.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ object Test3 {
33
def g(x: { type T ; def t: T ; def f(a: T): Boolean }) = x.f(x.t) // error: no ClassTag for x.T
44
g(new { type T = Int; def t = 4; def f(a:T) = true })
55
g(new { type T = Any; def t = 4; def f(a:T) = true })
6-
val y: { type T = Int; def t = 4; def f(a:T) = true }
6+
val y: { type T = Int; def t = 4; def f(a:T) = true } // error: illegal refinement // error: illegal refinement
77
= new { type T = Int; def t = 4; def f(a:T) = true }
88

99
def h(x: { def f[T](a: T): Int }) = x.f[Int](4) // error: polymorphic refinement method ... no longer allowed

0 commit comments

Comments
 (0)