@@ -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)
@@ -2439,7 +2440,7 @@ object Parsers {
2439
2440
closure(start, location, modifiers(BitSet (IMPLICIT )))
2440
2441
case LBRACKET =>
2441
2442
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
2443
2444
val arrowOffset = accept(ARROW )
2444
2445
val body = expr(location)
2445
2446
makePolyFunction(tparams, body, " literal" , errorTermTree(arrowOffset), start, arrowOffset)
@@ -3474,6 +3475,7 @@ object Parsers {
3474
3475
* DefParamClause ::= DefTypeParamClause
3475
3476
* | DefTermParamClause
3476
3477
* | UsingParamClause
3478
+ * | CapParamClause -- under capture checking
3477
3479
*/
3478
3480
def typeOrTermParamClauses (
3479
3481
paramOwner : ParamOwner , numLeadParams : Int = 0 ): List [List [TypeDef ] | List [ValDef ]] =
@@ -3491,16 +3493,54 @@ object Parsers {
3491
3493
else if in.token == LBRACKET then
3492
3494
if prevIsTypeClause then
3493
3495
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
3495
3497
in.offset
3496
3498
)
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 )
3498
3503
else Nil
3499
3504
end recur
3500
3505
3501
3506
recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
3502
3507
end typeOrTermParamClauses
3503
3508
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
+ }
3504
3544
3505
3545
/** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
3506
3546
* ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
@@ -3553,7 +3593,11 @@ object Parsers {
3553
3593
}
3554
3594
3555
3595
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
3557
3601
3558
3602
/** ContextTypes ::= FunArgType {‘,’ FunArgType}
3559
3603
*/
0 commit comments