@@ -224,6 +224,7 @@ object Parsers {
224
224
def isErasedKw = isErased && in.isSoftModifierInParamModifierPosition
225
225
// Are we seeing a `cap` soft keyword for declaring a capture-set member or at the beginning a capture-variable parameter list?
226
226
def isCapKw = Feature .ccEnabled && isIdent(nme.cap)
227
+ def isCapKwNext = Feature .ccEnabled && in.lookahead.isIdent(nme.cap)
227
228
def isSimpleLiteral =
228
229
simpleLiteralTokens.contains(in.token)
229
230
|| isIdent(nme.raw.MINUS ) && numericLitTokens.contains(in.lookahead.token)
@@ -2432,7 +2433,7 @@ object Parsers {
2432
2433
closure(start, location, modifiers(BitSet (IMPLICIT )))
2433
2434
case LBRACKET =>
2434
2435
val start = in.offset
2435
- val tparams = typeParamClause(ParamOwner .Type )
2436
+ val tparams = if isCapKwNext then capParamClause( ParamOwner . Type ) else typeParamClause(ParamOwner .Type ) // TODO document grammar
2436
2437
val arrowOffset = accept(ARROW )
2437
2438
val body = expr(location)
2438
2439
makePolyFunction(tparams, body, " literal" , errorTermTree(arrowOffset), start, arrowOffset)
@@ -3467,6 +3468,7 @@ object Parsers {
3467
3468
* DefParamClause ::= DefTypeParamClause
3468
3469
* | DefTermParamClause
3469
3470
* | UsingParamClause
3471
+ * | CapParamClause -- under capture checking
3470
3472
*/
3471
3473
def typeOrTermParamClauses (
3472
3474
paramOwner : ParamOwner , numLeadParams : Int = 0 ): List [List [TypeDef ] | List [ValDef ]] =
@@ -3484,16 +3486,54 @@ object Parsers {
3484
3486
else if in.token == LBRACKET then
3485
3487
if prevIsTypeClause then
3486
3488
syntaxError(
3487
- em " Type parameter lists must be separated by a term or using parameter list " ,
3489
+ em " Type parameter lists must be separated by a term or using parameter list " , // TODO adapt for capture params
3488
3490
in.offset
3489
3491
)
3490
- typeParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true )
3492
+ if isCapKwNext then // TODO refine
3493
+ capParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true )
3494
+ else
3495
+ typeParamClause(paramOwner) :: recur(numLeadParams, firstClause, prevIsTypeClause = true )
3491
3496
else Nil
3492
3497
end recur
3493
3498
3494
3499
recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
3495
3500
end typeOrTermParamClauses
3496
3501
3502
+ def capParamClause (paramOwner : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
3503
+
3504
+ def ensureNoVariance () =
3505
+ if isIdent(nme.raw.PLUS ) || isIdent(nme.raw.MINUS ) then
3506
+ syntaxError(em " no `+/-` variance annotation allowed here " )
3507
+ in.nextToken()
3508
+
3509
+ def ensureNoHKParams () =
3510
+ if in.token == LBRACKET then
3511
+ syntaxError(em " 'cap' parameters cannot have type parameters " )
3512
+ in.nextToken()
3513
+
3514
+ def captureParam (): TypeDef = {
3515
+ val start = in.offset
3516
+ var mods = annotsAsMods() | Param
3517
+ if paramOwner.isClass then
3518
+ mods |= PrivateLocal
3519
+ ensureNoVariance() // TODO: in the future, we might want to support variances on capture params, ruled out for now
3520
+ atSpan(start, nameStart) {
3521
+ val name =
3522
+ if paramOwner.acceptsWildcard && in.token == USCORE then
3523
+ in.nextToken()
3524
+ WildcardParamName .fresh().toTypeName
3525
+ else ident().toTypeName
3526
+ ensureNoHKParams()
3527
+ val bounds =
3528
+ if paramOwner.acceptsCtxBounds then captureSetAndCtxBounds(name) // TODO: do we need a new attribute for paramOwner?
3529
+ else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then captureSetAndCtxBounds(name)
3530
+ else captureSetBounds()
3531
+ TypeDef (name, bounds).withMods(mods)
3532
+ }
3533
+ }
3534
+ in.nextToken() // assumes we are just after the opening bracket at the 'cap' soft keyword
3535
+ commaSeparated(() => captureParam())
3536
+ }
3497
3537
3498
3538
/** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
3499
3539
* ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
@@ -3546,7 +3586,11 @@ object Parsers {
3546
3586
}
3547
3587
3548
3588
def typeParamClauseOpt (paramOwner : ParamOwner ): List [TypeDef ] =
3549
- if (in.token == LBRACKET ) typeParamClause(paramOwner) else Nil
3589
+ if (in.token == LBRACKET )
3590
+ if isCapKwNext then capParamClause(paramOwner) // TODO grammar doc
3591
+ else typeParamClause(paramOwner)
3592
+ else
3593
+ Nil
3550
3594
3551
3595
/** ContextTypes ::= FunArgType {‘,’ FunArgType}
3552
3596
*/
0 commit comments