@@ -227,6 +227,7 @@ object Parsers {
227
227
def isNumericLit = numericLitTokens contains in.token
228
228
def isTemplateIntro = templateIntroTokens contains in.token
229
229
def isDclIntro = dclIntroTokens contains in.token
230
+ def isDclIntroNext = dclIntroTokens contains in.lookahead.token
230
231
def isStatSeqEnd = in.isNestedEnd || in.token == EOF || in.token == RPAREN
231
232
def mustStartStat = mustStartStatTokens contains in.token
232
233
@@ -1601,7 +1602,7 @@ object Parsers {
1601
1602
case _ => None
1602
1603
}
1603
1604
1604
- /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`]
1605
+ /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`] [`.` `rd`] -- under captureChecking
1605
1606
* | [ { SimpleRef `.` } SimpleRef `.` ] id
1606
1607
*/
1607
1608
def captureRef (): Tree =
@@ -1628,9 +1629,13 @@ object Parsers {
1628
1629
1629
1630
/** CaptureSet ::= `{` CaptureRef {`,` CaptureRef} `}` -- under captureChecking
1630
1631
*/
1631
- def captureSet (): List [Tree ] = inBraces {
1632
- if in.token == RBRACE then Nil else commaSeparated(captureRef)
1633
- }
1632
+ def captureSet (): List [Tree ] =
1633
+ if in.token != LBRACE then
1634
+ syntaxError(em " expected '{' to start capture set " , in.offset)
1635
+ Nil
1636
+ else inBraces {
1637
+ if in.token == RBRACE then Nil else commaSeparated(captureRef)
1638
+ }
1634
1639
1635
1640
def capturesAndResult (core : () => Tree ): Tree =
1636
1641
if Feature .ccEnabled && in.token == LBRACE && canStartCaptureSetContentsTokens.contains(in.lookahead.token)
@@ -1644,9 +1649,9 @@ object Parsers {
1644
1649
* | InfixType
1645
1650
* FunType ::= (MonoFunType | PolyFunType)
1646
1651
* MonoFunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
1647
- * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions
1652
+ * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions and captureChecking
1648
1653
* PolyFunType ::= TypTypeParamClause '=>' Type
1649
- * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
1654
+ * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions and captureChecking
1650
1655
* FunTypeArgs ::= InfixType
1651
1656
* | `(' [ FunArgType {`,' FunArgType } ] `)'
1652
1657
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
@@ -1889,7 +1894,7 @@ object Parsers {
1889
1894
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
1890
1895
1891
1896
/** InfixType ::= RefinedType {id [nl] RefinedType}
1892
- * | RefinedType `^` // under capture checking
1897
+ * | RefinedType `^` -- under captureChecking
1893
1898
*/
1894
1899
def infixType (inContextBound : Boolean = false ): Tree = infixTypeRest(inContextBound)(refinedType())
1895
1900
@@ -1920,6 +1925,12 @@ object Parsers {
1920
1925
|| ! canStartInfixTypeTokens.contains(ahead.token)
1921
1926
|| ahead.lineOffset > 0
1922
1927
1928
+ inline def gobbleHat (): Boolean =
1929
+ if Feature .ccEnabled && isIdent(nme.UPARROW ) then
1930
+ in.nextToken()
1931
+ true
1932
+ else false
1933
+
1923
1934
def refinedTypeRest (t : Tree ): Tree = {
1924
1935
argumentStart()
1925
1936
if in.isNestedStart then
@@ -2176,35 +2187,45 @@ object Parsers {
2176
2187
atSpan(startOffset(t), startOffset(id)) { Select (t, id.name) }
2177
2188
}
2178
2189
2179
- /** ArgTypes ::= Type {`,' Type}
2180
- * | NamedTypeArg {`,' NamedTypeArg}
2181
- * NamedTypeArg ::= id `=' Type
2190
+ /** ArgTypes ::= TypeArg {‘,’ TypeArg}
2191
+ * | NamedTypeArg {‘,’ NamedTypeArg}
2192
+ * TypeArg ::= Type
2193
+ * | CaptureSet -- under captureChecking
2194
+ * NamedTypeArg ::= id ‘=’ TypeArg
2182
2195
* NamesAndTypes ::= NameAndType {‘,’ NameAndType}
2183
- * NameAndType ::= id ':' Type
2196
+ * NameAndType ::= id ‘:’ Type
2184
2197
*/
2185
2198
def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] =
2186
- def argType () =
2187
- val t = typ()
2199
+ inline def wildCardCheck ( inline gen : Tree ) : Tree =
2200
+ val t = gen
2188
2201
if wildOK then t else rejectWildcardType(t)
2189
2202
2190
- def namedArgType () =
2203
+ def argType () = wildCardCheck(typ())
2204
+
2205
+ def typeArg () = wildCardCheck :
2206
+ if Feature .ccEnabled && in.token == LBRACE && ! isDclIntroNext then // is this a capture set and not a refinement type?
2207
+ // This case is ambiguous w.r.t. an Object literal {}. But since CC is enabled, we probably expect it to designate the empty set
2208
+ concreteCapsType(captureSet())
2209
+ else typ()
2210
+
2211
+ def namedTypeArg () =
2191
2212
atSpan(in.offset):
2192
2213
val name = ident()
2193
2214
accept(EQUALS )
2194
- NamedArg (name.toTypeName, argType ())
2215
+ NamedArg (name.toTypeName, typeArg ())
2195
2216
2196
- def namedElem () =
2217
+ def nameAndType () =
2197
2218
atSpan(in.offset):
2198
2219
val name = ident()
2199
2220
acceptColon()
2200
2221
NamedArg (name, argType())
2201
2222
2202
- if namedOK && isIdent && in.lookahead.token == EQUALS then
2203
- commaSeparated(() => namedArgType ())
2223
+ if namedOK && ( isIdent && in.lookahead.token == EQUALS ) then
2224
+ commaSeparated(() => namedTypeArg ())
2204
2225
else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
2205
- commaSeparated(() => namedElem ())
2226
+ commaSeparated(() => nameAndType ()) // TODO: can capture-set variables occur here?
2206
2227
else
2207
- commaSeparated(() => argType ())
2228
+ commaSeparated(() => typeArg ())
2208
2229
end argTypes
2209
2230
2210
2231
def paramTypeOf (core : () => Tree ): Tree =
@@ -2248,7 +2269,7 @@ object Parsers {
2248
2269
PostfixOp (t, Ident (tpnme.raw.STAR ))
2249
2270
else t
2250
2271
2251
- /** TypeArgs ::= `[' Type {`,' Type } `]'
2272
+ /** TypeArgs ::= `[' TypeArg {`,' TypeArg } `]'
2252
2273
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
2253
2274
*/
2254
2275
def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] =
@@ -2262,25 +2283,34 @@ object Parsers {
2262
2283
else
2263
2284
inBraces(refineStatSeq())
2264
2285
2265
- /** TypeBounds ::= [`>:' Type] [`<:' Type]
2266
- * | `^` -- under captureChecking
2286
+ /** TypeBounds ::= [`>:' TypeBound ] [`<:' TypeBound ]
2287
+ * TypeBound ::= Type
2288
+ * | CaptureSet -- under captureChecking
2267
2289
*/
2268
- def typeBounds (): TypeBoundsTree =
2290
+ def typeBounds (isCapParamOrMem : Boolean = false ): TypeBoundsTree =
2269
2291
atSpan(in.offset):
2270
- if in.isIdent(nme.UPARROW ) && Feature .ccEnabled then
2271
- in.nextToken()
2272
- makeCapsBound()
2273
- else
2274
- TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
2292
+ TypeBoundsTree (bound(SUPERTYPE , isCapParamOrMem), bound(SUBTYPE , isCapParamOrMem))
2275
2293
2276
- private def bound (tok : Int ): Tree =
2277
- if (in.token == tok) { in.nextToken(); toplevelTyp() }
2294
+ private def bound (tok : Int , isCapParamOrMem : Boolean = false ): Tree =
2295
+ if (in.token == tok) then
2296
+ in.nextToken()
2297
+ if Feature .ccEnabled && (in.token == LBRACE && ! isDclIntroNext) then
2298
+ capsBound(captureSet(), isLowerBound = tok == SUPERTYPE )
2299
+ else toplevelTyp()
2300
+ else if Feature .ccEnabled && isCapParamOrMem then
2301
+ capsBound(Nil , isLowerBound = tok == SUPERTYPE ) // FIXME: should we avoid the CapSet^{} lower bound and make it Nothing?
2278
2302
else EmptyTree
2279
2303
2304
+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2305
+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2306
+ Select (scalaDot(nme.caps), tpnme.CapSet )
2307
+ else
2308
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2309
+
2280
2310
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2281
2311
*/
2282
- def typeAndCtxBounds (pname : TypeName ): Tree = {
2283
- val t = typeBounds()
2312
+ def typeAndCtxBounds (pname : TypeName , isCapParamOrMem : Boolean = false ): Tree = {
2313
+ val t = typeBounds(isCapParamOrMem )
2284
2314
val cbs = contextBounds(pname)
2285
2315
if (cbs.isEmpty) t
2286
2316
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
@@ -3397,7 +3427,7 @@ object Parsers {
3397
3427
* | opaque
3398
3428
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased |
3399
3429
* inline | transparent | infix |
3400
- * mut -- under cc
3430
+ * mut -- under captureChecking
3401
3431
*/
3402
3432
def modifiers (allowed : BitSet = modifierTokens, start : Modifiers = Modifiers ()): Modifiers = {
3403
3433
@ tailrec
@@ -3486,22 +3516,25 @@ object Parsers {
3486
3516
recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
3487
3517
end typeOrTermParamClauses
3488
3518
3489
-
3490
3519
/** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
3491
- * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3492
- * id [HkTypeParamClause] TypeAndCtxBounds
3520
+ * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3521
+ * id [HkTypeParamClause] TypeAndCtxBounds
3522
+ * | {Annotation} id [`^`] TypeAndCtxBounds -- under captureChecking
3493
3523
*
3494
3524
* DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
3495
- * DefTypeParam ::= {Annotation}
3496
- * id [HkTypeParamClause] TypeAndCtxBounds
3525
+ * DefTypeParam ::= {Annotation}
3526
+ * id [HkTypeParamClause] TypeAndCtxBounds
3527
+ * | {Annotation} id [`^`] TypeAndCtxBounds -- under captureChecking
3497
3528
*
3498
3529
* TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
3499
- * TypTypeParam ::= {Annotation}
3500
- * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3530
+ * TypTypeParam ::= {Annotation}
3531
+ * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3532
+ * | {Annotation} (id | ‘_’) [`^`] TypeAndCtxBounds -- under captureChecking
3501
3533
*
3502
3534
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
3503
- * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3504
- * (id | ‘_’) [HkTypeParamClause] TypeBounds
3535
+ * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3536
+ * (id | ‘_’) [HkTypePamClause] TypeBounds
3537
+ * | {Annotation} (id | ‘_’) [`^`] TypeBounds -- under captureChecking
3505
3538
*/
3506
3539
def typeParamClause (paramOwner : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
3507
3540
@@ -3526,11 +3559,17 @@ object Parsers {
3526
3559
in.nextToken()
3527
3560
WildcardParamName .fresh().toTypeName
3528
3561
else ident().toTypeName
3562
+ val isCap = gobbleHat()
3563
+ if isCap && mods.isOneOf(Covariant | Contravariant ) then
3564
+ syntaxError(em " capture parameters cannot have `+/-` variance annotations " ) // TODO we might want to allow those
3565
+ if isCap && in.token == LBRACKET then
3566
+ syntaxError(em " capture parameters do not take type parameters " )
3567
+ in.nextToken()
3529
3568
val hkparams = typeParamClauseOpt(ParamOwner .Hk )
3530
3569
val bounds =
3531
- if paramOwner.acceptsCtxBounds then typeAndCtxBounds(name)
3532
- else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then typeAndCtxBounds(name)
3533
- else typeBounds()
3570
+ if paramOwner.acceptsCtxBounds then typeAndCtxBounds(name, isCap )
3571
+ else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then typeAndCtxBounds(name, isCap )
3572
+ else typeBounds(isCap )
3534
3573
TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
3535
3574
}
3536
3575
}
@@ -4052,15 +4091,26 @@ object Parsers {
4052
4091
argumentExprss(mkApply(Ident (nme.CONSTRUCTOR ), argumentExprs()))
4053
4092
}
4054
4093
4055
- /** TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ Type]
4094
+ /** TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ TypeDefRHS ]
4095
+ * | id [`^`] TypeAndCtxBounds [‘=’ TypeDefRHS ] -- under captureChecking
4096
+ * TypeDefRHS ::= Type
4097
+ * | CaptureSet -- under captureChecking
4056
4098
*/
4057
- def typeDefOrDcl (start : Offset , mods : Modifiers ): Tree = {
4099
+ def typeDefOrDcl (start : Offset , mods : Modifiers ): Tree = { // FIXME: ^-qualified members should automatically receive the CapSet interval!
4100
+
4101
+ def typeDefRHS (): Tree =
4102
+ if Feature .ccEnabled && in.token == LBRACE && ! isDclIntroNext then
4103
+ concreteCapsType(captureSet())
4104
+ else toplevelTyp()
4105
+
4058
4106
newLinesOpt()
4059
4107
atSpan(start, nameStart) {
4060
4108
val nameIdent = typeIdent()
4109
+ val isCapDef = gobbleHat()
4110
+ if isCapDef && in.token == LBRACKET then syntaxError(em " capture-set member declarations cannot have type parameters " )
4061
4111
val tname = nameIdent.name.asTypeName
4062
- val tparams = typeParamClauseOpt(ParamOwner .Hk )
4063
- val vparamss = funParamClauses()
4112
+ val tparams = if ! isCapDef then typeParamClauseOpt(ParamOwner .Hk ) else Nil
4113
+ val vparamss = if ! isCapDef then funParamClauses() else Nil
4064
4114
4065
4115
def makeTypeDef (rhs : Tree ): Tree = {
4066
4116
val rhs1 = lambdaAbstractAll(tparams :: vparamss, rhs)
@@ -4073,12 +4123,12 @@ object Parsers {
4073
4123
in.token match {
4074
4124
case EQUALS =>
4075
4125
in.nextToken()
4076
- makeTypeDef(toplevelTyp ())
4126
+ makeTypeDef(typeDefRHS ())
4077
4127
case SUBTYPE | SUPERTYPE =>
4078
- typeAndCtxBounds(tname) match
4128
+ typeAndCtxBounds(tname, isCapDef ) match
4079
4129
case bounds : TypeBoundsTree if in.token == EQUALS =>
4080
4130
val eqOffset = in.skipToken()
4081
- var rhs = toplevelTyp ()
4131
+ var rhs = typeDefRHS ()
4082
4132
rhs match {
4083
4133
case mtt : MatchTypeTree =>
4084
4134
bounds match {
@@ -4096,17 +4146,20 @@ object Parsers {
4096
4146
makeTypeDef(rhs)
4097
4147
case bounds => makeTypeDef(bounds)
4098
4148
case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4099
- makeTypeDef(typeAndCtxBounds(tname))
4149
+ makeTypeDef(typeAndCtxBounds(tname, isCapDef ))
4100
4150
case _ if (staged & StageKind .QuotedPattern ) != 0
4101
4151
|| sourceVersion.enablesNewGivens && in.isColon =>
4102
- makeTypeDef(typeAndCtxBounds(tname))
4152
+ makeTypeDef(typeAndCtxBounds(tname, isCapDef ))
4103
4153
case _ =>
4104
4154
syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token))
4105
4155
return EmptyTree // return to avoid setting the span to EmptyTree
4106
4156
}
4107
4157
}
4108
4158
}
4109
4159
4160
+ private def concreteCapsType (refs : List [Tree ]): Tree =
4161
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4162
+
4110
4163
/** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
4111
4164
* | [‘case’] ‘object’ ObjectDef
4112
4165
* | ‘enum’ EnumDef
0 commit comments