@@ -224,6 +224,7 @@ object Parsers {
224224 def isErasedKw = isErased && in.isSoftModifierInParamModifierPosition
225225 // Are we seeing a `cap` soft keyword for declaring a capture-set member or at the beginning a capture-variable parameter list?
226226 def isCapKw = Feature .ccEnabled && isIdent(nme.cap)
227+ def isCapKwNext = Feature .ccEnabled && in.lookahead.isIdent(nme.cap)
227228 def isSimpleLiteral =
228229 simpleLiteralTokens.contains(in.token)
229230 || isIdent(nme.raw.MINUS ) && numericLitTokens.contains(in.lookahead.token)
@@ -2439,7 +2440,7 @@ object Parsers {
24392440 closure(start, location, modifiers(BitSet (IMPLICIT )))
24402441 case LBRACKET =>
24412442 val start = in.offset
2442- val tparams = typeParamClause(ParamOwner .Type )
2443+ val tparams = if isCapKwNext then capParamClause( ParamOwner . Type ) else typeParamClause(ParamOwner .Type ) // TODO document grammar
24432444 val arrowOffset = accept(ARROW )
24442445 val body = expr(location)
24452446 makePolyFunction(tparams, body, " literal" , errorTermTree(arrowOffset), start, arrowOffset)
@@ -3474,6 +3475,7 @@ object Parsers {
34743475 * DefParamClause ::= DefTypeParamClause
34753476 * | DefTermParamClause
34763477 * | UsingParamClause
3478+ * | CapParamClause -- under capture checking
34773479 */
34783480 def typeOrTermParamClauses (
34793481 paramOwner : ParamOwner , numLeadParams : Int = 0 ): List [List [TypeDef ] | List [ValDef ]] =
@@ -3491,16 +3493,54 @@ object Parsers {
34913493 else if in.token == LBRACKET then
34923494 if prevIsTypeClause then
34933495 syntaxError(
3494- em " Type parameter lists must be separated by a term or using parameter list " ,
3496+ em " Type parameter lists must be separated by a term or using parameter list " , // TODO adapt for capture params
34953497 in.offset
34963498 )
3497- typeParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true )
3499+ if isCapKwNext then // TODO refine
3500+ capParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true )
3501+ else
3502+ typeParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true )
34983503 else Nil
34993504 end recur
35003505
35013506 recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
35023507 end typeOrTermParamClauses
35033508
3509+ def capParamClause (paramOwner : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
3510+
3511+ def ensureNoVariance () =
3512+ if isIdent(nme.raw.PLUS ) || isIdent(nme.raw.MINUS ) then
3513+ syntaxError(em " no `+/-` variance annotation allowed here " )
3514+ in.nextToken()
3515+
3516+ def ensureNoHKParams () =
3517+ if in.token == LBRACKET then
3518+ syntaxError(em " 'cap' parameters cannot have type parameters " )
3519+ in.nextToken()
3520+
3521+ def captureParam (): TypeDef = {
3522+ val start = in.offset
3523+ var mods = annotsAsMods() | Param
3524+ if paramOwner.isClass then
3525+ mods |= PrivateLocal
3526+ ensureNoVariance() // TODO: in the future, we might want to support variances on capture params, ruled out for now
3527+ atSpan(start, nameStart) {
3528+ val name =
3529+ if paramOwner.acceptsWildcard && in.token == USCORE then
3530+ in.nextToken()
3531+ WildcardParamName .fresh().toTypeName
3532+ else ident().toTypeName
3533+ ensureNoHKParams()
3534+ val bounds =
3535+ if paramOwner.acceptsCtxBounds then captureSetAndCtxBounds(name) // TODO: do we need a new attribute for paramOwner?
3536+ else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then captureSetAndCtxBounds(name)
3537+ else captureSetBounds()
3538+ TypeDef (name, bounds).withMods(mods)
3539+ }
3540+ }
3541+ in.nextToken() // assumes we are just after the opening bracket at the 'cap' soft keyword
3542+ commaSeparated(() => captureParam())
3543+ }
35043544
35053545 /** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
35063546 * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
@@ -3553,7 +3593,11 @@ object Parsers {
35533593 }
35543594
35553595 def typeParamClauseOpt (paramOwner : ParamOwner ): List [TypeDef ] =
3556- if (in.token == LBRACKET ) typeParamClause(paramOwner) else Nil
3596+ if (in.token == LBRACKET )
3597+ if isCapKwNext then capParamClause(paramOwner) // TODO grammar doc
3598+ else typeParamClause(paramOwner)
3599+ else
3600+ Nil
35573601
35583602 /** ContextTypes ::= FunArgType {‘,’ FunArgType}
35593603 */
0 commit comments