Skip to content

Commit bbbf2ec

Browse files
authored
Merge pull request #6278 from dotty-staging/change-erased
Change `erased` syntax
2 parents 559b410 + 6687e2c commit bbbf2ec

Some content is hidden

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

69 files changed

+175
-167
lines changed

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@ class Definitions {
106106
* ErasedFunctionN traits follow this template:
107107
*
108108
* trait ErasedFunctionN[T0,...,T{N-1}, R] extends Object {
109-
* def apply(erased $x0: T0, ..., $x{N_1}: T{N-1}): R
109+
* def apply erased ($x0: T0, ..., $x{N_1}: T{N-1}): R
110110
* }
111111
*
112112
* ErasedImplicitFunctionN traits follow this template:
113113
*
114114
* trait ErasedImplicitFunctionN[T0,...,T{N-1}, R] extends Object {
115-
* def apply given (erased $x0: T0, ..., $x{N_1}: T{N-1}): R
115+
* def apply given erased ($x0: T0, ..., $x{N_1}: T{N-1}): R
116116
* }
117117
*
118118
* ErasedFunctionN and ErasedImplicitFunctionN erase to Function0.

compiler/src/dotty/tools/dotc/core/tasty/TastyFormat.scala

+2-4
Original file line numberDiff line numberDiff line change
@@ -432,15 +432,14 @@ object TastyFormat {
432432
final val CONTEXTUALMETHODtype = 182
433433
final val ERASEDCONTEXTUALMETHODtype = 183
434434
final val IMPLICITMETHODtype = 184
435-
final val ERASEDIMPLICITMETHODtype = 185
436435

437436
final val MATCHtype = 190
438437
final val MATCHtpt = 191
439438

440439
def methodType(isContextual: Boolean, isImplicit: Boolean, isErased: Boolean): Int = {
441440
val implicitOffset =
442441
if (isContextual) 2
443-
else if (isImplicit) 4
442+
else if (isImplicit) { assert(!isErased); 4 }
444443
else 0
445444
val erasedOffset = if (isErased) 1 else 0
446445
METHODtype + erasedOffset + implicitOffset
@@ -650,7 +649,6 @@ object TastyFormat {
650649
case CONTEXTUALMETHODtype => "CONTEXTUALMETHODtype"
651650
case ERASEDCONTEXTUALMETHODtype => "ERASEDCONTEXTUALMETHODtype"
652651
case IMPLICITMETHODtype => "IMPLICITMETHODtype"
653-
case ERASEDIMPLICITMETHODtype => "ERASEDIMPLICITMETHODtype"
654652
case TYPELAMBDAtype => "TYPELAMBDAtype"
655653
case LAMBDAtpt => "LAMBDAtpt"
656654
case MATCHtype => "MATCHtype"
@@ -672,7 +670,7 @@ object TastyFormat {
672670
case POLYtype | TYPELAMBDAtype |
673671
METHODtype | ERASEDMETHODtype |
674672
CONTEXTUALMETHODtype | ERASEDCONTEXTUALMETHODtype |
675-
IMPLICITMETHODtype | ERASEDIMPLICITMETHODtype => -1
673+
IMPLICITMETHODtype => -1
676674
case _ => 0
677675
}
678676
}

compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) {
8686
printNat(); printTrees()
8787
case METHODtype | ERASEDMETHODtype |
8888
CONTEXTUALMETHODtype | ERASEDCONTEXTUALMETHODtype |
89-
IMPLICITMETHODtype | ERASEDIMPLICITMETHODtype |
90-
POLYtype | TYPELAMBDAtype =>
89+
IMPLICITMETHODtype | POLYtype | TYPELAMBDAtype =>
9190
printTree()
9291
until(end) { printName(); printTree() }
9392
case PARAMtype =>

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

-2
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,6 @@ class TreeUnpickler(reader: TastyReader,
357357
readMethodic(ErasedContextualMethodType, _.toTermName)
358358
case IMPLICITMETHODtype =>
359359
readMethodic(ImplicitMethodType, _.toTermName)
360-
case ERASEDIMPLICITMETHODtype =>
361-
readMethodic(ErasedImplicitMethodType, _.toTermName)
362360
case TYPELAMBDAtype =>
363361
readMethodic(HKTypeLambda, _.toTypeName)
364362
case PARAMtype =>

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

+22-28
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ object Parsers {
12101210

12111211
def expr(location: Location.Value): Tree = {
12121212
val start = in.offset
1213-
if (in.token == IMPLICIT || in.token == ERASED || in.token == GIVEN) {
1213+
if (closureMods.contains(in.token)) {
12141214
val imods = modifiers(closureMods)
12151215
if (in.token == MATCH) implicitMatch(start, imods)
12161216
else implicitClosure(start, location, imods)
@@ -1994,11 +1994,9 @@ object Parsers {
19941994
normalize(loop(start))
19951995
}
19961996

1997-
/** FunArgMods ::= { `implicit` | `erased` }
1998-
* ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’}
1997+
/** ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’}
19991998
* FunTypeMods ::= { ‘erased’ | ‘given’}
20001999
*/
2001-
val funArgMods: BitSet = BitSet(IMPLICIT, ERASED)
20022000
val closureMods: BitSet = BitSet(GIVEN, IMPLICIT, ERASED)
20032001
val funTypeMods: BitSet = BitSet(GIVEN, ERASED)
20042002

@@ -2083,11 +2081,12 @@ object Parsers {
20832081
def typeParamClauseOpt(ownerKind: ParamOwner.Value): List[TypeDef] =
20842082
if (in.token == LBRACKET) typeParamClause(ownerKind) else Nil
20852083

2086-
/** ClsParamClause ::= [nl | ‘with’] `(' [FunArgMods] [ClsParams] ')'
2084+
/** ClsParamClause ::= [nl] [‘erased’] ‘(’ [ClsParams] ‘)’
2085+
* | ‘given’ [‘erased’] (‘(’ ClsParams ‘)’ | ContextTypes)
20872086
* ClsParams ::= ClsParam {`' ClsParam}
20882087
* ClsParam ::= {Annotation} [{ParamModifier} (`val' | `var') | `inline'] Param
2089-
* DefParamClause ::= [nl] `(' [FunArgMods] [DefParams] ')' | InferParamClause
2090-
* InferParamClause ::= ‘given’ (‘(’ DefParams ‘)’ | ContextTypes)
2088+
* DefParamClause ::= [nl] [‘erased’] ‘(’ [DefParams] ‘)’ | GivenParamClause
2089+
* GivenParamClause ::= ‘given’ [‘erased’] (‘(’ DefParams ‘)’ | ContextTypes)
20912090
* ContextTypes ::= RefinedType {`,' RefinedType}
20922091
* DefParams ::= DefParam {`,' DefParam}
20932092
* DefParam ::= {Annotation} [`inline'] Param
@@ -2158,17 +2157,10 @@ object Parsers {
21582157

21592158
// begin paramClause
21602159
inParens {
2161-
val isContextual = impliedMods.is(Given)
2162-
if (in.token == RPAREN && !prefix && !isContextual) Nil
2160+
if (in.token == RPAREN && !prefix && !impliedMods.is(Given)) Nil
21632161
else {
2164-
def funArgMods(mods: Modifiers): Modifiers =
2165-
if (in.token == IMPLICIT && !isContextual)
2166-
funArgMods(addMod(mods, atSpan(accept(IMPLICIT)) { Mod.Implicit() }))
2167-
else if (in.token == ERASED)
2168-
funArgMods(addMod(mods, atSpan(accept(ERASED)) { Mod.Erased() }))
2169-
else mods
2170-
2171-
impliedMods = funArgMods(impliedMods)
2162+
if (in.token == IMPLICIT && !impliedMods.is(Given | Erased))
2163+
impliedMods = addMod(impliedMods, atSpan(accept(IMPLICIT)) { Mod.Implicit() })
21722164
val clause =
21732165
if (prefix) param() :: Nil
21742166
else commaSeparated(() => param())
@@ -2178,22 +2170,24 @@ object Parsers {
21782170
}
21792171
}
21802172

2181-
/** ClsParamClauses ::= {ClsParamClause}
2182-
* DefParamClauses ::= {DefParamClause}
2183-
* InferParamClauses ::= {InferParamClause}
2173+
/** ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
2174+
* DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
21842175
*
21852176
* @return The parameter definitions
21862177
*/
21872178
def paramClauses(ofClass: Boolean = false,
21882179
ofCaseClass: Boolean = false,
21892180
ofInstance: Boolean = false): List[List[ValDef]] = {
21902181
def recur(firstClause: Boolean, nparams: Int): List[List[ValDef]] = {
2191-
val initialMods =
2192-
if (in.token == GIVEN) {
2193-
in.nextToken()
2194-
Modifiers(Given | Implicit)
2195-
}
2196-
else EmptyModifiers
2182+
var initialMods = EmptyModifiers
2183+
if (in.token == GIVEN) {
2184+
in.nextToken()
2185+
initialMods |= Given | Implicit
2186+
}
2187+
if (in.token == ERASED) {
2188+
in.nextToken()
2189+
initialMods |= Erased
2190+
}
21972191
val isContextual = initialMods.is(Given)
21982192
newLineOptWhenFollowedBy(LPAREN)
21992193
if (in.token == LPAREN) {
@@ -2617,7 +2611,7 @@ object Parsers {
26172611
}
26182612

26192613
/** InstanceDef ::= [id] InstanceParams InstanceBody
2620-
* InstanceParams ::= [DefTypeParamClause] {InferParamClause}
2614+
* InstanceParams ::= [DefTypeParamClause] {GivenParamClause}
26212615
* InstanceBody ::= [‘of’ ConstrApp {‘,’ ConstrApp }] [TemplateBody]
26222616
* | ‘of’ Type ‘=’ Expr
26232617
*/
@@ -2906,7 +2900,7 @@ object Parsers {
29062900
else if (isExprIntro)
29072901
stats += expr(Location.InBlock)
29082902
else if (isDefIntro(localModifierTokens))
2909-
if (in.token == IMPLICIT || in.token == ERASED || in.token == GIVEN) {
2903+
if (closureMods.contains(in.token)) {
29102904
val start = in.offset
29112905
var imods = modifiers(closureMods)
29122906
if (isBindingIntro)

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,10 @@ class PlainPrinter(_ctx: Context) extends Printer {
185185
"<noprefix>"
186186
case tp: MethodType =>
187187
changePrec(GlobalPrec) {
188-
(if (tp.isContextual) " given " else "") ~
189-
("(" + (if (tp.isErasedMethod) "erased " else "")
190-
+ (if (tp.isImplicitMethod && !tp.isContextual) "implicit " else "")
191-
) ~ paramsText(tp) ~
188+
(if (tp.isContextual) " given" else "") ~
189+
(if (tp.isErasedMethod) " erased" else "") ~~
190+
("(" + (if (tp.isImplicitMethod && !tp.isContextual) "implicit " else "")) ~
191+
paramsText(tp) ~
192192
(if (tp.resultType.isInstanceOf[MethodType]) ")" else "): ") ~
193193
toText(tp.resultType)
194194
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
136136
atPrec(InfixPrec) { argText(args.head) }
137137
else
138138
toTextTuple(args.init)
139-
(keywordText("erased ") provided isErased) ~
140139
(keywordText("given ") provided isContextual) ~
140+
(keywordText("erased ") provided isErased) ~
141141
argStr ~ " => " ~ argText(args.last)
142142
}
143143

144144
def toTextDependentFunction(appType: MethodType): Text =
145-
(keywordText("erased ") provided appType.isErasedMethod) ~
146145
(keywordText("given ") provided appType.isImplicitMethod) ~
146+
(keywordText("erased ") provided appType.isErasedMethod) ~
147147
"(" ~ paramsText(appType) ~ ") => " ~ toText(appType.resultType)
148148

149149
def isInfixType(tp: Type): Boolean = tp match {

compiler/src/dotty/tools/dotc/tastyreflect/KernelImpl.scala

+2
Original file line numberDiff line numberDiff line change
@@ -1653,13 +1653,15 @@ class KernelImpl(val rootContext: core.Contexts.Context, val rootPosition: util.
16531653
/** Intersection of the two flag sets */
16541654
def Flags_and(self: Flags)(that: Flags): Flags = self & that
16551655

1656+
def Flags_EmptyFlags: Flags = core.Flags.EmptyFlags
16561657
def Flags_Private: Flags = core.Flags.Private
16571658
def Flags_Protected: Flags = core.Flags.Protected
16581659
def Flags_Abstract: Flags = core.Flags.Abstract
16591660
def Flags_Final: Flags = core.Flags.Final
16601661
def Flags_Sealed: Flags = core.Flags.Sealed
16611662
def Flags_Case: Flags = core.Flags.Case
16621663
def Flags_Implicit: Flags = core.Flags.Implicit
1664+
def Flags_Given: Flags = core.Flags.Given
16631665
def Flags_Implied: Flags = core.Flags.Implied
16641666
def Flags_Erased: Flags = core.Flags.Erased
16651667
def Flags_Lazy: Flags = core.Flags.Lazy

compiler/test-resources/repl/erased

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
scala> def f(erased a: Int): Int = ???
2-
def f(erased a: Int): Int
1+
scala> def f erased (a: Int): Int = ???
2+
def f erased (a: Int): Int
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
scala> def f(erased implicit a: Int): Int = ???
2-
def f(erased implicit a: Int): Int
1+
scala> def f given erased (a: Int): Int = ???
2+
def f given erased (a: Int): Int

docs/docs/internals/syntax.md

+7-8
Original file line numberDiff line numberDiff line change
@@ -290,22 +290,21 @@ HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
290290
HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (Id[HkTypeParamClause] | ‘_’)
291291
SubtypeBounds
292292
293-
ClsParamClauses ::= {ClsParamClause}
294-
ClsParamClause ::= [nl] (’ [[FunArgMods] ClsParams] ‘)’
295-
| ‘given’ (‘(’ ([[FunArgMods] ClsParams] ‘)’ | ContextTypes)
293+
ClsParamClauses ::= {ClsParamClause} [[nl] ‘(’ [‘implicit’] ClsParams ‘)’]
294+
ClsParamClause ::= [nl] [‘erased’] ‘(’ [ClsParams] ‘)’
295+
| ‘given’ [‘erased’] (‘(’ ClsParams ‘)’ | ContextTypes)
296296
ClsParams ::= ClsParam {‘,’ ClsParam}
297297
ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var
298298
[{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
299299
Param ::= id ‘:’ ParamType [‘=’ Expr]
300300
| INT
301301
302-
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [FunArgMods] DefParams ‘)’]
303-
DefParamClause ::= [nl] (’ [DefParams] ‘)’ | InferParamClause
304-
InferParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | ContextTypes)
302+
DefParamClauses ::= {DefParamClause} [[nl] ‘(’ [‘implicit’] DefParams ‘)’]
303+
DefParamClause ::= [nl] [‘erased’] ‘(’ [DefParams] ‘)’ | GivenParamClause
304+
GivenParamClause ::= ‘given’ [‘erased’] (‘(’ DefParams ‘)’ | ContextTypes)
305305
DefParams ::= DefParam {‘,’ DefParam}
306306
DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
307307
ContextTypes ::= RefinedType {‘,’ RefinedType}
308-
FunArgMods ::= { ‘implicit’ | ‘erased’ }
309308
ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’}
310309
```
311310

@@ -379,7 +378,7 @@ ConstrMods ::= {Annotation} [AccessModifier]
379378
ObjectDef ::= id [Template] ModuleDef(mods, name, template) // no constructor
380379
EnumDef ::= id ClassConstr InheritClauses EnumBody EnumDef(mods, name, tparams, template)
381380
InstanceDef ::= [id] InstanceParams InstanceBody
382-
InstanceParams ::= [DefTypeParamClause] {InferParamClause}
381+
InstanceParams ::= [DefTypeParamClause] {GivenParamClause}
383382
InstanceBody ::= [‘of’ ConstrApp {‘,’ ConstrApp }] [TemplateBody]
384383
| ‘of’ Type ‘=’ Expr
385384
Template ::= InheritClauses [TemplateBody] Template(constr, parents, self, stats)

docs/docs/reference/other-new-features/erased-terms.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ present in some form in the generated code to be able to do separate compilation
3838

3939
How to define erased terms?
4040
-------------------------------
41-
Parameters of methods and functions can be declared as erased, placing `erased` at the start of the parameter list (like `implicit`).
41+
Parameters of methods and functions can be declared as erased, placing `erased` in front of a parameter list (like `given`).
4242

4343
```scala
44-
def methodWithErasedEv(erased ev: Ev): Int = 42
44+
def methodWithErasedEv erased (ev: Ev): Int = 42
4545

4646
val lambdaWithErasedEv: erased Ev => Int =
4747
erased (ev: Ev) => 42
@@ -50,10 +50,10 @@ val lambdaWithErasedEv: erased Ev => Int =
5050
`erased` parameters will not be usable for computations, though they can be used as arguments to other `erased` parameters.
5151

5252
```scala
53-
def methodWithErasedInt1(erased i: Int): Int =
53+
def methodWithErasedInt1 erased (i: Int): Int =
5454
i + 42 // ERROR: can not use i
5555

56-
def methodWithErasedInt2(erased i: Int): Int =
56+
def methodWithErasedInt2 erased (i: Int): Int =
5757
methodWithErasedInt1(i) // OK
5858
```
5959

@@ -70,7 +70,7 @@ As `erased` are guaranteed not to be used in computations, they can and will be
7070

7171
```scala
7272
// becomes def methodWithErasedEv(): Int at runtime
73-
def methodWithErasedEv(erased ev: Ev): Int = ...
73+
def methodWithErasedEv erased (ev: Ev): Int = ...
7474

7575
def evidence1: Ev = ...
7676
erased def erasedEvidence2: Ev = ... // does not exist at runtime
@@ -83,13 +83,13 @@ methodWithErasedEv(evidence1)
8383
State machine with erased evidence example
8484
------------------------------------------
8585
The following example is an extended implementation of a simple state machine which can be in a state `On` or `Off`.
86-
The machine can change state from `Off` to `On` with `turnedOn` only if it is currently `Off`,
86+
The machine can change state from `Off` to `On` with `turnedOn` only if it is currently `Off`,
8787
conversely from `On` to `Off` with `turnedOff` only if it is currently `On`. These last constraint are
88-
captured with the `IsOff[S]` and `IsOn[S]` implicit evidence only exist for `IsOff[Off]` and `IsOn[On]`.
89-
For example, not allowing calling `turnedOff` on in an `Off` state as we would require an evidence `IsOn[Off]`
88+
captured with the `IsOff[S]` and `IsOn[S]` implicit evidence only exist for `IsOff[Off]` and `IsOn[On]`.
89+
For example, not allowing calling `turnedOff` on in an `Off` state as we would require an evidence `IsOn[Off]`
9090
that will not be found.
9191

92-
As the implicit evidences of `turnedOn` and `turnedOff` are not used in the bodies of those functions
92+
As the implicit evidences of `turnedOn` and `turnedOff` are not used in the bodies of those functions
9393
we can mark them as `erased`. This will remove the evidence parameters at runtime, but we would still
9494
evaluate the `isOn` and `isOff` implicits that were found as arguments.
9595
As `isOn` and `isOff` are not used except as `erased` arguments, we can mark them as `erased`, hence
@@ -117,9 +117,9 @@ object IsOn {
117117
}
118118

119119
class Machine[S <: State] private {
120-
// ev will disapear from both functions
121-
def turnedOn(implicit erased ev: IsOff[S]): Machine[On] = new Machine[On]
122-
def turnedOff(implicit erased ev: IsOn[S]): Machine[Off] = new Machine[Off]
120+
// ev will disappear from both functions
121+
def turnedOn given erased (ev: IsOff[S]): Machine[On] = new Machine[On]
122+
def turnedOff given erased (ev: IsOn[S]): Machine[Off] = new Machine[Off]
123123
}
124124

125125
object Machine {
@@ -156,12 +156,12 @@ Rules
156156
erased val x = ...
157157
erased def f = ...
158158

159-
def g(erased x: Int) = ...
159+
def g erased (x: Int) = ...
160160

161-
(erased x: Int) => ...
161+
erased (x: Int) => ...
162162
def h(x: erased Int => Int) = ...
163163

164-
class K(erased x: Int) { ... }
164+
class K erased (x: Int) { ... }
165165
```
166166

167167

@@ -182,14 +182,14 @@ Rules
182182

183183
4. Eta expansion
184184

185-
if `def f(erased x: T): U` then `f: (erased T) => U`.
185+
if `def f erased (x: T): U` then `f: erased (T) => U`.
186186

187187

188188
5. Erasure Semantics
189189
* All `erased` parameters are removed from the function
190190
* All argument to `erased` parameters are not passed to the function
191191
* All `erased` definitions are removed
192-
* All `(erased T1, T2, ..., TN) => R` and `(given erased T1, T2, ..., TN) => R` become `() => R`
192+
* All ` erased (T1, T2, ..., TN) => R` and `(given erased T1, T2, ..., TN) => R` become `() => R`
193193

194194

195195
6. Overloading
@@ -198,6 +198,6 @@ Rules
198198

199199

200200
7. Overriding
201-
* Member definitions overidding each other must both be `erased` or not be `erased`
202-
* `def foo(x: T): U` cannot be overridden by `def foo(erased x: T): U` an viceversa
201+
* Member definitions overriding each other must both be `erased` or not be `erased`
202+
* `def foo(x: T): U` cannot be overridden by `def foo erased (x: T): U` an vice-versa
203203

0 commit comments

Comments
 (0)