Skip to content

Commit 6c380b2

Browse files
committed
Make with optional in extension methods
1 parent 6dd4a99 commit 6c380b2

19 files changed

+32
-31
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3544,7 +3544,7 @@ object Parsers {
35443544
val tparams = typeParamClauseOpt(ParamOwner.Def)
35453545
val extParams = paramClause(0, prefix = true)
35463546
val givenParamss = paramClauses(givenOnly = true)
3547-
accept(WITH)
3547+
possibleTemplateStart()
35483548
if !in.isNestedStart then syntaxError("Extension without extension methods")
35493549
val templ = templateBodyOpt(makeConstructor(tparams, extParams :: givenParamss), Nil, Nil)
35503550
templ.body.foreach(checkExtensionMethod(tparams, _))

docs/docs/internals/syntax.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,8 @@ GivenDef ::= [GivenSig (‘:’ | <:)] {FunArgTypes ‘=>’}
389389
| [GivenSig ‘:’] {FunArgTypes ‘=>’}
390390
ConstrApps [[‘with’] TemplateBody]
391391
GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause}
392-
ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause}
393-
‘with’ ExtMethods
394-
ExtMethods ::= ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
392+
ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause} ExtMethods
393+
ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
395394
ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’
396395
Template ::= InheritClauses [[‘with’] TemplateBody] Template(constr, parents, self, stats)
397396
InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}]

docs/docs/reference/contextual/extension-methods-new.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,19 @@ A collective extension defines one or more concrete methods that have the same t
128128
and prefix parameter. Examples:
129129

