Skip to content

Commit 815f479

Browse files
committed
Allow : instead of with in front of templates
1 parent d76aefe commit 815f479

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+213
-198
lines changed

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,10 @@ object Parsers {
913913
lookahead.nextToken()
914914
if lookahead.token == IDENTIFIER then
915915
lookahead.nextToken()
916-
lookahead.token == COLON
916+
if lookahead.token == COLON then
917+
lookahead.nextToken()
918+
!lookahead.isAfterLineEnd
919+
else false
917920
else false
918921
else false
919922

@@ -943,7 +946,10 @@ object Parsers {
943946
lookahead.nextToken()
944947
while lookahead.token == LPAREN || lookahead.token == LBRACKET do
945948
lookahead.skipParens()
946-
lookahead.token == COLON || lookahead.token == SUBTYPE
949+
if lookahead.token == COLON then
950+
lookahead.nextToken()
951+
!lookahead.isAfterLineEnd
952+
else lookahead.token == SUBTYPE
947953

948954
def followingIsExtension() =
949955
val lookahead = in.LookaheadScanner()
@@ -1304,7 +1310,12 @@ object Parsers {
13041310
}
13051311

13061312
def possibleTemplateStart(isNew: Boolean = false): Unit =
1307-
if in.token == WITH then
1313+
in.observeColonEOL()
1314+
if in.token == COLONEOL then
1315+
in.nextToken()
1316+
if in.token != INDENT then
1317+
syntaxError(i"indented definitions expected")
1318+
else if in.token == WITH then
13081319
in.nextToken()
13091320
if in.token != LBRACE && in.token != INDENT then
13101321
syntaxError(i"indented definitions or `{` expected")
@@ -3415,7 +3426,7 @@ object Parsers {
34153426
}
34163427

34173428
/** GivenDef ::= [GivenSig (‘:’ | <:)] {FunArgTypes ‘=>’} AnnotType ‘=’ Expr
3418-
* | [GivenSig ‘:’] {FunArgTypes ‘=>’} ConstrApps [[‘with’] TemplateBody]
3429+
* | [GivenSig ‘:’] {FunArgTypes ‘=>’} ConstrApps [‘:’ nl | ‘with’] TemplateBody]
34193430
* | [id ‘:’] ExtParamClause {GivenParamClause} ‘extended’ ‘with’ ExtMethods
34203431
* GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
34213432
* ExtParamClause ::= [DefTypeParamClause] DefParamClause

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,13 @@ object Scanners {
550550
|Previous indent : $lastWidth
551551
|Latest indent : $nextWidth"""
552552

553+
def observeColonEOL(): Unit =
554+
if token == COLON then
555+
lookahead()
556+
val atEOL = isAfterLineEnd
557+
reset()
558+
if atEOL then token = COLONEOL
559+
553560
def observeIndented(): Unit =
554561
if indentSyntax && isNewLine then
555562
val nextWidth = indentWidth(next.offset)
@@ -575,19 +582,21 @@ object Scanners {
575582
insert(OUTDENT, offset)
576583
case _ =>
577584

585+
def lookahead() = {
586+
prev.copyFrom(this)
587+
lastOffset = lastCharOffset
588+
fetchToken()
589+
}
590+
591+
def reset() = {
592+
next.copyFrom(this)
593+
this.copyFrom(prev)
594+
}
595+
578596
/** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + <EOL> => COLONEOL
579597
* - Insert missing OUTDENTs at EOF
580598
*/
581599
def postProcessToken(): Unit = {
582-
def lookahead() = {
583-
prev.copyFrom(this)
584-
lastOffset = lastCharOffset
585-
fetchToken()
586-
}
587-
def reset() = {
588-
next.copyFrom(this)
589-
this.copyFrom(prev)
590-
}
591600
def fuse(tok: Int) = {
592601
token = tok
593602
offset = prev.offset
@@ -611,10 +620,7 @@ object Scanners {
611620
/* skip the trailing comma */
612621
} else reset()
613622
case COLON =>
614-
lookahead()
615-
val atEOL = isAfterLineEnd
616-
reset()
617-
if (colonSyntax && atEOL) token = COLONEOL
623+
if colonSyntax then observeColonEOL()
618624
case EOF | RBRACE =>
619625
currentRegion match {
620626
case r: Indented if !r.isOutermost =>

tests/neg-custom-args/explicit-nulls/byname-nullables.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
object Test1 with
1+
object Test1:
22

33
def f(x: String) =
44
x ++ x
@@ -9,7 +9,7 @@ object Test1 with
99
else x
1010

1111

12-
object Test2 with
12+
object Test2:
1313

1414
def f(x: => String) =
1515
x ++ x
@@ -19,7 +19,7 @@ object Test2 with
1919
if x != null then f(x) // error: f is call-by-name
2020
else x
2121

22-
object Test3 with
22+
object Test3:
2323

2424
def f(x: String, y: String) = x
2525

@@ -31,7 +31,7 @@ object Test3 with
3131
if x != null then f(x, 1) // OK: not-null check successfully dropped
3232
else x
3333

34-
object Test4 with
34+
object Test4:
3535

3636
def f(x: String, y: String) = x
3737

@@ -43,7 +43,7 @@ object Test4 with
4343
if x != null then f(identity(x), 1) // error: dropping not null check fails typing
4444
else x
4545

46-
object Test5 with
46+
object Test5:
4747
import compiletime.byName
4848

4949
def f(x: String, y: String) = x
@@ -56,7 +56,7 @@ object Test5 with
5656
if x != null then f(byName(identity(x)), 1) // OK, byName avoids the flow typing
5757
else x
5858

59-
object Test6 with
59+
object Test6:
6060

6161
def f(x: String, y: String) = x
6262

@@ -68,7 +68,7 @@ object Test6 with
6868
if x != null then f(x, 1) // error: dropping not null check typechecks OK, but gives incompatible result type
6969
else x
7070

71-
object Test7 with
71+
object Test7:
7272
import compiletime.byName
7373

7474
def f(x: String, y: String) = x

tests/neg-custom-args/explicit-nulls/byname-nullables1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
def f(op: => Boolean): Unit = ()
22
def f(op: Int): Unit = ()
33

4-
class C with
4+
class C:
55
var fld: String | Null = null
66

77
def test() =

tests/neg/case-semi.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
object Test with
1+
object Test:
22
type X = Int
33
val x: X = 1
44

tests/neg/endmarkers1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ def f7[T](x: Option[T]) = x match
44
case None =>
55
end if // error: misaligned end marker
66

7-
object Test4 with
7+
object Test4:
88
def f[T](x: Option[T]) = x match
99
case Some(y) =>
1010
case None =>

tests/neg/i6900.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
object Test2 {
22

33
// Works with extension method
4-
extension on [A](a: A) with
4+
extension on [A](a: A):
55
def foo[C]: C => A = _ => a // error: extension method cannot have type parameters
66

77
1.foo.foo

tests/neg/i7526.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
type Tr[-I, +O, +A] = I => (O, A)
22

3-
trait NetApi with
3+
trait NetApi:
44
type Comp
55

6-
trait NetDB extends NetApi with
6+
trait NetDB extends NetApi:
77
class Comp
88

99
trait NetHelper extends NetApi

tests/neg/i7529.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
extension fooOps on [A](a: A) with
1+
extension fooOps on [A](a: A):
22

33
@nonsense // error: not found: nonsense
44
def foo = ???

tests/neg/missing-implicit1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
object testObjectInstance with
1+
object testObjectInstance:
22
trait Zip[F[_]]
33
trait Traverse[F[_]] {
44
def [A, B, G[_] : Zip](fa: F[A]) traverse(f: A => G[B]): G[F[B]]
@@ -7,7 +7,7 @@ object testObjectInstance with
77
object instances {
88
given zipOption: Zip[Option] = ???
99
given traverseList: Traverse[List] = ???
10-
extension listExtension on [T](xs: List[T]) with
10+
extension listExtension on [T](xs: List[T]):
1111
def second: T = xs.tail.head
1212
def [T](xs: List[T]) first: T = xs.head
1313
}

0 commit comments

Comments
 (0)