-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Unified extension methods #9255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
3cc3745
Unified extension methods
odersky d88a796
Change parser to accept new extension syntax
odersky f0c2e19
Doc fixes
odersky f87ec07
Desugaring of extensions
odersky e5ca6d5
Doc fixes
odersky 02de5dc
Prefix extension methods with `extension_`.
odersky 70d5ec8
Print extension methods with new syntax
odersky 28ef7b6
Update semanticDB expect files
odersky 74865c3
Disallow normal method names starting with `extension_`
odersky 4c50dbd
Adapt to new extension_ syntax in CB
odersky 5b1a2f7
Look for extension methods directly in implicit scope
odersky 71a853a
Fixes to parsing and desugaring of extension methods
odersky fb93f46
Fix: wrap extensions in toplevel package objects
odersky 1ad5ee9
Make type parameters after extension method `def` illegal
odersky 6ff0ac8
Update tests and docs to new extension syntax
odersky c148218
Update semanticDB expect files
odersky 330c32f
Fix test
odersky b63da92
Disable check file for missing-implicit
odersky 3e89b56
Allow `end extension` as an endmarker
odersky a7213cc
Fix extension method search in implicit scope
odersky 00cc25d
Fix syntax error messages for extensions
odersky 5cdb3da
Drop collective extensions from tests and docs
odersky ce6d9ca
Drop outdated repl test
odersky 40667a6
Update semanticDB expect files
odersky 3188b43
Avoid double-counting of extension methods
odersky 2cd1092
Handle missing case for extension/conversion ambiguity
odersky 8529885
Check no use of extension_ in definitions at Desugar
odersky c1b5150
Avoid printing same extension method attempt multiple times
odersky e33d36f
Drop check file
odersky 026b58a
Fix #8311: Propagate more information about extension method arguments
odersky 01ec288
Refine criterion for deepening after ambiguities
odersky 17a8026
Add clarification to doc page
odersky 7de235d
Add test
odersky 4aae35c
Fix printing right-associative extension methods
odersky c8d7be1
Address review comments
odersky a128dab
Drop `:` for collective extensions
odersky b179a8e
Change indentation.md to reflect no colon in extensions
odersky e160140
Allow optional `:` in extension
odersky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -559,7 +559,7 @@ object desugar { | |
val copiedAccessFlags = if migrateTo3 then EmptyFlags else AccessFlags | ||
|
||
// Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams) | ||
// def _1: T1 = this.p1 | ||
// def _1: T1 = this.p1 | ||
// ... | ||
// def _N: TN = this.pN (unless already given as valdef or parameterless defdef) | ||
// def copy(p1: T1 = p1: @uncheckedVariance, ..., | ||
|
@@ -572,7 +572,7 @@ object desugar { | |
val caseClassMeths = { | ||
def syntheticProperty(name: TermName, tpt: Tree, rhs: Tree) = | ||
DefDef(name, Nil, Nil, tpt, rhs).withMods(synthetic) | ||
|
||
def productElemMeths = | ||
val caseParams = derivedVparamss.head.toArray | ||
val selectorNamesInBody = normalizedBody.collect { | ||
|
@@ -850,6 +850,7 @@ object desugar { | |
* where every definition in `body` is expanded to an extension method | ||
* taking type parameters `tparams` and a leading paramter `(x: T)`. | ||
* See: collectiveExtensionBody | ||
* TODO: drop this part | ||
*/ | ||
def moduleDef(mdef: ModuleDef)(implicit ctx: Context): Tree = { | ||
val impl = mdef.impl | ||
|
@@ -906,6 +907,25 @@ object desugar { | |
} | ||
} | ||
|
||
/** Transform extension construct to list of extension methods */ | ||
def extMethods(ext: ExtMethods)(using Context): Tree = flatTree { | ||
for mdef <- ext.methods yield | ||
if mdef.tparams.nonEmpty then | ||
ctx.error("extension method cannot have type parameters here, all type parameters go after `extension`", | ||
mdef.tparams.head.sourcePos) | ||
defDef( | ||
cpy.DefDef(mdef)( | ||
name = mdef.name.toExtensionName, | ||
tparams = ext.tparams ++ mdef.tparams, | ||
vparamss = mdef.vparamss match | ||
case vparams1 :: vparamss1 if !isLeftAssoc(mdef.name) => | ||
vparams1 :: ext.vparamss ::: vparamss1 | ||
case _ => | ||
ext.vparamss ++ mdef.vparamss | ||
).withMods(mdef.mods | Extension) | ||
) | ||
} | ||
|
||
/** Transform the statements of a collective extension | ||
* @param stats the original statements as they were parsed | ||
* @param tparams the collective type parameters | ||
|
@@ -934,6 +954,7 @@ object desugar { | |
stat match | ||
case mdef: DefDef => | ||
cpy.DefDef(mdef)( | ||
name = mdef.name.toExtensionName, | ||
tparams = tparams ++ mdef.tparams, | ||
vparamss = vparamss ::: mdef.vparamss, | ||
).withMods(mdef.mods | Extension) | ||
|
@@ -964,16 +985,21 @@ object desugar { | |
/** The normalized name of `mdef`. This means | ||
* 1. Check that the name does not redefine a Scala core class. | ||
* If it does redefine, issue an error and return a mangled name instead of the original one. | ||
* 2. If the name is missing (this can be the case for instance definitions), invent one instead. | ||
* 2. Check that the name does not start with `extension_` unless the | ||
* method is an extension method. | ||
* 3. If the name is missing (this can be the case for instance definitions), invent one instead. | ||
*/ | ||
def normalizeName(mdef: MemberDef, impl: Tree)(implicit ctx: Context): Name = { | ||
var name = mdef.name | ||
if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName(impl)) | ||
def errPos = mdef.source.atSpan(mdef.nameSpan) | ||
if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) { | ||
val kind = if (name.isTypeName) "class" else "object" | ||
ctx.error(IllegalRedefinitionOfStandardKind(kind, name), mdef.sourcePos) | ||
ctx.error(IllegalRedefinitionOfStandardKind(kind, name), errPos) | ||
name = name.errorName | ||
} | ||
if name.isExtensionName && !mdef.mods.is(Extension) then | ||
ctx.error(em"illegal method name: $name may not start with `extension_`", errPos) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we have a migration for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's not common enough to spend the effort. |
||
name | ||
} | ||
|
||
|
@@ -1247,7 +1273,7 @@ object desugar { | |
} | ||
|
||
private def isTopLevelDef(stat: Tree)(using Context): Boolean = stat match | ||
case _: ValDef | _: PatDef | _: DefDef | _: Export => true | ||
case _: ValDef | _: PatDef | _: DefDef | _: Export | _: ExtMethods => true | ||
case stat: ModuleDef => | ||
stat.mods.isOneOf(GivenOrImplicit) | ||
case stat: TypeDef => | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.