Skip to content

Commit f46c030

Browse files
authored
Merge pull request #9476 from dotty-staging/drop-old-extension
Drop old extension method syntax
2 parents 15ae0aa + 4207d0b commit f46c030

File tree

15 files changed

+34
-157
lines changed

15 files changed

+34
-157
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 3 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -837,36 +837,10 @@ object desugar {
837837
*
838838
* <module> val name: name$ = New(name$)
839839
* <module> final class name$ extends parents { self: name.type => body }
840-
*
841-
* Special case for extension methods with collective parameters. Expand:
842-
*
843-
* given object name[tparams](x: T) extends parents { self => bpdy }
844-
*
845-
* to:
846-
*
847-
* given object name extends parents { self => body' }
848-
*
849-
* where every definition in `body` is expanded to an extension method
850-
* taking type parameters `tparams` and a leading paramter `(x: T)`.
851-
* See: collectiveExtensionBody
852-
* TODO: drop this part
853840
*/
854841
def moduleDef(mdef: ModuleDef)(using Context): Tree = {
855842
val impl = mdef.impl
856843
val mods = mdef.mods
857-
impl.constr match {
858-
case DefDef(_, tparams, vparamss @ (vparam :: Nil) :: givenParamss, _, _) =>
859-
// Transform collective extension
860-
assert(mods.is(Given))
861-
return moduleDef(
862-
cpy.ModuleDef(mdef)(
863-
mdef.name,
864-
cpy.Template(impl)(
865-
constr = emptyConstructor,
866-
body = collectiveExtensionBody(impl.body, tparams, vparamss))))
867-
case _ =>
868-
}
869-
870844
val moduleName = normalizeName(mdef, impl).asTermName
871845
def isEnumCase = mods.isEnumCase
872846

@@ -921,46 +895,10 @@ object desugar {
921895
vparams1 :: ext.vparamss ::: vparamss1
922896
case _ =>
923897
ext.vparamss ++ mdef.vparamss
924-
).withMods(mdef.mods | Extension)
898+
).withMods(mdef.mods | ExtensionMethod)
925899
)
926900
}
927901

