@@ -35,6 +35,7 @@ import config.SourceVersion.*
35
35
import config .SourceVersion
36
36
import dotty .tools .dotc .config .MigrationVersion
37
37
import dotty .tools .dotc .util .chaining .*
38
+ import dotty .tools .dotc .config .Feature .ccEnabled
38
39
39
40
object Parsers {
40
41
@@ -220,6 +221,10 @@ object Parsers {
220
221
def isErased = isIdent(nme.erased) && in.erasedEnabled
221
222
// Are we seeing an `erased` soft keyword that will not be an identifier?
222
223
def isErasedKw = isErased && in.isSoftModifierInParamModifierPosition
224
+ // Are we seeing a `cap` soft keyword for declaring a capture-set member or at the beginning a capture-variable parameter list?
225
+ def isCapKw = Feature .ccEnabled && isIdent(nme.cap)
226
+ // 'cap type' ?
227
+ def isCapTypeKw = isCapKw && in.lookahead.token == TYPE
223
228
def isSimpleLiteral =
224
229
simpleLiteralTokens.contains(in.token)
225
230
|| isIdent(nme.raw.MINUS ) && numericLitTokens.contains(in.lookahead.token)
@@ -1917,7 +1922,7 @@ object Parsers {
1917
1922
refinedTypeRest(atSpan(startOffset(t)) {
1918
1923
RefinedTypeTree (rejectWildcardType(t), refinement(indentOK = true ))
1919
1924
})
1920
- else if Feature .ccEnabled && in.isIdent(nme.UPARROW ) && isCaptureUpArrow then
1925
+ else if Feature .ccEnabled && in.isIdent(nme.UPARROW ) && isCaptureUpArrow then // TODO remove
1921
1926
atSpan(t.span.start):
1922
1927
in.nextToken()
1923
1928
if in.token == LBRACE
@@ -1972,7 +1977,8 @@ object Parsers {
1972
1977
1973
1978
def typeBlockStats (): List [Tree ] =
1974
1979
val tdefs = new ListBuffer [Tree ]
1975
- while in.token == TYPE do tdefs += typeBlockStat()
1980
+ while (in.token == TYPE ) do
1981
+ tdefs += typeBlockStat()
1976
1982
tdefs.toList
1977
1983
1978
1984
/** TypeBlockStat ::= ‘type’ {nl} TypeDef
@@ -2173,11 +2179,14 @@ object Parsers {
2173
2179
* NamesAndTypes ::= NameAndType {‘,’ NameAndType}
2174
2180
* NameAndType ::= id ':' Type
2175
2181
*/
2176
- def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] =
2177
- def argType ( ) =
2178
- val t = typ()
2182
+ def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] = // TOOD grammar doc
2183
+ def withWildCard ( gen : => Tree ) =
2184
+ val t = gen
2179
2185
if wildOK then t else rejectWildcardType(t)
2180
2186
2187
+ def argType () = withWildCard(typ())
2188
+ def argOrCapType () = withWildCard(if in.token == LBRACE then concreteCapsType(captureSet()) else typ())
2189
+
2181
2190
def namedArgType () =
2182
2191
atSpan(in.offset):
2183
2192
val name = ident()
@@ -2188,14 +2197,14 @@ object Parsers {
2188
2197
atSpan(in.offset):
2189
2198
val name = ident()
2190
2199
acceptColon()
2191
- NamedArg (name, argType())
2200
+ NamedArg (name, argType()) // TODO allow capsets here?
2192
2201
2193
- if namedOK && isIdent && in.lookahead.token == EQUALS then
2194
- commaSeparated(() => namedArgType())
2202
+ if namedOK && isIdent && in.lookahead.token == EQUALS then // TOOD support for named cap args
2203
+ commaSeparated(() => namedArgType())
2195
2204
else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
2196
2205
commaSeparated(() => namedElem())
2197
2206
else
2198
- commaSeparated(() => argType ())
2207
+ commaSeparated(() => argOrCapType ())
2199
2208
end argTypes
2200
2209
2201
2210
def paramTypeOf (core : () => Tree ): Tree =
@@ -2254,7 +2263,7 @@ object Parsers {
2254
2263
inBraces(refineStatSeq())
2255
2264
2256
2265
/** TypeBounds ::= [`>:' Type] [`<:' Type]
2257
- * | `^` -- under captureChecking
2266
+ * | `^` -- under captureChecking TODO remove
2258
2267
*/
2259
2268
def typeBounds (): TypeBoundsTree =
2260
2269
atSpan(in.offset):
@@ -2264,10 +2273,29 @@ object Parsers {
2264
2273
else
2265
2274
TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
2266
2275
2276
+ /** CaptureSetBounds ::= [`>:' CaptureSetOrRef ] [`<:' CaptureSetOrRef ] --- under captureChecking
2277
+ */
2278
+ def captureSetBounds (): TypeBoundsTree =
2279
+ atSpan(in.offset):
2280
+ TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2281
+
2267
2282
private def bound (tok : Int ): Tree =
2268
2283
if (in.token == tok) { in.nextToken(); toplevelTyp() }
2269
2284
else EmptyTree
2270
2285
2286
+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2287
+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2288
+ Select (scalaDot(nme.caps), tpnme.CapSet )
2289
+ else
2290
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2291
+
2292
+ private def capsBound (tok : Int ): Tree =
2293
+ if (in.token == tok) then
2294
+ in.nextToken()
2295
+ capsBound(captureSet(), isLowerBound = tok == SUPERTYPE )
2296
+ else
2297
+ capsBound(Nil , isLowerBound = tok == SUPERTYPE )
2298
+
2271
2299
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2272
2300
*/
2273
2301
def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -2277,6 +2305,15 @@ object Parsers {
2277
2305
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2278
2306
}
2279
2307
2308
+ /** CaptureSetAndCtxBounds ::= CaptureSetBounds [`:` ContextBounds] -- under captureChecking
2309
+ */
2310
+ def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2311
+ val t = captureSetBounds()
2312
+ val cbs = contextBounds(pname)
2313
+ if (cbs.isEmpty) t
2314
+ else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2315
+ }
2316
+
2280
2317
/** ContextBound ::= Type [`as` id] */
2281
2318
def contextBound (pname : TypeName ): Tree =
2282
2319
val t = toplevelTyp(inContextBound = true )
@@ -2796,7 +2833,10 @@ object Parsers {
2796
2833
in.nextToken()
2797
2834
simpleExprRest(selectorOrMatch(t), location, canApply = true )
2798
2835
case LBRACKET =>
2799
- val tapp = atSpan(startOffset(t), in.offset) { TypeApply (t, typeArgs(namedOK = true , wildOK = false )) }
2836
+ val tapp = atSpan(startOffset(t), in.offset) {
2837
+ val args = typeArgs(namedOK = true , wildOK = false )
2838
+ TypeApply (t, args)
2839
+ }
2800
2840
simpleExprRest(tapp, location, canApply = true )
2801
2841
case LPAREN | LBRACE | INDENT if canApply =>
2802
2842
val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) }
@@ -3320,6 +3360,7 @@ object Parsers {
3320
3360
case nme.tracked => Mod .Tracked ()
3321
3361
case nme.erased if in.erasedEnabled => Mod .Erased ()
3322
3362
case nme.mut if Feature .ccEnabled => Mod .Mut ()
3363
+ case nme.cap => Mod .CaptureParam ()
3323
3364
}
3324
3365
}
3325
3366
@@ -3388,7 +3429,7 @@ object Parsers {
3388
3429
* | opaque
3389
3430
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased |
3390
3431
* inline | transparent | infix |
3391
- * mut -- under cc
3432
+ * mut | cap -- under cc
3392
3433
*/
3393
3434
def modifiers (allowed : BitSet = modifierTokens, start : Modifiers = Modifiers ()): Modifiers = {
3394
3435
@ tailrec
@@ -3477,7 +3518,6 @@ object Parsers {
3477
3518
recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
3478
3519
end typeOrTermParamClauses
3479
3520
3480
-
3481
3521
/** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
3482
3522
* ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3483
3523
* id [HkTypeParamClause] TypeAndCtxBounds
@@ -3502,6 +3542,43 @@ object Parsers {
3502
3542
in.nextToken()
3503
3543
ok
3504
3544
3545
+ def ensureNoHKParams () = // for cap params
3546
+ if in.token == LBRACKET then
3547
+ syntaxError(em " 'cap' parameters cannot have type parameters " )
3548
+ in.nextToken()
3549
+
3550
+ def ensureNoVariance () = // for cap params
3551
+ if isIdent(nme.raw.PLUS ) || isIdent(nme.raw.MINUS ) then
3552
+ syntaxError(em " no `+/-` variance annotation allowed here " )
3553
+ in.nextToken()
3554
+
3555
+ def typeOrCapParam (): TypeDef =
3556
+ if isCapKw then
3557
+ in.nextToken()
3558
+ capParam()
3559
+ else typeParam()
3560
+
3561
+ def capParam (): TypeDef = {
3562
+ val start = in.offset
3563
+ var mods = annotsAsMods() | Param
3564
+ if paramOwner.isClass then
3565
+ mods |= PrivateLocal
3566
+ ensureNoVariance() // TODO: in the future, we might want to support variances on capture params, ruled out for now
3567
+ atSpan(start, nameStart) {
3568
+ val name =
3569
+ if paramOwner.acceptsWildcard && in.token == USCORE then
3570
+ in.nextToken()
3571
+ WildcardParamName .fresh().toTypeName
3572
+ else ident().toTypeName
3573
+ ensureNoHKParams()
3574
+ val bounds =
3575
+ if paramOwner.acceptsCtxBounds then captureSetAndCtxBounds(name)
3576
+ else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then captureSetAndCtxBounds(name)
3577
+ else captureSetBounds()
3578
+ TypeDef (name, bounds).withMods(mods)
3579
+ }
3580
+ }
3581
+
3505
3582
def typeParam (): TypeDef = {
3506
3583
val start = in.offset
3507
3584
var mods = annotsAsMods() | Param
@@ -3525,11 +3602,14 @@ object Parsers {
3525
3602
TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
3526
3603
}
3527
3604
}
3528
- commaSeparated(() => typeParam ())
3605
+ commaSeparated(() => typeOrCapParam ())
3529
3606
}
3530
3607
3531
3608
def typeParamClauseOpt (paramOwner : ParamOwner ): List [TypeDef ] =
3532
- if (in.token == LBRACKET ) typeParamClause(paramOwner) else Nil
3609
+ if (in.token == LBRACKET )
3610
+ typeParamClause(paramOwner)
3611
+ else
3612
+ Nil
3533
3613
3534
3614
/** ContextTypes ::= FunArgType {‘,’ FunArgType}
3535
3615
*/
@@ -3871,25 +3951,29 @@ object Parsers {
3871
3951
* | var VarDef
3872
3952
* | def DefDef
3873
3953
* | type {nl} TypeDef
3954
+ * | cap type {nl} CapDef -- under capture checking
3874
3955
* | TmplDef
3875
3956
* EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
3876
3957
*/
3877
- def defOrDcl (start : Int , mods : Modifiers ): Tree = in.token match {
3878
- case VAL =>
3879
- in.nextToken()
3880
- patDefOrDcl(start, mods)
3881
- case VAR =>
3882
- val mod = atSpan(in.skipToken()) { Mod .Var () }
3883
- val mod1 = addMod(mods, mod)
3884
- patDefOrDcl(start, mod1)
3885
- case DEF =>
3886
- defDefOrDcl(start, in.skipToken(mods))
3887
- case TYPE =>
3888
- typeDefOrDcl(start, in.skipToken(mods))
3889
- case CASE if inEnum =>
3890
- enumCase(start, mods)
3891
- case _ =>
3892
- tmplDef(start, mods)
3958
+ def defOrDcl (start : Int , mods : Modifiers ): Tree =
3959
+ in.token match {
3960
+ case VAL =>
3961
+ in.nextToken()
3962
+ patDefOrDcl(start, mods)
3963
+ case VAR =>
3964
+ val mod = atSpan(in.skipToken()) { Mod .Var () }
3965
+ val mod1 = addMod(mods, mod)
3966
+ patDefOrDcl(start, mod1)
3967
+ case DEF =>
3968
+ defDefOrDcl(start, in.skipToken(mods))
3969
+ case TYPE if mods.is(CaptureParam ) =>
3970
+ capDefOrDcl(start, in.skipToken(mods))
3971
+ case TYPE =>
3972
+ typeDefOrDcl(start, in.skipToken(mods))
3973
+ case CASE if inEnum =>
3974
+ enumCase(start, mods)
3975
+ case _ =>
3976
+ tmplDef(start, mods)
3893
3977
}
3894
3978
3895
3979
/** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
@@ -4098,6 +4182,43 @@ object Parsers {
4098
4182
}
4099
4183
}
4100
4184
4185
+ private def concreteCapsType (refs : List [Tree ]): Tree =
4186
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4187
+
4188
+ /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSetOrRef] -- under capture checking
4189
+ */
4190
+ def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
4191
+ newLinesOpt()
4192
+ atSpan(start, nameStart) {
4193
+ val nameIdent = typeIdent()
4194
+ val tname = nameIdent.name.asTypeName
4195
+ if in.token == LBRACKET then syntaxError(em " 'cap type' declarations cannot have type parameters " )
4196
+
4197
+ def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
4198
+ val tdef = TypeDef (nameIdent.name.toTypeName,
4199
+ refs.match
4200
+ case refs : List [Tree ] => concreteCapsType(refs)
4201
+ case bounds : Tree => bounds)
4202
+
4203
+ if (nameIdent.isBackquoted)
4204
+ tdef.pushAttachment(Backquoted , ())
4205
+ finalizeDef(tdef, mods, start)
4206
+ }
4207
+
4208
+ in.token.match
4209
+ case EQUALS =>
4210
+ in.nextToken()
4211
+ makeCapDef(captureSet())
4212
+ case SUBTYPE | SUPERTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4213
+ makeCapDef(captureSetAndCtxBounds(tname))
4214
+ case _ if (staged & StageKind .QuotedPattern ) != 0
4215
+ || sourceVersion.enablesNewGivens && in.isColon =>
4216
+ makeCapDef(captureSetAndCtxBounds(tname))
4217
+ case _ =>
4218
+ syntaxErrorOrIncomplete(ExpectedCaptureBoundOrEquals (in.token))
4219
+ return EmptyTree // return to avoid setting the span to EmptyTree
4220
+ }
4221
+
4101
4222
/** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
4102
4223
* | [‘case’] ‘object’ ObjectDef
4103
4224
* | ‘enum’ EnumDef
@@ -4691,6 +4812,7 @@ object Parsers {
4691
4812
* | ‘var’ VarDef
4692
4813
* | ‘def’ DefDef
4693
4814
* | ‘type’ {nl} TypeDef
4815
+ * | ‘cap’ ‘type’ {nl} CapDef -- under capture checking
4694
4816
* (in reality we admit class defs and vars and filter them out afterwards in `checkLegal`)
4695
4817
*/
4696
4818
def refineStatSeq (): List [Tree ] = {
@@ -4716,9 +4838,14 @@ object Parsers {
4716
4838
fail(em " this kind of definition cannot be a refinement " )
4717
4839
4718
4840
while
4841
+ val mods =
4842
+ if isCapTypeKw then // allow `cap type` in refinements
4843
+ in.nextToken()
4844
+ addMod(Modifiers (), Mod .CaptureParam ())
4845
+ else Modifiers ()
4719
4846
val dclFound = isDclIntro
4720
4847
if dclFound then
4721
- stats ++= checkLegal(defOrDcl(in.offset, Modifiers () ))
4848
+ stats ++= checkLegal(defOrDcl(in.offset, mods ))
4722
4849
var what = " declaration"
4723
4850
if inFunReturnType then what += " (possible cause: missing `=` in front of current method body)"
4724
4851
statSepOrEnd(stats, noPrevStat = ! dclFound, what)
0 commit comments