@@ -227,6 +227,7 @@ object Parsers {
227227 def isNumericLit = numericLitTokens contains in.token
228228 def isTemplateIntro = templateIntroTokens contains in.token
229229 def isDclIntro = dclIntroTokens contains in.token
230+ def isDclIntroNext = dclIntroTokens contains in.lookahead.token
230231 def isStatSeqEnd = in.isNestedEnd || in.token == EOF || in.token == RPAREN
231232 def mustStartStat = mustStartStatTokens contains in.token
232233
@@ -1601,7 +1602,7 @@ object Parsers {
16011602 case _ => None
16021603 }
16031604
1604- /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`]
1605+ /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`] [`.` `rd`] -- under captureChecking
16051606 * | [ { SimpleRef `.` } SimpleRef `.` ] id
16061607 */
16071608 def captureRef (): Tree =
@@ -1628,9 +1629,13 @@ object Parsers {
16281629
16291630 /** CaptureSet ::= `{` CaptureRef {`,` CaptureRef} `}` -- under captureChecking
16301631 */
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+ }
16341639
16351640 def capturesAndResult (core : () => Tree ): Tree =
16361641 if Feature .ccEnabled && in.token == LBRACE && canStartCaptureSetContentsTokens.contains(in.lookahead.token)
@@ -1644,9 +1649,9 @@ object Parsers {
16441649 * | InfixType
16451650 * FunType ::= (MonoFunType | PolyFunType)
16461651 * MonoFunType ::= FunTypeArgs (‘=>’ | ‘?=>’) Type
1647- * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions
1652+ * | (‘->’ | ‘?->’ ) [CaptureSet] Type -- under pureFunctions and captureChecking
16481653 * PolyFunType ::= TypTypeParamClause '=>' Type
1649- * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
1654+ * | TypTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions and captureChecking
16501655 * FunTypeArgs ::= InfixType
16511656 * | `(' [ FunArgType {`,' FunArgType } ] `)'
16521657 * | '(' [ TypedFunParam {',' TypedFunParam } ')'
@@ -1889,7 +1894,7 @@ object Parsers {
18891894 if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
18901895
18911896 /** InfixType ::= RefinedType {id [nl] RefinedType}
1892- * | RefinedType `^` // under capture checking
1897+ * | RefinedType `^` -- under captureChecking
18931898 */
18941899 def infixType (inContextBound : Boolean = false ): Tree = infixTypeRest(inContextBound)(refinedType())
18951900
@@ -1920,6 +1925,12 @@ object Parsers {
19201925 || ! canStartInfixTypeTokens.contains(ahead.token)
19211926 || ahead.lineOffset > 0
19221927
1928+ inline def gobbleHat (): Boolean =
1929+ if Feature .ccEnabled && isIdent(nme.UPARROW ) then
1930+ in.nextToken()
1931+ true
1932+ else false
1933+
19231934 def refinedTypeRest (t : Tree ): Tree = {
19241935 argumentStart()
19251936 if in.isNestedStart then
@@ -2176,35 +2187,45 @@ object Parsers {
21762187 atSpan(startOffset(t), startOffset(id)) { Select (t, id.name) }
21772188 }
21782189
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
21822195 * NamesAndTypes ::= NameAndType {‘,’ NameAndType}
2183- * NameAndType ::= id ':' Type
2196+ * NameAndType ::= id ‘:’ Type
21842197 */
21852198 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
21882201 if wildOK then t else rejectWildcardType(t)
21892202
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 () =
21912212 atSpan(in.offset):
21922213 val name = ident()
21932214 accept(EQUALS )
2194- NamedArg (name.toTypeName, argType ())
2215+ NamedArg (name.toTypeName, typeArg ())
21952216
2196- def namedElem () =
2217+ def nameAndType () =
21972218 atSpan(in.offset):
21982219 val name = ident()
21992220 acceptColon()
22002221 NamedArg (name, argType())
22012222
2202- if namedOK && isIdent && in.lookahead.token == EQUALS then
2203- commaSeparated(() => namedArgType ())
2223+ if namedOK && ( isIdent && in.lookahead.token == EQUALS ) then
2224+ commaSeparated(() => namedTypeArg ())
22042225 else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
2205- commaSeparated(() => namedElem ())
2226+ commaSeparated(() => nameAndType ()) // TODO: can capture-set variables occur here?
22062227 else
2207- commaSeparated(() => argType ())
2228+ commaSeparated(() => typeArg ())
22082229 end argTypes
22092230
22102231 def paramTypeOf (core : () => Tree ): Tree =
@@ -2248,7 +2269,7 @@ object Parsers {
22482269 PostfixOp (t, Ident (tpnme.raw.STAR ))
22492270 else t
22502271
2251- /** TypeArgs ::= `[' Type {`,' Type } `]'
2272+ /** TypeArgs ::= `[' TypeArg {`,' TypeArg } `]'
22522273 * NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
22532274 */
22542275 def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] =
@@ -2262,25 +2283,34 @@ object Parsers {
22622283 else
22632284 inBraces(refineStatSeq())
22642285
2265- /** TypeBounds ::= [`>:' Type] [`<:' Type]
2266- * | `^` -- under captureChecking
2286+ /** TypeBounds ::= [`>:' TypeBound ] [`<:' TypeBound ]
2287+ * TypeBound ::= Type
2288+ * | CaptureSet -- under captureChecking
22672289 */
2268- def typeBounds (): TypeBoundsTree =
2290+ def typeBounds (isCapParamOrMem : Boolean = false ): TypeBoundsTree =
22692291 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))
22752293
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?
22782302 else EmptyTree
22792303
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+
22802310 /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
22812311 */
2282- def typeAndCtxBounds (pname : TypeName ): Tree = {
2283- val t = typeBounds()
2312+ def typeAndCtxBounds (pname : TypeName , isCapParamOrMem : Boolean = false ): Tree = {
2313+ val t = typeBounds(isCapParamOrMem )
22842314 val cbs = contextBounds(pname)
22852315 if (cbs.isEmpty) t
22862316 else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
@@ -3397,7 +3427,7 @@ object Parsers {
33973427 * | opaque
33983428 * LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased |
33993429 * inline | transparent | infix |
3400- * mut -- under cc
3430+ * mut -- under captureChecking
34013431 */
34023432 def modifiers (allowed : BitSet = modifierTokens, start : Modifiers = Modifiers ()): Modifiers = {
34033433 @ tailrec
@@ -3486,22 +3516,25 @@ object Parsers {
34863516 recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
34873517 end typeOrTermParamClauses
34883518
3489-
34903519 /** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
3491- * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3492- * id [HkTypeParamClause] TypeAndCtxBounds
3520+ * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
3521+ * id [HkTypeParamClause] TypeAndCtxBounds
3522+ * | {Annotation} id [`^`] TypeAndCtxBounds -- under captureChecking
34933523 *
34943524 * DefTypeParamClause::= ‘[’ DefTypeParam {‘,’ DefTypeParam} ‘]’
3495- * DefTypeParam ::= {Annotation}
3496- * id [HkTypeParamClause] TypeAndCtxBounds
3525+ * DefTypeParam ::= {Annotation}
3526+ * id [HkTypeParamClause] TypeAndCtxBounds
3527+ * | {Annotation} id [`^`] TypeAndCtxBounds -- under captureChecking
34973528 *
34983529 * TypTypeParamClause::= ‘[’ TypTypeParam {‘,’ TypTypeParam} ‘]’
3499- * TypTypeParam ::= {Annotation}
3500- * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3530+ * TypTypeParam ::= {Annotation}
3531+ * (id | ‘_’) [HkTypeParamClause] TypeAndCtxBounds
3532+ * | {Annotation} (id | ‘_’) [`^`] TypeAndCtxBounds -- under captureChecking
35013533 *
35023534 * HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
3503- * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3504- * (id | ‘_’) [HkTypeParamClause] TypeBounds
3535+ * HkTypeParam ::= {Annotation} [‘+’ | ‘-’]
3536+ * (id | ‘_’) [HkTypePamClause] TypeBounds
3537+ * | {Annotation} (id | ‘_’) [`^`] TypeBounds -- under captureChecking
35053538 */
35063539 def typeParamClause (paramOwner : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
35073540
@@ -3526,11 +3559,17 @@ object Parsers {
35263559 in.nextToken()
35273560 WildcardParamName .fresh().toTypeName
35283561 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()
35293568 val hkparams = typeParamClauseOpt(ParamOwner .Hk )
35303569 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 )
35343573 TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
35353574 }
35363575 }
@@ -4052,15 +4091,26 @@ object Parsers {
40524091 argumentExprss(mkApply(Ident (nme.CONSTRUCTOR ), argumentExprs()))
40534092 }
40544093
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
40564098 */
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+
40584106 newLinesOpt()
40594107 atSpan(start, nameStart) {
40604108 val nameIdent = typeIdent()
4109+ val isCapDef = gobbleHat()
4110+ if isCapDef && in.token == LBRACKET then syntaxError(em " capture-set member declarations cannot have type parameters " )
40614111 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
40644114
40654115 def makeTypeDef (rhs : Tree ): Tree = {
40664116 val rhs1 = lambdaAbstractAll(tparams :: vparamss, rhs)
@@ -4073,12 +4123,12 @@ object Parsers {
40734123 in.token match {
40744124 case EQUALS =>
40754125 in.nextToken()
4076- makeTypeDef(toplevelTyp ())
4126+ makeTypeDef(typeDefRHS ())
40774127 case SUBTYPE | SUPERTYPE =>
4078- typeAndCtxBounds(tname) match
4128+ typeAndCtxBounds(tname, isCapDef ) match
40794129 case bounds : TypeBoundsTree if in.token == EQUALS =>
40804130 val eqOffset = in.skipToken()
4081- var rhs = toplevelTyp ()
4131+ var rhs = typeDefRHS ()
40824132 rhs match {
40834133 case mtt : MatchTypeTree =>
40844134 bounds match {
@@ -4096,17 +4146,20 @@ object Parsers {
40964146 makeTypeDef(rhs)
40974147 case bounds => makeTypeDef(bounds)
40984148 case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4099- makeTypeDef(typeAndCtxBounds(tname))
4149+ makeTypeDef(typeAndCtxBounds(tname, isCapDef ))
41004150 case _ if (staged & StageKind .QuotedPattern ) != 0
41014151 || sourceVersion.enablesNewGivens && in.isColon =>
4102- makeTypeDef(typeAndCtxBounds(tname))
4152+ makeTypeDef(typeAndCtxBounds(tname, isCapDef ))
41034153 case _ =>
41044154 syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token))
41054155 return EmptyTree // return to avoid setting the span to EmptyTree
41064156 }
41074157 }
41084158 }
41094159
4160+ private def concreteCapsType (refs : List [Tree ]): Tree =
4161+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4162+
41104163 /** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
41114164 * | [‘case’] ‘object’ ObjectDef
41124165 * | ‘enum’ EnumDef
0 commit comments