928-
/** Transform the statements of a collective extension
929-
* @param stats the original statements as they were parsed
930-
* @param tparams the collective type parameters
931-
* @param vparamss the collective value parameters, consisting
932-
* of a single leading value parameter, followed by
933-
* zero or more context parameter clauses
934-
*
935-
* Note: It is already assured by Parser.checkExtensionMethod that all
936-
* statements conform to requirements.
937-
*
938-
* Each method in stats is transformed into an extension method. Example:
939-
*
940-
* extension on [Ts](x: T)(using C):
941-
* def f(y: T) = ???
942-
* def g(z: T) = f(z)
943-
*
944-
* is turned into
945-
*
946-
* extension:
947-
* <extension> def f[Ts](x: T)(using C)(y: T) = ???
948-
* <extension> def g[Ts](x: T)(using C)(z: T) = f(z)
949-
*/
950-
def collectiveExtensionBody(stats: List[Tree],
951-
tparams: List[TypeDef], vparamss: List[List[ValDef]])(using Context): List[Tree] =
952-
for stat <- stats yield
953-
stat match
954-
case mdef: DefDef =>
955-
cpy.DefDef(mdef)(
956-
name = mdef.name.toExtensionName,
957-
tparams = tparams ++ mdef.tparams,
958-
vparamss = vparamss ::: mdef.vparamss,
959-
).withMods(mdef.mods | Extension)
960-
case mdef =>
961-
mdef
962-
end collectiveExtensionBody
963-
964902
/** Transforms
965903
*
966904
* <mods> type $T >: Low <: Hi
@@ -997,7 +935,7 @@ object desugar {
997935
report.error(IllegalRedefinitionOfStandardKind(kind, name), errPos)
998936
name = name.errorName
999937
}
1000-
if name.isExtensionName && !mdef.mods.is(Extension) then
938+
if name.isExtensionName && !mdef.mods.is(ExtensionMethod) then
1001939
report.error(em"illegal method name: $name may not start with `extension_`", errPos)
1002940
name
1003941
}
@@ -1008,7 +946,7 @@ object desugar {
1008946
case impl: Template =>
1009947
if impl.parents.isEmpty then
1010948
impl.body.find {
1011-
case dd: DefDef if dd.mods.is(Extension) => true
949+
case dd: DefDef if dd.mods.is(ExtensionMethod) => true
1012950
case _ => false
1013951
}
1014952
match

compiler/src/dotty/tools/dotc/ast/Positioned.scala

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import util.Spans._
66
import util.{SourceFile, NoSource, SourcePosition, SrcPos}
77
import core.Contexts._
88
import core.Decorators._
9-
import core.Flags.{JavaDefined, Extension}
9+
import core.Flags.{JavaDefined, ExtensionMethod}
1010
import core.StdNames.nme
1111
import ast.Trees.mods
1212
import annotation.constructorOnly
@@ -152,11 +152,6 @@ abstract class Positioned(implicit @constructorOnly src: SourceFile) extends Src
152152
}
153153
}
154154

155-
/** A hook that can be overridden if overlap checking in `checkPos` should be
156-
* disabled for this node.
157-
*/
158-
def disableOverlapChecks = false
159-
160155
/** Check that all positioned items in this tree satisfy the following conditions:
161156
* - Parent spans contain child spans
162157
* - If item is a non-empty tree, it has a position
@@ -179,7 +174,7 @@ abstract class Positioned(implicit @constructorOnly src: SourceFile) extends Src
179174
s"position error: position not set for $tree # ${tree.uniqueId}")
180175
case _ =>
181176
}
182-
if (nonOverlapping && !disableOverlapChecks) {
177+
if nonOverlapping then
183178
this match {
184179
case _: XMLBlock =>
185180
// FIXME: Trees generated by the XML parser do not satisfy `checkPos`
@@ -197,7 +192,6 @@ abstract class Positioned(implicit @constructorOnly src: SourceFile) extends Src
197192
}
198193
lastPositioned = p
199194
lastSpan = p.span
200-
}
201195
p.checkPos(nonOverlapping)
202196
case m: untpd.Modifiers =>
203197
m.annotations.foreach(check)
@@ -212,7 +206,7 @@ abstract class Positioned(implicit @constructorOnly src: SourceFile) extends Src
212206
// Leave out tparams, they are copied with wrong positions from parent class
213207
check(tree.mods)
214208
check(tree.vparamss)
215-
case tree: DefDef if tree.mods.is(Extension) =>
209+
case tree: DefDef if tree.mods.is(ExtensionMethod) =>
216210
tree.vparamss match {
217211
case vparams1 :: vparams2 :: rest if !isLeftAssoc(tree.name) =>
218212
check(tree.tparams)

compiler/src/dotty/tools/dotc/ast/Trees.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -757,11 +757,6 @@ object Trees {
757757
assert(tpt != genericEmptyTree)
758758
def unforced: LazyTree[T] = preRhs
759759
protected def force(x: Tree[T @uncheckedVariance]): Unit = preRhs = x
760-
761-
override def disableOverlapChecks = rawMods.is(Extension)
762-
// disable order checks for extension methods as long as we parse
763-
// type parameters both before and after the leading parameter section.
764-
// TODO drop this once syntax of type parameters has settled.
765760
}
766761

767762
/** mods class name template or

compiler/src/dotty/tools/dotc/core/Flags.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ object Flags {
302302
val (_, HasDefault @ _, _) = newFlags(27, "<hasdefault>")
303303

304304
/** An extension method, or a collective extension instance */
305-
val (_, Extension @ _, _) = newFlags(28, "<extension>")
305+
val (Extension @ _, ExtensionMethod @ _, _) = newFlags(28, "<extension>")
306306

