@@ -222,6 +222,8 @@ object Parsers {
222222 def isErased = isIdent(nme.erased) && in.erasedEnabled
223223 // Are we seeing an `erased` soft keyword that will not be an identifier?
224224 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)
225227 def isSimpleLiteral =
226228 simpleLiteralTokens.contains(in.token)
227229 || isIdent(nme.raw.MINUS ) && numericLitTokens.contains(in.lookahead.token)
@@ -258,7 +260,7 @@ object Parsers {
258260 || defIntroTokens.contains(in.token)
259261 || allowedMods.contains(in.token)
260262 || in.isSoftModifierInModifierPosition && ! excludedSoftModifiers.contains(in.name)
261- || Feature .ccEnabled && isIdent(nme.cap) // TODO have it as proper keyword/token instead?
263+ || isCapKw
262264
263265 def isStatSep : Boolean = in.isStatSep
264266
@@ -2260,22 +2262,28 @@ object Parsers {
22602262 else
22612263 TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
22622264
2265+ /** CaptureSetBounds ::= [`>:' CaptureSetOrRef ] [`<:' CaptureSetOrRef ] --- under captureChecking
2266+ */
2267+ def captureSetBounds (): TypeBoundsTree =
2268+ atSpan(in.offset):
2269+ TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2270+
22632271 private def bound (tok : Int ): Tree =
22642272 if (in.token == tok) { in.nextToken(); toplevelTyp() }
22652273 else EmptyTree
22662274
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
22692277 Select (scalaDot(nme.caps), tpnme.CapSet )
22702278 else
22712279 makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
22722280
22732281 private def capsBound (tok : Int ): Tree =
22742282 if (in.token == tok) then
22752283 in.nextToken()
2276- capsType (captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
2284+ capsBound (captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
22772285 else
2278- capsType (Nil , isLowerBound = tok == SUPERTYPE )
2286+ capsBound (Nil , isLowerBound = tok == SUPERTYPE )
22792287
22802288 /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
22812289 */
@@ -2286,10 +2294,10 @@ object Parsers {
22862294 else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
22872295 }
22882296
2289- /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds] -- under captureChecking
2297+ /** CaptureSetAndCtxBounds ::= CaptureSetBounds [`:` ContextBounds] -- under captureChecking
22902298 */
22912299 def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2292- val t = TypeBoundsTree (capsBound( SUPERTYPE ), capsBound( SUBTYPE ) )
2300+ val t = captureSetBounds( )
22932301 val cbs = contextBounds(pname)
22942302 if (cbs.isEmpty) t
22952303 else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
@@ -3907,7 +3915,7 @@ object Parsers {
39073915 case CASE if inEnum =>
39083916 enumCase(start, mods)
39093917 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
39113919 capDefOrDcl(start, in.skipToken(mods))
39123920 else tmplDef(start, mods)
39133921 }
@@ -4118,20 +4126,22 @@ object Parsers {
41184126 }
41194127 }
41204128
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
41224133 */
41234134 def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
41244135 newLinesOpt()
41254136 atSpan(start, nameStart) {
41264137 val nameIdent = typeIdent()
41274138 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 " )
41304140
41314141 def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
41324142 val tdef = TypeDef (nameIdent.name.toTypeName,
41334143 refs.match
4134- case refs : List [Tree ] => capsType (refs)
4144+ case refs : List [Tree ] => concreteCapsType (refs)
41354145 case bounds : Tree => bounds)
41364146
41374147 if (nameIdent.isBackquoted)
@@ -4143,24 +4153,13 @@ object Parsers {
41434153 case EQUALS =>
41444154 in.nextToken()
41454155 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 =>
41584157 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
41604159 || sourceVersion.enablesNewGivens && in.isColon =>
41614160 makeCapDef(captureSetAndCtxBounds(tname))
41624161 case _ =>
4163- syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token)) // TODO change error message
4162+ syntaxErrorOrIncomplete(ExpectedCaptureBoundOrEquals (in.token))
41644163 return EmptyTree // return to avoid setting the span to EmptyTree
41654164 }
41664165
0 commit comments