@@ -35,6 +35,7 @@ import config.SourceVersion.*
3535import config .SourceVersion
3636import dotty .tools .dotc .config .MigrationVersion
3737import dotty .tools .dotc .util .chaining .*
38+ import dotty .tools .dotc .config .Feature .ccEnabled
3839
3940object Parsers {
4041
@@ -220,6 +221,10 @@ object Parsers {
220221 def isErased = isIdent(nme.erased) && in.erasedEnabled
221222 // Are we seeing an `erased` soft keyword that will not be an identifier?
222223 def isErasedKw = isErased && in.isSoftModifierInParamModifierPosition
224+ // Are we seeing a `cap` soft keyword for declaring a capture-set member or at the beginning a capture-variable parameter list?
225+ def isCapKw = Feature .ccEnabled && isIdent(nme.cap)
226+ // 'cap type' ?
227+ def isCapTypeKw = isCapKw && in.lookahead.token == TYPE
223228 def isSimpleLiteral =
224229 simpleLiteralTokens.contains(in.token)
225230 || isIdent(nme.raw.MINUS ) && numericLitTokens.contains(in.lookahead.token)
@@ -1903,7 +1908,7 @@ object Parsers {
19031908 refinedTypeRest(atSpan(startOffset(t)) {
19041909 RefinedTypeTree (rejectWildcardType(t), refinement(indentOK = true ))
19051910 })
1906- else if Feature .ccEnabled && in.isIdent(nme.UPARROW ) && isCaptureUpArrow then
1911+ else if Feature .ccEnabled && in.isIdent(nme.UPARROW ) && isCaptureUpArrow then // TODO remove
19071912 atSpan(t.span.start):
19081913 in.nextToken()
19091914 if in.token == LBRACE
@@ -1958,7 +1963,8 @@ object Parsers {
19581963
19591964 def typeBlockStats (): List [Tree ] =
19601965 val tdefs = new ListBuffer [Tree ]
1961- while in.token == TYPE do tdefs += typeBlockStat()
1966+ while (in.token == TYPE ) do
1967+ tdefs += typeBlockStat()
19621968 tdefs.toList
19631969
19641970 /** TypeBlockStat ::= ‘type’ {nl} TypeDef
@@ -2159,11 +2165,14 @@ object Parsers {
21592165 * NamesAndTypes ::= NameAndType {‘,’ NameAndType}
21602166 * NameAndType ::= id ':' Type
21612167 */
2162- def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] =
2163- def argType ( ) =
2164- val t = typ()
2168+ def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] = // TOOD grammar doc
2169+ def withWildCard ( gen : => Tree ) =
2170+ val t = gen
21652171 if wildOK then t else rejectWildcardType(t)
21662172
2173+ def argType () = withWildCard(typ())
2174+ def argOrCapType () = withWildCard(if in.token == LBRACE then concreteCapsType(captureSet()) else typ())
2175+
21672176 def namedArgType () =
21682177 atSpan(in.offset):
21692178 val name = ident()
@@ -2174,14 +2183,14 @@ object Parsers {
21742183 atSpan(in.offset):
21752184 val name = ident()
21762185 acceptColon()
2177- NamedArg (name, argType())
2186+ NamedArg (name, argType()) // TODO allow capsets here?
21782187
2179- if namedOK && isIdent && in.lookahead.token == EQUALS then
2180- commaSeparated(() => namedArgType())
2188+ if namedOK && isIdent && in.lookahead.token == EQUALS then // TOOD support for named cap args
2189+ commaSeparated(() => namedArgType())
21812190 else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
21822191 commaSeparated(() => namedElem())
21832192 else
2184- commaSeparated(() => argType ())
2193+ commaSeparated(() => argOrCapType ())
21852194 end argTypes
21862195
21872196 def paramTypeOf (core : () => Tree ): Tree =
@@ -2240,7 +2249,7 @@ object Parsers {
22402249 inBraces(refineStatSeq())
22412250
22422251 /** TypeBounds ::= [`>:' Type] [`<:' Type]
2243- * | `^` -- under captureChecking
2252+ * | `^` -- under captureChecking TODO remove
22442253 */
22452254 def typeBounds (): TypeBoundsTree =
22462255 atSpan(in.offset):
@@ -2250,10 +2259,29 @@ object Parsers {
22502259 else
22512260 TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
22522261
2262+ /** CaptureSetBounds ::= [`>:' CaptureSetOrRef ] [`<:' CaptureSetOrRef ] --- under captureChecking
2263+ */
2264+ def captureSetBounds (): TypeBoundsTree =
2265+ atSpan(in.offset):
2266+ TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2267+
22532268 private def bound (tok : Int ): Tree =
22542269 if (in.token == tok) { in.nextToken(); toplevelTyp() }
22552270 else EmptyTree
22562271
2272+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2273+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2274+ Select (scalaDot(nme.caps), tpnme.CapSet )
2275+ else
2276+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2277+
2278+ private def capsBound (tok : Int ): Tree =
2279+ if (in.token == tok) then
2280+ in.nextToken()
2281+ capsBound(captureSet(), isLowerBound = tok == SUPERTYPE )
2282+ else
2283+ capsBound(Nil , isLowerBound = tok == SUPERTYPE )
2284+
22572285 /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
22582286 */
22592287 def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -2263,6 +2291,15 @@ object Parsers {
22632291 else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
22642292 }
22652293
2294+ /** CaptureSetAndCtxBounds ::= CaptureSetBounds [`:` ContextBounds] -- under captureChecking
2295+ */
2296+ def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2297+ val t = captureSetBounds()
2298+ val cbs = contextBounds(pname)
2299+ if (cbs.isEmpty) t
2300+ else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2301+ }
2302+
22662303 /** ContextBound ::= Type [`as` id] */
22672304 def contextBound (pname : TypeName ): Tree =
22682305 val t = toplevelTyp(inContextBound = true )
@@ -2782,7 +2819,10 @@ object Parsers {
27822819 in.nextToken()
27832820 simpleExprRest(selectorOrMatch(t), location, canApply = true )
27842821 case LBRACKET =>
2785- val tapp = atSpan(startOffset(t), in.offset) { TypeApply (t, typeArgs(namedOK = true , wildOK = false )) }
2822+ val tapp = atSpan(startOffset(t), in.offset) {
2823+ val args = typeArgs(namedOK = true , wildOK = false )
2824+ TypeApply (t, args)
2825+ }
27862826 simpleExprRest(tapp, location, canApply = true )
27872827 case LPAREN | LBRACE | INDENT if canApply =>
27882828 val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) }
@@ -3305,6 +3345,7 @@ object Parsers {
33053345 case nme.transparent => Mod .Transparent ()
33063346 case nme.infix => Mod .Infix ()
33073347 case nme.tracked => Mod .Tracked ()
3348+ case nme.cap => Mod .CaptureParam ()
33083349 }
33093350 }
33103351
@@ -3372,7 +3413,7 @@ object Parsers {
33723413 * | override
33733414 * | opaque
33743415 * LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased |
3375- * inline | transparent | infix
3416+ * inline | transparent | infix | cap
33763417 */
33773418 def modifiers (allowed : BitSet = modifierTokens, start : Modifiers = Modifiers ()): Modifiers = {
33783419 @ tailrec
@@ -3461,7 +3502,6 @@ object Parsers {
34613502 recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
34623503 end typeOrTermParamClauses
34633504
3464-
34653505 /** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
34663506 * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
34673507 * id [HkTypeParamClause] TypeAndCtxBounds
@@ -3486,6 +3526,43 @@ object Parsers {
34863526 in.nextToken()
34873527 ok
34883528
3529+ def ensureNoHKParams () = // for cap params
3530+ if in.token == LBRACKET then
3531+ syntaxError(em " 'cap' parameters cannot have type parameters " )
3532+ in.nextToken()
3533+
3534+ def ensureNoVariance () = // for cap params
3535+ if isIdent(nme.raw.PLUS ) || isIdent(nme.raw.MINUS ) then
3536+ syntaxError(em " no `+/-` variance annotation allowed here " )
3537+ in.nextToken()
3538+
3539+ def typeOrCapParam (): TypeDef =
3540+ if isCapKw then
3541+ in.nextToken()
3542+ capParam()
3543+ else typeParam()
3544+
3545+ def capParam (): TypeDef = {
3546+ val start = in.offset
3547+ var mods = annotsAsMods() | Param
3548+ if paramOwner.isClass then
3549+ mods |= PrivateLocal
3550+ ensureNoVariance() // TODO: in the future, we might want to support variances on capture params, ruled out for now
3551+ atSpan(start, nameStart) {
3552+ val name =
3553+ if paramOwner.acceptsWildcard && in.token == USCORE then
3554+ in.nextToken()
3555+ WildcardParamName .fresh().toTypeName
3556+ else ident().toTypeName
3557+ ensureNoHKParams()
3558+ val bounds =
3559+ if paramOwner.acceptsCtxBounds then captureSetAndCtxBounds(name)
3560+ else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then captureSetAndCtxBounds(name)
3561+ else captureSetBounds()
3562+ TypeDef (name, bounds).withMods(mods)
3563+ }
3564+ }
3565+
34893566 def typeParam (): TypeDef = {
34903567 val start = in.offset
34913568 var mods = annotsAsMods() | Param
@@ -3509,11 +3586,14 @@ object Parsers {
35093586 TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
35103587 }
35113588 }
3512- commaSeparated(() => typeParam ())
3589+ commaSeparated(() => typeOrCapParam ())
35133590 }
35143591
35153592 def typeParamClauseOpt (paramOwner : ParamOwner ): List [TypeDef ] =
3516- if (in.token == LBRACKET ) typeParamClause(paramOwner) else Nil
3593+ if (in.token == LBRACKET )
3594+ typeParamClause(paramOwner)
3595+ else
3596+ Nil
35173597
35183598 /** ContextTypes ::= FunArgType {‘,’ FunArgType}
35193599 */
@@ -3855,25 +3935,29 @@ object Parsers {
38553935 * | var VarDef
38563936 * | def DefDef
38573937 * | type {nl} TypeDef
3938+ * | cap type {nl} CapDef -- under capture checking
38583939 * | TmplDef
38593940 * EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
38603941 */
3861- def defOrDcl (start : Int , mods : Modifiers ): Tree = in.token match {
3862- case VAL =>
3863- in.nextToken()
3864- patDefOrDcl(start, mods)
3865- case VAR =>
3866- val mod = atSpan(in.skipToken()) { Mod .Var () }
3867- val mod1 = addMod(mods, mod)
3868- patDefOrDcl(start, mod1)
3869- case DEF =>
3870- defDefOrDcl(start, in.skipToken(mods))
3871- case TYPE =>
3872- typeDefOrDcl(start, in.skipToken(mods))
3873- case CASE if inEnum =>
3874- enumCase(start, mods)
3875- case _ =>
3876- tmplDef(start, mods)
3942+ def defOrDcl (start : Int , mods : Modifiers ): Tree =
3943+ in.token match {
3944+ case VAL =>
3945+ in.nextToken()
3946+ patDefOrDcl(start, mods)
3947+ case VAR =>
3948+ val mod = atSpan(in.skipToken()) { Mod .Var () }
3949+ val mod1 = addMod(mods, mod)
3950+ patDefOrDcl(start, mod1)
3951+ case DEF =>
3952+ defDefOrDcl(start, in.skipToken(mods))
3953+ case TYPE if mods.is(CaptureParam ) =>
3954+ capDefOrDcl(start, in.skipToken(mods))
3955+ case TYPE =>
3956+ typeDefOrDcl(start, in.skipToken(mods))
3957+ case CASE if inEnum =>
3958+ enumCase(start, mods)
3959+ case _ =>
3960+ tmplDef(start, mods)
38773961 }
38783962
38793963 /** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
@@ -4082,6 +4166,43 @@ object Parsers {
40824166 }
40834167 }
40844168
4169+ private def concreteCapsType (refs : List [Tree ]): Tree =
4170+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4171+
4172+ /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSetOrRef] -- under capture checking
4173+ */
4174+ def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
4175+ newLinesOpt()
4176+ atSpan(start, nameStart) {
4177+ val nameIdent = typeIdent()
4178+ val tname = nameIdent.name.asTypeName
4179+ if in.token == LBRACKET then syntaxError(em " 'cap type' declarations cannot have type parameters " )
4180+
4181+ def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
4182+ val tdef = TypeDef (nameIdent.name.toTypeName,
4183+ refs.match
4184+ case refs : List [Tree ] => concreteCapsType(refs)
4185+ case bounds : Tree => bounds)
4186+
4187+ if (nameIdent.isBackquoted)
4188+ tdef.pushAttachment(Backquoted , ())
4189+ finalizeDef(tdef, mods, start)
4190+ }
4191+
4192+ in.token.match
4193+ case EQUALS =>
4194+ in.nextToken()
4195+ makeCapDef(captureSet())
4196+ case SUBTYPE | SUPERTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4197+ makeCapDef(captureSetAndCtxBounds(tname))
4198+ case _ if (staged & StageKind .QuotedPattern ) != 0
4199+ || sourceVersion.enablesNewGivens && in.isColon =>
4200+ makeCapDef(captureSetAndCtxBounds(tname))
4201+ case _ =>
4202+ syntaxErrorOrIncomplete(ExpectedCaptureBoundOrEquals (in.token))
4203+ return EmptyTree // return to avoid setting the span to EmptyTree
4204+ }
4205+
40854206 /** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
40864207 * | [‘case’] ‘object’ ObjectDef
40874208 * | ‘enum’ EnumDef
@@ -4675,6 +4796,7 @@ object Parsers {
46754796 * | ‘var’ VarDef
46764797 * | ‘def’ DefDef
46774798 * | ‘type’ {nl} TypeDef
4799+ * | ‘cap’ ‘type’ {nl} CapDef -- under capture checking
46784800 * (in reality we admit class defs and vars and filter them out afterwards in `checkLegal`)
46794801 */
46804802 def refineStatSeq (): List [Tree ] = {
@@ -4699,9 +4821,14 @@ object Parsers {
46994821 fail(em " this kind of definition cannot be a refinement " )
47004822
47014823 while
4824+ val mods =
4825+ if isCapTypeKw then // allow `cap type` in refinements
4826+ in.nextToken()
4827+ addMod(Modifiers (), Mod .CaptureParam ())
4828+ else Modifiers ()
47024829 val dclFound = isDclIntro
47034830 if dclFound then
4704- stats ++= checkLegal(defOrDcl(in.offset, Modifiers () ))
4831+ stats ++= checkLegal(defOrDcl(in.offset, mods ))
47054832 var what = " declaration"
47064833 if inFunReturnType then what += " (possible cause: missing `=` in front of current method body)"
47074834 statSepOrEnd(stats, noPrevStat = ! dclFound, what)
0 commit comments