@@ -222,6 +222,8 @@ object Parsers {
222
222
def isErased = isIdent(nme.erased) && in.erasedEnabled
223
223
// Are we seeing an `erased` soft keyword that will not be an identifier?
224
224
def isErasedKw = isErased && in.isSoftModifierInParamModifierPosition
225
+ // Are we seeing a `cap` soft keyword for declaring a capture-set member or at the beginning a capture-variable parameter list?
226
+ def isCapKw = Feature .ccEnabled && isIdent(nme.cap)
225
227
def isSimpleLiteral =
226
228
simpleLiteralTokens.contains(in.token)
227
229
|| isIdent(nme.raw.MINUS ) && numericLitTokens.contains(in.lookahead.token)
@@ -258,7 +260,7 @@ object Parsers {
258
260
|| defIntroTokens.contains(in.token)
259
261
|| allowedMods.contains(in.token)
260
262
|| in.isSoftModifierInModifierPosition && ! excludedSoftModifiers.contains(in.name)
261
- || Feature .ccEnabled && isIdent(nme.cap) // TODO have it as proper keyword/token instead?
263
+ || isCapKw
262
264
263
265
def isStatSep : Boolean = in.isStatSep
264
266
@@ -2253,22 +2255,28 @@ object Parsers {
2253
2255
else
2254
2256
TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
2255
2257
2258
+ /** CaptureSetBounds ::= [`>:' CaptureSetOrRef ] [`<:' CaptureSetOrRef ] --- under captureChecking
2259
+ */
2260
+ def captureSetBounds (): TypeBoundsTree =
2261
+ atSpan(in.offset):
2262
+ TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2263
+
2256
2264
private def bound (tok : Int ): Tree =
2257
2265
if (in.token == tok) { in.nextToken(); toplevelTyp() }
2258
2266
else EmptyTree
2259
2267
2260
- private def capsType (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2261
- if isLowerBound && refs.isEmpty then
2268
+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2269
+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2262
2270
Select (scalaDot(nme.caps), tpnme.CapSet )
2263
2271
else
2264
2272
makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2265
2273
2266
2274
private def capsBound (tok : Int ): Tree =
2267
2275
if (in.token == tok) then
2268
2276
in.nextToken()
2269
- capsType (captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
2277
+ capsBound (captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
2270
2278
else
2271
- capsType (Nil , isLowerBound = tok == SUPERTYPE )
2279
+ capsBound (Nil , isLowerBound = tok == SUPERTYPE )
2272
2280
2273
2281
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2274
2282
*/
@@ -2279,10 +2287,10 @@ object Parsers {
2279
2287
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2280
2288
}
2281
2289
2282
- /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds] -- under captureChecking
2290
+ /** CaptureSetAndCtxBounds ::= CaptureSetBounds [`:` ContextBounds] -- under captureChecking
2283
2291
*/
2284
2292
def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2285
- val t = TypeBoundsTree (capsBound( SUPERTYPE ), capsBound( SUBTYPE ) )
2293
+ val t = captureSetBounds( )
2286
2294
val cbs = contextBounds(pname)
2287
2295
if (cbs.isEmpty) t
2288
2296
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
@@ -3900,7 +3908,7 @@ object Parsers {
3900
3908
case CASE if inEnum =>
3901
3909
enumCase(start, mods)
3902
3910
case _ =>
3903
- if Feature .ccEnabled && isIdent(nme.cap) then // TODO do we want a dedicated CAP token? TokensCommon would need a Ctx to check if ccenabled
3911
+ if isCapKw then
3904
3912
capDefOrDcl(start, in.skipToken(mods))
3905
3913
else tmplDef(start, mods)
3906
3914
}
@@ -4111,20 +4119,22 @@ object Parsers {
4111
4119
}
4112
4120
}
4113
4121
4114
- /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSet] -- under capture checking
4122
+ private def concreteCapsType (refs : List [Tree ]): Tree =
4123
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4124
+
4125
+ /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSetOrRef] -- under capture checking
4115
4126
*/
4116
4127
def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
4117
4128
newLinesOpt()
4118
4129
atSpan(start, nameStart) {
4119
4130
val nameIdent = typeIdent()
4120
4131
val tname = nameIdent.name.asTypeName
4121
- // val tparams = typeParamClauseOpt(ParamOwner.Hk) TODO: error message: type parameters not allowed
4122
- // val vparamss = funParamClauses()
4132
+ if in.token == LBRACKET then syntaxError(em " 'cap' declarations cannot have type parameters " )
4123
4133
4124
4134
def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
4125
4135
val tdef = TypeDef (nameIdent.name.toTypeName,
4126
4136
refs.match
4127
- case refs : List [Tree ] => capsType (refs)
4137
+ case refs : List [Tree ] => concreteCapsType (refs)
4128
4138
case bounds : Tree => bounds)
4129
4139
4130
4140
if (nameIdent.isBackquoted)
@@ -4136,24 +4146,13 @@ object Parsers {
4136
4146
case EQUALS =>
4137
4147
in.nextToken()
4138
4148
makeCapDef(captureSetOrRef())
4139
- case SUBTYPE | SUPERTYPE =>
4140
- captureSetAndCtxBounds(tname) match
4141
- case bounds : TypeBoundsTree if in.token == EQUALS => // TODO ask Martin: can this case even happen?
4142
- val eqOffset = in.skipToken()
4143
- var rhs = capsType(captureSetOrRef())
4144
- if mods.is(Opaque ) then
4145
- rhs = TypeBoundsTree (bounds.lo, bounds.hi, rhs)
4146
- else
4147
- syntaxError(em " cannot combine bound and alias " , eqOffset)
4148
- makeCapDef(rhs)
4149
- case bounds => makeCapDef(bounds)
4150
- case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4149
+ case SUBTYPE | SUPERTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4151
4150
makeCapDef(captureSetAndCtxBounds(tname))
4152
- case _ if (staged & StageKind .QuotedPattern ) != 0 // TODO not sure if we need this case for capsets
4151
+ case _ if (staged & StageKind .QuotedPattern ) != 0
4153
4152
|| sourceVersion.enablesNewGivens && in.isColon =>
4154
4153
makeCapDef(captureSetAndCtxBounds(tname))
4155
4154
case _ =>
4156
- syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token)) // TODO change error message
4155
+ syntaxErrorOrIncomplete(ExpectedCaptureBoundOrEquals (in.token))
4157
4156
return EmptyTree // return to avoid setting the span to EmptyTree
4158
4157
}
4159
4158
0 commit comments