@@ -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
@@ -1591,7 +1592,7 @@ object Parsers {
1591
1592
case _ => None
1592
1593
}
1593
1594
1594
- /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`]
1595
+ /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`] [`.` `rd`] -- under captureChecking
1595
1596
* | [ { SimpleRef `.` } SimpleRef `.` ] id
1596
1597
*/
1597
1598
def captureRef (): Tree =
@@ -1618,9 +1619,13 @@ object Parsers {
1618
1619
1619
1620
/** CaptureSet ::= `{` CaptureRef {`,` CaptureRef} `}` -- under captureChecking
1620
1621
*/
1621
- def captureSet (): List [Tree ] = inBraces {
1622
- if in.token == RBRACE then Nil else commaSeparated(captureRef)
1623
- }
1622
+ def captureSet (): List [Tree ] =
1623
+ if in.token != LBRACE then
1624
+ syntaxError(em " expected '{' to start capture set " , in.offset)
1625
+ Nil
1626
+ else inBraces {
1627
+ if in.token == RBRACE then Nil else commaSeparated(captureRef)
1628
+ }
1624
1629
1625
1630
def capturesAndResult (core : () => Tree ): Tree =
1626
1631
if Feature .ccEnabled && in.token == LBRACE && canStartCaptureSetContentsTokens.contains(in.lookahead.token)
@@ -1634,9 +1639,9 @@ object Parsers {
1634
1639
* | InfixType
1635
1640
* FunType ::= (MonoFunType | PolyFunType)
1636
1641
* MonoFunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
1637
- * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions
1642
+ * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions and captureChecking
1638
1643
* PolyFunType ::= TypTypeParamClause '=>' Type
1639
- * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
1644
+ * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions and captureChecking
1640
1645
* FunTypeArgs ::= InfixType
1641
1646
* | `(' [ FunArgType {`,' FunArgType } ] `)'
1642
1647
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
@@ -1879,7 +1884,7 @@ object Parsers {
1879
1884
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
1880
1885
1881
1886
/** InfixType ::= RefinedType {id [nl] RefinedType}
1882
- * | RefinedType `^` // under capture checking
1887
+ * | RefinedType `^` -- under captureChecking
1883
1888
*/
1884
1889
def infixType (inContextBound : Boolean = false ): Tree = infixTypeRest(inContextBound)(refinedType())
1885
1890
@@ -1910,6 +1915,12 @@ object Parsers {
1910
1915
|| ! canStartInfixTypeTokens.contains(ahead.token)
1911
1916
|| ahead.lineOffset > 0
1912
1917
1918
+ inline def gobbleHat (): Boolean =
1919
+ if Feature .ccEnabled && isIdent(nme.UPARROW ) then
1920
+ in.nextToken()
1921
+ true
1922
+ else false
1923
+
1913
1924
def refinedTypeRest (t : Tree ): Tree = {
1914
1925
argumentStart()
1915
1926
if in.isNestedStart then
@@ -2166,35 +2177,45 @@ object Parsers {
2166
2177
atSpan(startOffset(t), startOffset(id)) { Select (t, id.name) }
2167
2178
}
2168
2179
2169
- /** ArgTypes ::= Type {`,' Type}
2170
- * | NamedTypeArg {`,' NamedTypeArg}
2171
- * NamedTypeArg ::= id `=' Type
2180
+ /** ArgTypes ::= TypeArg {‘,’ TypeArg}
2181
+ * | NamedTypeArg {‘,’ NamedTypeArg}
2182
+ * TypeArg ::= Type
2183
+ * | CaptureSet -- under captureChecking
2184
+ * NamedTypeArg ::= id ‘=’ TypeArg
2172
2185
* NamesAndTypes ::= NameAndType {‘,’ NameAndType}
2173
- * NameAndType ::= id ':' Type
2186
+ * NameAndType ::= id ‘:’ Type
2174
2187
*/
2175
2188
def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] =
2176
- def argType () =
2177
- val t = typ()
2189
+ inline def wildCardCheck ( inline gen : Tree ) : Tree =
2190
+ val t = gen
2178
2191
if wildOK then t else rejectWildcardType(t)
2179
2192
2180
- def namedArgType () =
2193
+ def argType () = wildCardCheck(typ())
2194
+
2195
+ def typeArg () = wildCardCheck :
2196
+ if Feature .ccEnabled && in.token == LBRACE && ! isDclIntroNext then // is this a capture set and not a refinement type?
2197
+ // This case is ambiguous w.r.t. an Object literal {}. But since CC is enabled, we probably expect it to designate the empty set
2198
+ concreteCapsType(captureSet())
2199
+ else typ()
2200
+
2201
+ def namedTypeArg () =
2181
2202
atSpan(in.offset):
2182
2203
val name = ident()
2183
2204
accept(EQUALS )
2184
- NamedArg (name.toTypeName, argType ())
2205
+ NamedArg (name.toTypeName, typeArg ())
2185
2206
2186
- def namedElem () =
2207
+ def nameAndType () =
2187
2208
atSpan(in.offset):
2188
2209
val name = ident()
2189
2210
acceptColon()
2190
2211
NamedArg (name, argType())
2191
2212
2192
- if namedOK && isIdent && in.lookahead.token == EQUALS then
2193
- commaSeparated(() => namedArgType ())
2213
+ if namedOK && ( isIdent && in.lookahead.token == EQUALS ) then
2214
+ commaSeparated(() => namedTypeArg ())
2194
2215
else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
2195
- commaSeparated(() => namedElem ())
2216
+ commaSeparated(() => nameAndType ()) // TODO: can capture-set variables occur here?
2196
2217
else
2197
- commaSeparated(() => argType ())
2218
+ commaSeparated(() => typeArg ())
2198
2219
end argTypes
2199
2220
2200
2221
def paramTypeOf (core : () => Tree ): Tree =
@@ -2238,7 +2259,7 @@ object Parsers {
2238
2259
PostfixOp (t, Ident (tpnme.raw.STAR ))
2239
2260
else t
2240
2261
2241
- /** TypeArgs ::= `[' Type {`,' Type } `]'
2262
+ /** TypeArgs ::= `[' TypeArg {`,' TypeArg } `]'
2242
2263
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
2243
2264
*/
2244
2265
def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] =
@@ -2252,25 +2273,34 @@ object Parsers {
2252
2273
else
2253
2274
inBraces(refineStatSeq())
2254
2275
2255
- /** TypeBounds ::= [`>:' Type] [`<:' Type]
2256
- * | `^` -- under captureChecking
2276
+ /** TypeBounds ::= [`>:' TypeBound ] [`<:' TypeBound ]
2277
+ * TypeBound ::= Type
2278
+ * | CaptureSet -- under captureChecking
2257
2279
*/
2258
- def typeBounds (): TypeBoundsTree =
2280
+ def typeBounds (isCapParamOrMem : Boolean = false ): TypeBoundsTree =
2259
2281
atSpan(in.offset):
2260
- if in.isIdent(nme.UPARROW ) && Feature .ccEnabled then
2261
- in.nextToken()
2262
- makeCapsBound()
2263
- else
2264
- TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
2282
+ TypeBoundsTree (bound(SUPERTYPE , isCapParamOrMem), bound(SUBTYPE , isCapParamOrMem))
2265
2283
2266
- private def bound (tok : Int ): Tree =
2267
- if (in.token == tok) { in.nextToken(); toplevelTyp() }
2284
+ private def bound (tok : Int , isCapParamOrMem : Boolean = false ): Tree =
2285
+ if (in.token == tok) then
2286
+ in.nextToken()
2287
+ if Feature .ccEnabled && (in.token == LBRACE && ! isDclIntroNext) then
2288
+ capsBound(captureSet(), isLowerBound = tok == SUPERTYPE )
2289
+ else toplevelTyp()
2290
+ else if Feature .ccEnabled && isCapParamOrMem then
2291
+ capsBound(Nil , isLowerBound = tok == SUPERTYPE ) // FIXME: should we avoid the CapSet^{} lower bound and make it Nothing?
2268
2292
else EmptyTree
2269
2293
2294
+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2295
+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2296
+ Select (scalaDot(nme.caps), tpnme.CapSet )
2297
+ else
2298
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2299
+
2270
2300
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2271
2301
*/
2272
- def typeAndCtxBounds (pname : TypeName ): Tree = {
2273
- val t = typeBounds()
2302
+ def typeAndCtxBounds (pname : TypeName , isCapParamOrMem : Boolean = false ): Tree = {
2303
+ val t = typeBounds(isCapParamOrMem )
2274
2304
val cbs = contextBounds(pname)
2275
2305
if (cbs.isEmpty) t
2276
2306
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
@@ -3387,7 +3417,7 @@ object Parsers {
3387
3417
* | opaque
3388
3418
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased |
3389
3419
* inline | transparent | infix |
3390
- * mut -- under cc
3420
+ * mut -- under captureChecking
3391
3421
*/
3392
3422
def modifiers (allowed : BitSet = modifierTokens, start : Modifiers = Modifiers ()): Modifiers = {
3393
3423
@ tailrec
@@ -3476,22 +3506,25 @@ object Parsers {
3476
3506
recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
3477
3507
end typeOrTermParamClauses
3478
3508
3479
-
3480
3509
/** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
3481
- * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3482
- * id [HkTypeParamClause] TypeAndCtxBounds
3510
+ * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3511
+ * id [HkTypeParamClause] TypeAndCtxBounds
3512
+ * | {Annotation} id [`^`] TypeAndCtxBounds -- under captureChecking
3483
3513
*
3484
3514
* DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
3485
- * DefTypeParam ::= {Annotation}
3486
- * id [HkTypeParamClause] TypeAndCtxBounds
3515
+ * DefTypeParam ::= {Annotation}
3516
+ * id [HkTypeParamClause] TypeAndCtxBounds
3517
+ * | {Annotation} id [`^`] TypeAndCtxBounds -- under captureChecking
3487
3518
*
3488
3519
* TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
3489
- * TypTypeParam ::= {Annotation}
3490
- * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3520
+ * TypTypeParam ::= {Annotation}
3521
+ * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3522
+ * | {Annotation} (id | ‘_’) [`^`] TypeAndCtxBounds -- under captureChecking
3491
3523
*
3492
3524
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
3493
- * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3494
- * (id | ‘_’) [HkTypeParamClause] TypeBounds
3525
+ * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3526
+ * (id | ‘_’) [HkTypePamClause] TypeBounds
3527
+ * | {Annotation} (id | ‘_’) [`^`] TypeBounds -- under captureChecking
3495
3528
*/
3496
3529
def typeParamClause (paramOwner : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
3497
3530
@@ -3516,11 +3549,17 @@ object Parsers {
3516
3549
in.nextToken()
3517
3550
WildcardParamName .fresh().toTypeName
3518
3551
else ident().toTypeName
3552
+ val isCap = gobbleHat()
3553
+ if isCap && mods.isOneOf(Covariant | Contravariant ) then
3554
+ syntaxError(em " capture parameters cannot have `+/-` variance annotations " ) // TODO we might want to allow those
3555
+ if isCap && in.token == LBRACKET then
3556
+ syntaxError(em " capture parameters do not take type parameters " )
3557
+ in.nextToken()
3519
3558
val hkparams = typeParamClauseOpt(ParamOwner .Hk )
3520
3559
val bounds =
3521
- if paramOwner.acceptsCtxBounds then typeAndCtxBounds(name)
3522
- else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then typeAndCtxBounds(name)
3523
- else typeBounds()
3560
+ if paramOwner.acceptsCtxBounds then typeAndCtxBounds(name, isCap )
3561
+ else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then typeAndCtxBounds(name, isCap )
3562
+ else typeBounds(isCap )
3524
3563
TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
3525
3564
}
3526
3565
}
@@ -4042,15 +4081,26 @@ object Parsers {
4042
4081
argumentExprss(mkApply(Ident (nme.CONSTRUCTOR ), argumentExprs()))
4043
4082
}
4044
4083
4045
- /** TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ Type]
4084
+ /** TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ TypeDefRHS ]
4085
+ * | id [`^`] TypeAndCtxBounds [‘=’ TypeDefRHS ] -- under captureChecking
4086
+ * TypeDefRHS ::= Type
4087
+ * | CaptureSet -- under captureChecking
4046
4088
*/
4047
- def typeDefOrDcl (start : Offset , mods : Modifiers ): Tree = {
4089
+ def typeDefOrDcl (start : Offset , mods : Modifiers ): Tree = { // FIXME: ^-qualified members should automatically receive the CapSet interval!
4090
+
4091
+ def typeDefRHS (): Tree =
4092
+ if Feature .ccEnabled && in.token == LBRACE && ! isDclIntroNext then
4093
+ concreteCapsType(captureSet())
4094
+ else toplevelTyp()
4095
+
4048
4096
newLinesOpt()
4049
4097
atSpan(start, nameStart) {
4050
4098
val nameIdent = typeIdent()
4099
+ val isCapDef = gobbleHat()
4100
+ if isCapDef && in.token == LBRACKET then syntaxError(em " capture-set member declarations cannot have type parameters " )
4051
4101
val tname = nameIdent.name.asTypeName
4052
- val tparams = typeParamClauseOpt(ParamOwner .Hk )
4053
- val vparamss = funParamClauses()
4102
+ val tparams = if ! isCapDef then typeParamClauseOpt(ParamOwner .Hk ) else Nil
4103
+ val vparamss = if ! isCapDef then funParamClauses() else Nil
4054
4104
4055
4105
def makeTypeDef (rhs : Tree ): Tree = {
4056
4106
val rhs1 = lambdaAbstractAll(tparams :: vparamss, rhs)
@@ -4063,12 +4113,12 @@ object Parsers {
4063
4113
in.token match {
4064
4114
case EQUALS =>
4065
4115
in.nextToken()
4066
- makeTypeDef(toplevelTyp ())
4116
+ makeTypeDef(typeDefRHS ())
4067
4117
case SUBTYPE | SUPERTYPE =>
4068
- typeAndCtxBounds(tname) match
4118
+ typeAndCtxBounds(tname, isCapDef ) match
4069
4119
case bounds : TypeBoundsTree if in.token == EQUALS =>
4070
4120
val eqOffset = in.skipToken()
4071
- var rhs = toplevelTyp ()
4121
+ var rhs = typeDefRHS ()
4072
4122
rhs match {
4073
4123
case mtt : MatchTypeTree =>
4074
4124
bounds match {
@@ -4086,17 +4136,20 @@ object Parsers {
4086
4136
makeTypeDef(rhs)
4087
4137
case bounds => makeTypeDef(bounds)
4088
4138
case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4089
- makeTypeDef(typeAndCtxBounds(tname))
4139
+ makeTypeDef(typeAndCtxBounds(tname, isCapDef ))
4090
4140
case _ if (staged & StageKind .QuotedPattern ) != 0
4091
4141
|| sourceVersion.enablesNewGivens && in.isColon =>
4092
- makeTypeDef(typeAndCtxBounds(tname))
4142
+ makeTypeDef(typeAndCtxBounds(tname, isCapDef ))
4093
4143
case _ =>
4094
4144
syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token))
4095
4145
return EmptyTree // return to avoid setting the span to EmptyTree
4096
4146
}
4097
4147
}
4098
4148
}
4099
4149
4150
+ private def concreteCapsType (refs : List [Tree ]): Tree =
4151
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4152
+
4100
4153
/** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
4101
4154
* | [‘case’] ‘object’ ObjectDef
4102
4155
* | ‘enum’ EnumDef
0 commit comments