From a7d6b4da6ee68058f797a8e05d65edefa0a44462 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 10:55:47 +0100 Subject: [PATCH 01/11] Syntax refactoring - Break out optional `with` from TemplateBody production - Disallow `new with { ...}`. --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 12 ++++++------ docs/docs/internals/syntax.md | 11 +++++------ tests/neg/new-with.scala | 1 + 3 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 tests/neg/new-with.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 62d9a086eb63..14a4291a232d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2046,7 +2046,7 @@ object Parsers { } else simpleExpr() - /** SimpleExpr ::= ‘new’ (ConstrApp [TemplateBody] | TemplateBody) + /** SimpleExpr ::= ‘new’ (ConstrApp [[‘with’] TemplateBody] | TemplateBody) * | BlockExpr * | ‘$’ ‘{’ Block ‘}’ * | Quoted @@ -2141,7 +2141,7 @@ object Parsers { } } - /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody] + /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [[‘with’] TemplateBody] * | ‘new’ TemplateBody */ def newExpr(): Tree = @@ -2150,7 +2150,7 @@ object Parsers { def reposition(t: Tree) = t.withSpan(Span(start, in.lastOffset)) possibleBracesStart() val parents = - if in.token == LBRACE || in.token == WITH then Nil + if in.token == LBRACE then Nil else constrApps(commaOK = false, templateCanFollow = true) colonAtEOLOpt() possibleTemplateStart(isNew = true) @@ -3312,7 +3312,7 @@ object Parsers { } } - /** EnumDef ::= id ClassConstr InheritClauses EnumBody + /** EnumDef ::= id ClassConstr InheritClauses [‘with’] EnumBody */ def enumDef(start: Offset, mods: Modifiers): TypeDef = atSpan(start, nameStart) { val modulName = ident() @@ -3381,7 +3381,7 @@ object Parsers { } /** GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr - * | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [TemplateBody] + * | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [[‘with’] TemplateBody] * | [id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} ExtMethods * GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} * ExtParamClause ::= [DefTypeParamClause] DefParamClause {GivenParamClause} @@ -3505,7 +3505,7 @@ object Parsers { else Nil t :: ts - /** Template ::= InheritClauses [TemplateBody] + /** Template ::= InheritClauses [[‘with’] TemplateBody] * InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}] */ def template(constr: DefDef, isEnum: Boolean = false): Template = { diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index c4784d5d4e4e..c7081751546f 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -214,7 +214,7 @@ SimpleExpr ::= Path | ‘$’ ‘{’ Block ‘}’ | Quoted | quoteId // only inside splices - | ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody] New(constr | templ) + | ‘new’ ConstrApp {‘with’ ConstrApp} [[‘with’] TemplateBody] New(constr | templ) | ‘new’ TemplateBody | ‘(’ ExprsInParens ‘)’ Parens(exprs) | SimpleExpr ‘.’ id Select(expr, id) @@ -383,15 +383,15 @@ ClassDef ::= id ClassConstr [Template] ClassConstr ::= [ClsTypeParamClause] [ConstrMods] ClsParamClauses with DefDef(_, , Nil, vparamss, EmptyTree, EmptyTree) as first stat ConstrMods ::= {Annotation} [AccessModifier] ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor -EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template) +EnumDef ::= id ClassConstr InheritClauses [‘with’] EnumBody EnumDef(mods, name, tparams, template) GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr - | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [TemplateBody] + | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [[‘with’] TemplateBody] | [[id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} ExtMethods GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’ ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’ -Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats) +Template ::= InheritClauses [[‘with’] TemplateBody] Template(constr, parents, self, stats) InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}] ConstrApps ::= ConstrApp {(‘,’ | ‘with’) ConstrApp} ConstrApp ::= AnnotType {ParArgumentExprs} Apply(tp, args) @@ -399,8 +399,7 @@ ConstrExpr ::= SelfInvocation | ‘{’ SelfInvocation {semi BlockStat} ‘}’ SelfInvocation ::= ‘this’ ArgumentExprs {ArgumentExprs} -TemplateBody ::= [nl | ‘with’] - ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’ (self, stats) +TemplateBody ::= [nl] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’ (self, stats) TemplateStat ::= Import | Export | {Annotation [nl]} {Modifier} Def diff --git a/tests/neg/new-with.scala b/tests/neg/new-with.scala new file mode 100644 index 000000000000..a4a18e2406d5 --- /dev/null +++ b/tests/neg/new-with.scala @@ -0,0 +1 @@ +val x = new with { } // error \ No newline at end of file From 7475bcfdd26b49b42106e605fee8400ec2591b17 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 14:35:03 +0100 Subject: [PATCH 02/11] Drop criticism point in contextual abstractions motivation We don't actually solve this one. `given` still applies to all parameters in a clause. --- docs/docs/reference/contextual/motivation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/reference/contextual/motivation.md b/docs/docs/reference/contextual/motivation.md index 89677c0fe08b..f0277de5d014 100644 --- a/docs/docs/reference/contextual/motivation.md +++ b/docs/docs/reference/contextual/motivation.md @@ -29,7 +29,7 @@ Particular criticisms are: 3. The syntax of implicit definitions is too minimal. It consists of a single modifier, `implicit`, that can be attached to a large number of language constructs. A problem with this for newcomers is that it conveys mechanism instead of intent. For instance, a typeclass instance is an implicit object or val if unconditional and an implicit def with implicit parameters referring to some class if conditional. This describes precisely what the implicit definitions translate to -- just drop the `implicit` modifier, and that's it! But the cues that define intent are rather indirect and can be easily misread, as demonstrated by the definitions of `i1` and `i2` above. - 4. The syntax of implicit parameters also has shortcomings. It starts with the position of `implicit` as a pseudo-modifier that applies to a whole parameter section instead of a single parameter. This represents an irregular case with respect to the rest of Scala's syntax. Furthermore, while implicit _parameters_ are designated specifically, arguments are not. Passing an argument to an implicit parameter looks like a regular application `f(arg)`. This is problematic because it means there can be confusion regarding what parameter gets instantiated in a call. For instance, in + 4. The syntax of implicit parameters also has shortcomings. While implicit _parameters_ are designated specifically, arguments are not. Passing an argument to an implicit parameter looks like a regular application `f(arg)`. This is problematic because it means there can be confusion regarding what parameter gets instantiated in a call. For instance, in ```scala def currentMap(implicit ctx: Context): Map[String, Int] ``` From 7a2cff6cbfa6c7c77c3c5f5e5858025431e6ccec Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 14:41:01 +0100 Subject: [PATCH 03/11] Use new extension method syntax --- .../src/dotty/tools/dotc/core/Flags.scala | 50 +++++++++---------- .../contextual/relationship-implicits.md | 6 +-- .../reference/other-new-features/opaques.md | 8 +-- library/src-bootstrapped/scala/IArray.scala | 2 +- tests/neg/extmethod-overload.scala | 12 ++--- tests/neg/i6801.scala | 4 +- tests/pos/i6900.scala | 31 +++++++++++- tests/pos/i7084.scala | 4 +- tests/pos/i7087.scala | 4 +- tests/pos/implicit-scope.scala | 6 +-- tests/pos/mirror-implicit-scope.scala | 8 +-- tests/pos/reference/opaque.scala | 8 +-- tests/run/extmethod-overload.scala | 6 +-- tests/run/extmethods2.scala | 8 +-- tests/run/i6902.scala | 4 +- tests/run/instances-anonymous.scala | 14 +++--- tests/run/instances.scala | 2 +- 17 files changed, 103 insertions(+), 74 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 6dcd33a15df5..de468ac884b8 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -22,16 +22,16 @@ object Flags { type Flag = opaques.Flag - given /*FlagOps*/ { + given extension (x: FlagSet) with - def (x: FlagSet) bits: Long = opaques.toBits(x) + def bits: Long = opaques.toBits(x) /** The union of the given flag sets. * Combining two FlagSets with `|` will give a FlagSet * that has the intersection of the applicability to terms/types * of the two flag sets. It is checked that the intersection is not empty. */ - def (x: FlagSet) | (y: FlagSet): FlagSet = + def | (y: FlagSet): FlagSet = if (x.bits == 0) y else if (y.bits == 0) x else { @@ -42,22 +42,22 @@ object Flags { } /** The intersection of the given flag sets */ - def (x: FlagSet) & (y: FlagSet): FlagSet = FlagSet(x.bits & y.bits) + def & (y: FlagSet): FlagSet = FlagSet(x.bits & y.bits) /** The intersection of a flag set with the complement of another flag set */ - def (x: FlagSet) &~ (y: FlagSet): FlagSet = { + def &~ (y: FlagSet): FlagSet = { val tbits = x.bits & KINDFLAGS if ((tbits & y.bits) == 0) x else FlagSet(tbits | ((x.bits & ~y.bits) & ~KINDFLAGS)) } - def (x: FlagSet) ^ (y: FlagSet) = + def ^ (y: FlagSet) = FlagSet((x.bits | y.bits) & KINDFLAGS | (x.bits ^ y.bits) & ~KINDFLAGS) /** Does the given flag set contain the given flag? * This means that both the kind flags and the carrier bits have non-empty intersection. */ - def (x: FlagSet) is (flag: Flag): Boolean = { + def is (flag: Flag): Boolean = { val fs = x.bits & flag.bits (fs & KINDFLAGS) != 0 && (fs & ~KINDFLAGS) != 0 } @@ -65,12 +65,12 @@ object Flags { /** Does the given flag set contain the given flag * and at the same time contain none of the flags in the `butNot` set? */ - def (x: FlagSet) is (flag: Flag, butNot: FlagSet): Boolean = x.is(flag) && !x.isOneOf(butNot) + def is (flag: Flag, butNot: FlagSet): Boolean = x.is(flag) && !x.isOneOf(butNot) /** Does the given flag set have a non-empty intersection with another flag set? * This means that both the kind flags and the carrier bits have non-empty intersection. */ - def (x: FlagSet) isOneOf (flags: FlagSet): Boolean = { + def isOneOf (flags: FlagSet): Boolean = { val fs = x.bits & flags.bits (fs & KINDFLAGS) != 0 && (fs & ~KINDFLAGS) != 0 } @@ -78,12 +78,12 @@ object Flags { /** Does the given flag set have a non-empty intersection with another flag set, * and at the same time contain none of the flags in the `butNot` set? */ - def (x: FlagSet) isOneOf (flags: FlagSet, butNot: FlagSet): Boolean = x.isOneOf(flags) && !x.isOneOf(butNot) + def isOneOf (flags: FlagSet, butNot: FlagSet): Boolean = x.isOneOf(flags) && !x.isOneOf(butNot) /** Does a given flag set have all of the flags of another flag set? * Pre: The intersection of the term/type flags of both sets must be non-empty. */ - def (x: FlagSet) isAllOf (flags: FlagSet): Boolean = { + def isAllOf (flags: FlagSet): Boolean = { val fs = x.bits & flags.bits ((fs & KINDFLAGS) != 0 || flags.bits == 0) && (fs >>> TYPESHIFT) == (flags.bits >>> TYPESHIFT) @@ -93,36 +93,36 @@ object Flags { * and at the same time contain none of the flags in the `butNot` set? * Pre: The intersection of the term/type flags of both sets must be non-empty. */ - def (x: FlagSet) isAllOf (flags: FlagSet, butNot: FlagSet): Boolean = x.isAllOf(flags) && !x.isOneOf(butNot) + def isAllOf (flags: FlagSet, butNot: FlagSet): Boolean = x.isAllOf(flags) && !x.isOneOf(butNot) - def (x: FlagSet) isEmpty: Boolean = (x.bits & ~KINDFLAGS) == 0 + def isEmpty: Boolean = (x.bits & ~KINDFLAGS) == 0 /** Is a given flag set a subset of another flag set? */ - def (x: FlagSet) <= (y: FlagSet): Boolean = (x.bits & y.bits) == x.bits + def <= (y: FlagSet): Boolean = (x.bits & y.bits) == x.bits /** Does the given flag set apply to terms? */ - def (x: FlagSet) isTermFlags: Boolean = (x.bits & TERMS) != 0 + def isTermFlags: Boolean = (x.bits & TERMS) != 0 /** Does the given flag set apply to terms? */ - def (x: FlagSet) isTypeFlags: Boolean = (x.bits & TYPES) != 0 + def isTypeFlags: Boolean = (x.bits & TYPES) != 0 /** The given flag set with all flags transposed to be type flags */ - def (x: FlagSet) toTypeFlags: FlagSet = if (x.bits == 0) x else FlagSet(x.bits & ~KINDFLAGS | TYPES) + def toTypeFlags: FlagSet = if (x.bits == 0) x else FlagSet(x.bits & ~KINDFLAGS | TYPES) /** The given flag set with all flags transposed to be term flags */ - def (x: FlagSet) toTermFlags: FlagSet = if (x.bits == 0) x else FlagSet(x.bits & ~KINDFLAGS | TERMS) + def toTermFlags: FlagSet = if (x.bits == 0) x else FlagSet(x.bits & ~KINDFLAGS | TERMS) /** The given flag set with all flags transposed to be common flags */ - def (x: FlagSet) toCommonFlags: FlagSet = if (x.bits == 0) x else FlagSet(x.bits | KINDFLAGS) + def toCommonFlags: FlagSet = if (x.bits == 0) x else FlagSet(x.bits | KINDFLAGS) /** The number of non-kind flags in the given flag set */ - def (x: FlagSet) numFlags: Int = java.lang.Long.bitCount(x.bits & ~KINDFLAGS) + def numFlags: Int = java.lang.Long.bitCount(x.bits & ~KINDFLAGS) /** The lowest non-kind bit set in the given flag set */ - def (x: FlagSet) firstBit: Int = java.lang.Long.numberOfTrailingZeros(x.bits & ~KINDFLAGS) + def firstBit: Int = java.lang.Long.numberOfTrailingZeros(x.bits & ~KINDFLAGS) /** The list of non-empty names of flags with given index idx that are set in the given flag set */ - private def (x: FlagSet) flagString(idx: Int): List[String] = + private def flagString(idx: Int): List[String] = if ((x.bits & (1L << idx)) == 0) Nil else { def halfString(kind: Int) = @@ -134,7 +134,7 @@ object Flags { } /** The list of non-empty names of flags that are set in teh given flag set */ - def (x: FlagSet) flagStrings(privateWithin: String): Seq[String] = { + def flagStrings(privateWithin: String): Seq[String] = { var rawStrings = (2 to MaxFlag).flatMap(x.flagString(_)) // DOTTY problem: cannot drop with (_) if (!privateWithin.isEmpty && !x.is(Protected)) rawStrings = rawStrings :+ "private" @@ -149,8 +149,8 @@ object Flags { } /** The string representation of the given flag set */ - def (x: FlagSet) flagsString: String = x.flagStrings("").mkString(" ") - } + def flagsString: String = x.flagStrings("").mkString(" ") + end given def termFlagSet(x: Long) = FlagSet(TERMS | x) diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index 318cd5dac8a7..42f716ae50cb 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -61,12 +61,12 @@ The synthesized type names are formed from Tuples are treated as transparent, i.e. a type `F[(X, Y)]` would get the synthesized name `F_X_Y`. Directly implemented function types `A => B` are represented as `A_to_B`. Function types used as arguments to other type constructors are represented as `Function`. -Anonymous given instances that define extension methods without also implementing a type +Anonymous given instances that define extension methods get their name from the name of the first extension method and the toplevel type constructor of its first parameter. For example, the given instance ```scala -given { - def (xs: List[T]) second[T] = ... +given extension [T] (xs: List[T]) { + def second = ... } ``` gets the synthesized name `given_second_of_List_T`. diff --git a/docs/docs/reference/other-new-features/opaques.md b/docs/docs/reference/other-new-features/opaques.md index f954f51d2d5d..0777b5ec027b 100644 --- a/docs/docs/reference/other-new-features/opaques.md +++ b/docs/docs/reference/other-new-features/opaques.md @@ -20,10 +20,10 @@ object Logarithms { } // Extension methods define opaque types' public APIs - given logarithmOps: { - def (x: Logarithm) toDouble: Double = math.exp(x) - def (x: Logarithm) + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) - def (x: Logarithm) * (y: Logarithm): Logarithm = Logarithm(x + y) + given logarithmOps: extension (x: Logarithm) { + def toDouble: Double = math.exp(x) + def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) + def * (y: Logarithm): Logarithm = Logarithm(x + y) } } ``` diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 3ab5cdfcdc5f..723c839b8384 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -8,7 +8,7 @@ object opaques { opaque type IArray[+T] = Array[_ <: T] /** Defines extension methods for immutable arrays */ - given arrayOps: { + given arrayOps: AnyRef { /** The selection operation on an immutable array. * diff --git a/tests/neg/extmethod-overload.scala b/tests/neg/extmethod-overload.scala index 1471c165d3c1..9916134d1783 100644 --- a/tests/neg/extmethod-overload.scala +++ b/tests/neg/extmethod-overload.scala @@ -1,14 +1,14 @@ object Test { - given A: { - def (x: Int) |+| (y: Int) = x + y - } - given B: { - def (x: Int) |+| (y: String) = x + y.length + given a: extension (x: Int) + def |+| (y: Int) = x + y + + given b: extension (x: Int) { + def |+| (y: String) = x + y.length } assert((1 |+| 2) == 3) // error ambiguous locally { - import B.|+| + import b.|+| assert((1 |+| "2") == 2) // OK } } \ No newline at end of file diff --git a/tests/neg/i6801.scala b/tests/neg/i6801.scala index 06f922fd4603..2ef624924e86 100644 --- a/tests/neg/i6801.scala +++ b/tests/neg/i6801.scala @@ -1,5 +1,5 @@ -given MyNumericOps[T]: { - def (x: T) +(y: T)(given n: Numeric[T]): T = n.plus(x,y) +given MyNumericOps: extension [T](x: T) { + def + (y: T)(given n: Numeric[T]): T = n.plus(x,y) } def foo[T: Numeric](x: T) = 1f + x // error: no implicit argument of type Numeric[Any] def bar[T: Numeric](x: T) = x + 1f // error: no implicit argument of type Numeric[Any] \ No newline at end of file diff --git a/tests/pos/i6900.scala b/tests/pos/i6900.scala index 63e01e3550ed..5f4952f7f683 100644 --- a/tests/pos/i6900.scala +++ b/tests/pos/i6900.scala @@ -1,8 +1,35 @@ -object Test { - given bla[A]: { def [C](a: A) foo: C => A = _ => a } +object Test1 { + trait Foo[A] with + def foo[C]: C => A + + // Works with old-style conversion + implicit def i2f[A](a: A): Foo[A] = new Foo[A] with + def foo[C]: C => A = _ => a + + // But not with newstyle + /* + given [A]: Conversion[A, Foo[A]] with + def apply(a: A) = new Foo[A] with + def foo[C]: C => A = _ => a + */ 1.foo.foo 1.foo.foo[String] 1.foo[String].foo 1.foo[String].foo[String] } +object Test2 { + + // Works with extension method + given extension [A, C](a: A) with + def foo: C => A = _ => a + + 1.foo.foo + + // ... but have to pass 2 parameters + 1.foo.foo[Any => Int, String] + 1.foo[Int, String].foo + 1.foo[Int, String].foo[String => Int, String] + +} + diff --git a/tests/pos/i7084.scala b/tests/pos/i7084.scala index 044ea8e06ec3..19150b595c19 100644 --- a/tests/pos/i7084.scala +++ b/tests/pos/i7084.scala @@ -2,8 +2,8 @@ object Test { type Foo - given { - def (y: Any) g(given Foo): Any = ??? + given extension (y: Any) { + def g(given Foo): Any = ??? } def f(x: Any)(given Foo): Any = { diff --git a/tests/pos/i7087.scala b/tests/pos/i7087.scala index 03e939ef7efd..38ae0470d903 100644 --- a/tests/pos/i7087.scala +++ b/tests/pos/i7087.scala @@ -6,8 +6,8 @@ type F[T] = T match { case G[a] => String } -given { - def [T](tup: T) g (given Foo: F[T]) = ??? +given extension [T](tup: T) { + def g(given Foo: F[T]) = ??? } def f(x: G[Int])(given Foo: String) = x.g \ No newline at end of file diff --git a/tests/pos/implicit-scope.scala b/tests/pos/implicit-scope.scala index 219daa1d62df..077ae40eb9d8 100644 --- a/tests/pos/implicit-scope.scala +++ b/tests/pos/implicit-scope.scala @@ -9,9 +9,9 @@ object A { type FlagSet = opaques.FlagSet def FlagSet(bits: Long): FlagSet = opaques.FlagSet(bits) - given { - def (xs: FlagSet) bits: Long = opaques.toBits(xs) - def (xs: FlagSet) | (ys: FlagSet): FlagSet = FlagSet(xs.bits | ys.bits) + given extension (xs: FlagSet) { + def bits: Long = opaques.toBits(xs) + def | (ys: FlagSet): FlagSet = FlagSet(xs.bits | ys.bits) } } diff --git a/tests/pos/mirror-implicit-scope.scala b/tests/pos/mirror-implicit-scope.scala index c06a6d21d604..615d53ad4562 100644 --- a/tests/pos/mirror-implicit-scope.scala +++ b/tests/pos/mirror-implicit-scope.scala @@ -3,15 +3,15 @@ import scala.deriving._ object Test { object K0 { type Generic[T] = Mirror { type Scope = K0.type ; type MirroredType = T ; type MirroredElemTypes } - given { - inline def [T <: Product](gen: Generic[T]) toRepr (t: T): gen.MirroredElemTypes = Tuple.fromProduct(t).asInstanceOf + given extension [T <: Product](gen: Generic[T]) { + inline def toRepr (t: T): gen.MirroredElemTypes = Tuple.fromProduct(t).asInstanceOf } } object K1 { type Generic[F[_]] = Mirror { type Scope = K1.type ; type MirroredType = F ; type MirroredElemTypes[_] } - given { - inline def [F[_] <: Product, T](gen: Generic[F]) toRepr (t: F[T]): gen.MirroredElemTypes[T] = Tuple.fromProduct(t).asInstanceOf + given extension [F[_] <: Product, T](gen: Generic[F]) { + inline def toRepr (t: F[T]): gen.MirroredElemTypes[T] = Tuple.fromProduct(t).asInstanceOf } } diff --git a/tests/pos/reference/opaque.scala b/tests/pos/reference/opaque.scala index 86b1eb7d04ae..ab813349cb8f 100644 --- a/tests/pos/reference/opaque.scala +++ b/tests/pos/reference/opaque.scala @@ -12,10 +12,10 @@ object Logarithms { } // Extension methods define opaque types' public APIs - given { - def (x: Logarithm) toDouble: Double = math.exp(x) - def (x: Logarithm) + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) - def (x: Logarithm) * (y: Logarithm): Logarithm = Logarithm(x + y) + given extension (x: Logarithm) { + def toDouble: Double = math.exp(x) + def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) + def * (y: Logarithm): Logarithm = Logarithm(x + y) } } diff --git a/tests/run/extmethod-overload.scala b/tests/run/extmethod-overload.scala index dd0fe7352eb7..673b587145df 100644 --- a/tests/run/extmethod-overload.scala +++ b/tests/run/extmethod-overload.scala @@ -22,7 +22,7 @@ object Test extends App { // Test with extension methods in given object object test1 { - given Foo: { + given Foo: AnyRef { def (x: Int) |+| (y: Int) = x + y def (x: Int) |+| (y: String) = x + y.length @@ -97,8 +97,8 @@ object Test extends App { def (x: Int) yy (y: Int) = x + y } - given { - def (x: Int) yy (y: Int) = x - y + given extension (x: Int) { + def yy (y: Int) = x - y } import D._ diff --git a/tests/run/extmethods2.scala b/tests/run/extmethods2.scala index 70cb2e108476..f16168f193e2 100644 --- a/tests/run/extmethods2.scala +++ b/tests/run/extmethods2.scala @@ -2,7 +2,7 @@ object Test extends App { class TC - given stringListOps(given TC): { + given stringListOps(given TC): Object { type T = List[String] def (x: T) foo (y: T) = (x ++ y, summon[TC]) def (x: T) bar (y: Int) = (x(0)(y), summon[TC]) @@ -16,11 +16,13 @@ object Test extends App { test(given TC()) object A { - given listOps: [T](xs: List[T]) { + given listOps: extension [T](xs: List[T]) { def second: T = xs.tail.head def third: T = xs.tail.tail.head def concat(ys: List[T]) = xs ++ ys - def zipp[U](ys: List[U]): List[(T, U)] = xs.zip(ys) + } + given polyListOps: extension [T, U](xs: List[T]) { + def zipp(ys: List[U]): List[(T, U)] = xs.zip(ys) } given extension (xs: List[Int]) { def prod = (1 /: xs)(_ * _) diff --git a/tests/run/i6902.scala b/tests/run/i6902.scala index 5996a36a09a0..807e1addb172 100644 --- a/tests/run/i6902.scala +++ b/tests/run/i6902.scala @@ -1,6 +1,6 @@ object Test { - given [A]: { def (a: A) <<< : A = a } - given { def (b: Int) <<<< : Int = b } + given extension[A](a: A) { def <<< : A = a } + given extension (b: Int) { def <<<< : Int = b } def main(args: Array[String]): Unit = { 1.<<< diff --git a/tests/run/instances-anonymous.scala b/tests/run/instances-anonymous.scala index 4e7d375df890..358534c63c3e 100644 --- a/tests/run/instances-anonymous.scala +++ b/tests/run/instances-anonymous.scala @@ -8,15 +8,15 @@ object Test extends App { case class Circle(x: Double, y: Double, radius: Double) - given { - def (c: Circle) circumference: Double = c.radius * math.Pi * 2 + given extension (c: Circle) { + def circumference: Double = c.radius * math.Pi * 2 } val circle = new Circle(1, 1, 2.0) println(circle.circumference) - given { + given AnyRef { def (xs: Seq[String]) longestStrings: Seq[String] = { val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) @@ -25,14 +25,14 @@ object Test extends App { val names = List("hi", "hello", "world") assert(names.longestStrings == List("hello", "world")) - given { - def [T](xs: Seq[T]) second = xs.tail.head + given extension [T](xs: Seq[T]) { + def second = xs.tail.head } assert(names.longestStrings.second == "world") - given { - def [T](xs: List[List[T]]) flattened = xs.foldLeft[List[T]](Nil)(_ ++ _) + given extension [T](xs: List[List[T]]) { + def flattened = xs.foldLeft[List[T]](Nil)(_ ++ _) } assert(List(names, List("!")).flattened == names :+ "!") diff --git a/tests/run/instances.scala b/tests/run/instances.scala index aeb85d01d624..27864b44a7c6 100644 --- a/tests/run/instances.scala +++ b/tests/run/instances.scala @@ -32,7 +32,7 @@ object Test extends App { def flattened = xs.foldLeft[List[T]](Nil)(_ ++ _) // A right associative op. Note: can't use given extension for this! - given prepend: { + given prepend: AnyRef { def [T](x: T) :: (xs: Seq[T]) = x +: xs } From e538e896d8907b6b0eb8345edfa02b3d886dc795 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 14:56:25 +0100 Subject: [PATCH 04/11] Don't allow two type parameter sections for extension methods Don't allow extension methods to have type parameters if collective type parameters were already given. The reason to disallow is that we don't support multiple consecutive type argument sections yet. And merging two type parameter sections into one would break a future extension where we do allow multiple consecutive type argument sections. --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 11 +++++++---- tests/neg/i6900.scala | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 tests/neg/i6900.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 14a4291a232d..5354b67fdce6 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3372,11 +3372,14 @@ object Parsers { case _ => syntaxError(em"extension clause must start with a single regular parameter", start) - def checkExtensionMethod(stat: Tree): Unit = stat match { + def checkExtensionMethod(tparams: List[Tree], stat: Tree): Unit = stat match { case stat: DefDef => if stat.mods.is(Extension) then syntaxError(i"no extension method allowed here since leading parameter was already given", stat.span) - case _ => + else if tparams.nonEmpty && stat.tparams.nonEmpty then + syntaxError(i"extension method cannot have type parameters since some were already given previously", + stat.tparams.head.span) + case stat => syntaxError(i"extension clause can only define methods", stat.span) } @@ -3406,7 +3409,7 @@ object Parsers { possibleTemplateStart() val templ = templateBodyOpt( makeConstructor(tparams, extParams :: givenParamss), Nil, Nil) - templ.body.foreach(checkExtensionMethod) + templ.body.foreach(checkExtensionMethod(tparams, _)) ModuleDef(name, templ) else var tparams: List[TypeDef] = Nil @@ -3467,7 +3470,7 @@ object Parsers { vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal))) val templ = templateBodyOpt(makeConstructor(tparams, vparamss), parents, Nil) if hasExtensionParams then - templ.body.foreach(checkExtensionMethod) + templ.body.foreach(checkExtensionMethod(tparams, _)) ModuleDef(name, templ) else if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ) else TypeDef(name.toTypeName, templ) diff --git a/tests/neg/i6900.scala b/tests/neg/i6900.scala new file mode 100644 index 000000000000..76a07ee4fe02 --- /dev/null +++ b/tests/neg/i6900.scala @@ -0,0 +1,15 @@ +object Test2 { + + // Works with extension method + given extension [A](a: A) with + def foo[C]: C => A = _ => a // error: extension method cannot have type parameters + + 1.foo.foo + + // ... but have to pass 2 parameters + 1.foo.foo[Any => Int, String] + 1.foo[Int, String].foo + 1.foo[Int, String].foo[String => Int, String] + +} + From 37c9d4213652bc63c5b897eb74d2e4a88f10d8e9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 15:00:06 +0100 Subject: [PATCH 05/11] Allow to use `with` between given parents So far we allowed `given A, B with ... ` but not `given A with B with ... ` --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 16 ++++++---------- docs/docs/internals/syntax.md | 2 +- tests/pos/multi-given.scala | 4 +++- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 5354b67fdce6..850a86e27f53 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3384,7 +3384,7 @@ object Parsers { } /** GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr - * | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [[‘with’] TemplateBody] + * | [GivenSig ‘:’] ConstrApps [[‘with’] TemplateBody] * | [id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} ExtMethods * GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} * ExtParamClause ::= [DefTypeParamClause] DefParamClause {GivenParamClause} @@ -3433,24 +3433,20 @@ object Parsers { val parents = if in.token == COLON then in.nextToken() - if in.token == LBRACE - || in.token == WITH - || in.token == LBRACKET - || in.token == LPAREN && followingIsParamOrGivenType() + if in.token == LBRACKET + || in.token == LPAREN && followingIsParamOrGivenType() then parseParams(isExtension = true) Nil else - tokenSeparated(COMMA, constrApp) + constrApps(commaOK = true, templateCanFollow = true) else if in.token == SUBTYPE then if !mods.is(Inline) then syntaxError("`<:' is only allowed for given with `inline' modifier") in.nextToken() TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil - else if name.isEmpty - && in.token != LBRACE && in.token != WITH - && !hasExtensionParams - then tokenSeparated(COMMA, constrApp) + else if name.isEmpty && !hasExtensionParams then + constrApps(commaOK = true, templateCanFollow = true) else Nil if in.token == EQUALS && parents.length == 1 && parents.head.isType then diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index c7081751546f..cf367995318e 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -385,7 +385,7 @@ ConstrMods ::= {Annotation} [AccessModifier] ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor EnumDef ::= id ClassConstr InheritClauses [‘with’] EnumBody EnumDef(mods, name, tparams, template) GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr - | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [[‘with’] TemplateBody] + | [GivenSig ‘:’] ConstrApps [[‘with’] TemplateBody] | [[id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} ExtMethods GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} diff --git a/tests/pos/multi-given.scala b/tests/pos/multi-given.scala index b3d8e59626c1..97092fc7ae00 100644 --- a/tests/pos/multi-given.scala +++ b/tests/pos/multi-given.scala @@ -5,4 +5,6 @@ trait C def fancy(given a: A, b: B, c: C) = "Fancy!" def foo(implicit a: A, b: B, c: C) = "foo" -given A, B {} \ No newline at end of file +given A, B {} + +given ops: A with B {} \ No newline at end of file From 30e1aef5bdc1d40c6014b11a47b8bca01b23d060 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 15:02:13 +0100 Subject: [PATCH 06/11] Harden a condition in Types --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- compiler/src/dotty/tools/dotc/reporting/Reporter.scala | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 25289c455127..06d8d23f33c8 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2006,7 +2006,7 @@ object Types { val idx = typeParams.indexOf(param) - if (idx < args.length) { + if (0 <= idx && idx < args.length) { val argInfo = args(idx) match { case arg: TypeBounds => val v = param.paramVariance diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index a01a9874ad77..049074aff748 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -133,8 +133,7 @@ trait Reporting { this: Context => def error(msg: => Message, pos: SourcePosition = NoSourcePosition, sticky: Boolean = false): Unit = { val fullPos = addInlineds(pos) reporter.report(if (sticky) new StickyError(msg, fullPos) else new Error(msg, fullPos)) - if (ctx.settings.YdebugError.value) - Thread.dumpStack() + if ctx.settings.YdebugError.value then Thread.dumpStack() } def error(ex: TypeError, pos: SourcePosition): Unit = { From f648da1ae71725465703cf8bbf293fc9ea57476d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 15:12:56 +0100 Subject: [PATCH 07/11] Use extension method syntax in Matcher and IArray --- library/src-bootstrapped/scala/IArray.scala | 8 ++++---- library/src/scala/internal/quoted/Matcher.scala | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/src-bootstrapped/scala/IArray.scala b/library/src-bootstrapped/scala/IArray.scala index 723c839b8384..85b7188c49a0 100644 --- a/library/src-bootstrapped/scala/IArray.scala +++ b/library/src-bootstrapped/scala/IArray.scala @@ -4,11 +4,11 @@ import reflect.ClassTag /** An immutable array. An `IArray[T]` has the same representation as an `Array[T]`, * but it cannot be updated. Unlike regular arrays, immutable arrays are covariant. */ -object opaques { +object opaques opaque type IArray[+T] = Array[_ <: T] /** Defines extension methods for immutable arrays */ - given arrayOps: AnyRef { + given arrayOps: Object with /** The selection operation on an immutable array. * @@ -38,8 +38,8 @@ object opaques { def (arr: IArray[Double]) length: Int = arr.asInstanceOf[Array[Double]].length def (arr: IArray[Object]) length: Int = arr.asInstanceOf[Array[Object]].length def [T](arr: IArray[T]) length: Int = arr.asInstanceOf[Array[T]].length - } -} +end opaques + type IArray[+T] = opaques.IArray[T] object IArray { diff --git a/library/src/scala/internal/quoted/Matcher.scala b/library/src/scala/internal/quoted/Matcher.scala index 2acfeea99207..e480f064b2da 100644 --- a/library/src/scala/internal/quoted/Matcher.scala +++ b/library/src/scala/internal/quoted/Matcher.scala @@ -86,15 +86,15 @@ private[quoted] object Matcher { case _ => notMatched } - private given treeListOps: { + private given treeListOps: extension (scrutinees: List[Tree]) with /** Check that all trees match with =?= and concatenate the results with && */ - def (scrutinees: List[Tree]) =?= (patterns: List[Tree])(given Context, Env): Matching = + def =?= (patterns: List[Tree])(given Context, Env): Matching = matchLists(scrutinees, patterns)(_ =?= _) - } + end treeListOps - private given treeOps: { + private given treeOps: extension (scrutinee0: Tree) with /** Check that the trees match and return the contents from the pattern holes. * Return None if the trees do not match otherwise return Some of a tuple containing all the contents in the holes. @@ -104,7 +104,7 @@ private[quoted] object Matcher { * @param `summon[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`. * @return `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes. */ - def (scrutinee0: Tree) =?= (pattern0: Tree)(given Context, Env): Matching = { + def =?= (pattern0: Tree)(given Context, Env): Matching = { /** Normalize the tree */ def normalize(tree: Tree): Tree = tree match { @@ -275,7 +275,7 @@ private[quoted] object Matcher { notMatched } } - } + end treeOps private def treeOptMatches(scrutinee: Option[Tree], pattern: Option[Tree])(given Context, Env): Matching = { (scrutinee, pattern) match { From 8f5efd4a841415d24ae19d2492edbee9d5dfaac0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 2 Dec 2019 17:25:14 +0100 Subject: [PATCH 08/11] Drop old extension method syntax --- community-build/community-projects/shapeless | 2 +- community-build/community-projects/xml-interpolator | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/community-build/community-projects/shapeless b/community-build/community-projects/shapeless index 8f049cfa67de..613dad5e2346 160000 --- a/community-build/community-projects/shapeless +++ b/community-build/community-projects/shapeless @@ -1 +1 @@ -Subproject commit 8f049cfa67de9c6e6fcca11cefee4f211b3eefe3 +Subproject commit 613dad5e2346eeadeb90d74c3efa408180f8f242 diff --git a/community-build/community-projects/xml-interpolator b/community-build/community-projects/xml-interpolator index 435d9e076531..f3185019a161 160000 --- a/community-build/community-projects/xml-interpolator +++ b/community-build/community-projects/xml-interpolator @@ -1 +1 @@ -Subproject commit 435d9e076531555ebc5bac8f196645a157bc6c11 +Subproject commit f3185019a16182a2fba20523ccfff6665436424a From 790a5d545aa0c870a67db14eb48e2488abb3e742 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 3 Dec 2019 09:32:27 +0100 Subject: [PATCH 09/11] Drop old extension method syntax --- .../src/dotty/tools/dotc/core/Contexts.scala | 2 +- .../dotty/tools/dotc/typer/Nullables.scala | 6 +- .../src/scala/tasty/reflect/CommentOps.scala | 2 +- .../src/scala/tasty/reflect/ConstantOps.scala | 2 +- .../src/scala/tasty/reflect/ContextOps.scala | 2 +- .../src/scala/tasty/reflect/FlagsOps.scala | 2 +- library/src/scala/tasty/reflect/IdOps.scala | 2 +- .../scala/tasty/reflect/ImplicitsOps.scala | 4 +- .../tasty/reflect/ImportSelectorOps.scala | 6 +- .../src/scala/tasty/reflect/PositionOps.scala | 4 +- .../scala/tasty/reflect/SignatureOps.scala | 2 +- .../src/scala/tasty/reflect/SymbolOps.scala | 2 +- library/src/scala/tasty/reflect/TreeOps.scala | 104 +++++++++--------- .../scala/tasty/reflect/TypeOrBoundsOps.scala | 40 +++---- tests/neg/i7529.scala | 2 +- tests/pos/reference/delegates.scala | 2 +- .../pos/tasty-reflect-opaque-api-proto.scala | 2 +- 17 files changed, 93 insertions(+), 93 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 3379ed2dc50c..16b1af74aa96 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -593,7 +593,7 @@ object Contexts { def setDebug: this.type = setSetting(base.settings.Ydebug, true) } - given ops: (c: Context) + given ops: extension (c: Context) with def addNotNullInfo(info: NotNullInfo) = c.withNotNullInfos(c.notNullInfos.extendWith(info)) diff --git a/compiler/src/dotty/tools/dotc/typer/Nullables.scala b/compiler/src/dotty/tools/dotc/typer/Nullables.scala index bb5cc87f281b..1f6fe39b2b1d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Nullables.scala +++ b/compiler/src/dotty/tools/dotc/typer/Nullables.scala @@ -137,7 +137,7 @@ object Nullables with // TODO: Add constant pattern if the constant type is not nullable case _ => false - given notNullInfoOps: (infos: List[NotNullInfo]) + given notNullInfoOps: extension (infos: List[NotNullInfo]) with /** Do the current not-null infos imply that `ref` is not null? * Not-null infos are as a history where earlier assertions and retractions replace @@ -161,7 +161,7 @@ object Nullables with then infos else info :: infos - given treeOps: (tree: Tree) + given treeOps: extension (tree: Tree) with /* The `tree` with added nullability attachment */ def withNotNullInfo(info: NotNullInfo): tree.type = @@ -251,7 +251,7 @@ object Nullables with tree.computeNullable() }.traverse(tree) - given assignOps: (tree: Assign) + given assignOps: extension (tree: Assign) with def computeAssignNullable()(given Context): tree.type = tree.lhs match case TrackedRef(ref) => tree.withNotNullInfo(NotNullInfo(Set(), Set(ref))) // TODO: refine with nullability type info diff --git a/library/src/scala/tasty/reflect/CommentOps.scala b/library/src/scala/tasty/reflect/CommentOps.scala index f3efecbac643..3fb13070cbd1 100644 --- a/library/src/scala/tasty/reflect/CommentOps.scala +++ b/library/src/scala/tasty/reflect/CommentOps.scala @@ -2,7 +2,7 @@ package scala.tasty.reflect trait CommentOps extends Core { - given CommentOps: (self: Comment) { + given CommentOps: extension (self: Comment) { /** Raw comment string */ def raw: String = internal.Comment_raw(self) diff --git a/library/src/scala/tasty/reflect/ConstantOps.scala b/library/src/scala/tasty/reflect/ConstantOps.scala index ec6c25b8c567..3623883d429d 100644 --- a/library/src/scala/tasty/reflect/ConstantOps.scala +++ b/library/src/scala/tasty/reflect/ConstantOps.scala @@ -3,7 +3,7 @@ package reflect trait ConstantOps extends Core { - given ConstantOps: (const: Constant) { + given ConstantOps: extension (const: Constant) { def value: Any = internal.Constant_value(const) } diff --git a/library/src/scala/tasty/reflect/ContextOps.scala b/library/src/scala/tasty/reflect/ContextOps.scala index 414324a8bf52..f09fcf353dc7 100644 --- a/library/src/scala/tasty/reflect/ContextOps.scala +++ b/library/src/scala/tasty/reflect/ContextOps.scala @@ -3,7 +3,7 @@ package reflect trait ContextOps extends Core { - given ContextOps: (self: Context) { + given ContextOps: extension (self: Context) { /** Returns the owner of the context */ def owner: Symbol = internal.Context_owner(self) diff --git a/library/src/scala/tasty/reflect/FlagsOps.scala b/library/src/scala/tasty/reflect/FlagsOps.scala index 10b416c33b1f..9588ab37a256 100644 --- a/library/src/scala/tasty/reflect/FlagsOps.scala +++ b/library/src/scala/tasty/reflect/FlagsOps.scala @@ -2,7 +2,7 @@ package scala.tasty.reflect trait FlagsOps extends Core { - given FlagsOps: (self: Flags) { + given FlagsOps: extension (self: Flags) { /** Is the given flag set a subset of this flag sets */ def is(that: Flags): Boolean = internal.Flags_is(self)(that) diff --git a/library/src/scala/tasty/reflect/IdOps.scala b/library/src/scala/tasty/reflect/IdOps.scala index f9fd494f6945..708c905a4403 100644 --- a/library/src/scala/tasty/reflect/IdOps.scala +++ b/library/src/scala/tasty/reflect/IdOps.scala @@ -3,7 +3,7 @@ package reflect trait IdOps extends Core { - given IsOps: (id: Id) { + given IdOps: extension (id: Id) { /** Position in the source code */ def pos(given ctx: Context): Position = internal.Id_pos(id) diff --git a/library/src/scala/tasty/reflect/ImplicitsOps.scala b/library/src/scala/tasty/reflect/ImplicitsOps.scala index 335941ac8e87..a252c351bd04 100644 --- a/library/src/scala/tasty/reflect/ImplicitsOps.scala +++ b/library/src/scala/tasty/reflect/ImplicitsOps.scala @@ -11,7 +11,7 @@ trait ImplicitsOps extends Core { @deprecated("Use _: ImplicitSearchSuccess", "") def unapply(isr: ImplicitSearchSuccess)(given ctx: Context): Option[ImplicitSearchSuccess] = Some(isr) - given SuccessOps: (self: ImplicitSearchSuccess) { + given successOps: extension (self: ImplicitSearchSuccess) { def tree(given ctx: Context): Term = internal.ImplicitSearchSuccess_tree(self) } @@ -21,7 +21,7 @@ trait ImplicitsOps extends Core { @deprecated("Use _: ImplicitSearchFailure", "") def unapply(isr: ImplicitSearchFailure)(given ctx: Context): Option[ImplicitSearchFailure] = Some(isr) - given FailureOps: (self: ImplicitSearchFailure) { + given failureOps: extension (self: ImplicitSearchFailure) { def explanation(given ctx: Context): String = internal.ImplicitSearchFailure_explanation(self) } diff --git a/library/src/scala/tasty/reflect/ImportSelectorOps.scala b/library/src/scala/tasty/reflect/ImportSelectorOps.scala index c955d3b082f0..df88dd036565 100644 --- a/library/src/scala/tasty/reflect/ImportSelectorOps.scala +++ b/library/src/scala/tasty/reflect/ImportSelectorOps.scala @@ -3,7 +3,7 @@ package reflect trait ImportSelectorOps extends Core { - given SimpleSelectorOps: (self: SimpleSelector) { + given simpleSelectorOps: extension (self: SimpleSelector) { def selection(given ctx: Context): Id = internal.SimpleSelector_selection(self) } @@ -13,7 +13,7 @@ trait ImportSelectorOps extends Core { object SimpleSelector def unapply(x: SimpleSelector)(given ctx: Context): Option[Id] = Some(x.selection) - given RenameSelectorOps: (self: RenameSelector) { + given renameSelectorOps: extension (self: RenameSelector) { def from(given ctx: Context): Id = internal.RenameSelector_from(self) @@ -26,7 +26,7 @@ trait ImportSelectorOps extends Core { object RenameSelector def unapply(x: RenameSelector)(given ctx: Context): Option[(Id, Id)] = Some((x.from, x.to)) - given OmitSelectorOps: (self: OmitSelector) { + given omitSelectorOps: extension (self: OmitSelector) { def omitted(given ctx: Context): Id = internal.SimpleSelector_omitted(self) } diff --git a/library/src/scala/tasty/reflect/PositionOps.scala b/library/src/scala/tasty/reflect/PositionOps.scala index eeaf51204df0..f52d9dc4385a 100644 --- a/library/src/scala/tasty/reflect/PositionOps.scala +++ b/library/src/scala/tasty/reflect/PositionOps.scala @@ -2,7 +2,7 @@ package scala.tasty.reflect trait PositionOps extends Core { - given PositionOps: (pos: Position) { + given positionOps: extension (pos: Position) { /** The start offset in the source file */ def start: Int = internal.Position_start(pos) @@ -33,7 +33,7 @@ trait PositionOps extends Core { } - given SourceFileOps: (sourceFile: SourceFile) { + given sourceFileOps: extension (sourceFile: SourceFile) { /** Path to this source file */ def jpath: java.nio.file.Path = internal.SourceFile_jpath(sourceFile) diff --git a/library/src/scala/tasty/reflect/SignatureOps.scala b/library/src/scala/tasty/reflect/SignatureOps.scala index ee16b2cb27f7..8e26005fa655 100644 --- a/library/src/scala/tasty/reflect/SignatureOps.scala +++ b/library/src/scala/tasty/reflect/SignatureOps.scala @@ -9,7 +9,7 @@ trait SignatureOps extends Core { Some((sig.paramSigs, sig.resultSig)) } - given SignatureOps: (sig: Signature) { + given signatureOps: extension (sig: Signature) { /** The signatures of the method parameters. * diff --git a/library/src/scala/tasty/reflect/SymbolOps.scala b/library/src/scala/tasty/reflect/SymbolOps.scala index cceaf785fe17..e3004cc404be 100644 --- a/library/src/scala/tasty/reflect/SymbolOps.scala +++ b/library/src/scala/tasty/reflect/SymbolOps.scala @@ -14,7 +14,7 @@ trait SymbolOps extends Core { selfSymbolOps: FlagsOps => internal.Symbol_noSymbol } - given SymbolOps: (self: Symbol) { + given symbolOps: extension (self: Symbol) { /** Owner of this symbol. The owner is the symbol in which this symbol is defined */ def owner(given ctx: Context): Symbol = internal.Symbol_owner(self) diff --git a/library/src/scala/tasty/reflect/TreeOps.scala b/library/src/scala/tasty/reflect/TreeOps.scala index fa8f771c82df..c015361b3662 100644 --- a/library/src/scala/tasty/reflect/TreeOps.scala +++ b/library/src/scala/tasty/reflect/TreeOps.scala @@ -5,7 +5,7 @@ trait TreeOps extends Core { // ----- Tree ----------------------------------------------------- - given TreeOps: (self: Tree) { + given TreeOps: extension (self: Tree) { /** Position in the source code */ def pos(given ctx: Context): Position = internal.Tree_pos(self) @@ -27,7 +27,7 @@ trait TreeOps extends Core { Some((tree.pid, tree.stats)) } - given PackageClauseOps: (self: PackageClause) { + given PackageClauseOps: extension (self: PackageClause) { def pid(given ctx: Context): Ref = internal.PackageClause_pid(self) def stats(given ctx: Context): List[Tree] = internal.PackageClause_stats(self) } @@ -47,7 +47,7 @@ trait TreeOps extends Core { Some((tree.expr, tree.selectors)) } - given ImportOps: (self: Import) { + given ImportOps: extension (self: Import) { def expr(given ctx: Context): Term = internal.Import_expr(self) def selectors(given ctx: Context): List[ImportSelector] = internal.Import_selectors(self) @@ -67,7 +67,7 @@ trait TreeOps extends Core { @deprecated("Use _: Definition", "") def unapply(x: Definition): Option[Definition] = Some(x) - given DefinitionOps: (self: Definition) { + given DefinitionOps: extension (self: Definition) { def name(given ctx: Context): String = internal.Definition_name(self) } @@ -87,7 +87,7 @@ trait TreeOps extends Core { Some((cdef.name, cdef.constructor, cdef.parents, cdef.derived, cdef.self, cdef.body)) } - given ClassDefOps: (self: ClassDef) { + given ClassDefOps: extension (self: ClassDef) { def constructor(given ctx: Context): DefDef = internal.ClassDef_constructor(self) def parents(given ctx: Context): List[Tree /* Term | TypeTree */] = internal.ClassDef_parents(self) def derived(given ctx: Context): List[TypeTree] = internal.ClassDef_derived(self) @@ -112,7 +112,7 @@ trait TreeOps extends Core { Some((ddef.name, ddef.typeParams, ddef.paramss, ddef.returnTpt, ddef.rhs)) } - given DefDefOps: (self: DefDef) { + given DefDefOps: extension (self: DefDef) { def typeParams(given ctx: Context): List[TypeDef] = internal.DefDef_typeParams(self) def paramss(given ctx: Context): List[List[ValDef]] = internal.DefDef_paramss(self) def returnTpt(given ctx: Context): TypeTree = internal.DefDef_returnTpt(self) // TODO rename to tpt @@ -136,7 +136,7 @@ trait TreeOps extends Core { Some((vdef.name, vdef.tpt, vdef.rhs)) } - given ValDefOps: (self: ValDef) { + given ValDefOps: extension (self: ValDef) { def tpt(given ctx: Context): TypeTree = internal.ValDef_tpt(self) def rhs(given ctx: Context): Option[Term] = internal.ValDef_rhs(self) } @@ -158,7 +158,7 @@ trait TreeOps extends Core { Some((tdef.name, tdef.rhs)) } - given TypeDefOps: (self: TypeDef) { + given TypeDefOps: extension (self: TypeDef) { def rhs(given ctx: Context): Tree /*TypeTree | TypeBoundsTree*/ = internal.TypeDef_rhs(self) } @@ -166,7 +166,7 @@ trait TreeOps extends Core { given (given Context): IsInstanceOf[PackageDef] = internal.isInstanceOfPackageDef - given PackageDefOps: (self: PackageDef) { + given PackageDefOps: extension (self: PackageDef) { def owner(given ctx: Context): PackageDef = internal.PackageDef_owner(self) def members(given ctx: Context): List[Statement] = internal.PackageDef_members(self) } @@ -182,7 +182,7 @@ trait TreeOps extends Core { // ----- Terms ---------------------------------------------------- - given TermOps: (self: Term) { + given TermOps: extension (self: Term) { def tpe(given ctx: Context): Type = internal.Term_tpe(self) def underlyingArgument(given ctx: Context): Term = internal.Term_underlyingArgument(self) def underlying(given ctx: Context): Term = internal.Term_underlying(self) @@ -251,7 +251,7 @@ trait TreeOps extends Core { given (given Context): IsInstanceOf[Ident] = internal.isInstanceOfIdent - given IdentOps: (self: Ident) { + given IdentOps: extension (self: Ident) { def name(given ctx: Context): String = internal.Ident_name(self) } @@ -306,7 +306,7 @@ trait TreeOps extends Core { Some((x.qualifier, x.name)) } - given SelectOps: (self: Select) { + given SelectOps: extension (self: Select) { def qualifier(given ctx: Context): Term = internal.Select_qualifier(self) def name(given ctx: Context): String = internal.Select_name(self) def signature(given ctx: Context): Option[Signature] = internal.Select_signature(self) @@ -334,7 +334,7 @@ trait TreeOps extends Core { Some(x.constant) } - given LiteralOps: (self: Literal) { + given LiteralOps: extension (self: Literal) { def constant(given ctx: Context): Constant = internal.Literal_constant(self) } @@ -359,7 +359,7 @@ trait TreeOps extends Core { } - given ThisOps: (self: This) { + given ThisOps: extension (self: This) { def id(given ctx: Context): Option[Id] = internal.This_id(self) } @@ -383,7 +383,7 @@ trait TreeOps extends Core { def unapply(x: New)(given ctx: Context): Option[TypeTree] = Some(x.tpt) } - given NewOps: (self: New) { + given NewOps: extension (self: New) { def tpt(given ctx: Context): TypeTree = internal.New_tpt(self) } @@ -409,7 +409,7 @@ trait TreeOps extends Core { } - given NamedArgOps: (self: NamedArg) { + given NamedArgOps: extension (self: NamedArg) { def name(given ctx: Context): String = internal.NamedArg_name(self) def value(given ctx: Context): Term = internal.NamedArg_value(self) } @@ -435,7 +435,7 @@ trait TreeOps extends Core { Some((x.fun, x.args)) } - given ApplyOps: (self: Apply) { + given ApplyOps: extension (self: Apply) { def fun(given ctx: Context): Term = internal.Apply_fun(self) def args(given ctx: Context): List[Term] = internal.Apply_args(self) } @@ -462,7 +462,7 @@ trait TreeOps extends Core { } - given TypeApplyOps: (self: TypeApply) { + given TypeApplyOps: extension (self: TypeApply) { def fun(given ctx: Context): Term = internal.TypeApply_fun(self) def args(given ctx: Context): List[TypeTree] = internal.TypeApply_args(self) } @@ -488,7 +488,7 @@ trait TreeOps extends Core { Some((x.qualifier, x.id)) } - given SuperOps: (self: Super) { + given SuperOps: extension (self: Super) { def qualifier(given ctx: Context): Term = internal.Super_qualifier(self) def id(given ctx: Context): Option[Id] = internal.Super_id(self) } @@ -515,7 +515,7 @@ trait TreeOps extends Core { } - given TypedOps: (self: Typed) { + given TypedOps: extension (self: Typed) { def expr(given ctx: Context): Term = internal.Typed_expr(self) def tpt(given ctx: Context): TypeTree = internal.Typed_tpt(self) } @@ -541,7 +541,7 @@ trait TreeOps extends Core { Some((x.lhs, x.rhs)) } - given AssignOps: (self: Assign) { + given AssignOps: extension (self: Assign) { def lhs(given ctx: Context): Term = internal.Assign_lhs(self) def rhs(given ctx: Context): Term = internal.Assign_rhs(self) } @@ -567,7 +567,7 @@ trait TreeOps extends Core { Some((x.statements, x.expr)) } - given BlockOps: (self: Block) { + given BlockOps: extension (self: Block) { def statements(given ctx: Context): List[Statement] = internal.Block_statements(self) def expr(given ctx: Context): Term = internal.Block_expr(self) } @@ -590,7 +590,7 @@ trait TreeOps extends Core { Some((x.meth, x.tpeOpt)) } - given ClosureOps: (self: Closure) { + given ClosureOps: extension (self: Closure) { def meth(given ctx: Context): Term = internal.Closure_meth(self) def tpeOpt(given ctx: Context): Option[Type] = internal.Closure_tpeOpt(self) } @@ -639,7 +639,7 @@ trait TreeOps extends Core { } - given IfOps: (self: If) { + given IfOps: extension (self: If) { def cond(given ctx: Context): Term = internal.If_cond(self) def thenp(given ctx: Context): Term = internal.If_thenp(self) def elsep(given ctx: Context): Term = internal.If_elsep(self) @@ -667,7 +667,7 @@ trait TreeOps extends Core { } - given MatchOps: (self: Match) { + given MatchOps: extension (self: Match) { def scrutinee(given ctx: Context): Term = internal.Match_scrutinee(self) def cases(given ctx: Context): List[CaseDef] = internal.Match_cases(self) } @@ -693,7 +693,7 @@ trait TreeOps extends Core { } - given GivenMatchOps: (self: GivenMatch) { + given GivenMatchOps: extension (self: GivenMatch) { def cases(given ctx: Context): List[CaseDef] = internal.GivenMatch_cases(self) } @@ -719,7 +719,7 @@ trait TreeOps extends Core { } - given TryOps: (self: Try) { + given TryOps: extension (self: Try) { def body(given ctx: Context): Term = internal.Try_body(self) def cases(given ctx: Context): List[CaseDef] = internal.Try_cases(self) def finalizer(given ctx: Context): Option[Term] = internal.Try_finalizer(self) @@ -746,7 +746,7 @@ trait TreeOps extends Core { } - given ReturnOps: (self: Return) { + given ReturnOps: extension (self: Return) { def expr(given ctx: Context): Term = internal.Return_expr(self) } @@ -769,7 +769,7 @@ trait TreeOps extends Core { } - given RepeatedOps: (self: Repeated) { + given RepeatedOps: extension (self: Repeated) { def elems(given ctx: Context): List[Term] = internal.Repeated_elems(self) def elemtpt(given ctx: Context): TypeTree = internal.Repeated_elemtpt(self) } @@ -793,7 +793,7 @@ trait TreeOps extends Core { } - given InlinedOps: (self: Inlined) { + given InlinedOps: extension (self: Inlined) { def call(given ctx: Context): Option[Tree /* Term | TypeTree */] = internal.Inlined_call(self) def bindings(given ctx: Context): List[Definition] = internal.Inlined_bindings(self) def body(given ctx: Context): Term = internal.Inlined_body(self) @@ -818,7 +818,7 @@ trait TreeOps extends Core { } - given SelectOuterOps: (self: SelectOuter) { + given SelectOuterOps: extension (self: SelectOuter) { def qualifier(given ctx: Context): Term = internal.SelectOuter_qualifier(self) def level(given ctx: Context): Int = internal.SelectOuter_level(self) } @@ -844,14 +844,14 @@ trait TreeOps extends Core { } - given WhileOps: (self: While) { + given WhileOps: extension (self: While) { def cond(given ctx: Context): Term = internal.While_cond(self) def body(given ctx: Context): Term = internal.While_body(self) } // ----- TypeTrees ------------------------------------------------ - given TypeTreeOps: (self: TypeTree) { + given TypeTreeOps: extension (self: TypeTree) { /** Type of this type tree */ def tpe(given ctx: Context): Type = internal.TypeTree_tpe(self) } @@ -879,7 +879,7 @@ trait TreeOps extends Core { given (given Context): IsInstanceOf[TypeIdent] = internal.isInstanceOfTypeIdent - given TypeIdentOps: (self: TypeIdent) { + given TypeIdentOps: extension (self: TypeIdent) { def name(given ctx: Context): String = internal.TypeIdent_name(self) } @@ -909,7 +909,7 @@ trait TreeOps extends Core { Some((x.qualifier, x.name)) } - given TypeSelectOps: (self: TypeSelect) { + given TypeSelectOps: extension (self: TypeSelect) { def qualifier(given ctx: Context): Term = internal.TypeSelect_qualifier(self) def name(given ctx: Context): String = internal.TypeSelect_name(self) } @@ -928,7 +928,7 @@ trait TreeOps extends Core { Some((x.qualifier, x.name)) } - given ProjectionOps: (self: Projection) { + given ProjectionOps: extension (self: Projection) { def qualifier(given ctx: Context): TypeTree = internal.Projection_qualifier(self) def name(given ctx: Context): String = internal.Projection_name(self) } @@ -949,7 +949,7 @@ trait TreeOps extends Core { Some(x.ref) } - given SingletonOps: (self: Singleton) { + given SingletonOps: extension (self: Singleton) { def ref(given ctx: Context): Term = internal.Singleton_ref(self) } @@ -967,7 +967,7 @@ trait TreeOps extends Core { Some((x.tpt, x.refinements)) } - given RefinedOps: (self: Refined) { + given RefinedOps: extension (self: Refined) { def tpt(given ctx: Context): TypeTree = internal.Refined_tpt(self) def refinements(given ctx: Context): List[Definition] = internal.Refined_refinements(self) } @@ -987,7 +987,7 @@ trait TreeOps extends Core { Some((x.tpt, x.args)) } - given AppliedOps: (self: Applied) { + given AppliedOps: extension (self: Applied) { def tpt(given ctx: Context): TypeTree = internal.Applied_tpt(self) def args(given ctx: Context): List[Tree /*TypeTree | TypeBoundsTree*/] = internal.Applied_args(self) } @@ -1008,7 +1008,7 @@ trait TreeOps extends Core { Some((x.arg, x.annotation)) } - given AnnotatedOps: (self: Annotated) { + given AnnotatedOps: extension (self: Annotated) { def arg(given ctx: Context): TypeTree = internal.Annotated_arg(self) def annotation(given ctx: Context): Term = internal.Annotated_annotation(self) } @@ -1029,7 +1029,7 @@ trait TreeOps extends Core { Some((x.bound, x.selector, x.cases)) } - given MatchTypeTreeOps: (self: MatchTypeTree) { + given MatchTypeTreeOps: extension (self: MatchTypeTree) { def bound(given ctx: Context): Option[TypeTree] = internal.MatchTypeTree_bound(self) def selector(given ctx: Context): TypeTree = internal.MatchTypeTree_selector(self) def cases(given ctx: Context): List[TypeCaseDef] = internal.MatchTypeTree_cases(self) @@ -1051,7 +1051,7 @@ trait TreeOps extends Core { Some(x.result) } - given ByNameOps: (self: ByName) { + given ByNameOps: extension (self: ByName) { def result(given ctx: Context): TypeTree = internal.ByName_result(self) } @@ -1070,7 +1070,7 @@ trait TreeOps extends Core { Some((tree.tparams, tree.body)) } - given LambdaTypeTreeOps: (self: LambdaTypeTree) { + given LambdaTypeTreeOps: extension (self: LambdaTypeTree) { def tparams(given ctx: Context): List[TypeDef] = internal.Lambdatparams(self) def body(given ctx: Context): Tree /*TypeTree | TypeBoundsTree*/ = internal.Lambdabody(self) } @@ -1089,7 +1089,7 @@ trait TreeOps extends Core { Some((x.name, x.body)) } - given TypeBindOps: (self: TypeBind) { + given TypeBindOps: extension (self: TypeBind) { def name(given ctx: Context): String = internal.TypeBind_name(self) def body(given ctx: Context): Tree /*TypeTree | TypeBoundsTree*/ = internal.TypeBind_body(self) } @@ -1109,14 +1109,14 @@ trait TreeOps extends Core { Some((x.aliases, x.tpt)) } - given TypeBlockOps: (self: TypeBlock) { + given TypeBlockOps: extension (self: TypeBlock) { def aliases(given ctx: Context): List[TypeDef] = internal.TypeBlock_aliases(self) def tpt(given ctx: Context): TypeTree = internal.TypeBlock_tpt(self) } // ----- TypeBoundsTrees ------------------------------------------------ - given TypeBoundsTreeOps: (self: TypeBoundsTree) { + given TypeBoundsTreeOps: extension (self: TypeBoundsTree) { def tpe(given ctx: Context): TypeBounds = internal.TypeBoundsTree_tpe(self) def low(given ctx: Context): TypeTree = internal.TypeBoundsTree_low(self) def hi(given ctx: Context): TypeTree = internal.TypeBoundsTree_hi(self) @@ -1133,7 +1133,7 @@ trait TreeOps extends Core { Some((x.low, x.hi)) } - given WildcardTypeTreeOps: (self: WildcardTypeTree) { + given WildcardTypeTreeOps: extension (self: WildcardTypeTree) { def tpe(given ctx: Context): TypeOrBounds = internal.WildcardTypeTree_tpe(self) } @@ -1151,7 +1151,7 @@ trait TreeOps extends Core { // ----- CaseDefs ------------------------------------------------ - given CaseDefOps: (caseDef: CaseDef) { + given CaseDefOps: extension (caseDef: CaseDef) { def pattern(given ctx: Context): Tree = internal.CaseDef_pattern(caseDef) def guard(given ctx: Context): Option[Term] = internal.CaseDef_guard(caseDef) def rhs(given ctx: Context): Term = internal.CaseDef_rhs(caseDef) @@ -1174,7 +1174,7 @@ trait TreeOps extends Core { Some((x.pattern, x.guard, x.rhs)) } - given TypeCaseDefOps: (caseDef: TypeCaseDef) { + given TypeCaseDefOps: extension (caseDef: TypeCaseDef) { def pattern(given ctx: Context): TypeTree = internal.TypeCaseDef_pattern(caseDef) def rhs(given ctx: Context): TypeTree = internal.TypeCaseDef_rhs(caseDef) } @@ -1213,7 +1213,7 @@ trait TreeOps extends Core { Some((pattern.name, pattern.pattern)) } - given BindOps: (bind: Bind) { + given BindOps: extension (bind: Bind) { def name(given ctx: Context): String = internal.Tree_Bind_name(bind) def pattern(given ctx: Context): Tree = internal.Tree_Bind_pattern(bind) } @@ -1232,7 +1232,7 @@ trait TreeOps extends Core { Some((x.fun, x.implicits, x.patterns)) } - given UnapplyOps: (unapply: Unapply) { + given UnapplyOps: extension (unapply: Unapply) { def fun(given ctx: Context): Term = internal.Tree_Unapply_fun(unapply) def implicits(given ctx: Context): List[Term] = internal.Tree_Unapply_implicits(unapply) def patterns(given ctx: Context): List[Tree] = internal.Tree_Unapply_patterns(unapply) @@ -1253,7 +1253,7 @@ trait TreeOps extends Core { Some(x.patterns) } - given AlternativesOps: (alternatives: Alternatives) { + given AlternativesOps: extension (alternatives: Alternatives) { def patterns(given ctx: Context): List[Tree] = internal.Tree_Alternatives_patterns(alternatives) } diff --git a/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala b/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala index d05575a83fcc..bcaf2d747dcf 100644 --- a/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala +++ b/library/src/scala/tasty/reflect/TypeOrBoundsOps.scala @@ -7,7 +7,7 @@ trait TypeOrBoundsOps extends Core { def typeOf[T: scala.quoted.Type]: Type - given TypeOps: (self: Type) { + given TypeOps: extension (self: Type) { /** Is `self` type the same as `that` type? * This is the case iff `self <:< that` and `that <:< self`. @@ -92,7 +92,7 @@ trait TypeOrBoundsOps extends Core { def unapply(x: ConstantType)(given ctx: Context): Option[Constant] = Some(x.constant) } - given ConstantTypeOps: (self: ConstantType) { + given ConstantTypeOps: extension (self: ConstantType) { def constant(given ctx: Context): Constant = internal.ConstantType_constant(self) } @@ -109,7 +109,7 @@ trait TypeOrBoundsOps extends Core { Some((x.qualifier, x.name)) } - given TermRefOps: (self: TermRef) { + given TermRefOps: extension (self: TermRef) { def qualifier(given ctx: Context): TypeOrBounds /* Type | NoPrefix */ = internal.TermRef_qualifier(self) def name(given ctx: Context): String = internal.TermRef_name(self) } @@ -125,7 +125,7 @@ trait TypeOrBoundsOps extends Core { Some((x.qualifier, x.name)) } - given TypeRefOps: (self: TypeRef) { + given TypeRefOps: extension (self: TypeRef) { def qualifier(given ctx: Context): TypeOrBounds /* Type | NoPrefix */ = internal.TypeRef_qualifier(self) def name(given ctx: Context): String = internal.TypeRef_name(self) } @@ -141,7 +141,7 @@ trait TypeOrBoundsOps extends Core { Some((x.thistpe, x.supertpe)) } - given SuperTypeOps: (self: SuperType) { + given SuperTypeOps: extension (self: SuperType) { def thistpe(given ctx: Context): Type = internal.SuperType_thistpe(self) def supertpe(given ctx: Context): Type = internal.SuperType_supertpe(self) } @@ -157,7 +157,7 @@ trait TypeOrBoundsOps extends Core { Some((x.parent, x.name, x.info)) } - given RefinementOps: (self: Refinement) { + given RefinementOps: extension (self: Refinement) { def parent(given ctx: Context): Type = internal.Refinement_parent(self) def name(given ctx: Context): String = internal.Refinement_name(self) def info(given ctx: Context): TypeOrBounds = internal.Refinement_info(self) @@ -176,7 +176,7 @@ trait TypeOrBoundsOps extends Core { Some((x.tycon, x.args)) } - given AppliedTypeOps: (self: AppliedType) { + given AppliedTypeOps: extension (self: AppliedType) { def tycon(given ctx: Context): Type = internal.AppliedType_tycon(self) def args(given ctx: Context): List[TypeOrBounds /* Type | TypeBounds */] = internal.AppliedType_args(self) } @@ -192,7 +192,7 @@ trait TypeOrBoundsOps extends Core { Some((x.underlying, x.annot)) } - given AnnotatedTypeOps: (self: AnnotatedType) { + given AnnotatedTypeOps: extension (self: AnnotatedType) { def underlying(given ctx: Context): Type = internal.AnnotatedType_underlying(self) def annot(given ctx: Context): Term = internal.AnnotatedType_annot(self) } @@ -208,7 +208,7 @@ trait TypeOrBoundsOps extends Core { Some((x.left, x.right)) } - given AndTypeOps: (self: AndType) { + given AndTypeOps: extension (self: AndType) { def left(given ctx: Context): Type = internal.AndType_left(self) def right(given ctx: Context): Type = internal.AndType_right(self) } @@ -224,7 +224,7 @@ trait TypeOrBoundsOps extends Core { Some((x.left, x.right)) } - given OrTypeOps: (self: OrType) { + given OrTypeOps: extension (self: OrType) { def left(given ctx: Context): Type = internal.OrType_left(self) def right(given ctx: Context): Type = internal.OrType_right(self) } @@ -240,7 +240,7 @@ trait TypeOrBoundsOps extends Core { Some((x.bound, x.scrutinee, x.cases)) } - given MatchTypeOps: (self: MatchType) { + given MatchTypeOps: extension (self: MatchType) { def bound(given ctx: Context): Type = internal.MatchType_bound(self) def scrutinee(given ctx: Context): Type = internal.MatchType_scrutinee(self) def cases(given ctx: Context): List[Type] = internal.MatchType_cases(self) @@ -256,7 +256,7 @@ trait TypeOrBoundsOps extends Core { def unapply(x: ByNameType)(given ctx: Context): Option[Type] = Some(x.underlying) } - given ByNameTypeOps: (self: ByNameType) { + given ByNameTypeOps: extension (self: ByNameType) { def underlying(given ctx: Context): Type = internal.ByNameType_underlying(self) } @@ -271,7 +271,7 @@ trait TypeOrBoundsOps extends Core { Some((x.binder, x.paramNum)) } - given ParamRefOps: (self: ParamRef) { + given ParamRefOps: extension (self: ParamRef) { def binder(given ctx: Context): LambdaType[TypeOrBounds] = internal.ParamRef_binder(self) def paramNum(given ctx: Context): Int = internal.ParamRef_paramNum(self) } @@ -286,7 +286,7 @@ trait TypeOrBoundsOps extends Core { def unapply(x: ThisType)(given ctx: Context): Option[Type] = Some(x.tref) } - given ThisTypeOps: (self: ThisType) { + given ThisTypeOps: extension (self: ThisType) { def tref(given ctx: Context): Type = internal.ThisType_tref(self) } @@ -300,7 +300,7 @@ trait TypeOrBoundsOps extends Core { def unapply(x: RecursiveThis)(given ctx: Context): Option[RecursiveType] = Some(x.binder) } - given RecursiveThisOps: (self: RecursiveThis) { + given RecursiveThisOps: extension (self: RecursiveThis) { def binder(given ctx: Context): RecursiveType = internal.RecursiveThis_binder(self) } @@ -314,7 +314,7 @@ trait TypeOrBoundsOps extends Core { def unapply(x: RecursiveType)(given ctx: Context): Option[Type] = Some(x.underlying) } - given RecursiveTypeOps: (self: RecursiveType) { + given RecursiveTypeOps: extension (self: RecursiveType) { def underlying(given ctx: Context): Type = internal.RecursiveType_underlying(self) } @@ -329,7 +329,7 @@ trait TypeOrBoundsOps extends Core { Some((x.paramNames, x.paramTypes, x.resType)) } - given MethodTypeOps: (self: MethodType) { + given MethodTypeOps: extension (self: MethodType) { def isImplicit: Boolean = internal.MethodType_isImplicit(self) def isErased: Boolean = internal.MethodType_isErased(self) def paramNames(given ctx: Context): List[String] = internal.MethodType_paramNames(self) @@ -348,7 +348,7 @@ trait TypeOrBoundsOps extends Core { Some((x.paramNames, x.paramBounds, x.resType)) } - given PolyTypeOps: (self: PolyType) { + given PolyTypeOps: extension (self: PolyType) { def paramNames(given ctx: Context): List[String] = internal.PolyType_paramNames(self) def paramBounds(given ctx: Context): List[TypeBounds] = internal.PolyType_paramBounds(self) def resType(given ctx: Context): Type = internal.PolyType_resType(self) @@ -365,7 +365,7 @@ trait TypeOrBoundsOps extends Core { Some((x.paramNames, x.paramBounds, x.resType)) } - given TypeLambdaOps: (self: TypeLambda) { + given TypeLambdaOps: extension (self: TypeLambda) { def paramNames(given ctx: Context): List[String] = internal.TypeLambda_paramNames(self) def paramBounds(given ctx: Context): List[TypeBounds] = internal.TypeLambda_paramBounds(self) def resType(given ctx: Context): Type = internal.TypeLambda_resType(self) @@ -383,7 +383,7 @@ trait TypeOrBoundsOps extends Core { def unapply(x: TypeBounds)(given ctx: Context): Option[(Type, Type)] = Some((x.low, x.hi)) } - given TypeBoundsOps: (self: TypeBounds) { + given TypeBoundsOps: extension (self: TypeBounds) { def low(given ctx: Context): Type = internal.TypeBounds_low(self) def hi(given ctx: Context): Type = internal.TypeBounds_hi(self) } diff --git a/tests/neg/i7529.scala b/tests/neg/i7529.scala index efdaca97c40b..dc8395f3155a 100644 --- a/tests/neg/i7529.scala +++ b/tests/neg/i7529.scala @@ -1,4 +1,4 @@ -given fooOps: [A](a: A) with +given fooOps: extension [A](a: A) with @nonsense // error: not found: nonsense def foo = ??? \ No newline at end of file diff --git a/tests/pos/reference/delegates.scala b/tests/pos/reference/delegates.scala index 2c398e4d3e66..28bb44833122 100644 --- a/tests/pos/reference/delegates.scala +++ b/tests/pos/reference/delegates.scala @@ -39,7 +39,7 @@ object Instances extends Common with if (fst != 0) fst else xs1.compareTo(ys1) end listOrd - given stringOps: (xs: Seq[String]) + given stringOps: extension (xs: Seq[String]) with def longestStrings: Seq[String] = val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) diff --git a/tests/pos/tasty-reflect-opaque-api-proto.scala b/tests/pos/tasty-reflect-opaque-api-proto.scala index a07bd8528273..8fd8a5446f24 100644 --- a/tests/pos/tasty-reflect-opaque-api-proto.scala +++ b/tests/pos/tasty-reflect-opaque-api-proto.scala @@ -10,7 +10,7 @@ class Reflect(val internal: CompilerInterface) { opaque type Term <: Tree = internal.Term object Tree { - given Ops: (tree: Tree) { + given Ops: extension (tree: Tree) { def show: String = ??? } } From b12463b9a9b49b19badca7dce3da13dce80306cd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 3 Dec 2019 11:46:55 +0100 Subject: [PATCH 10/11] Fix #7669: Implement `extended with` syntax Implement `extended with` syntax for extension methods. --- .../src/dotty/tools/dotc/core/StdNames.scala | 1 + .../dotty/tools/dotc/parsing/Parsers.scala | 127 ++++++++---------- docs/docs/internals/syntax.md | 4 +- .../reference/contextual/extension-methods.md | 6 +- .../reference/other-new-features/opaques.md | 2 +- tests/neg/extmethod-overload.scala | 4 +- tests/neg/i6801.scala | 2 +- tests/neg/i7529.scala | 2 +- tests/pos/reference/delegates.scala | 4 +- tests/pos/reference/extension-methods.scala | 6 +- .../pos/tasty-reflect-opaque-api-proto.scala | 2 +- tests/run/extension-specificity.scala | 4 +- tests/run/extmethods2.scala | 4 +- tests/run/instances.scala | 6 +- 14 files changed, 81 insertions(+), 93 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index ad5c5d5dc9f0..f3654e1ab53b 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -435,6 +435,7 @@ object StdNames { val eval: N = "eval" val eqlAny: N = "eqlAny" val ex: N = "ex" + val extended: N = "extended" val extension: N = "extension" val experimental: N = "experimental" val f: N = "f" diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 850a86e27f53..fc348a41716c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3362,16 +3362,6 @@ object Parsers { Template(constr, parents, Nil, EmptyValDef, Nil) } - /** Check that `vparamss` represents a legal collective parameter list for a given extension - */ - def checkExtensionParams(start: Offset, vparamss: List[List[ValDef]]): Unit = vparamss match - case (vparam :: Nil) :: vparamss1 if !vparam.mods.is(Given) => - vparamss1.foreach(_.foreach(vparam => - if !vparam.mods.is(Given) then - syntaxError(em"follow-on parameter in extension clause must be `given`", vparam.span))) - case _ => - syntaxError(em"extension clause must start with a single regular parameter", start) - def checkExtensionMethod(tparams: List[Tree], stat: Tree): Unit = stat match { case stat: DefDef => if stat.mods.is(Extension) then @@ -3385,22 +3375,23 @@ object Parsers { /** GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr * | [GivenSig ‘:’] ConstrApps [[‘with’] TemplateBody] - * | [id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} ExtMethods + * | [id ‘:’] ExtParamClause {GivenParamClause} ‘extended’ ‘with’ ExtMethods * GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} - * ExtParamClause ::= [DefTypeParamClause] DefParamClause {GivenParamClause} + * ExtParamClause ::= [DefTypeParamClause] DefParamClause * ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’ */ def givenDef(start: Offset, mods: Modifiers, instanceMod: Mod) = atSpan(start, nameStart) { var mods1 = addMod(mods, instanceMod) val hasGivenSig = followingIsGivenSig() - val (name, isExtension) = + val nameStart = in.offset + val (name, isOldExtension) = if isIdent && hasGivenSig then (ident(), in.token == COLON && in.lookaheadIn(nme.extension)) else (EmptyTermName, isIdent(nme.extension)) val gdef = in.endMarkerScope(if name.isEmpty then GIVEN else name) { - if isExtension then + if isOldExtension then if (in.token == COLON) in.nextToken() assert(ident() == nme.extension) val tparams = typeParamClauseOpt(ParamOwner.Def) @@ -3412,65 +3403,61 @@ object Parsers { templ.body.foreach(checkExtensionMethod(tparams, _)) ModuleDef(name, templ) else - var tparams: List[TypeDef] = Nil - var vparamss: List[List[ValDef]] = Nil - var hasExtensionParams = false - - def parseParams(isExtension: Boolean): Unit = - if isExtension && (in.token == LBRACKET || in.token == LPAREN) then - hasExtensionParams = true - if tparams.nonEmpty || vparamss.nonEmpty then - syntaxError(i"cannot have parameters before and after `:` in extension") - if in.token == LBRACKET then - tparams = typeParamClause(ParamOwner.Def) - if in.token == LPAREN && followingIsParamOrGivenType() then - val paramsStart = in.offset - vparamss = paramClauses(givenOnly = !isExtension) - if isExtension then - checkExtensionParams(paramsStart, vparamss) - - parseParams(isExtension = false) - val parents = - if in.token == COLON then - in.nextToken() - if in.token == LBRACKET - || in.token == LPAREN && followingIsParamOrGivenType() - then - parseParams(isExtension = true) - Nil - else - constrApps(commaOK = true, templateCanFollow = true) - else if in.token == SUBTYPE then - if !mods.is(Inline) then - syntaxError("`<:' is only allowed for given with `inline' modifier") - in.nextToken() - TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil - else if name.isEmpty && !hasExtensionParams then - constrApps(commaOK = true, templateCanFollow = true) + val hasLabel = !name.isEmpty && in.token == COLON + if hasLabel then in.nextToken() + val tparams = typeParamClauseOpt(ParamOwner.Def) + val paramsStart = in.offset + val vparamss = + if in.token == LPAREN && followingIsParamOrGivenType() + then paramClauses() else Nil - - if in.token == EQUALS && parents.length == 1 && parents.head.isType then + val isExtension = isIdent(nme.extended) + def checkAllGivens(vparamss: List[List[ValDef]], what: String) = + vparamss.foreach(_.foreach(vparam => + if !vparam.mods.is(Given) then syntaxError(em"$what must be `given`", vparam.span))) + if isExtension then + if !name.isEmpty && !hasLabel then + syntaxError(em"name $name of extension clause must be followed by `:`", nameStart) + vparamss match + case (vparam :: Nil) :: vparamss1 if !vparam.mods.is(Given) => + checkAllGivens(vparamss1, "follow-on parameter in extension clause") + case _ => + syntaxError("extension clause must start with a single regular parameter", paramsStart) in.nextToken() - mods1 |= Final - DefDef(name, tparams, vparamss, parents.head, subExpr()) + accept(WITH) + val (self, stats) = templateBody() + stats.foreach(checkExtensionMethod(tparams, _)) + ModuleDef(name, Template(makeConstructor(tparams, vparamss), Nil, Nil, self, stats)) else - parents match - case TypeBoundsTree(_, _) :: _ => syntaxError("`=' expected") - case _ => - possibleTemplateStart() - if hasExtensionParams then - in.observeIndented() + checkAllGivens(vparamss, "parameter of given instance") + val parents = + if hasLabel then + constrApps(commaOK = true, templateCanFollow = true) + else if in.token == SUBTYPE then + if !mods.is(Inline) then + syntaxError("`<:' is only allowed for given with `inline' modifier") + in.nextToken() + TypeBoundsTree(EmptyTree, toplevelTyp()) :: Nil + else + if !(name.isEmpty && tparams.isEmpty && vparamss.isEmpty) then + accept(COLON) + constrApps(commaOK = true, templateCanFollow = true) + if in.token == EQUALS && parents.length == 1 && parents.head.isType then + in.nextToken() + mods1 |= Final + DefDef(name, tparams, vparamss, parents.head, subExpr()) else - tparams = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal)) - vparamss = vparamss.map(_.map(vparam => + parents match + case TypeBoundsTree(_, _) :: _ => syntaxError("`=' expected") + case _ => + possibleTemplateStart() + val tparams1 = tparams.map(tparam => tparam.withMods(tparam.mods | PrivateLocal)) + val vparamss1 = vparamss.map(_.map(vparam => vparam.withMods(vparam.mods &~ Param | ParamAccessor | PrivateLocal))) - val templ = templateBodyOpt(makeConstructor(tparams, vparamss), parents, Nil) - if hasExtensionParams then - templ.body.foreach(checkExtensionMethod(tparams, _)) - ModuleDef(name, templ) - else if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ) - else TypeDef(name.toTypeName, templ) - } + val templ = templateBodyOpt(makeConstructor(tparams1, vparamss1), parents, Nil) + if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ) + else TypeDef(name.toTypeName, templ) + } finalizeDef(gdef, mods1, start) } @@ -3547,8 +3534,8 @@ object Parsers { checkNextNotIndented() Template(constr, Nil, Nil, EmptyValDef, Nil) - /** TemplateBody ::= [nl | `with'] `{' TemplateStatSeq `}' - * EnumBody ::= [nl | ‘with’] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’ + /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' + * EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’ */ def templateBodyOpt(constr: DefDef, parents: List[Tree], derived: List[Tree]): Template = val (self, stats) = diff --git a/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index cf367995318e..cd16311d5f8d 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -386,8 +386,8 @@ ObjectDef ::= id [Template] EnumDef ::= id ClassConstr InheritClauses [‘with’] EnumBody EnumDef(mods, name, tparams, template) GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr | [GivenSig ‘:’] ConstrApps [[‘with’] TemplateBody] - | [[id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} - ExtMethods + | [id ‘:’] ExtParamClause {GivenParamClause} + ‘extended’ ‘with’ ExtMethods GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’ ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’ diff --git a/docs/docs/reference/contextual/extension-methods.md b/docs/docs/reference/contextual/extension-methods.md index 956a1d620914..933d2ca723e7 100644 --- a/docs/docs/reference/contextual/extension-methods.md +++ b/docs/docs/reference/contextual/extension-methods.md @@ -126,19 +126,19 @@ List(1, 2, 3).second[Int] `given` extensions are given instances that define extension methods and nothing else. Examples: ```scala -given stringOps: extension (xs: Seq[String]) { +given stringOps: (xs: Seq[String]) extended with { def longestStrings: Seq[String] = { val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) } } -given listOps: extension [T](xs: List[T]) { +given listOps: [T](xs: List[T]) extended with { def second = xs.tail.head def third: T = xs.tail.tail.head } -given extension [T](xs: List[T])(given Ordering[T]) { +given [T](xs: List[T])(given Ordering[T]) extended with { def largest(n: Int) = xs.sorted.takeRight(n) } ``` diff --git a/docs/docs/reference/other-new-features/opaques.md b/docs/docs/reference/other-new-features/opaques.md index 0777b5ec027b..ebf77f696d5d 100644 --- a/docs/docs/reference/other-new-features/opaques.md +++ b/docs/docs/reference/other-new-features/opaques.md @@ -20,7 +20,7 @@ object Logarithms { } // Extension methods define opaque types' public APIs - given logarithmOps: extension (x: Logarithm) { + given logarithmOps: (x: Logarithm) extended with { def toDouble: Double = math.exp(x) def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) def * (y: Logarithm): Logarithm = Logarithm(x + y) diff --git a/tests/neg/extmethod-overload.scala b/tests/neg/extmethod-overload.scala index 9916134d1783..ecf6afc73402 100644 --- a/tests/neg/extmethod-overload.scala +++ b/tests/neg/extmethod-overload.scala @@ -1,8 +1,8 @@ object Test { - given a: extension (x: Int) + given a: (x: Int) extended with def |+| (y: Int) = x + y - given b: extension (x: Int) { + given b: (x: Int) extended with { def |+| (y: String) = x + y.length } assert((1 |+| 2) == 3) // error ambiguous diff --git a/tests/neg/i6801.scala b/tests/neg/i6801.scala index 2ef624924e86..94e417e7719c 100644 --- a/tests/neg/i6801.scala +++ b/tests/neg/i6801.scala @@ -1,4 +1,4 @@ -given MyNumericOps: extension [T](x: T) { +given myNumericOps: [T](x: T) extended with { def + (y: T)(given n: Numeric[T]): T = n.plus(x,y) } def foo[T: Numeric](x: T) = 1f + x // error: no implicit argument of type Numeric[Any] diff --git a/tests/neg/i7529.scala b/tests/neg/i7529.scala index dc8395f3155a..974d59b268b0 100644 --- a/tests/neg/i7529.scala +++ b/tests/neg/i7529.scala @@ -1,4 +1,4 @@ -given fooOps: extension [A](a: A) with +given fooOps: [A](a: A) extended with @nonsense // error: not found: nonsense def foo = ??? \ No newline at end of file diff --git a/tests/pos/reference/delegates.scala b/tests/pos/reference/delegates.scala index 28bb44833122..5d6f8834eaad 100644 --- a/tests/pos/reference/delegates.scala +++ b/tests/pos/reference/delegates.scala @@ -39,12 +39,12 @@ object Instances extends Common with if (fst != 0) fst else xs1.compareTo(ys1) end listOrd - given stringOps: extension (xs: Seq[String]) with + given stringOps: (xs: Seq[String]) extended with def longestStrings: Seq[String] = val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) - given extension [T](xs: List[T]) + given [T](xs: List[T]) extended with def second = xs.tail.head def third = xs.tail.tail.head diff --git a/tests/pos/reference/extension-methods.scala b/tests/pos/reference/extension-methods.scala index 343ae7149128..d8e3d566a615 100644 --- a/tests/pos/reference/extension-methods.scala +++ b/tests/pos/reference/extension-methods.scala @@ -41,19 +41,19 @@ object ExtMethods with List(1, 2, 3).second[Int] - given stringOps: extension (xs: Seq[String]) { + given stringOps: (xs: Seq[String]) extended with { def longestStrings: Seq[String] = { val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) } } - given listOps: extension [T](xs: List[T]) with + given listOps: [T](xs: List[T]) extended with def second = xs.tail.head def third: T = xs.tail.tail.head - given extension [T](xs: List[T])(given Ordering[T]) with + given [T](xs: List[T])(given Ordering[T]) extended with def largest(n: Int) = xs.sorted.takeRight(n) given stringOps1: AnyRef { diff --git a/tests/pos/tasty-reflect-opaque-api-proto.scala b/tests/pos/tasty-reflect-opaque-api-proto.scala index 8fd8a5446f24..089e3c28437d 100644 --- a/tests/pos/tasty-reflect-opaque-api-proto.scala +++ b/tests/pos/tasty-reflect-opaque-api-proto.scala @@ -10,7 +10,7 @@ class Reflect(val internal: CompilerInterface) { opaque type Term <: Tree = internal.Term object Tree { - given Ops: extension (tree: Tree) { + given ops: (tree: Tree) extended with { def show: String = ??? } } diff --git a/tests/run/extension-specificity.scala b/tests/run/extension-specificity.scala index dce5942b5682..35ac40ff1e3a 100644 --- a/tests/run/extension-specificity.scala +++ b/tests/run/extension-specificity.scala @@ -1,10 +1,10 @@ class A class B extends A -given a: extension (x: A) with +given a: (x: A) extended with def foo: Int = 1 -given b: extension (x: B) with +given b: (x: B) extended with def foo: Int = 2 @main def Test = diff --git a/tests/run/extmethods2.scala b/tests/run/extmethods2.scala index f16168f193e2..ad976a340013 100644 --- a/tests/run/extmethods2.scala +++ b/tests/run/extmethods2.scala @@ -16,12 +16,12 @@ object Test extends App { test(given TC()) object A { - given listOps: extension [T](xs: List[T]) { + given listOps: [T](xs: List[T]) extended with { def second: T = xs.tail.head def third: T = xs.tail.tail.head def concat(ys: List[T]) = xs ++ ys } - given polyListOps: extension [T, U](xs: List[T]) { + given polyListOps: [T, U](xs: List[T]) extended with { def zipp(ys: List[U]): List[(T, U)] = xs.zip(ys) } given extension (xs: List[Int]) { diff --git a/tests/run/instances.scala b/tests/run/instances.scala index 27864b44a7c6..e9520f3d5615 100644 --- a/tests/run/instances.scala +++ b/tests/run/instances.scala @@ -8,14 +8,14 @@ object Test extends App { case class Circle(x: Double, y: Double, radius: Double) - given circleOps: extension (c: Circle) with + given circleOps: (c: Circle) extended with def circumference: Double = c.radius * math.Pi * 2 val circle = new Circle(1, 1, 2.0) assert(circle.circumference == circleOps.circumference(circle)) - given stringOps: extension (xs: Seq[String]) with + given stringOps: (xs: Seq[String]) extended with def longestStrings: Seq[String] = val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) @@ -28,7 +28,7 @@ object Test extends App { assert(names.longestStrings.second == "world") - given listListOps: extension [T](xs: List[List[T]]) with + given listListOps: [T](xs: List[List[T]]) extended with def flattened = xs.foldLeft[List[T]](Nil)(_ ++ _) // A right associative op. Note: can't use given extension for this! From f41f4b87c617ac0764c4c6aca46bd28b17a3b464 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 3 Dec 2019 16:26:04 +0100 Subject: [PATCH 11/11] Change more tests to new `extended with` syntax --- compiler/src/dotty/tools/dotc/parsing/Parsers.scala | 6 ++---- docs/docs/reference/contextual/relationship-implicits.md | 2 +- tests/neg/extension-methods.scala | 2 +- tests/neg/i5455.scala | 2 +- tests/neg/i6900.scala | 2 +- tests/pos/i6900.scala | 2 +- tests/pos/i7084.scala | 2 +- tests/pos/i7087.scala | 2 +- tests/pos/implicit-scope.scala | 2 +- tests/pos/matrixOps.scala | 2 +- tests/pos/mirror-implicit-scope.scala | 4 ++-- tests/pos/reference/delegates.scala | 6 +++--- tests/pos/reference/opaque.scala | 2 +- tests/run/extmethod-overload.scala | 2 +- tests/run/extmethods2.scala | 2 +- tests/run/i6902.scala | 4 ++-- tests/run/instances-anonymous.scala | 6 +++--- tests/run/instances.scala | 2 +- 18 files changed, 25 insertions(+), 27 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index fc348a41716c..992b98fffbf5 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3546,15 +3546,13 @@ object Parsers { (EmptyValDef, Nil) Template(constr, parents, derived, self, stats) - def templateBody(): (ValDef, List[Tree]) = { + def templateBody(): (ValDef, List[Tree]) = val r = inDefScopeBraces { templateStatSeq() } - if (in.token == WITH) { + if in.token == WITH then syntaxError(EarlyDefinitionsNotSupported()) in.nextToken() template(emptyConstructor) - } r - } /* -------- STATSEQS ------------------------------------------- */ diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index 42f716ae50cb..c623cefd4115 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -65,7 +65,7 @@ Anonymous given instances that define extension methods get their name from the name of the first extension method and the toplevel type constructor of its first parameter. For example, the given instance ```scala -given extension [T] (xs: List[T]) { +given [T] (xs: List[T]) extended with { def second = ... } ``` diff --git a/tests/neg/extension-methods.scala b/tests/neg/extension-methods.scala index dc613cfdede2..4eefd041f624 100644 --- a/tests/neg/extension-methods.scala +++ b/tests/neg/extension-methods.scala @@ -10,7 +10,7 @@ object Test { "".l2 // error 1.l1 // error - given extension [T](xs: List[T]) { + given [T](xs: List[T]) extended with { def (x: Int) f1: T = ??? // error: No extension method allowed here, since collective parameters are given def f2[T]: T = ??? // error: T is already defined as type T def f3(xs: List[T]) = ??? // error: xs is already defined as value xs diff --git a/tests/neg/i5455.scala b/tests/neg/i5455.scala index dfccfdc6aaf5..c73da95e2062 100644 --- a/tests/neg/i5455.scala +++ b/tests/neg/i5455.scala @@ -11,7 +11,7 @@ object Library { def toInt(n: Nat): Int = n } - given extension (x: Nat) + given (x: Nat) extended with def * (y: Nat): Nat = x * y def toInt: Int = x } diff --git a/tests/neg/i6900.scala b/tests/neg/i6900.scala index 76a07ee4fe02..7e696e320828 100644 --- a/tests/neg/i6900.scala +++ b/tests/neg/i6900.scala @@ -1,7 +1,7 @@ object Test2 { // Works with extension method - given extension [A](a: A) with + given [A](a: A) extended with def foo[C]: C => A = _ => a // error: extension method cannot have type parameters 1.foo.foo diff --git a/tests/pos/i6900.scala b/tests/pos/i6900.scala index 5f4952f7f683..3c3b23c11b9f 100644 --- a/tests/pos/i6900.scala +++ b/tests/pos/i6900.scala @@ -21,7 +21,7 @@ object Test1 { object Test2 { // Works with extension method - given extension [A, C](a: A) with + given [A, C](a: A) extended with def foo: C => A = _ => a 1.foo.foo diff --git a/tests/pos/i7084.scala b/tests/pos/i7084.scala index 19150b595c19..b76042ee431c 100644 --- a/tests/pos/i7084.scala +++ b/tests/pos/i7084.scala @@ -2,7 +2,7 @@ object Test { type Foo - given extension (y: Any) { + given (y: Any) extended with { def g(given Foo): Any = ??? } diff --git a/tests/pos/i7087.scala b/tests/pos/i7087.scala index 38ae0470d903..c6340d61730f 100644 --- a/tests/pos/i7087.scala +++ b/tests/pos/i7087.scala @@ -6,7 +6,7 @@ type F[T] = T match { case G[a] => String } -given extension [T](tup: T) { +given [T](tup: T) extended with { def g(given Foo: F[T]) = ??? } diff --git a/tests/pos/implicit-scope.scala b/tests/pos/implicit-scope.scala index 077ae40eb9d8..813b6b42775f 100644 --- a/tests/pos/implicit-scope.scala +++ b/tests/pos/implicit-scope.scala @@ -9,7 +9,7 @@ object A { type FlagSet = opaques.FlagSet def FlagSet(bits: Long): FlagSet = opaques.FlagSet(bits) - given extension (xs: FlagSet) { + given (xs: FlagSet) extended with { def bits: Long = opaques.toBits(xs) def | (ys: FlagSet): FlagSet = FlagSet(xs.bits | ys.bits) } diff --git a/tests/pos/matrixOps.scala b/tests/pos/matrixOps.scala index c7d800c65a0a..067d23830877 100644 --- a/tests/pos/matrixOps.scala +++ b/tests/pos/matrixOps.scala @@ -3,7 +3,7 @@ object Test with type Matrix = Array[Array[Double]] type Vector = Array[Double] - given extension (m: Matrix) + given (m: Matrix) extended with def nRows = m.length def nCols = m(0).length def row(i: Int): Vector = m(i) diff --git a/tests/pos/mirror-implicit-scope.scala b/tests/pos/mirror-implicit-scope.scala index 615d53ad4562..a4c2dbcd7b3a 100644 --- a/tests/pos/mirror-implicit-scope.scala +++ b/tests/pos/mirror-implicit-scope.scala @@ -3,14 +3,14 @@ import scala.deriving._ object Test { object K0 { type Generic[T] = Mirror { type Scope = K0.type ; type MirroredType = T ; type MirroredElemTypes } - given extension [T <: Product](gen: Generic[T]) { + given [T <: Product](gen: Generic[T]) extended with { inline def toRepr (t: T): gen.MirroredElemTypes = Tuple.fromProduct(t).asInstanceOf } } object K1 { type Generic[F[_]] = Mirror { type Scope = K1.type ; type MirroredType = F ; type MirroredElemTypes[_] } - given extension [F[_] <: Product, T](gen: Generic[F]) { + given [F[_] <: Product, T](gen: Generic[F]) extended with { inline def toRepr (t: F[T]): gen.MirroredElemTypes[T] = Tuple.fromProduct(t).asInstanceOf } } diff --git a/tests/pos/reference/delegates.scala b/tests/pos/reference/delegates.scala index 5d6f8834eaad..6b9702375e9c 100644 --- a/tests/pos/reference/delegates.scala +++ b/tests/pos/reference/delegates.scala @@ -133,7 +133,7 @@ object PostConditions with def result[T](given x: WrappedResult[T]): T = x - given extension [T](x: T) + given [T](x: T) extended with def ensuring(condition: (given WrappedResult[T]) => Boolean): T = assert(condition(given x)) x @@ -153,12 +153,12 @@ object AnonymousInstances extends Common with val fst = x.compareTo(y) if (fst != 0) fst else xs1.compareTo(ys1) - given extension (xs: Seq[String]) + given (xs: Seq[String]) extended with def longestStrings: Seq[String] = val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) - given extension [T](xs: List[T]) + given [T](xs: List[T]) extended with def second = xs.tail.head given [From, To](given c: Convertible[From, To]) : Convertible[List[From], List[To]] with diff --git a/tests/pos/reference/opaque.scala b/tests/pos/reference/opaque.scala index ab813349cb8f..617fbbe17b2d 100644 --- a/tests/pos/reference/opaque.scala +++ b/tests/pos/reference/opaque.scala @@ -12,7 +12,7 @@ object Logarithms { } // Extension methods define opaque types' public APIs - given extension (x: Logarithm) { + given (x: Logarithm) extended with { def toDouble: Double = math.exp(x) def + (y: Logarithm): Logarithm = Logarithm(math.exp(x) + math.exp(y)) def * (y: Logarithm): Logarithm = Logarithm(x + y) diff --git a/tests/run/extmethod-overload.scala b/tests/run/extmethod-overload.scala index 673b587145df..fe80ccebf54a 100644 --- a/tests/run/extmethod-overload.scala +++ b/tests/run/extmethod-overload.scala @@ -97,7 +97,7 @@ object Test extends App { def (x: Int) yy (y: Int) = x + y } - given extension (x: Int) { + given (x: Int) extended with { def yy (y: Int) = x - y } diff --git a/tests/run/extmethods2.scala b/tests/run/extmethods2.scala index ad976a340013..4264b7d8b1eb 100644 --- a/tests/run/extmethods2.scala +++ b/tests/run/extmethods2.scala @@ -24,7 +24,7 @@ object Test extends App { given polyListOps: [T, U](xs: List[T]) extended with { def zipp(ys: List[U]): List[(T, U)] = xs.zip(ys) } - given extension (xs: List[Int]) { + given (xs: List[Int]) extended with { def prod = (1 /: xs)(_ * _) } } diff --git a/tests/run/i6902.scala b/tests/run/i6902.scala index 807e1addb172..e3a40dd02f1e 100644 --- a/tests/run/i6902.scala +++ b/tests/run/i6902.scala @@ -1,6 +1,6 @@ object Test { - given extension[A](a: A) { def <<< : A = a } - given extension (b: Int) { def <<<< : Int = b } + given [A](a: A) extended with { def <<< : A = a } + given (b: Int) extended with { def <<<< : Int = b } def main(args: Array[String]): Unit = { 1.<<< diff --git a/tests/run/instances-anonymous.scala b/tests/run/instances-anonymous.scala index 358534c63c3e..4d4774e98bf1 100644 --- a/tests/run/instances-anonymous.scala +++ b/tests/run/instances-anonymous.scala @@ -8,7 +8,7 @@ object Test extends App { case class Circle(x: Double, y: Double, radius: Double) - given extension (c: Circle) { + given (c: Circle) extended with { def circumference: Double = c.radius * math.Pi * 2 } @@ -25,13 +25,13 @@ object Test extends App { val names = List("hi", "hello", "world") assert(names.longestStrings == List("hello", "world")) - given extension [T](xs: Seq[T]) { + given [T](xs: Seq[T]) extended with { def second = xs.tail.head } assert(names.longestStrings.second == "world") - given extension [T](xs: List[List[T]]) { + given [T](xs: List[List[T]]) extended with { def flattened = xs.foldLeft[List[T]](Nil)(_ ++ _) } diff --git a/tests/run/instances.scala b/tests/run/instances.scala index e9520f3d5615..0778d8a4fed5 100644 --- a/tests/run/instances.scala +++ b/tests/run/instances.scala @@ -23,7 +23,7 @@ object Test extends App { val names = List("hi", "hello", "world") assert(names.longestStrings == List("hello", "world")) - given extension [T](xs: Seq[T]) with + given [T](xs: Seq[T]) extended with def second = xs.tail.head assert(names.longestStrings.second == "world")