130130
```scala
131-
extension stringOps of (xs: Seq[String]) with {
131+
extension stringOps of (xs: Seq[String]) {
132132
def longestStrings: Seq[String] = {
133133
val maxLength = xs.map(_.length).max
134134
xs.filter(_.length == maxLength)
135135
}
136136
}
137137

138-
extension listOps of [T](xs: List[T]) with {
138+
extension listOps of [T](xs: List[T]) {
139139
def second = xs.tail.head
140140
def third: T = xs.tail.tail.head
141141
}
142142

143-
extension of [T](xs: List[T])(given Ordering[T]) with {
143+
extension of [T](xs: List[T])(given Ordering[T]) {
144144
def largest(n: Int) = xs.sorted.takeRight(n)
145145
}
146146
```
@@ -176,6 +176,6 @@ DefSig ::= ...
176176
ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’
177177
TmplDef ::= ...
178178
| ‘extension’ ExtensionDef
179-
ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause} ‘with’ ExtMethods
179+
ExtensionDef ::= [id] ‘of’ ExtParamClause {GivenParamClause} ExtMethods
180180
ExtMethods ::= ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’
181181
```

docs/docs/reference/contextual/relationship-implicits.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Anonymous collective extensions also get compiler synthesized names, which are f
7272

7373
For example, the extension
7474
```scala
75-
extension of [T] (xs: List[T]) with {
75+
extension of [T] (xs: List[T]) {
7676
def second = ...
7777
}
7878
```

tests/neg/extension-methods.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ object Test {
1010
"".l2 // error
1111
1.l1 // error
1212

13-
extension of [T](xs: List[T]) with {
13+
extension of [T](xs: List[T]) {
1414
def (x: Int).f1: T = ??? // error: No extension method allowed here, since collective parameters are given
1515
def f2[T]: T = ??? // error: T is already defined as type T
1616
def f3(xs: List[T]) = ??? // error: xs is already defined as value xs

tests/neg/extmethod-overload.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
object Test {
2-
extension a of (x: Int) with
2+
extension a of (x: Int) {
33
def |+| (y: Int) = x + y
4+
}
45

5-
extension b of (x: Int) with {
6+
extension b of (x: Int) {
67
def |+| (y: String) = x + y.length
78
}
89
assert((1 |+| 2) == 3) // error ambiguous

tests/neg/i5455.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ object Library {
1111
def toInt(n: Nat): Int = n
1212

1313
}
14-
extension of (x: Nat) with
14+
extension of (x: Nat) {
1515
def * (y: Nat): Nat = x * y
1616
def toInt: Int = x
17+
}
1718
}
1819

1920
object User extends App {

tests/neg/i6801.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
extension myNumericOps of [T](x: T) with {
1+
extension myNumericOps of [T](x: T) {
22
def + (y: T)(given n: Numeric[T]): T = n.plus(x,y)
33
}
44
def foo[T: Numeric](x: T) = 1f + x // error: no implicit argument of type Numeric[Any]

tests/pos/i7084.scala

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

33
type Foo
44

5-
extension of (y: Any) with {
5+
extension of (y: Any) {
66
def g(given Foo): Any = ???
77
}
88

tests/pos/i7087.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ type F[T] = T match {
66
case G[a] => String
77
}
88

9-
extension of [T](tup: T) with {
9+
extension of [T](tup: T) {
1010
def g(given Foo: F[T]) = ???
1111
}
1212

tests/pos/implicit-scope.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ object A {
99
type FlagSet = opaques.FlagSet
1010
def FlagSet(bits: Long): FlagSet = opaques.FlagSet(bits)
1111

12-
extension of (xs: FlagSet) with {
12+
extension of (xs: FlagSet) {
1313
def bits: Long = opaques.toBits(xs)
1414
def | (ys: FlagSet): FlagSet = FlagSet(xs.bits | ys.bits)
1515
}

tests/pos/mirror-implicit-scope.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import scala.deriving._
33
object Test {
44
object K0 {
55
type Generic[T] = Mirror { type Scope = K0.type ; type MirroredType = T ; type MirroredElemTypes }
6-
extension of [T <: Product](gen: Generic[T]) with {
6+
extension of [T <: Product](gen: Generic[T]) {
77
inline def toRepr (t: T): gen.MirroredElemTypes = Tuple.fromProduct(t).asInstanceOf
88
}
99
}
1010

1111
object K1 {
1212
type Generic[F[_]] = Mirror { type Scope = K1.type ; type MirroredType = F ; type MirroredElemTypes[_] }
13-
extension of [F[_] <: Product, T](gen: Generic[F]) with {
13+
extension of [F[_] <: Product, T](gen: Generic[F]) {
1414
inline def toRepr (t: F[T]): gen.MirroredElemTypes[T] = Tuple.fromProduct(t).asInstanceOf
1515
}
1616
}

tests/pos/reference/extension-methods.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ object ExtMethods with
4141

4242
List(1, 2, 3).second[Int]
4343

44-
extension stringOps of (xs: Seq[String]) with {
44+
extension stringOps of (xs: Seq[String]) {
4545
def longestStrings: Seq[String] = {
4646
val maxLength = xs.map(_.length).max
4747
xs.filter(_.length == maxLength)

tests/pos/reference/opaque.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ object Logarithms {
1212
}
1313

1414
// Extension methods define opaque types' public APIs
15-
extension of (x: Logarithm) with {
15+
extension of (x: Logarithm) {
1616
def toDouble: Double = math.exp(x)
1717
def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y))
1818
def * (y: Logarithm): Logarithm = Logarithm(x + y)

tests/pos/tasty-reflect-opaque-api-proto.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Reflect(val internal: CompilerInterface) {
1010
opaque type Term <: Tree = internal.Term
1111

1212
object Tree {
13-
extension ops of (tree: Tree) with {
13+
extension ops of (tree: Tree) {
1414
def show: String = ???
1515
}
1616
}

tests/run/extmethod-overload.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ object Test extends App {
9797
def (x: Int).yy(y: Int) = x + y
9898
}
9999

100-
extension of (x: Int) with {
100+
extension of (x: Int) {
101101
def yy (y: Int) = x - y
102102
}
103103

tests/run/extmethods2.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ object Test extends App {
1616
test(given TC())
1717

1818
object A {
19-
extension listOps of [T](xs: List[T]) with {
19+
extension listOps of [T](xs: List[T]) {
2020
def second: T = xs.tail.head
2121
def third: T = xs.tail.tail.head
2222
def concat(ys: List[T]) = xs ++ ys
2323
}
24-
extension polyListOps of [T, U](xs: List[T]) with {
24+
extension polyListOps of [T, U](xs: List[T]) {
2525
def zipp(ys: List[U]): List[(T, U)] = xs.zip(ys)
2626
}
27-
extension of (xs: List[Int]) with {
27+
extension of (xs: List[Int]) {
2828
def prod = (1 /: xs)(_ * _)
2929
}
3030
}

tests/run/i6902.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
object Test {
2-
extension of [A](a: A) with { def <<< : A = a }
3-
extension of (b: Int) with { def <<<< : Int = b }
2+
extension of [A](a: A) { def <<< : A = a }
3+
extension of (b: Int) { def <<<< : Int = b }
44

55
def main(args: Array[String]): Unit = {
66
1.<<<

tests/run/instances-anonymous.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ object Test extends App {
88

99
case class Circle(x: Double, y: Double, radius: Double)
1010

11-
extension of (c: Circle) with {
11+
extension of (c: Circle) {
1212
def circumference: Double = c.radius * math.Pi * 2
1313
}
1414

@@ -25,13 +25,13 @@ object Test extends App {
2525
val names = List("hi", "hello", "world")
2626
assert(names.longestStrings == List("hello", "world"))
2727

28-
extension of [T](xs: Seq[T]) with {
28+
extension of [T](xs: Seq[T]) {
2929
def second = xs.tail.head
3030
}
3131

3232
assert(names.longestStrings.second == "world")
3333

34-
extension of [T](xs: List[List[T]]) with {
34+
extension of [T](xs: List[List[T]]) {
3535
def flattened = xs.foldLeft[List[T]](Nil)(_ ++ _)
3636
}
3737

0 commit comments

Comments
 (0)