@@ -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
@@ -2260,22 +2262,28 @@ object Parsers {
2260
2262
else
2261
2263
TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
2262
2264
2265
+ /** CaptureSetBounds ::= [`>:' CaptureSetOrRef ] [`<:' CaptureSetOrRef ] --- under captureChecking
2266
+ */
2267
+ def captureSetBounds (): TypeBoundsTree =
2268
+ atSpan(in.offset):
2269
+ TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2270
+
2263
2271
private def bound (tok : Int ): Tree =
2264
2272
if (in.token == tok) { in.nextToken(); toplevelTyp() }
2265
2273
else EmptyTree
2266
2274
2267
- private def capsType (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2268
- if isLowerBound && refs.isEmpty then
2275
+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2276
+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2269
2277
Select (scalaDot(nme.caps), tpnme.CapSet )
2270
2278
else
2271
2279
makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2272
2280
2273
2281
private def capsBound (tok : Int ): Tree =
2274
2282
if (in.token == tok) then
2275
2283
in.nextToken()
2276
- capsType (captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
2284
+ capsBound (captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
2277
2285
else
2278
- capsType (Nil , isLowerBound = tok == SUPERTYPE )
2286
+ capsBound (Nil , isLowerBound = tok == SUPERTYPE )
2279
2287
2280
2288
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2281
2289
*/
@@ -2286,10 +2294,10 @@ object Parsers {
2286
2294
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2287
2295
}
2288
2296
2289
- /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds] -- under captureChecking
2297
+ /** CaptureSetAndCtxBounds ::= CaptureSetBounds [`:` ContextBounds] -- under captureChecking
2290
2298
*/
2291
2299
def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2292
- val t = TypeBoundsTree (capsBound( SUPERTYPE ), capsBound( SUBTYPE ) )
2300
+ val t = captureSetBounds( )
2293
2301
val cbs = contextBounds(pname)
2294
2302
if (cbs.isEmpty) t
2295
2303
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
@@ -3907,7 +3915,7 @@ object Parsers {
3907
3915
case CASE if inEnum =>
3908
3916
enumCase(start, mods)
3909
3917
case _ =>
3910
- if Feature .ccEnabled && isIdent(nme.cap) then // TODO do we want a dedicated CAP token? TokensCommon would need a Ctx to check if ccenabled
3918
+ if isCapKw then
3911
3919
capDefOrDcl(start, in.skipToken(mods))
3912
3920
else tmplDef(start, mods)
3913
3921
}
@@ -4118,20 +4126,22 @@ object Parsers {
4118
4126
}
4119
4127
}
4120
4128
4121
- /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSet] -- under capture checking
4129
+ private def concreteCapsType (refs : List [Tree ]): Tree =
4130
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4131
+
4132
+ /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSetOrRef] -- under capture checking
4122
4133
*/
4123
4134
def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
4124
4135
newLinesOpt()
4125
4136
atSpan(start, nameStart) {
4126
4137
val nameIdent = typeIdent()
4127
4138
val tname = nameIdent.name.asTypeName
4128
- // val tparams = typeParamClauseOpt(ParamOwner.Hk) TODO: error message: type parameters not allowed
4129
- // val vparamss = funParamClauses()
4139
+ if in.token == LBRACKET then syntaxError(em " 'cap' declarations cannot have type parameters " )
4130
4140
4131
4141
def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
4132
4142
val tdef = TypeDef (nameIdent.name.toTypeName,
4133
4143
refs.match
4134
- case refs : List [Tree ] => capsType (refs)
4144
+ case refs : List [Tree ] => concreteCapsType (refs)
4135
4145
case bounds : Tree => bounds)
4136
4146
4137
4147
if (nameIdent.isBackquoted)
@@ -4143,24 +4153,13 @@ object Parsers {
4143
4153
case EQUALS =>
4144
4154
in.nextToken()
4145
4155
makeCapDef(captureSetOrRef())
4146
- case SUBTYPE | SUPERTYPE =>
4147
- captureSetAndCtxBounds(tname) match
4148
- case bounds : TypeBoundsTree if in.token == EQUALS => // TODO ask Martin: can this case even happen?
4149
- val eqOffset = in.skipToken()
4150
- var rhs = capsType(captureSetOrRef())
4151
- if mods.is(Opaque ) then
4152
- rhs = TypeBoundsTree (bounds.lo, bounds.hi, rhs)
4153
- else
4154
- syntaxError(em " cannot combine bound and alias " , eqOffset)
4155
- makeCapDef(rhs)
4156
- case bounds => makeCapDef(bounds)
4157
- case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4156
+ case SUBTYPE | SUPERTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4158
4157
makeCapDef(captureSetAndCtxBounds(tname))
4159
- case _ if (staged & StageKind .QuotedPattern ) != 0 // TODO not sure if we need this case for capsets
4158
+ case _ if (staged & StageKind .QuotedPattern ) != 0
4160
4159
|| sourceVersion.enablesNewGivens && in.isColon =>
4161
4160
makeCapDef(captureSetAndCtxBounds(tname))
4162
4161
case _ =>
4163
- syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token)) // TODO change error message
4162
+ syntaxErrorOrIncomplete(ExpectedCaptureBoundOrEquals (in.token))
4164
4163
return EmptyTree // return to avoid setting the span to EmptyTree
4165
4164
}
4166
4165
0 commit comments