Skip to content

Commit 5aee01c

Browse files
authored
Merge pull request #7185 from dotty-staging/change-indent-colon
Don't require colon after class or object signatures
2 parents 7c88400 + 94ff30a commit 5aee01c

21 files changed

+557
-517
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeAsmCommon.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package jvm
77
* the compiler cake (Global).
88
*/
99
final class BCodeAsmCommon[I <: BackendInterface](val interface: I) {
10-
import interface._
10+
import interface._
1111

1212
/**
1313
* True if `classSym` is an anonymous class or a local class. I.e., false if `classSym` is a

compiler/src/dotty/tools/backend/jvm/GenBCode.scala

+410-411
Large diffs are not rendered by default.

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

+17-10
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,11 @@ object Parsers {
11781178
newLineOptWhenFollowedBy(LBRACE)
11791179
}
11801180

1181+
def possibleTemplateStart(): Unit = {
1182+
in.observeIndented()
1183+
newLineOptWhenFollowedBy(LBRACE)
1184+
}
1185+
11811186
def indentRegion[T](tag: EndMarkerTag)(op: => T): T = {
11821187
val iw = in.currentRegion.indentWidth
11831188
val t = op
@@ -3330,7 +3335,7 @@ object Parsers {
33303335
if (in.token == LPAREN)
33313336
try paramClause(prefix = true) :: Nil
33323337
finally {
3333-
possibleBracesStart()
3338+
possibleTemplateStart()
33343339
if (!in.isNestedStart) syntaxErrorOrIncomplete("`{' expected")
33353340
}
33363341
else Nil
@@ -3348,7 +3353,7 @@ object Parsers {
33483353
DefDef(name, tparams, vparamss, parents.head, expr())
33493354
}
33503355
else {
3351-
possibleBracesStart()
3356+
possibleTemplateStart()
33523357
val (tparams1, vparamss1) =
33533358
if (leadingParamss.nonEmpty)
33543359
(tparams, leadingParamss)
@@ -3448,7 +3453,7 @@ object Parsers {
34483453
*/
34493454
def template(constr: DefDef, isEnum: Boolean = false): Template = {
34503455
val (parents, derived) = inheritClauses()
3451-
possibleBracesStart()
3456+
possibleTemplateStart()
34523457
if (isEnum) {
34533458
val (self, stats) = withinEnum(templateBody())
34543459
Template(constr, parents, derived, self, stats)
@@ -3458,13 +3463,15 @@ object Parsers {
34583463

34593464
/** TemplateOpt = [Template]
34603465
*/
3461-
def templateOpt(constr: DefDef): Template = {
3466+
def templateOpt(constr: DefDef): Template =
34623467
possibleBracesStart()
3463-
if (in.token == EXTENDS || isIdent(nme.derives) || in.isNestedStart)
3468+
if (in.token == EXTENDS || isIdent(nme.derives))
34643469
template(constr)
3465-
else
3466-
Template(constr, Nil, Nil, EmptyValDef, Nil)
3467-
}
3470+
else {
3471+
possibleTemplateStart()
3472+
if (in.isNestedStart) template(constr)
3473+
else Template(constr, Nil, Nil, EmptyValDef, Nil)
3474+
}
34683475

34693476
/** TemplateBody ::= [nl] `{' TemplateStatSeq `}'
34703477
*/
@@ -3496,7 +3503,7 @@ object Parsers {
34963503
def packaging(start: Int): Tree = {
34973504
val pkg = qualId()
34983505
indentRegion(pkg) {
3499-
possibleBracesStart()
3506+
possibleTemplateStart()
35003507
val stats = inDefScopeBraces(topStatSeq())
35013508
makePackaging(start, pkg, stats)
35023509
}
@@ -3702,7 +3709,7 @@ object Parsers {
37023709
else {
37033710
val pkg = qualId()
37043711
indentRegion(pkg) {
3705-
possibleBracesStart()
3712+
possibleTemplateStart()
37063713
if (in.token == EOF)
37073714
ts += makePackaging(start, pkg, List())
37083715
else if (in.isNestedStart) {

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

+34-12
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ object Scanners {
2828

2929
type Token = Int
3030

31+
private val identity: IndentWidth => IndentWidth = Predef.identity
32+
3133
trait TokenData {
3234

3335
/** the next token */
@@ -372,7 +374,7 @@ object Scanners {
372374
def isLeadingInfixOperator() = (
373375
allowLeadingInfixOperators
374376
&& ( token == BACKQUOTED_IDENT
375-
|| token == IDENTIFIER && isOperatorPart(name(name.length - 1)))
377+
|| token == IDENTIFIER && isOperatorPart(name(name.length - 1)))
376378
&& ch == ' '
377379
&& !pastBlankLine
378380
&& {
@@ -392,25 +394,24 @@ object Scanners {
392394
}
393395
)
394396

395-
/** The indentation width of the given offset.
396-
* It is assumed that only blank characters are between the start of the line and the offset.
397-
*/
397+
/** The indentation width of the given offset */
398398
def indentWidth(offset: Offset): IndentWidth = {
399399
import IndentWidth.{Run, Conc}
400-
def recur(idx: Int, ch: Char, n: Int): IndentWidth =
401-
if (idx < 0) Run(ch, n)
400+
def recur(idx: Int, ch: Char, n: Int, k: IndentWidth => IndentWidth): IndentWidth =
401+
if (idx < 0) k(Run(ch, n))
402402
else {
403403
val nextChar = buf(idx)
404-
if (nextChar == ' ' || nextChar == '\t')
404+
if (nextChar == LF) k(Run(ch, n))
405+
else if (nextChar == ' ' || nextChar == '\t')
405406
if (nextChar == ch)
406-
recur(idx - 1, ch, n + 1)
407+
recur(idx - 1, ch, n + 1, k)
407408
else {
408-
val prefix = recur(idx - 1, nextChar, 1)
409-
if (n == 0) prefix else Conc(prefix, Run(ch, n))
409+
val k1: IndentWidth => IndentWidth = if (n == 0) k else Conc(_, Run(ch, n))
410+
recur(idx - 1, nextChar, 1, k1)
410411
}
411-
else Run(ch, n)
412+
else recur(idx - 1, ' ', 0, identity)
412413
}
413-
recur(offset - 1, ' ', 0)
414+
recur(offset - 1, ' ', 0, identity)
414415
}
415416

416417
/** Handle newlines, possibly inserting an INDENT, OUTDENT, NEWLINE, or NEWLINES token
@@ -531,6 +532,25 @@ object Scanners {
531532
}
532533
}
533534

535+
def observeIndented(): Unit =
536+
if (indentSyntax && isAfterLineEnd && token != INDENT) {
537+
val newLineInserted = token == NEWLINE || token == NEWLINES
538+
val nextOffset = if (newLineInserted) next.offset else offset
539+
val nextWidth = indentWidth(nextOffset)
540+
val lastWidth = currentRegion match {
541+
case r: Indented => r.width
542+
case r: InBraces => r.width
543+
case _ => nextWidth
544+
}
545+
546+
if (lastWidth < nextWidth) {
547+
currentRegion = Indented(nextWidth, Set(), COLONEOL, currentRegion)
548+
if (!newLineInserted) next.copyFrom(this)
549+
offset = nextOffset
550+
token = INDENT
551+
}
552+
}
553+
534554
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
535555
* - Insert missing OUTDENTs at EOF
536556
*/
@@ -1267,6 +1287,7 @@ object Scanners {
12671287
/* Initialization: read first char, then first token */
12681288
nextChar()
12691289
nextToken()
1290+
currentRegion = Indented(indentWidth(offset), Set(), EMPTY, null)
12701291
}
12711292
// end Scanner
12721293

@@ -1342,6 +1363,7 @@ object Scanners {
13421363
}
13431364
}
13441365
}
1366+
13451367
object IndentWidth {
13461368
private inline val MaxCached = 40
13471369
private val spaces = Array.tabulate(MaxCached + 1)(new Run(' ', _))

language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class DocumentSymbolTest {
3434

3535
@Test def documentSymbolShowClassAndCompanion: Unit = {
3636
code"""object ${m1}Foo${m2}
37-
class ${m3}Foo${m4}""".withSource
37+
|class ${m3}Foo${m4}""".withSource
3838
.documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Module),
3939
(m3 to m4).symInfo("Foo", SymbolKind.Class))
4040
}

language-server/test/dotty/tools/languageserver/ReferencesTest.scala

+19-19
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class ReferencesTest {
3737

3838
@Test def classReferenceCompanion: Unit = {
3939
code"""class ${m1}Foo${m2}(x: Any)
40-
object ${m3}Foo${m4} { val bar = new ${m5}Foo${m6}(${m7}Foo${m8}) }""".withSource
40+
|object ${m3}Foo${m4} { val bar = new ${m5}Foo${m6}(${m7}Foo${m8}) }""".withSource
4141
.references(m1 to m2, List(m1 to m2, m5 to m6), withDecl = true)
4242
.references(m1 to m2, List(m5 to m6), withDecl = false)
4343
.references(m3 to m4, List(m3 to m4, m7 to m8), withDecl = true)
@@ -50,9 +50,9 @@ class ReferencesTest {
5050

5151
@Test def anonClassTrait: Unit = {
5252
code"""trait ${m1}Foo${m2}
53-
object O {
54-
val foo = new ${m3}Foo${m4} {}
55-
}""".withSource
53+
|object O {
54+
| val foo = new ${m3}Foo${m4} {}
55+
|}""".withSource
5656
.references(m1 to m2, List(m1 to m2, m3 to m4), withDecl = true)
5757
.references(m1 to m2, List(m3 to m4), withDecl = false)
5858
.references(m3 to m4, List(m1 to m2, m3 to m4), withDecl = true)
@@ -170,12 +170,12 @@ class ReferencesTest {
170170

171171
val p1 = Project.dependingOn(p0).withSources(
172172
code"""class B {
173-
val a = new A()
174-
val z = new a.Z()
175-
val y = new z.Y()
176-
val x = new y.X()
177-
x.${m3}x${m4}
178-
}"""
173+
| val a = new A()
174+
| val z = new a.Z()
175+
| val y = new z.Y()
176+
| val x = new y.X()
177+
| x.${m3}x${m4}
178+
|}"""
179179
)
180180

181181
withProjects(p0, p1)
@@ -204,12 +204,12 @@ class ReferencesTest {
204204
@Test def findReferencesInUntouchedProject: Unit = {
205205
val p0 = Project.withSources(
206206
code"""package hello
207-
object A { def ${m1}foo${m2} = 1 }"""
207+
|object A { def ${m1}foo${m2} = 1 }"""
208208
)
209209

210210
val p1 = Project.dependingOn(p0).withSources(
211211
tasty"""package hello
212-
object B { def bar = A.${m3}foo${m4} }"""
212+
|object B { def bar = A.${m3}foo${m4} }"""
213213
)
214214

215215
withProjects(p0, p1)
@@ -219,8 +219,8 @@ class ReferencesTest {
219219

220220
@Test def importReference1: Unit = {
221221
code"""import ${m1}Foo${m2}._
222-
object ${m3}Foo${m4} { def ${m5}bar${m6}: Int = 0 }
223-
trait Bar { def buzz = ${m7}bar${m8} }""".withSource
222+
|object ${m3}Foo${m4} { def ${m5}bar${m6}: Int = 0 }
223+
|trait Bar { def buzz = ${m7}bar${m8} }""".withSource
224224

225225
.references(m1 to m2, List(m1 to m2, m3 to m4), withDecl = true)
226226
.references(m1 to m2, List(m1 to m2), withDecl = false)
@@ -266,7 +266,7 @@ class ReferencesTest {
266266

267267
@Test def importReferenceClassAndCompanion: Unit = {
268268
code"""object Foo { object ${m1}Bar${m2}; class ${m3}Bar${m4} }
269-
trait Buzz { import Foo.${m5}Bar${m6} }""".withSource
269+
|trait Buzz { import Foo.${m5}Bar${m6} }""".withSource
270270
.references(m1 to m2, List(m1 to m2, m5 to m6), withDecl = true)
271271
.references(m1 to m2, List(m5 to m6), withDecl = false)
272272
.references(m3 to m4, List(m3 to m4, m5 to m6), withDecl = true)
@@ -277,7 +277,7 @@ class ReferencesTest {
277277

278278
@Test def importReferenceWithRename: Unit = {
279279
code"""object ${m1}Foo${m2} { object ${m3}Bar${m4} { object ${m5}Baz${m6} } }
280-
trait Buzz { import ${m7}Foo${m8}.${m9}Bar${m10}.{${m11}Baz${m12} => ${m13}Quux${m14}}""".withSource
280+
|trait Buzz { import ${m7}Foo${m8}.${m9}Bar${m10}.{${m11}Baz${m12} => ${m13}Quux${m14}}""".withSource
281281

282282
.references(m1 to m2, List(m1 to m2, m7 to m8), withDecl = true)
283283
.references(m1 to m2, List(m7 to m8), withDecl = false)
@@ -297,7 +297,7 @@ class ReferencesTest {
297297

298298
@Test def importReferenceClassAndCompanionWithRename: Unit = {
299299
code"""object ${m1}Foo${m2} { object ${m3}Bar${m4}; class ${m5}Bar${m6} }
300-
trait Buzz { import ${m7}Foo${m8}.{${m9}Bar${m10} => ${m11}Baz${m12}} }""".withSource
300+
|trait Buzz { import ${m7}Foo${m8}.{${m9}Bar${m10} => ${m11}Baz${m12}} }""".withSource
301301

302302
.references(m1 to m2, List(m1 to m2, m7 to m8), withDecl = true)
303303
.references(m1 to m2, List(m7 to m8), withDecl = false)
@@ -315,7 +315,7 @@ class ReferencesTest {
315315

316316
@Test def importReferenceMembers: Unit = {
317317
code"""object Foo { def ${m1}bar${m2} = 2; type ${m3}bar${m4} = fizz; class fizz }
318-
trait Quux { import Foo.{${m5}bar${m6} => ${m7}buzz${m8}} }""".withSource
318+
|trait Quux { import Foo.{${m5}bar${m6} => ${m7}buzz${m8}} }""".withSource
319319

320320
.references(m1 to m2, List(m1 to m2, m5 to m6, m7 to m8), withDecl = true)
321321
.references(m1 to m2, List(m5 to m6, m7 to m8), withDecl = false)
@@ -331,7 +331,7 @@ class ReferencesTest {
331331
withSources(
332332
code"""object A { class ${m1}B${m2}; class ${m3}C${m4} }""",
333333
code"""import A.{${m5}B${m6} => ${m7}B2${m8}, ${m9}C${m10} => ${m11}C2${m12}}
334-
class E"""
334+
|class E"""
335335
).references(m1 to m2, List(m1 to m2, m5 to m6, m7 to m8), withDecl = true)
336336
.references(m1 to m2, List(m5 to m6, m7 to m8), withDecl = false)
337337
.references(m3 to m4, List(m3 to m4, m9 to m10, m11 to m12), withDecl = true)

language-server/test/dotty/tools/languageserver/SymbolTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class SymbolTest {
3535

3636
@Test def symbolShowClassAndCompanion: Unit = {
3737
code"""object ${m1}Foo${m2}
38-
class ${m3}Foo${m4}""".withSource
38+
|class ${m3}Foo${m4}""".withSource
3939
.symbol("Foo", (m1 to m2).symInfo("Foo", SymbolKind.Module),
4040
(m3 to m4).symInfo("Foo", SymbolKind.Class))
4141
}

language-server/test/dotty/tools/languageserver/WorksheetTest.scala

+5-5
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class WorksheetTest {
4242

4343
@Test def defineCaseClass: Unit = {
4444
ws"""${m1}case class Foo(x: Int)${m2}
45-
${m3}Foo(1)${m4}""".withSource
45+
|${m3}Foo(1)${m4}""".withSource
4646
.run(m1,
4747
((m1 to m2), "// defined case class Foo"),
4848
((m3 to m4), "val res0: Foo = Foo(1)"))
@@ -68,10 +68,10 @@ class WorksheetTest {
6868

6969
@Test def defineAnonymousClass1: Unit = {
7070
ws"""${m1}class Foo${m2}
71-
${m3}trait Bar${m4}
72-
${m5}new Foo with Bar {
73-
override def toString: String = "Foo"
74-
}${m6}""".withSource
71+
|${m3}trait Bar${m4}
72+
|${m5}new Foo with Bar {
73+
| override def toString: String = "Foo"
74+
|}${m6}""".withSource
7575
.run(m1,
7676
((m1 to m2), "// defined class Foo"),
7777
((m3 to m4), "// defined trait Bar"),

tests/neg/endmarkers.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
object Test:
1+
object Test
22

33
locally:
44
var x = 0
@@ -52,28 +52,28 @@ object Test:
5252
x < 10
5353
do ()
5454

55-
class Test2:
55+
class Test2
5656
self =>
5757
def foo = 1
5858

59-
object x:
59+
object x
6060
new Test2:
6161
override def foo = 2
6262
end new // error: end of statement expected but new found // error: not found: end
6363
def bar = 2 // error: ';' expected, but unindent found
6464
end Test2 // error: misaligned end marker
6565
end Test2
6666

67-
class Test3:
67+
class Test3
6868
self =>
6969
def foo = 1
7070
end Test3 // error: not found: end
7171

7272
import collection.mutable.HashMap
7373

74-
class Coder(words: List[String]):
74+
class Coder(words: List[String])
7575

76-
class Foo:
76+
class Foo
7777
println()
7878
end Foo // error: not found: end
7979

0 commit comments

Comments
 (0)