diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index dc891b235135..d3b4083c9105 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -830,14 +830,14 @@ object desugar { val impl = mdef.impl val mods = mdef.mods impl.constr match { - case DefDef(_, tparams, (vparams @ (vparam :: Nil)) :: _, _, _) => + case DefDef(_, tparams, (vparams @ (vparam :: Nil)) :: givenParamss, _, _) => assert(mods.is(Given)) return moduleDef( cpy.ModuleDef(mdef)( mdef.name, cpy.Template(impl)( constr = emptyConstructor, - body = impl.body.map(makeExtensionDef(_, tparams, vparams))))) + body = impl.body.map(makeExtensionDef(_, tparams, vparams, givenParamss))))) case _ => } @@ -892,7 +892,8 @@ object desugar { * If the given member `mdef` is not of this form, flag it as an error. */ - def makeExtensionDef(mdef: Tree, tparams: List[TypeDef], leadingParams: List[ValDef])(given ctx: Context): Tree = { + def makeExtensionDef(mdef: Tree, tparams: List[TypeDef], leadingParams: List[ValDef], + givenParamss: List[List[ValDef]])(given ctx: Context): Tree = { val allowed = "allowed here, since collective parameters are given" mdef match { case mdef: DefDef => @@ -900,8 +901,10 @@ object desugar { ctx.error(em"No extension method $allowed", mdef.sourcePos) mdef } - else cpy.DefDef(mdef)(tparams = tparams ++ mdef.tparams, vparamss = leadingParams :: mdef.vparamss) - .withFlags(Extension) + else cpy.DefDef(mdef)( + tparams = tparams ++ mdef.tparams, + vparamss = leadingParams :: givenParamss ::: mdef.vparamss + ).withFlags(Extension) case mdef: Import => mdef case mdef => diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 11ef4ef2a778..342021713c94 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -596,7 +596,7 @@ object Contexts { def setDebug: this.type = setSetting(base.settings.Ydebug, true) } - given (c: Context) + given ops: (c: Context) def addNotNullInfo(info: NotNullInfo) = c.withNotNullInfos(c.notNullInfos.extendWith(info)) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index d4f78f93155e..3748ae6b1460 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -92,7 +92,7 @@ class Definitions { * ImplicitFunctionN traits follow this template: * * trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object { - * def apply given ($x0: T0, ..., $x{N_1}: T{N-1}): R + * def apply(given $x0: T0, ..., $x{N_1}: T{N-1}): R * } * * ErasedFunctionN traits follow this template: diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala index 927a5477f311..b6c9fb0ee38b 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala @@ -167,7 +167,7 @@ Standard-Section: "ASTs" TopLevelStat* POLYtype Length result_Type NamesTypes -- A polymorphic method type `[NamesTypes]result`, used in refinements METHODtype Length result_Type NamesTypes -- A method type `(NamesTypes)result`, needed for refinements ERASEDMETHODtype Length result_Type NamesTypes -- A method type `erased (NamesTypes)result`, needed for refinements - GIVENMETHODtype Length result_Type NamesTypes -- A method type `given (NamesTypes)result`, needed for refinements + GIVENMETHODtype Length result_Type NamesTypes -- A method type `(given NamesTypes)result`, needed for refinements ERASEDGIVENMETHODtype Length result_Type NamesTypes -- A method type `given(erased NamesTypes)result`, needed for refinements IMPLICITMETHODtype Length result_Type NamesTypes -- A method type `(implicit NamesTypes)result`, needed for refinements // TODO: remove ERASEDIMPLICITMETHODtype diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 3309db3e81c8..30267960859d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2733,7 +2733,7 @@ object Parsers { * DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’ * DefTypeParam ::= {Annotation} id [HkTypeParamClause] TypeParamBounds * - * TypTypeParamCaluse::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’ + * TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’ * TypTypeParam ::= {Annotation} id [HkTypePamClause] TypeBounds * * HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’ @@ -2799,6 +2799,7 @@ object Parsers { ofClass: Boolean = false, // owner is a class ofCaseClass: Boolean = false, // owner is a case class prefix: Boolean = false, // clause precedes name of an extension method + givenOnly: Boolean = false, // only given parameters allowed firstClause: Boolean = false // clause is the first in regular list of clauses ): List[ValDef] = { var impliedMods: Modifiers = EmptyModifiers @@ -2870,6 +2871,8 @@ object Parsers { if !impliedModOpt(IMPLICIT, () => Mod.Implicit()) then impliedModOpt(GIVEN, () => Mod.Given()) impliedModOpt(ERASED, () => Mod.Erased()) + if givenOnly && !impliedMods.is(Given) then + syntaxError(ExpectedTokenButFound(GIVEN, in.token)) val isParams = !impliedMods.is(Given) || startParamTokens.contains(in.token) @@ -2890,7 +2893,7 @@ object Parsers { */ def paramClauses(ofClass: Boolean = false, ofCaseClass: Boolean = false, - ofInstance: Boolean = false): List[List[ValDef]] = + givenOnly: Boolean = false): List[List[ValDef]] = def recur(firstClause: Boolean, nparams: Int): List[List[ValDef]] = newLineOptWhenFollowedBy(LPAREN) @@ -2900,6 +2903,7 @@ object Parsers { nparams, ofClass = ofClass, ofCaseClass = ofCaseClass, + givenOnly = givenOnly, firstClause = firstClause) val lastClause = params.nonEmpty && params.head.mods.flags.is(Implicit) params :: ( @@ -3394,7 +3398,7 @@ object Parsers { /** GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr * | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [TemplateBody] - * | [id ‘:’] ExtParamClause ExtMethods + * | [id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} ExtMethods * GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} * ExtParamClause ::= [DefTypeParamClause] DefParamClause {GivenParamClause} * ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’ @@ -3402,50 +3406,66 @@ object Parsers { def givenDef(start: Offset, mods: Modifiers, instanceMod: Mod) = atSpan(start, nameStart) { var mods1 = addMod(mods, instanceMod) val hasGivenSig = followingIsGivenSig() - val name = if isIdent && hasGivenSig then ident() else EmptyTermName - indentRegion(name) { - 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(ofInstance = !isExtension) - if isExtension then - checkExtensionParams(paramsStart, vparamss) - - parseParams(isExtension = !hasGivenSig) - val parents = - if in.token == COLON then - in.nextToken() - if in.token == LBRACE - || in.token == WITH - || in.token == LBRACKET - || in.token == LPAREN && followingIsParamOrGivenType() - then - parseParams(isExtension = true) - Nil - else - tokenSeparated(COMMA, constrApp) - 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 Nil + val (name, isExtension) = + if isIdent && hasGivenSig then + (ident(), in.token == COLON && in.lookaheadIn(nme.extension)) + else + (EmptyTermName, isIdent(nme.extension)) + + val gdef = indentRegion(name) { + if isExtension then + if (in.token == COLON) in.nextToken() + assert(ident() == nme.extension) + val tparams = typeParamClauseOpt(ParamOwner.Def) + val extParams = paramClause(0, prefix = true) + val givenParamss = paramClauses(givenOnly = true) + possibleTemplateStart() + val templ = templateBodyOpt( + makeConstructor(tparams, extParams :: givenParamss), Nil, Nil) + templ.body.foreach(checkExtensionMethod) + 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 == LBRACE + || in.token == WITH + || in.token == LBRACKET + || in.token == LPAREN && followingIsParamOrGivenType() + then + parseParams(isExtension = true) + Nil + else + tokenSeparated(COMMA, constrApp) + 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 Nil - val gdef = if in.token == EQUALS && parents.length == 1 && parents.head.isType then in.nextToken() mods1 |= Final @@ -3467,9 +3487,8 @@ object Parsers { ModuleDef(name, templ) else if tparams.isEmpty && vparamss.isEmpty then ModuleDef(name, templ) else TypeDef(name.toTypeName, templ) - - finalizeDef(gdef, mods1, start) } + finalizeDef(gdef, mods1, start) } /* -------- TEMPLATES ------------------------------------------- */ diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 7b9f2e8565dd..05a93e7df547 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -895,14 +895,15 @@ object Scanners { nextToken() /** Is the token following the current one in `tokens`? */ - def lookaheadIn(tokens: BitSet): Boolean = { + def lookaheadIn(follow: BitSet | TermName): Boolean = val lookahead = LookaheadScanner() while lookahead.nextToken() lookahead.isNewLine do () - tokens.contains(lookahead.token) - } + follow match + case tokens: BitSet => tokens.contains(lookahead.token) + case name: TermName => lookahead.token == IDENTIFIER && lookahead.name == name /** Is the current token in a position where a modifier is allowed? */ def inModifierPosition(): Boolean = { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 4e903d519af8..dbd5369d25ae 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -1455,16 +1455,29 @@ trait Implicits { self: Typer => * - If alt2 is preferred over alt1, pick alt2, otherwise return an * ambiguous implicits error. */ - def disambiguate(alt1: SearchResult, alt2: SearchSuccess) = alt1 match { + def disambiguate(alt1: SearchResult, alt2: SearchSuccess) = alt1 match case alt1: SearchSuccess => - val diff = compareCandidate(alt1, alt2.ref, alt2.level) + var diff = compareCandidate(alt1, alt2.ref, alt2.level) assert(diff <= 0) // diff > 0 candidates should already have been eliminated in `rank` - if (diff < 0) alt2 - else - // numericValueTypeBreak(alt1, alt2) recoverWith - SearchFailure(new AmbiguousImplicits(alt1, alt2, pt, argument)) + + if diff == 0 then + // Fall back: if both results are extension method applications, + // compare the extension methods instead of their wrappers. + object extMethodApply with + def unapply(t: Tree): Option[Type] = t match + case t: Applications.ExtMethodApply => Some(methPart(stripApply(t.app)).tpe) + case _ => None + end extMethodApply + + (alt1.tree, alt2.tree) match + case (extMethodApply(ref1: TermRef), extMethodApply(ref2: TermRef)) => + diff = compare(ref1, ref2) + case _ => + + if diff < 0 then alt2 + else if diff > 0 then alt1 + else SearchFailure(new AmbiguousImplicits(alt1, alt2, pt, argument)) case _: SearchFailure => alt2 - } /** Faced with an ambiguous implicits failure `fail`, try to find another * alternative among `pending` that is strictly better than both ambiguous diff --git a/compiler/src/dotty/tools/dotc/typer/Nullables.scala b/compiler/src/dotty/tools/dotc/typer/Nullables.scala index d3b2d146d9c1..bb5cc87f281b 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 (infos: List[NotNullInfo]) + given notNullInfoOps: (infos: List[NotNullInfo]) /** 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 (tree: Tree) + given treeOps: (tree: Tree) /* The `tree` with added nullability attachment */ def withNotNullInfo(info: NotNullInfo): tree.type = @@ -251,7 +251,7 @@ object Nullables with tree.computeNullable() }.traverse(tree) - given (tree: Assign) + given assignOps: (tree: Assign) 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/docs/docs/internals/syntax.md b/docs/docs/internals/syntax.md index 91c6a1308d45..481f5e78dfe8 100644 --- a/docs/docs/internals/syntax.md +++ b/docs/docs/internals/syntax.md @@ -388,9 +388,10 @@ ObjectDef ::= id [Template] EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template) GivenDef ::= [GivenSig (‘:’ | <:)] Type ‘=’ Expr | [GivenSig ‘:’] [ConstrApp {‘,’ ConstrApp }] [TemplateBody] - | [GivenSig ‘:’] ExtParamClause ExtMethods + | [[id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} + ExtMethods GivenSig ::= [id] [DefTypeParamClause] {GivenParamClause} -ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’ {GivenParamClause} +ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’ ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’ Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats) InheritClauses ::= [‘extends’ ConstrApps] [‘derives’ QualId {‘,’ QualId}] diff --git a/docs/docs/reference/changed-features/numeric-literals.md b/docs/docs/reference/changed-features/numeric-literals.md index 562db962bf7a..ab67018861b3 100644 --- a/docs/docs/reference/changed-features/numeric-literals.md +++ b/docs/docs/reference/changed-features/numeric-literals.md @@ -201,7 +201,7 @@ no code that can be executed at runtime. That's why we define an intermediary cl method in the `FromDigits` given instance. That method is defined in terms of a macro implementation method `fromDigitsImpl`. Here is its definition: ```scala - private def fromDigitsImpl(digits: Expr[String]) given (ctx: QuoteContext): Expr[BigFloat] = + private def fromDigitsImpl(digits: Expr[String])(given ctx: QuoteContext): Expr[BigFloat] = digits match { case Const(ds) => try { diff --git a/docs/docs/reference/contextual/extension-methods.md b/docs/docs/reference/contextual/extension-methods.md index 70f58eb8b9b0..79e48e1a9282 100644 --- a/docs/docs/reference/contextual/extension-methods.md +++ b/docs/docs/reference/contextual/extension-methods.md @@ -81,50 +81,6 @@ and where `T` is the expected type. The following two rewritings are tried in or So `circle.circumference` translates to `CircleOps.circumference(circle)`, provided `circle` has type `Circle` and `CircleOps` is given (i.e. it is visible at the point of call or it is defined in the companion object of `Circle`). -### Given Instances for Extension Methods - -Given instances that define extension methods can also be defined without a parent. E.g., - -```scala -given stringOps: { - def (xs: Seq[String]) longestStrings: Seq[String] = { - val maxLength = xs.map(_.length).max - xs.filter(_.length == maxLength) - } -} - -given { - def [T](xs: List[T]) second = xs.tail.head -} -``` -If such given instances are anonymous (as in the second clause), their name is synthesized from the name of the first defined extension method. - -### Given Instances with Collective Parameters - -If a given instance has no parent but several extension methods one can pull out the left parameter section -as well as any type parameters of these extension methods into the given instance itself. -For instance, here is a given instance with two extension methods. -```scala -given listOps: { - def [T](xs: List[T]) second: T = xs.tail.head - def [T](xs: List[T]) third: T = xs.tail.tail.head -} -``` -The repetition in the parameters can be avoided by hoisting the parameters up into the given instance itself. The following version is a shorthand for the code above. -```scala -given listOps: [T](xs: List[T]) { - def second: T = xs.tail.head - def third: T = xs.tail.tail.head -} -``` -This syntax just adds convenience at the definition site. Applications of such extension methods are exactly the same as if their parameters were repeated in each extension method. -Examples: -```scala -val xs = List(1, 2, 3) -xs.second[Int] -ListOps.third[T](xs) -``` - ### Operators The extension method syntax also applies to the definition of operators. @@ -165,15 +121,56 @@ If an extension method has type parameters, they come immediately after the `def ```scala List(1, 2, 3).second[Int] ``` +### Given Instances for Extension Methods + +`given` extensions are given instances that define extension methods and nothing else. Examples: + +```scala +given stringOps: extension (xs: Seq[String]) { + def longestStrings: Seq[String] = { + val maxLength = xs.map(_.length).max + xs.filter(_.length == maxLength) + } +} + +given listOps: extension [T](xs: List[T]) { + def second = xs.tail.head + def third: T = xs.tail.tail.head +} + +given extension [T](xs: List[T])(given Ordering[T]) { + def largest(n: Int) = xs.sorted.takeRight(n) +} +``` +If a given extension is anonymous (as in the last clause), its name is synthesized from the name of the first defined extension method. + +The extensions above are equivalent to the following regular given instances where the implemented parent is `AnyRef` and the parameters in the `extension` clause are repeated in each extension method definition: +```scala +given stringOps: AnyRef { + def (xs: Seq[String]) longestStrings: Seq[String] = { + val maxLength = xs.map(_.length).max + xs.filter(_.length == maxLength) + } +} +given listOps: AnyRef { + def [T](xs: List[T]) second = xs.tail.head + def [T](xs: List[T]) third: T = xs.tail.tail.head +} +given given_largest_of_List_T: AnyRef { + def [T](xs: List[T]) largest (given Ordering[T])(n: Int) = + xs.sorted.takeRight(n) +} +``` ### Syntax -The required syntax extension just adds one clause for extension methods relative -to the [current syntax](../../internals/syntax.md). +Here are the syntax changes for extension methods and given extensions relative +to the [current syntax](../../internals/syntax.md). `extension` is a soft keyword, recognized only after a `given`. It can be used as an identifier everywhere else. ``` DefSig ::= ... | ExtParamClause [nl] id DefParamClauses GivenDef ::= ... - [GivenSig ‘:’] [ExtParamClause] TemplateBody -ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’ {GivenParamClause} + [id ‘:’] ‘extension’ ExtParamClause {GivenParamClause} ExtMethods +ExtParamClause ::= [DefTypeParamClause] ‘(’ DefParam ‘)’ +ExtMethods ::= [nl] ‘{’ ‘def’ DefDef {semi ‘def’ DefDef} ‘}’ ``` diff --git a/docs/docs/reference/contextual/relationship-implicits.md b/docs/docs/reference/contextual/relationship-implicits.md index ce19e6a4389a..318cd5dac8a7 100644 --- a/docs/docs/reference/contextual/relationship-implicits.md +++ b/docs/docs/reference/contextual/relationship-implicits.md @@ -21,7 +21,7 @@ Given instances can be mapped to combinations of implicit objects, classes and i ``` 2. Parameterized given instances are mapped to combinations of classes and implicit methods. E.g., ```scala - given listOrd[T](given (ord: Ord[T]): Ord[List[T]] { ... } + given listOrd[T](given ord: Ord[T]): Ord[List[T]] { ... } ``` maps to ```scala diff --git a/docs/docs/reference/metaprogramming/macros.md b/docs/docs/reference/metaprogramming/macros.md index 32c8e47bbd65..85d39e304560 100644 --- a/docs/docs/reference/metaprogramming/macros.md +++ b/docs/docs/reference/metaprogramming/macros.md @@ -170,7 +170,7 @@ quote but no splice between the parameter binding of `T` and its usage. But the code can be made phase correct by adding a binding of a `Type[T]` tag: ```scala -def reflect[T, U](f: Expr[T] => Expr[U]) given (t: Type[T]): Expr[T => U] = +def reflect[T, U](f: Expr[T] => Expr[U])(given t: Type[T]): Expr[T => U] = '{ (x: $t) => ${ f('x) } } ``` In this version of `reflect`, the type of `x` is now the result of diff --git a/docs/docs/reference/other-new-features/tupled-function.md b/docs/docs/reference/other-new-features/tupled-function.md index 42bc40d07a05..7dff362febd7 100644 --- a/docs/docs/reference/other-new-features/tupled-function.md +++ b/docs/docs/reference/other-new-features/tupled-function.md @@ -28,7 +28,7 @@ The compiler will synthesize an instance of `TupledFunction[F, G]` if: * `F` is a function type of arity `N` * `G` is a function with a single tuple argument of size `N` and it's types are equal to the arguments of `F` * The return type of `F` is equal to the return type of `G` -* `F` and `G` are the same kind of function (both are `(...) => R` or both are `given (...) => R`) +* `F` and `G` are the same kind of function (both are `(...) => R` or both are `(given ...) => R`) * If only one of `F` or `G` is instantiated the second one is inferred. Examples @@ -43,7 +43,7 @@ Examples * @tparam Args the tuple type with the same types as the function arguments of F * @tparam R the return type of F */ -def (f: F) tupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f) +def (f: F) tupled[F, Args <: Tuple, R](given tf: TupledFunction[F, Args => R]): Args => R = tf.tupled(f) ``` `TupledFunction` can be used to generalize the `Function.untupled` methods to functions of any arities ([full example](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-untupled.scala)) @@ -58,7 +58,7 @@ def (f: F) tupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): * @tparam Args the tuple type with the same types as the function arguments of F * @tparam R the return type of F */ -def (f: Args => R) untupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Args => R]): F = tf.untupled(f) +def (f: Args => R) untupled[F, Args <: Tuple, R](given tf: TupledFunction[F, Args => R]): F = tf.untupled(f) ``` `TupledFunction` can also be used to generalize the [`Tuple1.compose`](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-compose.scala) and [`Tuple1.andThen`](https://github.com/lampepfl/dotty/blob/master/tests/run/tupled-function-andThen.scala) methods to compose functions of larger arities and with functions that return tuples. @@ -72,7 +72,7 @@ def (f: Args => R) untupled[F, Args <: Tuple, R] given (tf: TupledFunction[F, Ar * @tparam GArgs the tuple type with the same types as the function arguments of G * @tparam R the return type of F */ -def (f: F) compose[F, G, FArgs <: Tuple, GArgs <: Tuple, R](g: G) given (tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = { +def (f: F) compose[F, G, FArgs <: Tuple, GArgs <: Tuple, R](g: G)(given tg: TupledFunction[G, GArgs => FArgs], tf: TupledFunction[F, FArgs => R]): GArgs => R = { (x: GArgs) => tf.tupled(f)(tg.tupled(g)(x)) } ``` diff --git a/library/src/scala/tasty/reflect/CommentOps.scala b/library/src/scala/tasty/reflect/CommentOps.scala index 0995f010a184..f3efecbac643 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 (self: Comment) { + given CommentOps: (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 22d2bace2cd3..ec6c25b8c567 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 (const: Constant) { + given ConstantOps: (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 15597c9eb60f..414324a8bf52 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 (self: Context) { + given ContextOps: (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 54b4ae2271c9..10b416c33b1f 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 (self: Flags) { + given FlagsOps: (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 b56c38986db8..f9fd494f6945 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 (id: Id) { + given IsOps: (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 4fb1a473e5f3..a274572d6b98 100644 --- a/library/src/scala/tasty/reflect/ImplicitsOps.scala +++ b/library/src/scala/tasty/reflect/ImplicitsOps.scala @@ -10,7 +10,7 @@ trait ImplicitsOps extends Core { internal.matchImplicitSearchSuccess(isr) } - given (self: ImplicitSearchSuccess) { + given SuccessOps: (self: ImplicitSearchSuccess) { def tree(given ctx: Context): Term = internal.ImplicitSearchSuccess_tree(self) } @@ -19,7 +19,7 @@ trait ImplicitsOps extends Core { internal.matchImplicitSearchFailure(isr) } - given (self: ImplicitSearchFailure) { + given FailureOps: (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 59dbf7981aa5..9b4d4460409c 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 (self: SimpleSelector) { + given SimpleSelectorOps: (self: SimpleSelector) { def selection(given ctx: Context): Id = internal.SimpleSelector_selection(self) } @@ -13,7 +13,7 @@ trait ImportSelectorOps extends Core { internal.matchSimpleSelector(importSelector).map(_.selection) } - given (self: RenameSelector) { + given RenameSelectorOps: (self: RenameSelector) { def from(given ctx: Context): Id = internal.RenameSelector_from(self) @@ -26,7 +26,7 @@ trait ImportSelectorOps extends Core { internal.matchRenameSelector(importSelector).map(x => (x.from, x.to)) } - given (self: OmitSelector) { + given OmitSelectorOps: (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 43e4af171c53..eeaf51204df0 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 (pos: Position) { + given PositionOps: (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 (sourceFile: SourceFile) { + given SourceFileOps: (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 ca2a2f713df0..ee16b2cb27f7 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 (sig: Signature) { + given SignatureOps: (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 1bdcf2229a79..cceaf785fe17 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 (self: Symbol) { + given SymbolOps: (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 5f0e91f35ec0..62bb944e44d5 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 (self: Tree) { + given TreeOps: (self: Tree) { /** Position in the source code */ def pos(given ctx: Context): Position = internal.Tree_pos(self) @@ -26,7 +26,7 @@ trait TreeOps extends Core { internal.matchPackageClause(tree).map(x => (x.pid, x.stats)) } - given (self: PackageClause) { + given PackageClauseOps: (self: PackageClause) { def pid(given ctx: Context): Ref = internal.PackageClause_pid(self) def stats(given ctx: Context): List[Tree] = internal.PackageClause_stats(self) } @@ -45,7 +45,7 @@ trait TreeOps extends Core { internal.matchImport(tree).map(x => (x.expr, x.selectors)) } - given (self: Import) { + given ImportOps: (self: Import) { def expr(given ctx: Context): Term = internal.Import_expr(self) def selectors(given ctx: Context): List[ImportSelector] = internal.Import_selectors(self) @@ -62,7 +62,7 @@ trait TreeOps extends Core { def unapply(tree: Tree)(given ctx: Context): Option[Definition] = internal.matchDefinition(tree) } - given (self: Definition) { + given DefinitionOps: (self: Definition) { def name(given ctx: Context): String = internal.Definition_name(self) } @@ -80,7 +80,7 @@ trait TreeOps extends Core { internal.matchClassDef(tree).map(x => (x.name, x.constructor, x.parents, x.derived, x.self, x.body)) } - given (self: ClassDef) { + given ClassDefOps: (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) @@ -103,7 +103,7 @@ trait TreeOps extends Core { internal.matchDefDef(tree).map(x => (x.name, x.typeParams, x.paramss, x.returnTpt, x.rhs)) } - given (self: DefDef) { + given DefDefOps: (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 @@ -125,7 +125,7 @@ trait TreeOps extends Core { internal.matchValDef(tree).map(x => (x.name, x.tpt, x.rhs)) } - given (self: ValDef) { + given ValDefOps: (self: ValDef) { def tpt(given ctx: Context): TypeTree = internal.ValDef_tpt(self) def rhs(given ctx: Context): Option[Term] = internal.ValDef_rhs(self) } @@ -145,7 +145,7 @@ trait TreeOps extends Core { internal.matchTypeDef(tree).map(x => (x.name, x.rhs)) } - given (self: TypeDef) { + given TypeDefOps: (self: TypeDef) { def rhs(given ctx: Context): Tree /*TypeTree | TypeBoundsTree*/ = internal.TypeDef_rhs(self) } @@ -156,7 +156,7 @@ trait TreeOps extends Core { internal.matchPackageDef(tree) } - given (self: PackageDef) { + given PackageDefOps: (self: PackageDef) { def owner(given ctx: Context): PackageDef = internal.PackageDef_owner(self) def members(given ctx: Context): List[Statement] = internal.PackageDef_members(self) } @@ -168,7 +168,7 @@ trait TreeOps extends Core { // ----- Terms ---------------------------------------------------- - given (self: Term) { + given TermOps: (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) @@ -239,7 +239,7 @@ trait TreeOps extends Core { def unapply(tree: Tree)(given ctx: Context): Option[Ident] = internal.matchIdent(tree) } - given (self: Ident) { + given IdentOps: (self: Ident) { def name(given ctx: Context): String = internal.Ident_name(self) } @@ -289,7 +289,7 @@ trait TreeOps extends Core { internal.matchSelect(tree).map(x => (x.qualifier, x.name)) } - given (self: Select) { + given SelectOps: (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) @@ -315,7 +315,7 @@ trait TreeOps extends Core { internal.matchLiteral(tree).map(_.constant) } - given (self: Literal) { + given LiteralOps: (self: Literal) { def constant(given ctx: Context): Constant = internal.Literal_constant(self) } @@ -340,7 +340,7 @@ trait TreeOps extends Core { } - given (self: This) { + given ThisOps: (self: This) { def id(given ctx: Context): Option[Id] = internal.This_id(self) } @@ -364,7 +364,7 @@ trait TreeOps extends Core { internal.matchNew(tree).map(_.tpt) } - given (self: New) { + given NewOps: (self: New) { def tpt(given ctx: Context): TypeTree = internal.New_tpt(self) } @@ -389,7 +389,7 @@ trait TreeOps extends Core { } - given (self: NamedArg) { + given NamedArgOps: (self: NamedArg) { def name(given ctx: Context): String = internal.NamedArg_name(self) def value(given ctx: Context): Term = internal.NamedArg_value(self) } @@ -414,7 +414,7 @@ trait TreeOps extends Core { internal.matchApply(tree).map(x => (x.fun, x.args)) } - given (self: Apply) { + given ApplyOps: (self: Apply) { def fun(given ctx: Context): Term = internal.Apply_fun(self) def args(given ctx: Context): List[Term] = internal.Apply_args(self) } @@ -441,7 +441,7 @@ trait TreeOps extends Core { } - given (self: TypeApply) { + given TypeApplyOps: (self: TypeApply) { def fun(given ctx: Context): Term = internal.TypeApply_fun(self) def args(given ctx: Context): List[TypeTree] = internal.TypeApply_args(self) } @@ -466,7 +466,7 @@ trait TreeOps extends Core { internal.matchSuper(tree).map(x => (x.qualifier, x.id)) } - given (self: Super) { + given SuperOps: (self: Super) { def qualifier(given ctx: Context): Term = internal.Super_qualifier(self) def id(given ctx: Context): Option[Id] = internal.Super_id(self) } @@ -492,7 +492,7 @@ trait TreeOps extends Core { } - given (self: Typed) { + given TypedOps: (self: Typed) { def expr(given ctx: Context): Term = internal.Typed_expr(self) def tpt(given ctx: Context): TypeTree = internal.Typed_tpt(self) } @@ -517,7 +517,7 @@ trait TreeOps extends Core { internal.matchAssign(tree).map(x => (x.lhs, x.rhs)) } - given (self: Assign) { + given AssignOps: (self: Assign) { def lhs(given ctx: Context): Term = internal.Assign_lhs(self) def rhs(given ctx: Context): Term = internal.Assign_rhs(self) } @@ -542,7 +542,7 @@ trait TreeOps extends Core { internal.matchBlock(tree).map(x => (x.statements, x.expr)) } - given (self: Block) { + given BlockOps: (self: Block) { def statements(given ctx: Context): List[Statement] = internal.Block_statements(self) def expr(given ctx: Context): Term = internal.Block_expr(self) } @@ -564,7 +564,7 @@ trait TreeOps extends Core { internal.matchClosure(tree).map(x => (x.meth, x.tpeOpt)) } - given (self: Closure) { + given ClosureOps: (self: Closure) { def meth(given ctx: Context): Term = internal.Closure_meth(self) def tpeOpt(given ctx: Context): Option[Type] = internal.Closure_tpeOpt(self) } @@ -612,7 +612,7 @@ trait TreeOps extends Core { } - given (self: If) { + given IfOps: (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) @@ -639,7 +639,7 @@ trait TreeOps extends Core { } - given (self: Match) { + given MatchOps: (self: Match) { def scrutinee(given ctx: Context): Term = internal.Match_scrutinee(self) def cases(given ctx: Context): List[CaseDef] = internal.Match_cases(self) } @@ -665,7 +665,7 @@ trait TreeOps extends Core { } - given (self: ImpliedMatch) { + given ImpliedMatchOps: (self: ImpliedMatch) { def cases(given ctx: Context): List[CaseDef] = internal.ImplicitMatch_cases(self) } @@ -690,7 +690,7 @@ trait TreeOps extends Core { } - given (self: Try) { + given TryOps: (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) @@ -717,7 +717,7 @@ trait TreeOps extends Core { } - given (self: Return) { + given ReturnOps: (self: Return) { def expr(given ctx: Context): Term = internal.Return_expr(self) } @@ -739,7 +739,7 @@ trait TreeOps extends Core { } - given (self: Repeated) { + given RepeatedOps: (self: Repeated) { def elems(given ctx: Context): List[Term] = internal.Repeated_elems(self) def elemtpt(given ctx: Context): TypeTree = internal.Repeated_elemtpt(self) } @@ -762,7 +762,7 @@ trait TreeOps extends Core { } - given (self: Inlined) { + given InlinedOps: (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) @@ -786,7 +786,7 @@ trait TreeOps extends Core { } - given (self: SelectOuter) { + given SelectOuterOps: (self: SelectOuter) { def qualifier(given ctx: Context): Term = internal.SelectOuter_qualifier(self) def level(given ctx: Context): Int = internal.SelectOuter_level(self) } @@ -811,14 +811,14 @@ trait TreeOps extends Core { } - given (self: While) { + given WhileOps: (self: While) { def cond(given ctx: Context): Term = internal.While_cond(self) def body(given ctx: Context): Term = internal.While_body(self) } // ----- TypeTrees ------------------------------------------------ - given (self: TypeTree) { + given TypeTreeOps: (self: TypeTree) { /** Type of this type tree */ def tpe(given ctx: Context): Type = internal.TypeTree_tpe(self) } @@ -849,7 +849,7 @@ trait TreeOps extends Core { internal.matchTypeIdent(tree) } - given (self: TypeIdent) { + given TypeIdentOps: (self: TypeIdent) { def name(given ctx: Context): String = internal.TypeIdent_name(self) } @@ -876,7 +876,7 @@ trait TreeOps extends Core { internal.matchTypeSelect(tree).map(x => (x.qualifier, x.name)) } - given (self: TypeSelect) { + given TypeSelectOps: (self: TypeSelect) { def qualifier(given ctx: Context): Term = internal.TypeSelect_qualifier(self) def name(given ctx: Context): String = internal.TypeSelect_name(self) } @@ -895,7 +895,7 @@ trait TreeOps extends Core { internal.matchProjection(tree).map(x => (x.qualifier, x.name)) } - given (self: Projection) { + given ProjectionOps: (self: Projection) { def qualifier(given ctx: Context): TypeTree = internal.Projection_qualifier(self) def name(given ctx: Context): String = internal.Projection_name(self) } @@ -915,7 +915,7 @@ trait TreeOps extends Core { internal.matchSingleton(tree).map(_.ref) } - given (self: Singleton) { + given SingletonOps: (self: Singleton) { def ref(given ctx: Context): Term = internal.Singleton_ref(self) } @@ -933,7 +933,7 @@ trait TreeOps extends Core { internal.matchRefined(tree).map(x => (x.tpt, x.refinements)) } - given (self: Refined) { + given RefinedOps: (self: Refined) { def tpt(given ctx: Context): TypeTree = internal.Refined_tpt(self) def refinements(given ctx: Context): List[Definition] = internal.Refined_refinements(self) } @@ -953,7 +953,7 @@ trait TreeOps extends Core { internal.matchApplied(tree).map(x => (x.tpt, x.args)) } - given (self: Applied) { + given AppliedOps: (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) } @@ -973,7 +973,7 @@ trait TreeOps extends Core { internal.matchAnnotated(tree).map(x => (x.arg, x.annotation)) } - given (self: Annotated) { + given AnnotatedOps: (self: Annotated) { def arg(given ctx: Context): TypeTree = internal.Annotated_arg(self) def annotation(given ctx: Context): Term = internal.Annotated_annotation(self) } @@ -993,7 +993,7 @@ trait TreeOps extends Core { internal.matchMatchTypeTree(tree).map(x => (x.bound, x.selector, x.cases)) } - given (self: MatchTypeTree) { + given MatchTypeTreeOps: (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) @@ -1014,7 +1014,7 @@ trait TreeOps extends Core { internal.matchByName(tree).map(_.result) } - given (self: ByName) { + given ByNameOps: (self: ByName) { def result(given ctx: Context): TypeTree = internal.ByName_result(self) } @@ -1033,7 +1033,7 @@ trait TreeOps extends Core { internal.matchLambdaTypeTree(tree).map(x => (x.tparams, x.body)) } - given (self: LambdaTypeTree) { + given LambdaTypeTreeOps: (self: LambdaTypeTree) { def tparams(given ctx: Context): List[TypeDef] = internal.Lambdatparams(self) def body(given ctx: Context): Tree /*TypeTree | TypeBoundsTree*/ = internal.Lambdabody(self) } @@ -1052,7 +1052,7 @@ trait TreeOps extends Core { internal.matchTypeBind(tree).map(x => (x.name, x.body)) } - given (self: TypeBind) { + given TypeBindOps: (self: TypeBind) { def name(given ctx: Context): String = internal.TypeBind_name(self) def body(given ctx: Context): Tree /*TypeTree | TypeBoundsTree*/ = internal.TypeBind_body(self) } @@ -1072,14 +1072,14 @@ trait TreeOps extends Core { internal.matchTypeBlock(tree).map(x => (x.aliases, x.tpt)) } - given (self: TypeBlock) { + given TypeBlockOps: (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 (self: TypeBoundsTree) { + given TypeBoundsTreeOps: (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) @@ -1095,7 +1095,7 @@ trait TreeOps extends Core { internal.matchTypeBoundsTree(tree).map(x => (x.low, x.hi)) } - given (self: WildcardTypeTree) { + given WildcardTypeTreeOps: (self: WildcardTypeTree) { def tpe(given ctx: Context): TypeOrBounds = internal.WildcardTypeTree_tpe(self) } @@ -1113,7 +1113,7 @@ trait TreeOps extends Core { // ----- CaseDefs ------------------------------------------------ - given (caseDef: CaseDef) { + given CaseDefOps: (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) @@ -1135,7 +1135,7 @@ trait TreeOps extends Core { internal.matchCaseDef(tree).map( x => (x.pattern, x.guard, x.rhs)) } - given (caseDef: TypeCaseDef) { + given TypeCaseDefOps: (caseDef: TypeCaseDef) { def pattern(given ctx: Context): TypeTree = internal.TypeCaseDef_pattern(caseDef) def rhs(given ctx: Context): TypeTree = internal.TypeCaseDef_rhs(caseDef) } @@ -1171,7 +1171,7 @@ trait TreeOps extends Core { internal.matchTree_Bind(pattern).map(x => (x.name, x.pattern)) } - given (bind: Bind) { + given BindOps: (bind: Bind) { def name(given ctx: Context): String = internal.Tree_Bind_name(bind) def pattern(given ctx: Context): Tree = internal.Tree_Bind_pattern(bind) } @@ -1189,7 +1189,7 @@ trait TreeOps extends Core { internal.matchTree_Unapply(pattern).map(x => (x.fun, x.implicits, x.patterns)) } - given (unapply: Unapply) { + given UnapplyOps: (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) @@ -1209,7 +1209,7 @@ trait TreeOps extends Core { internal.matchTree_Alternatives(pattern).map(_.patterns) } - given (alternatives: Alternatives) { + given AlternativesOps: (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 7543f2923c81..498aaae38f40 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 (self: Type) { + given TypeOps: (self: Type) { def =:=(that: Type)(given ctx: Context): Boolean = internal.`Type_=:=`(self)(that) def <:<(that: Type)(given ctx: Context): Boolean = internal.`Type_<:<`(self)(that) def widen(given ctx: Context): Type = internal.Type_widen(self) @@ -84,7 +84,7 @@ trait TypeOrBoundsOps extends Core { internal.matchConstantType(typeOrBounds).map(_.constant) } - given (self: ConstantType) { + given ConstantTypeOps: (self: ConstantType) { def constant(given ctx: Context): Constant = internal.ConstantType_constant(self) } @@ -101,7 +101,7 @@ trait TypeOrBoundsOps extends Core { internal.matchTermRef(typeOrBounds).map(x => (x.qualifier, x.name)) } - given (self: TermRef) { + given TermRefOps: (self: TermRef) { def qualifier(given ctx: Context): TypeOrBounds /* Type | NoPrefix */ = internal.TermRef_qualifier(self) def name(given ctx: Context): String = internal.TermRef_name(self) } @@ -117,7 +117,7 @@ trait TypeOrBoundsOps extends Core { internal.matchTypeRef(typeOrBounds).map(x => (x.qualifier, x.name)) } - given (self: TypeRef) { + given TypeRefOps: (self: TypeRef) { def qualifier(given ctx: Context): TypeOrBounds /* Type | NoPrefix */ = internal.TypeRef_qualifier(self) def name(given ctx: Context): String = internal.TypeRef_name(self) } @@ -133,7 +133,7 @@ trait TypeOrBoundsOps extends Core { internal.matchSuperType(typeOrBounds).map(x => (x.thistpe, x.supertpe)) } - given (self: SuperType) { + given SuperTypeOps: (self: SuperType) { def thistpe(given ctx: Context): Type = internal.SuperType_thistpe(self) def supertpe(given ctx: Context): Type = internal.SuperType_supertpe(self) } @@ -149,7 +149,7 @@ trait TypeOrBoundsOps extends Core { internal.matchRefinement(typeOrBounds).map(x => (x.parent, x.name, x.info)) } - given (self: Refinement) { + given RefinementOps: (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) @@ -168,7 +168,7 @@ trait TypeOrBoundsOps extends Core { internal.matchAppliedType(typeOrBounds).map(x => (x.tycon, x.args)) } - given (self: AppliedType) { + given AppliedTypeOps: (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) } @@ -184,7 +184,7 @@ trait TypeOrBoundsOps extends Core { internal.matchAnnotatedType(typeOrBounds).map(x => (x.underlying, x.annot)) } - given (self: AnnotatedType) { + given AnnotatedTypeOps: (self: AnnotatedType) { def underlying(given ctx: Context): Type = internal.AnnotatedType_underlying(self) def annot(given ctx: Context): Term = internal.AnnotatedType_annot(self) } @@ -200,7 +200,7 @@ trait TypeOrBoundsOps extends Core { internal.matchAndType(typeOrBounds).map(x => (x.left, x.right)) } - given (self: AndType) { + given AndTypeOps: (self: AndType) { def left(given ctx: Context): Type = internal.AndType_left(self) def right(given ctx: Context): Type = internal.AndType_right(self) } @@ -216,7 +216,7 @@ trait TypeOrBoundsOps extends Core { internal.matchOrType(typeOrBounds).map(x => (x.left, x.right)) } - given (self: OrType) { + given OrTypeOps: (self: OrType) { def left(given ctx: Context): Type = internal.OrType_left(self) def right(given ctx: Context): Type = internal.OrType_right(self) } @@ -232,7 +232,7 @@ trait TypeOrBoundsOps extends Core { internal.matchMatchType(typeOrBounds).map(x => (x.bound, x.scrutinee, x.cases)) } - given (self: MatchType) { + given MatchTypeOps: (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) @@ -249,7 +249,7 @@ trait TypeOrBoundsOps extends Core { internal.matchByNameType(typeOrBounds).map(_.underlying) } - given (self: ByNameType) { + given ByNameTypeOps: (self: ByNameType) { def underlying(given ctx: Context): Type = internal.ByNameType_underlying(self) } @@ -264,7 +264,7 @@ trait TypeOrBoundsOps extends Core { internal.matchParamRef(typeOrBounds).map(x => (x.binder, x.paramNum)) } - given (self: ParamRef) { + given ParamRefOps: (self: ParamRef) { def binder(given ctx: Context): LambdaType[TypeOrBounds] = internal.ParamRef_binder(self) def paramNum(given ctx: Context): Int = internal.ParamRef_paramNum(self) } @@ -280,7 +280,7 @@ trait TypeOrBoundsOps extends Core { internal.matchThisType(typeOrBounds).map(_.tref) } - given (self: ThisType) { + given ThisTypeOps: (self: ThisType) { def tref(given ctx: Context): Type = internal.ThisType_tref(self) } @@ -295,7 +295,7 @@ trait TypeOrBoundsOps extends Core { internal.matchRecursiveThis(typeOrBounds).map(_.binder) } - given (self: RecursiveThis) { + given RecursiveThisOps: (self: RecursiveThis) { def binder(given ctx: Context): RecursiveType = internal.RecursiveThis_binder(self) } @@ -310,7 +310,7 @@ trait TypeOrBoundsOps extends Core { internal.matchRecursiveType(typeOrBounds).map(_.underlying) } - given (self: RecursiveType) { + given RecursiveTypeOps: (self: RecursiveType) { def underlying(given ctx: Context): Type = internal.RecursiveType_underlying(self) } @@ -325,7 +325,7 @@ trait TypeOrBoundsOps extends Core { internal.matchMethodType(typeOrBounds).map(x => (x.paramNames, x.paramTypes, x.resType)) } - given (self: MethodType) { + given MethodTypeOps: (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) @@ -344,7 +344,7 @@ trait TypeOrBoundsOps extends Core { internal.matchPolyType(typeOrBounds).map(x => (x.paramNames, x.paramBounds, x.resType)) } - given (self: PolyType) { + given PolyTypeOps: (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) @@ -361,7 +361,7 @@ trait TypeOrBoundsOps extends Core { internal.matchTypeLambda(typeOrBounds).map(x => (x.paramNames, x.paramBounds, x.resType)) } - given (self: TypeLambda) { + given TypeLambdaOps: (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) @@ -379,7 +379,7 @@ trait TypeOrBoundsOps extends Core { internal.matchTypeBounds(typeOrBounds).map(x => (x.low, x.hi)) } - given (self: TypeBounds) { + given TypeBoundsOps: (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/extension-methods.scala b/tests/neg/extension-methods.scala index 095d9148b466..dc613cfdede2 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 [T](xs: List[T]) { + given extension [T](xs: List[T]) { 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 35b94bd53012..dfccfdc6aaf5 100644 --- a/tests/neg/i5455.scala +++ b/tests/neg/i5455.scala @@ -11,7 +11,7 @@ object Library { def toInt(n: Nat): Int = n } - given (x: Nat) + given extension (x: Nat) def * (y: Nat): Nat = x * y def toInt: Int = x } diff --git a/tests/pos/i7515.scala b/tests/pos/i7515.scala new file mode 100644 index 000000000000..918a10cc24ef --- /dev/null +++ b/tests/pos/i7515.scala @@ -0,0 +1 @@ +given (Int => Int) = identity[Int] \ No newline at end of file diff --git a/tests/pos/matrixOps.scala b/tests/pos/matrixOps.scala index 1824bc5fbbbf..c7d800c65a0a 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 (m: Matrix) + given extension (m: Matrix) def nRows = m.length def nCols = m(0).length def row(i: Int): Vector = m(i) diff --git a/tests/pos/reference/delegates.scala b/tests/pos/reference/delegates.scala index 2931ed4916c3..2c398e4d3e66 100644 --- a/tests/pos/reference/delegates.scala +++ b/tests/pos/reference/delegates.scala @@ -44,7 +44,7 @@ object Instances extends Common with val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) - given [T](xs: List[T]) + given extension [T](xs: List[T]) def second = xs.tail.head def third = xs.tail.tail.head @@ -133,7 +133,7 @@ object PostConditions with def result[T](given x: WrappedResult[T]): T = x - given [T](x: T) + given extension [T](x: T) 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 (xs: Seq[String]) + given extension (xs: Seq[String]) def longestStrings: Seq[String] = val maxLength = xs.map(_.length).max xs.filter(_.length == maxLength) - given [T](xs: List[T]) + given extension [T](xs: List[T]) 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/extension-methods.scala b/tests/pos/reference/extension-methods.scala new file mode 100644 index 000000000000..343ae7149128 --- /dev/null +++ b/tests/pos/reference/extension-methods.scala @@ -0,0 +1,76 @@ +object ExtMethods with + + case class Circle(x: Double, y: Double, radius: Double) + + def (c: Circle) circumference: Double = c.radius * math.Pi * 2 + + val circle = Circle(0, 0, 1) + circle.circumference + assert(circle.circumference == circumference(circle)) + + trait StringSeqOps { + def (xs: Seq[String]) longestStrings = { + val maxLength = xs.map(_.length).max + xs.filter(_.length == maxLength) + } + } + given ops1: StringSeqOps + + List("here", "is", "a", "list").longestStrings + + locally { + object ops2 extends StringSeqOps + import ops2.longestStrings + List("here", "is", "a", "list").longestStrings + } + + def (x: String) < (y: String) = x.compareTo(y) < 0 + def [Elem](x: Elem) #: (xs: Seq[Elem]) = x +: xs + + assert("a" < "bb") + val xs = 1 #: Vector(2, 3) + + def [T](xs: List[T]) second = + xs.tail.head + + def [T](xs: List[List[T]]) flattened = + xs.foldLeft[List[T]](Nil)(_ ++ _) + + def [T: Numeric](x: T) + (y: T): T = + summon[Numeric[T]].plus(x, y) + + List(1, 2, 3).second[Int] + + given stringOps: extension (xs: Seq[String]) { + def longestStrings: Seq[String] = { + val maxLength = xs.map(_.length).max + xs.filter(_.length == maxLength) + } + } + + given listOps: extension [T](xs: List[T]) with + def second = xs.tail.head + def third: T = xs.tail.tail.head + + + given extension [T](xs: List[T])(given Ordering[T]) with + def largest(n: Int) = xs.sorted.takeRight(n) + + given stringOps1: AnyRef { + def (xs: Seq[String]) longestStrings: Seq[String] = { + val maxLength = xs.map(_.length).max + xs.filter(_.length == maxLength) + } + } + + given listOps1: AnyRef { + def [T](xs: List[T]) second = xs.tail.head + def [T](xs: List[T]) third: T = xs.tail.tail.head + } + + given AnyRef { + def [T](xs: List[T]) largest (given Ordering[T])(n: Int) = + xs.sorted.takeRight(n) + } + +end ExtMethods \ No newline at end of file diff --git a/tests/run/extension-specificity.scala b/tests/run/extension-specificity.scala new file mode 100644 index 000000000000..dce5942b5682 --- /dev/null +++ b/tests/run/extension-specificity.scala @@ -0,0 +1,14 @@ +class A +class B extends A + +given a: extension (x: A) with + def foo: Int = 1 + +given b: extension (x: B) with + def foo: Int = 2 + +@main def Test = + val a = A() + assert(a.foo == 1) + val b = B() + assert(b.foo == 2) diff --git a/tests/run/extmethods2.scala b/tests/run/extmethods2.scala index 4ee5e57146d1..70cb2e108476 100644 --- a/tests/run/extmethods2.scala +++ b/tests/run/extmethods2.scala @@ -22,7 +22,7 @@ object Test extends App { def concat(ys: List[T]) = xs ++ ys def zipp[U](ys: List[U]): List[(T, U)] = xs.zip(ys) } - given (xs: List[Int]) { + given extension (xs: List[Int]) { def prod = (1 /: xs)(_ * _) } }