@@ -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,8 +1592,7 @@ object Parsers {
1591
1592
case _ => None
1592
1593
}
1593
1594
1594
- /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`] [`.` rd]
1595
- * | [ { SimpleRef `.` } SimpleRef `.` ] id `^`
1595
+ /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`] [`.` `rd`] -- under captureChecking
1596
1596
*/
1597
1597
def captureRef (): Tree =
1598
1598
@@ -1611,22 +1611,17 @@ object Parsers {
1611
1611
in.nextToken()
1612
1612
derived(reachRef, nme.CC_READONLY )
1613
1613
else reachRef
1614
- else if isIdent(nme.UPARROW ) then
1615
- in.nextToken()
1616
- atSpan(startOffset(ref)):
1617
- convertToTypeId(ref) match
1618
- case ref : RefTree => makeCapsOf(ref)
1619
- case ref => ref
1620
1614
else ref
1621
1615
1622
1616
recur(simpleRef())
1623
1617
end captureRef
1624
1618
1625
1619
/** CaptureSet ::= `{` CaptureRef {`,` CaptureRef} `}` -- under captureChecking
1626
1620
*/
1627
- def captureSet (): List [Tree ] = inBraces {
1628
- if in.token == RBRACE then Nil else commaSeparated(captureRef)
1629
- }
1621
+ def captureSet (): List [Tree ] =
1622
+ inBraces {
1623
+ if in.token == RBRACE then Nil else commaSeparated(captureRef)
1624
+ }
1630
1625
1631
1626
def capturesAndResult (core : () => Tree ): Tree =
1632
1627
if Feature .ccEnabled && in.token == LBRACE && canStartCaptureSetContentsTokens.contains(in.lookahead.token)
@@ -1640,9 +1635,9 @@ object Parsers {
1640
1635
* | InfixType
1641
1636
* FunType ::= (MonoFunType | PolyFunType)
1642
1637
* MonoFunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
1643
- * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions
1638
+ * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions and captureChecking
1644
1639
* PolyFunType ::= TypTypeParamClause '=>' Type
1645
- * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
1640
+ * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions and captureChecking
1646
1641
* FunTypeArgs ::= InfixType
1647
1642
* | `(' [ FunArgType {`,' FunArgType } ] `)'
1648
1643
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
@@ -1885,7 +1880,7 @@ object Parsers {
1885
1880
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
1886
1881
1887
1882
/** InfixType ::= RefinedType {id [nl] RefinedType}
1888
- * | RefinedType `^` // under capture checking
1883
+ * | RefinedType `^` -- under captureChecking
1889
1884
*/
1890
1885
def infixType (inContextBound : Boolean = false ): Tree = infixTypeRest(inContextBound)(refinedType())
1891
1886
@@ -1916,6 +1911,12 @@ object Parsers {
1916
1911
|| ! canStartInfixTypeTokens.contains(ahead.token)
1917
1912
|| ahead.lineOffset > 0
1918
1913
1914
+ inline def gobbleHat (): Boolean =
1915
+ if Feature .ccEnabled && isIdent(nme.UPARROW ) then
1916
+ in.nextToken()
1917
+ true
1918
+ else false
1919
+
1919
1920
def refinedTypeRest (t : Tree ): Tree = {
1920
1921
argumentStart()
1921
1922
if in.isNestedStart then
@@ -2172,35 +2173,45 @@ object Parsers {
2172
2173
atSpan(startOffset(t), startOffset(id)) { Select (t, id.name) }
2173
2174
}
2174
2175
2175
- /** ArgTypes ::= Type {`,' Type}
2176
- * | NamedTypeArg {`,' NamedTypeArg}
2177
- * NamedTypeArg ::= id `=' Type
2176
+ /** ArgTypes ::= TypeArg {‘,’ TypeArg}
2177
+ * | NamedTypeArg {‘,’ NamedTypeArg}
2178
+ * TypeArg ::= Type
2179
+ * | CaptureSet -- under captureChecking
2180
+ * NamedTypeArg ::= id ‘=’ TypeArg
2178
2181
* NamesAndTypes ::= NameAndType {‘,’ NameAndType}
2179
- * NameAndType ::= id ':' Type
2182
+ * NameAndType ::= id ‘:’ Type
2180
2183
*/
2181
2184
def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] =
2182
- def argType () =
2183
- val t = typ()
2185
+ def wildCardCheck ( gen : Tree ) : Tree =
2186
+ val t = gen
2184
2187
if wildOK then t else rejectWildcardType(t)
2185
2188
2186
- def namedArgType () =
2189
+ def argType () = wildCardCheck(typ())
2190
+
2191
+ def typeArg () = wildCardCheck :
2192
+ if Feature .ccEnabled && in.token == LBRACE && ! isDclIntroNext then // is this a capture set and not a refinement type?
2193
+ // This case is ambiguous w.r.t. an Object literal {}. But since CC is enabled, we probably expect it to designate the empty set
2194
+ concreteCapsType(captureSet())
2195
+ else typ()
2196
+
2197
+ def namedTypeArg () =
2187
2198
atSpan(in.offset):
2188
2199
val name = ident()
2189
2200
accept(EQUALS )
2190
- NamedArg (name.toTypeName, argType ())
2201
+ NamedArg (name.toTypeName, typeArg ())
2191
2202
2192
- def namedElem () =
2203
+ def nameAndType () =
2193
2204
atSpan(in.offset):
2194
2205
val name = ident()
2195
2206
acceptColon()
2196
2207
NamedArg (name, argType())
2197
2208
2198
- if namedOK && isIdent && in.lookahead.token == EQUALS then
2199
- commaSeparated(() => namedArgType ())
2209
+ if namedOK && ( isIdent && in.lookahead.token == EQUALS ) then
2210
+ commaSeparated(() => namedTypeArg ())
2200
2211
else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
2201
- commaSeparated(() => namedElem ())
2212
+ commaSeparated(() => nameAndType ())
2202
2213
else
2203
- commaSeparated(() => argType ())
2214
+ commaSeparated(() => typeArg ())
2204
2215
end argTypes
2205
2216
2206
2217
def paramTypeOf (core : () => Tree ): Tree =
@@ -2244,7 +2255,7 @@ object Parsers {
2244
2255
PostfixOp (t, Ident (tpnme.raw.STAR ))
2245
2256
else t
2246
2257
2247
- /** TypeArgs ::= `[' Type {`,' Type } `]'
2258
+ /** TypeArgs ::= `[' TypeArg {`,' TypeArg } `]'
2248
2259
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
2249
2260
*/
2250
2261
def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] =
@@ -2258,21 +2269,28 @@ object Parsers {
2258
2269
else
2259
2270
inBraces(refineStatSeq())
2260
2271
2261
- /** TypeBounds ::= [`>:' Type] [`<:' Type]
2262
- * | `^` -- under captureChecking
2272
+ /** TypeBounds ::= [`>:' TypeBound ] [`<:' TypeBound ]
2273
+ * TypeBound ::= Type
2274
+ * | CaptureSet -- under captureChecking
2263
2275
*/
2264
2276
def typeBounds (): TypeBoundsTree =
2265
2277
atSpan(in.offset):
2266
- if in.isIdent(nme.UPARROW ) && Feature .ccEnabled then
2267
- in.nextToken()
2268
- makeCapsBound()
2269
- else
2270
- TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
2278
+ TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
2271
2279
2272
2280
private def bound (tok : Int ): Tree =
2273
- if (in.token == tok) { in.nextToken(); toplevelTyp() }
2281
+ if in.token == tok then
2282
+ in.nextToken()
2283
+ if Feature .ccEnabled && in.token == LBRACE && ! isDclIntroNext then
2284
+ capsBound(captureSet(), isLowerBound = tok == SUPERTYPE )
2285
+ else toplevelTyp()
2274
2286
else EmptyTree
2275
2287
2288
+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2289
+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2290
+ Select (scalaDot(nme.caps), tpnme.CapSet )
2291
+ else
2292
+ concreteCapsType(refs)
2293
+
2276
2294
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2277
2295
*/
2278
2296
def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -3397,7 +3415,7 @@ object Parsers {
3397
3415
* | opaque
3398
3416
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased |
3399
3417
* inline | transparent | infix |
3400
- * mut -- under cc
3418
+ * mut -- under captureChecking
3401
3419
*/
3402
3420
def modifiers (allowed : BitSet = modifierTokens, start : Modifiers = Modifiers ()): Modifiers = {
3403
3421
@ tailrec
@@ -3486,22 +3504,25 @@ object Parsers {
3486
3504
recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
3487
3505
end typeOrTermParamClauses
3488
3506
3489
-
3490
3507
/** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
3491
- * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3492
- * id [HkTypeParamClause] TypeAndCtxBounds
3508
+ * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3509
+ * id [HkTypeParamClause] TypeAndCtxBounds
3510
+ * | {Annotation} [‘+’ | ‘-’] id `^` TypeAndCtxBounds -- under captureChecking
3493
3511
*
3494
3512
* DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
3495
- * DefTypeParam ::= {Annotation}
3496
- * id [HkTypeParamClause] TypeAndCtxBounds
3513
+ * DefTypeParam ::= {Annotation}
3514
+ * id [HkTypeParamClause] TypeAndCtxBounds
3515
+ * | {Annotation} id `^` TypeAndCtxBounds -- under captureChecking
3497
3516
*
3498
3517
* TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
3499
- * TypTypeParam ::= {Annotation}
3500
- * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3518
+ * TypTypeParam ::= {Annotation}
3519
+ * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3520
+ * | {Annotation} (id | ‘_’) `^` TypeAndCtxBounds -- under captureChecking
3501
3521
*
3502
3522
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
3503
- * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3504
- * (id | ‘_’) [HkTypeParamClause] TypeBounds
3523
+ * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3524
+ * (id | ‘_’) [HkTypePamClause] TypeBounds
3525
+ * | {Annotation} [‘+’ | ‘-’] (id | ‘_’) `^` TypeBounds -- under captureChecking
3505
3526
*/
3506
3527
def typeParamClause (paramOwner : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
3507
3528
@@ -3526,12 +3547,18 @@ object Parsers {
3526
3547
in.nextToken()
3527
3548
WildcardParamName .fresh().toTypeName
3528
3549
else ident().toTypeName
3550
+ val isCap = gobbleHat()
3529
3551
val hkparams = typeParamClauseOpt(ParamOwner .Hk )
3530
3552
val bounds =
3531
3553
if paramOwner.acceptsCtxBounds then typeAndCtxBounds(name)
3532
3554
else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then typeAndCtxBounds(name)
3533
3555
else typeBounds()
3534
- TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
3556
+ val res = TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
3557
+ if isCap then
3558
+ res.pushAttachment(CaptureVar , ())
3559
+ // putting the attachment here as well makes post-processing in the typer easier
3560
+ bounds.pushAttachment(CaptureVar , ())
3561
+ res
3535
3562
}
3536
3563
}
3537
3564
commaSeparated(() => typeParam())
@@ -4052,33 +4079,47 @@ object Parsers {
4052
4079
argumentExprss(mkApply(Ident (nme.CONSTRUCTOR ), argumentExprs()))
4053
4080
}
4054
4081
4055
- /** TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ Type]
4082
+ /** TypeDef ::= id [HkTypeParamClause] {FunParamClause} TypeAndCtxBounds [‘=’ TypeDefRHS ]
4083
+ * | id `^` TypeAndCtxBounds [‘=’ TypeDefRHS ] -- under captureChecking
4084
+ * TypeDefRHS ::= Type
4085
+ * | CaptureSet -- under captureChecking
4056
4086
*/
4057
4087
def typeDefOrDcl (start : Offset , mods : Modifiers ): Tree = {
4088
+
4089
+ def typeDefRHS (): Tree =
4090
+ if Feature .ccEnabled && in.token == LBRACE && ! isDclIntroNext then
4091
+ concreteCapsType(captureSet())
4092
+ else toplevelTyp()
4093
+
4058
4094
newLinesOpt()
4059
4095
atSpan(start, nameStart) {
4060
4096
val nameIdent = typeIdent()
4097
+ val isCapDef = gobbleHat()
4061
4098
val tname = nameIdent.name.asTypeName
4062
4099
val tparams = typeParamClauseOpt(ParamOwner .Hk )
4063
4100
val vparamss = funParamClauses()
4064
4101
4065
4102
def makeTypeDef (rhs : Tree ): Tree = {
4066
4103
val rhs1 = lambdaAbstractAll(tparams :: vparamss, rhs)
4067
4104
val tdef = TypeDef (nameIdent.name.toTypeName, rhs1)
4068
- if ( nameIdent.isBackquoted)
4105
+ if nameIdent.isBackquoted then
4069
4106
tdef.pushAttachment(Backquoted , ())
4107
+ if isCapDef then
4108
+ tdef.pushAttachment(CaptureVar , ())
4109
+ // putting the attachment here as well makes post-processing in the typer easier
4110
+ rhs.pushAttachment(CaptureVar , ())
4070
4111
finalizeDef(tdef, mods, start)
4071
4112
}
4072
4113
4073
4114
in.token match {
4074
4115
case EQUALS =>
4075
4116
in.nextToken()
4076
- makeTypeDef(toplevelTyp ())
4117
+ makeTypeDef(typeDefRHS ())
4077
4118
case SUBTYPE | SUPERTYPE =>
4078
4119
typeAndCtxBounds(tname) match
4079
4120
case bounds : TypeBoundsTree if in.token == EQUALS =>
4080
4121
val eqOffset = in.skipToken()
4081
- var rhs = toplevelTyp ()
4122
+ var rhs = typeDefRHS ()
4082
4123
rhs match {
4083
4124
case mtt : MatchTypeTree =>
4084
4125
bounds match {
@@ -4107,6 +4148,9 @@ object Parsers {
4107
4148
}
4108
4149
}
4109
4150
4151
+ private def concreteCapsType (refs : List [Tree ]): Tree =
4152
+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4153
+
4110
4154
/** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
4111
4155
* | [‘case’] ‘object’ ObjectDef
4112
4156
* | ‘enum’ EnumDef
0 commit comments