307307
/** An inferable (`given`) parameter */
308308
val (Given @ _, _, _) = newFlags(29, "given")
@@ -495,7 +495,7 @@ object Flags {
495495

496496
/** Flags that can apply to a module val */
497497
val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags |
498-
Override | Final | Method | Implicit | Given | Lazy | Extension |
498+
Override | Final | Method | Implicit | Given | Lazy |
499499
Accessor | AbsOverride | StableRealizable | Captured | Synchronized | Erased
500500

501501
/** Flags that can apply to a module class */
@@ -527,7 +527,6 @@ object Flags {
527527
val DeferredOrTypeParam: FlagSet = Deferred | TypeParam // type symbols without right-hand sides
528528
val EnumValue: FlagSet = Enum | StableRealizable // A Scala enum value
529529
val StableOrErased: FlagSet = Erased | StableRealizable // Assumed to be pure
530-
val ExtensionMethod: FlagSet = Extension | Method
531530
val FinalOrInline: FlagSet = Final | Inline
532531
val FinalOrModuleClass: FlagSet = Final | ModuleClass // A module class or a final class
533532
val EffectivelyFinalFlags: FlagSet = Final | Private

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@ object SymDenotations {
11041104
* provided the extension method appears in the same class.
11051105
*/
11061106
final def enclosingExtensionMethod(using Context): Symbol =
1107-
if this.isAllOf(ExtensionMethod) then symbol
1107+
if this.is(ExtensionMethod) then symbol
11081108
else if this.isClass then NoSymbol
11091109
else if this.exists then owner.enclosingExtensionMethod
11101110
else NoSymbol

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

Lines changed: 12 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ object Parsers {
225225
|| defIntroTokens.contains(in.token)
226226
|| allowedMods.contains(in.token)
227227
|| in.isSoftModifierInModifierPosition && !excludedSoftModifiers.contains(in.name)
228-
|| isIdent(nme.extension) && followingIsOldExtension()
229228

230229
def isStatSep: Boolean = in.isNewLine || in.token == SEMI
231230

@@ -919,23 +918,10 @@ object Parsers {
919918
skipParams()
920919
lookahead.isIdent(nme.as)
921920

922-
def followingIsNewExtension() =
921+
def followingIsExtension() =
923922
val next = in.lookahead.token
924923
next == LBRACKET || next == LPAREN
925924

926-
def followingIsOldExtension() =
927-
val lookahead = in.LookaheadScanner()
928-
lookahead.nextToken()
929-
if lookahead.isIdent && !lookahead.isIdent(nme.on) then
930-
lookahead.nextToken()
931-
if lookahead.isNewLine then
932-
lookahead.nextToken()
933-
lookahead.isIdent(nme.on)
934-
|| lookahead.token == LBRACE
935-
|| lookahead.token == COLON
936-
937-
def followingIsExtension() = followingIsOldExtension() || followingIsNewExtension()
938-
939925
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
940926

941927
var opStack: List[OpInfo] = Nil
@@ -1311,7 +1297,7 @@ object Parsers {
13111297
case stat: MemberDef if !stat.name.isEmpty =>
13121298
if stat.name == nme.CONSTRUCTOR then in.token == THIS
13131299
else in.isIdent && in.name == stat.name.toTermName
1314-
case ModuleDef(_, Template(_, Nil, _, _)) | ExtMethods(_, _, _) =>
1300+
case ExtMethods(_, _, _) =>
13151301
in.token == IDENTIFIER && in.name == nme.extension
13161302
case PackageDef(pid: RefTree, _) =>
13171303
in.isIdent && in.name == pid.name
@@ -3305,7 +3291,7 @@ object Parsers {
33053291
def extParamss() =
33063292
try paramClause(0, prefix = true) :: Nil
33073293
finally
3308-
mods1 = addFlag(mods, Extension)
3294+
mods1 = addFlag(mods, ExtensionMethod)
33093295
if in.token == DOT then in.nextToken()
33103296
else
33113297
isInfix = true
@@ -3319,14 +3305,14 @@ object Parsers {
33193305
(Nil, Nil)
33203306
val ident = termIdent()
33213307
var name = ident.name.asTermName
3322-
if mods1.is(Extension) then name = name.toExtensionName
3308+
if mods1.is(ExtensionMethod) then name = name.toExtensionName
33233309
if isInfix && !name.isOperatorName then
33243310
val infixAnnot = Apply(wrapNew(scalaAnnotationDot(tpnme.infix)), Nil)
33253311
.withSpan(Span(start, start))
33263312
mods1 = mods1.withAddedAnnotation(infixAnnot)
33273313
val tparams =
33283314
if in.token == LBRACKET then
3329-
if mods1.is(Extension) then syntaxError("no type parameters allowed here")
3315+
if mods1.is(ExtensionMethod) then syntaxError("no type parameters allowed here")
33303316
typeParamClause(ParamOwner.Def)
33313317
else leadingTparams
33323318
val vparamss = paramClauses() match
@@ -3465,11 +3451,8 @@ object Parsers {
34653451
case GIVEN =>
34663452
givenDef(start, mods, atSpan(in.skipToken()) { Mod.Given() })
34673453
case _ =>
3468-
if isIdent(nme.extension) && followingIsOldExtension() then
3469-
extensionDef(start, mods)
3470-
else
3471-
syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition())
3472-
EmptyTree
3454+
syntaxErrorOrIncomplete(ExpectedStartOfTopLevelDefinition())
3455+
EmptyTree
34733456
}
34743457

34753458
/** ClassDef ::= id ClassConstr TemplateOpt
@@ -3563,9 +3546,9 @@ object Parsers {
35633546
def checkExtensionMethod(tparams: List[Tree],
35643547
vparamss: List[List[Tree]], stat: Tree): Unit = stat match {
35653548
case stat: DefDef =>
3566-
if stat.mods.is(Extension) && vparamss.nonEmpty then
3549+
if stat.mods.is(ExtensionMethod) && vparamss.nonEmpty then
35673550
syntaxError(i"no extension method allowed here since leading parameter was already given", stat.span)
3568-
else if !stat.mods.is(Extension) && vparamss.isEmpty then
3551+
else if !stat.mods.is(ExtensionMethod) && vparamss.isEmpty then
35693552
syntaxError(i"an extension method is required here", stat.span)
35703553
else if tparams.nonEmpty && stat.tparams.nonEmpty then
35713554
syntaxError(i"extension method cannot have type parameters since some were already given previously",
@@ -3614,28 +3597,6 @@ object Parsers {
36143597
finalizeDef(gdef, mods1, start)
36153598
}
36163599

3617-
/** ExtensionDef ::= [id] [‘on’ ExtParamClause {UsingParamClause}] TemplateBody
3618-
*/
3619-
def extensionDef(start: Offset, mods: Modifiers): ModuleDef =
3620-
in.nextToken()
3621-
val nameOffset = in.offset
3622-
val name = if isIdent && !isIdent(nme.on) then ident() else EmptyTermName
3623-
val (tparams, vparamss, extensionFlag) =
3624-
if isIdent(nme.on) then
3625-
in.nextToken()
3626-
val tparams = typeParamClauseOpt(ParamOwner.Def)
3627-
val extParams = paramClause(0, prefix = true)
3628-
val givenParamss = paramClauses(givenOnly = true)
3629-
(tparams, extParams :: givenParamss, Extension)
3630-
else
3631-
(Nil, Nil, EmptyFlags)
3632-
possibleTemplateStart()
3633-
if !in.isNestedStart then syntaxError("Extension without extension methods")
3634-
val templ = templateBodyOpt(makeConstructor(tparams, vparamss), Nil, Nil)
3635-
templ.body.foreach(checkExtensionMethod(tparams, vparamss, _))
3636-
val edef = atSpan(start, nameOffset, in.offset)(ModuleDef(name, templ))
3637-
finalizeDef(edef, addFlag(mods, Given | extensionFlag), start)
3638-
36393600
/** Extension ::= ‘extension’ [DefTypeParamClause] ‘(’ DefParam ‘)’
36403601
* {UsingParamClause} ExtMethods
36413602
*/
@@ -3816,7 +3777,7 @@ object Parsers {
38163777
stats ++= importClause(IMPORT, mkImport(outermost))
38173778
else if (in.token == EXPORT)
38183779
stats ++= importClause(EXPORT, Export.apply)
3819-
else if isIdent(nme.extension) && followingIsNewExtension() then
3780+
else if isIdent(nme.extension) && followingIsExtension() then
38203781
stats += extension()
38213782
else if isDefIntro(modifierTokens)
38223783
stats +++= defOrDcl(in.offset, defAnnotsMods(modifierTokens))
@@ -3870,7 +3831,7 @@ object Parsers {
38703831
stats ++= importClause(IMPORT, mkImport())
38713832
else if (in.token == EXPORT)
38723833
stats ++= importClause(EXPORT, Export.apply)
3873-
else if isIdent(nme.extension) && followingIsNewExtension() then
3834+
else if isIdent(nme.extension) && followingIsExtension() then
38743835
stats += extension()
38753836
else if (isDefIntro(modifierTokensOrCase))
38763837
stats +++= defOrDcl(in.offset, defAnnotsMods(modifierTokens))
@@ -3952,7 +3913,7 @@ object Parsers {
39523913
stats += expr(Location.InBlock)
39533914
else if in.token == IMPLICIT && !in.inModifierPosition() then
39543915
stats += closure(in.offset, Location.InBlock, modifiers(BitSet(IMPLICIT)))
3955-
else if isIdent(nme.extension) && followingIsNewExtension() then
3916+
else if isIdent(nme.extension) && followingIsExtension() then
39563917
stats += extension()
39573918
else if isDefIntro(localModifierTokens, excludedSoftModifiers = Set(nme.`opaque`)) then
39583919
stats +++= localDef(in.offset)

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
745745
protected def nameIdText[T >: Untyped](tree: NameTree[T], dropExtension: Boolean = false): Text =
746746
if (tree.hasType && tree.symbol.exists) {
747747
var str = nameString(tree.symbol)
748-
if tree.symbol.isExtensionMethod && dropExtension && str.startsWith("extension_") then
748+
if tree.symbol.is(ExtensionMethod) && dropExtension && str.startsWith("extension_") then
749749
str = str.drop("extension_".length)
750750
tree match {
751751
case tree: RefTree => withPos(str, tree.sourcePos)
@@ -788,7 +788,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
788788
import untpd._
789789
dclTextOr(tree) {
790790
val defKeyword = modText(tree.mods, tree.symbol, keywordStr("def"), isType = false)
791-
val isExtension = tree.hasType && tree.symbol.isExtensionMethod
791+
val isExtension = tree.hasType && tree.symbol.is(ExtensionMethod)
792792
withEnclosingDef(tree) {
793793
val (prefix, vparamss) =
794794
if isExtension then

compiler/src/dotty/tools/dotc/transform/SymUtils.scala

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -213,16 +213,6 @@ object SymUtils {
213213
def isTypeSplice(using Context): Boolean =
214214
self == defn.QuotedType_splice
215215

216-
/** Is symbol an extension method? Accessors are excluded since
217-
* after the getters phase collective extension objects become accessors
218-
*/
219-
def isExtensionMethod(using Context): Boolean =
220-
self.isAllOf(ExtensionMethod, butNot = Accessor)
221-
222-
/** Is symbol the module class of a collective extension object? */
223-
def isCollectiveExtensionClass(using Context): Boolean =
224-
self.is(ModuleClass) && self.sourceModule.is(Extension) && !self.sourceModule.isExtensionMethod
225-
226216
def isScalaStatic(using Context): Boolean =
227217
self.hasAnnotation(defn.ScalaStaticAnnot)
228218

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,8 +2108,8 @@ trait Applications extends Compatibility {
21082108
}
21092109
def isExtension(tree: Tree): Boolean = methPart(tree) match {
21102110
case Inlined(call, _, _) => isExtension(call)
2111-
case tree @ Select(qual, nme.apply) => tree.symbol.is(Extension) || isExtension(qual)
2112-
case tree => tree.symbol.is(Extension)
2111+
case tree @ Select(qual, nme.apply) => tree.symbol.is(ExtensionMethod) || isExtension(qual)
2112+
case tree => tree.symbol.is(ExtensionMethod)
21132113
}
21142114
if (!isExtension(app))
21152115
report.error(em"not an extension method: $methodRef", receiver.srcPos)

0 commit comments

Comments
 (0)