Skip to content

Commit 6ff952d

Browse files
committed
Update tests and docs to new extension syntax
1 parent ebd16a1 commit 6ff952d

File tree

110 files changed

+312
-302
lines changed

Some content is hidden

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

110 files changed

+312
-302
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ trait Inferencing { this: Typer =>
530530
* is in i7558.scala:
531531
*
532532
* type Tr[+V1, +O1 <: V1]
533-
* def [V2, O2 <: V2](tr: Tr[V2, O2]) sl: Tr[V2, O2] = ???
533+
* extension [V2, O2 <: V2](tr: Tr[V2, O2]) def sl: Tr[V2, O2] = ???
534534
* def as[V3, O3 <: V3](tr: Tr[V3, O3]) : Tr[V3, O3] = tr.sl
535535
*
536536
* Here we interpolate at some point V2 and O2 given the constraint

docs/docs/contributing/debugging.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ But you can also do:
8888
assertPositioned(tree.reporting(s"Tree is: $result"))
8989
```
9090

91-
`def (a: A).reporting(f: WrappedResult[T] ?=> String, p: Printer = Printers.default): A` is defined on all types. The function `f` can be written without the argument since it is a context function`. The `result` variable is a part of the `WrapperResult` – a tiny framework powering the `reporting` function. Basically, whenever you are using `reporting` on an object `A`, you can use the `result: A` variable from this function and it will be equal to the object you are calling `reporting` on.
91+
`extension (a: A) def reporting(f: WrappedResult[T] ?=> String, p: Printer = Printers.default): A` is defined on all types. The function `f` can be written without the argument since it is a context function`. The `result` variable is a part of the `WrapperResult` – a tiny framework powering the `reporting` function. Basically, whenever you are using `reporting` on an object `A`, you can use the `result: A` variable from this function and it will be equal to the object you are calling `reporting` on.
9292

9393
## Printing out trees after phases
9494
To print out the trees you are compiling after the FrontEnd (scanner, parser, namer, typer) phases:

docs/docs/reference/contextual/context-functions.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ the same way methods with context parameters are applied. For instance:
1616
given ec as ExecutionContext = ...
1717

1818
def f(x: Int): ExecutionContext ?=> Int = ...
19-
19+
2020
// could be written as follows with the type alias from above
2121
// def f(x: Int): Executable[Int] = ...
2222

@@ -125,7 +125,7 @@ object PostConditions {
125125

126126
def result[T](using r: WrappedResult[T]): T = r
127127

128-
def [T] (x: T).ensuring(condition: WrappedResult[T] ?=> Boolean): T = {
128+
extension [T](x: T) def ensuring(condition: WrappedResult[T] ?=> Boolean): T = {
129129
assert(condition(using x))
130130
x
131131
}

docs/docs/reference/contextual/derivation-macro.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ Alternatively and what is shown below is that we can call the `eqv` method
120120
directly. The `eqGen` can trigger the derivation.
121121

122122
```scala
123-
inline def [T](x: =>T) === (y: =>T)(using eq: Eq[T]): Boolean = eq.eqv(x, y)
123+
extension [T](x: =>T)
124+
inline def === (y: =>T)(using eq: Eq[T]): Boolean = eq.eqv(x, y)
124125

125126
implicit inline def eqGen[T]: Eq[T] = ${ Eq.derived[T] }
126127
```
@@ -216,7 +217,8 @@ object Eq {
216217
}
217218

218219
object Macro3 {
219-
inline def [T](x: =>T) === (y: =>T)(using eq: Eq[T]): Boolean = eq.eqv(x, y)
220+
extension [T](x: =>T)
221+
inline def === (y: =>T)(using eq: Eq[T]): Boolean = eq.eqv(x, y)
220222

221223
implicit inline def eqGen[T]: Eq[T] = ${ Eq.derived[T] }
222224
}

docs/docs/reference/contextual/givens.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ that serve for synthesizing arguments to [context parameters](./using-clauses.ht
99
```scala
1010
trait Ord[T] {
1111
def compare(x: T, y: T): Int
12-
def (x: T) < (y: T) = compare(x, y) < 0
13-
def (x: T) > (y: T) = compare(x, y) > 0
12+
extension (x: T) def < (y: T) = compare(x, y) < 0
13+
extension (x: T) def > (y: T) = compare(x, y) > 0
1414
}
1515

1616
given intOrd as Ord[Int] {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ will map to with clauses instead.
111111

112112
Extension methods have no direct counterpart in Scala 2, but they can be simulated with implicit classes. For instance, the extension method
113113
```scala
114-
def (c: Circle).circumference: Double = c.radius * math.Pi * 2
114+
extension (c: Circle) def circumference: Double = c.radius * math.Pi * 2
115115
```
116116
could be simulated to some degree by
117117
```scala

docs/docs/reference/contextual/type-classes.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ A `List` can be turned into a monad via this `given` instance:
156156
given listMonad as Monad[List]:
157157
def pure[A](x: A): List[A] =
158158
List(x)
159-
extension def [A, B](xs: List[A])
159+
extension [A, B](xs: List[A])
160160
def flatMap(f: A => List[B]): List[B] =
161161
xs.flatMap(f) // rely on the existing `flatMap` method of `List`
162162
```

docs/docs/reference/dropped-features/package-objects.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def b = a._2
2222
case class C()
2323

2424
implicit object Cops {
25-
def (x: C).pair(y: C) = (x, y)
25+
extension (x: C) def pair(y: C) = (x, y)
2626
}
2727
```
2828
There may be several source files in a package containing such toplevel definitions, and source files can freely mix toplevel value, method, and type definitions with classes and objects.

docs/docs/reference/metaprogramming/macros.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ This might be used to then perform an implicit search as in:
717717

718718

719719
```scala
720-
inline def (inline sc: StringContext).showMe(inline args: Any*): String = ${ showMeExpr('sc, 'args) }
720+
extension (inline sc: StringContext) inline def showMe(inline args: Any*): String = ${ showMeExpr('sc, 'args) }
721721

722722
private def showMeExpr(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(using QuoteContext): Expr[String] = {
723723
argsExpr match {

docs/docs/reference/other-new-features/opaques.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ object Logarithms {
2929
}
3030
```
3131

32-
This introduces `Logarithm` as a new abstract type, which is implemented as `Double`.
32+
This introduces `Logarithm` as a new abstract type, which is implemented as `Double`.
3333
The fact that `Logarithm` is the same as `Double` is only known in the scope where
3434
`Logarithm` is defined which in the above example corresponds to the object `Logarithms`.
35-
Or in other words, within the scope it is treated as type alias, but this is opaque to the outside world
35+
Or in other words, within the scope it is treated as type alias, but this is opaque to the outside world
3636
where in consequence `Logarithm` is seen as an abstract type and has nothing to do with `Double`.
3737

38-
The public API of `Logarithm` consists of the `apply` and `safe` methods defined in the companion object.
38+
The public API of `Logarithm` consists of the `apply` and `safe` methods defined in the companion object.
3939
They convert from `Double`s to `Logarithm` values. Moreover, a collective extension `logarithmOps` provides the extension methods `toDouble` that converts the other way,
40-
and operations `+` and `*` on `Logarithm` values.
40+
and operations `+` and `*` on `Logarithm` values.
4141
The following operations would be valid because they use functionality implemented in the `Logarithms` object.
4242

4343
```scala
@@ -68,10 +68,10 @@ object Access {
6868
opaque type PermissionChoice = Int
6969
opaque type Permission <: Permissions & PermissionChoice = Int
7070

71-
def (x: Permissions) & (y: Permissions): Permissions = x | y
72-
def (x: PermissionChoice) | (y: PermissionChoice): PermissionChoice = x | y
73-
def (granted: Permissions).is(required: Permissions) = (granted & required) == required
74-
def (granted: Permissions).isOneOf(required: PermissionChoice) = (granted & required) != 0
71+
extension (x: Permissions) def & (y: Permissions): Permissions = x | y
72+
extension (x: PermissionChoice) def | (y: PermissionChoice): PermissionChoice = x | y
73+
extension (granted: Permissions) def is(required: Permissions) = (granted & required) == required
74+
extension (granted: Permissions) def isOneOf(required: PermissionChoice) = (granted & required) != 0
7575

7676
val NoPermission: Permission = 0
7777
val Read: Permission = 1

docs/docs/reference/other-new-features/quoted-pattern-spec.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ type Env
4646
def notMatched = None
4747
def matched = Some(()) // aka Some(Tuple0())
4848
def matched[T](x: T) = Some(Tuple1(x))
49-
def (x: Matching) && (y: Matching) = if (x == None || y == None) None else Some(x.get ++ y.get)
49+
extension (x: Matching) def && (y: Matching) = if (x == None || y == None) None else Some(x.get ++ y.get)
5050
def fold[T](m: Mattching*)(using Env): Matching = m.fold(matched)(_ && _)
5151

5252
// `a =#= b` stands for `a` matches `b`
53-
def (scrutinee: Tree) =#= pattern: Tree)(using Env): Matching // described by cases in the tables below
53+
extension (scrutinee: Tree) def =#= pattern: Tree)(using Env): Matching // described by cases in the tables below
5454

5555
def envWith(equiv: (Symbol, Symbol)*)(using Env): Env // Adds to the current environment the fact that s1 from the scrutinee is equivalent to s2 in the pattern
5656

docs/docs/reference/other-new-features/tupled-function.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ The following defines `tupled` as [extension method](../contextual/extension-met
4444
* @tparam Args the tuple type with the same types as the function arguments of F
4545
* @tparam R the return type of F
4646
*/
47-
def [F, Args <: Tuple, R](f: F).tupled(using tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f)
47+
extension [F, Args <: Tuple, R](f: F)
48+
def tupled(using tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f)
4849
```
4950

5051
`TupledFunction` can be used to generalize the `Function.untupled` to a function of any arities ([full example](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-untupled.scala))
@@ -59,7 +60,8 @@ def [F, Args <: Tuple, R](f: F).tupled(using tf: TupledFunction[F, Args => R]):
5960
* @tparam Args the tuple type with the same types as the function arguments of F
6061
* @tparam R the return type of F
6162
*/
62-
def [F, Args <: Tuple, R](f: Args => R).untupled(using tf: TupledFunction[F, Args => R]): F = tf.untupled(f)
63+
extension [F, Args <: Tuple, R](f: Args => R)
64+
def untupled(using tf: TupledFunction[F, Args => R]): F = tf.untupled(f)
6365
```
6466

6567
`TupledFunction` can also be used to generalize the [`Tuple1.compose`](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-compose.scala) and [`Tuple1.andThen`](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-andThen.scala) methods to compose functions of larger arities and with functions that return tuples.
@@ -73,7 +75,8 @@ def [F, Args <: Tuple, R](f: Args => R).untupled(using tf: TupledFunction[F, Arg
7375
* @tparam GArgs the tuple type with the same types as the function arguments of G
7476
* @tparam R the return type of F
7577
*/
76-
def [F, G, FArgs <: Tuple, GArgs <: Tuple, R](f: F).compose(g: G)(using tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = {
78+
extension [F, G, FArgs <: Tuple, GArgs <: Tuple, R](f: F)
79+
def compose(g: G)(using tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = {
7780
(x: GArgs) => tf.tupled(f)(tg.tupled(g)(x))
7881
}
7982
```

tests/init/crash/i5606.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
object Test extends App {
22

3-
def [A, B](f: A => B) `$` (a: A): B = f(a)
3+
extension [A, B](f: A => B) def `$` (a: A): B = f(a)
44

55
assert((((a: Int) => a.toString()) `$` 10) == "10")
66

tests/init/crash/i7821.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ object XObject {
44
def anX: X = 5
55

66
given ops as Object {
7-
def (x: X) + (y: X): X = x + y
7+
extension (x: X) def + (y: X): X = x + y
88
}
99
}
1010

@@ -14,7 +14,7 @@ object MyXObject {
1414
def anX: MyX = XObject.anX
1515

1616
given ops as Object {
17-
def (x: MyX) + (y: MyX): MyX = x + y // error: warring: Infinite recursive call
17+
extension (x: MyX) def + (y: MyX): MyX = x + y // error: warring: Infinite recursive call
1818
}
1919
}
2020

tests/neg-custom-args/fatal-warnings/i7821.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ object XObject {
44
def anX: X = 5
55

66
given ops as Object {
7-
def (x: X) + (y: X): X = x + y
7+
extension (x: X) def + (y: X): X = x + y
88
}
99
}
1010

@@ -14,7 +14,7 @@ object MyXObject {
1414
def anX: MyX = XObject.anX
1515

1616
given ops as Object {
17-
def (x: MyX) + (y: MyX): MyX = x + y // error: warring: Infinite recursive call
17+
extension (x: MyX) def + (y: MyX): MyX = x + y // error: warring: Infinite recursive call
1818
}
1919
}
2020

tests/neg-custom-args/infix.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ class C:
88

99
object C:
1010
given AnyRef:
11-
def (x: C) iop (y: Int) = ???
12-
def (x: C).mop (y: Int) = ???
13-
def (x: C) ++ (y: Int) = ???
11+
extension (x: C) @infix def iop (y: Int) = ???
12+
extension (x: C) def mop (y: Int) = ???
13+
extension (x: C) def ++ (y: Int) = ???
1414

1515
val c = C()
1616
def test() = {

tests/neg-macros/i6432/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import scala.quoted.autolift
44

55

66
object Macro {
7-
inline def (inline sc: StringContext).foo(args: String*): Unit = ${ impl('sc) }
7+
extension (inline sc: StringContext) inline def foo(args: String*): Unit = ${ impl('sc) }
88

99
def impl(sc: Expr[StringContext])(using qctx: QuoteContext) : Expr[Unit] = {
1010
import qctx.tasty._

tests/neg-macros/i6432b/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import scala.quoted.autolift
44

55

66
object Macro {
7-
inline def (inline sc: StringContext).foo(args: String*): Unit = ${ impl('sc) }
7+
extension (inline sc: StringContext) inline def foo(args: String*): Unit = ${ impl('sc) }
88

99
def impl(sc: Expr[StringContext])(using qctx: QuoteContext) : Expr[Unit] = {
1010
import qctx.tasty._

tests/neg-macros/i7698.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ def showInterpolatorImpl(sc: Expr[StringContext], argsExpr: Expr[Seq[Any]])(usin
1010
case '[ Int ] => // error
1111
???
1212

13-
inline def (inline sc: StringContext) show (args: Any*): String = ${ showInterpolatorImpl('sc, 'args) }
13+
extension (inline sc: StringContext) inline def show (args: Any*): String = ${ showInterpolatorImpl('sc, 'args) }

tests/neg-macros/reflect-inline/assert_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import scala.quoted._
22

33
object api {
4-
inline def (inline x: String).stripMargin2: String =
4+
extension (inline x: String) inline def stripMargin2: String =
55
${ stripImpl('x) }
66

77
private def stripImpl(x: Expr[String])(using qctx: QuoteContext): Expr[String] =

tests/neg-macros/tasty-string-interpolator-position-a/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import scala.language.implicitConversions
33

44
object Macro {
55

6-
implicit inline def (strCtx: => StringContext).f2(args: =>Any*): String = ${FIntepolator.apply('strCtx, 'args)}
6+
extension (strCtx: => StringContext) implicit inline def f2(args: =>Any*): String = ${FIntepolator.apply('strCtx, 'args)}
77

88
}
99

tests/neg-macros/tasty-string-interpolator-position-b/Macro_1.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import scala.language.implicitConversions
33

44
object Macro {
55

6-
implicit inline def (strCtx: => StringContext).f3(args: =>Any*): String = ${FIntepolator.apply('strCtx, 'args)}
6+
extension (strCtx: => StringContext) implicit inline def f3(args: =>Any*): String = ${FIntepolator.apply('strCtx, 'args)}
77

88
}
99

tests/neg/capture1.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ object Test extends App {
44

55
val l: mutable.Seq[String] = mutable.ArrayBuffer()
66

7-
def [T, U](xs: List[T]) emap (f: T => U): List[U] = xs.map(f)
7+
extension [T, U](xs: List[T]) def emap (f: T => U): List[U] = xs.map(f)
88

9-
def [T](xs: List[T]) ereduce (f: (T, T) => T): T = xs.reduceLeft(f)
9+
extension [T](xs: List[T]) def ereduce (f: (T, T) => T): T = xs.reduceLeft(f)
1010

11-
def [T](xs: mutable.Seq[T]) append (ys: mutable.Seq[T]): mutable.Seq[T] = xs ++ ys
11+
extension [T](xs: mutable.Seq[T]) def append (ys: mutable.Seq[T]): mutable.Seq[T] = xs ++ ys
1212

1313
List(l, mutable.ArrayBuffer(1))
1414
.emap(list => list)
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Error: tests/neg/extension-method-not-allowed.scala:3:8 -------------------------------------------------------------
2-
3 | def (c: T).f: T = ??? // error : No extension method allowed here
3-
| ^^^^^^^^^^^^^^^^^^^^^
4-
| no extension method allowed here since leading parameter was already given
1+
-- Error: tests/neg/extension-method-not-allowed.scala:3:15 ------------------------------------------------------------
2+
3 | extension (c: T) def f: T = ??? // error : No extension method allowed here
3+
| ^^^^^^^^^^^^^^^^^^^^
4+
| extension clause can only define methods
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object Test {
22
extension on[T] (t: T) {
3-
def (c: T).f: T = ??? // error : No extension method allowed here
3+
extension (c: T) def f: T = ??? // error : No extension method allowed here
44
}
55
}

tests/neg/extension-methods.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
object Test {
22

33
implicit object O {
4-
def (x: String).l1 = x.length
4+
extension (x: String) def l1 = x.length
55
def l1(x: Int) = x * x
66
def l2(x: String) = x.length
77
}
@@ -11,7 +11,7 @@ object Test {
1111
1.l1 // error
1212

1313
extension on [T](xs: List[T]) {
14-
def (x: Int).f1: T = ??? // error: No extension method allowed here, since collective parameters are given
14+
extension (x: Int) def 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
1717
}

tests/neg/extmethod-override.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
class A {
22
def f(x: Int)(y: Int): Int = 0
3-
def (x: Int).g(y: Int): Int = 1
3+
extension (x: Int) def g(y: Int): Int = 1
44
}
55
class B extends A {
6-
override def (x: Int).f(y: Int): Int = 1 // error
6+
extension (x: Int) override def f(y: Int): Int = 1 // error
77
override def g(x: Int)(y: Int): Int = 0 // error
88
}

tests/neg/i5773.scala

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
trait Semigroup[T] {
2-
def (lhs: T).append(rhs: T): T
3-
def (lhs: Int).appendS(rhs: T): T = ???
2+
extension (lhs: T) def append(rhs: T): T
3+
extension (lhs: Int) def appendS(rhs: T): T = ???
44
}
55

66
object Semigroup {
77
implicit object stringAppend extends Semigroup[String] {
8-
override def (lhs: String).append(rhs: String): String = lhs + rhs
8+
extension (lhs: String) override def append(rhs: String): String = lhs + rhs
99
}
1010

1111
implicit def sumSemigroup[N](implicit N: Numeric[N]): Semigroup[N] = new {
12-
override def (lhs: N).append(rhs: N): N = N.plus(lhs, rhs)
13-
def (lhs: Int).appendS(rhs: N): N = ??? // N.plus(lhs, rhs)
12+
extension (lhs: N) override def append(rhs: N): N = N.plus(lhs, rhs)
13+
extension (lhs: Int) def appendS(rhs: N): N = ??? // N.plus(lhs, rhs)
1414
}
1515
}
1616

tests/neg/i6662.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
opaque type Opt[A >: Null] = A
22

3-
inline def [A >: Null](x: Opt[A]) nonEmpty: Boolean = x.get != null // error: Implementation restriction
4-
inline def [A >: Null](x: Opt[A]) isEmpty: Boolean = x.get == null // error: Implementation restriction
5-
inline def [A >: Null](x: Opt[A]) isDefined: Boolean = x.nonEmpty // error: Implementation restriction
6-
inline def [A >: Null](x: Opt[A]) get: A = Opt.unOpt(x) // error: Implementation restriction
3+
extension [A >: Null](x: Opt[A]) inline def nonEmpty: Boolean = x.get != null // error: Implementation restriction
4+
extension [A >: Null](x: Opt[A]) inline def isEmpty: Boolean = x.get == null // error: Implementation restriction
5+
extension [A >: Null](x: Opt[A]) inline def isDefined: Boolean = x.nonEmpty // error: Implementation restriction
6+
extension [A >: Null](x: Opt[A]) inline def get: A = Opt.unOpt(x) // error: Implementation restriction
77

88
object Opt
99
{

tests/neg/i6762b.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ type Liftable
99
given Liftable = ???
1010

1111
implicit object ExprOps {
12-
def [T](x: T).toExpr(using Liftable): Expr[T] = ???
12+
extension [T](x: T) def toExpr(using Liftable): Expr[T] = ???
1313
}

0 commit comments

Comments
 (0)