@@ -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)
@@ -1917,7 +1922,7 @@ object Parsers {
19171922 refinedTypeRest(atSpan(startOffset(t)) {
19181923 RefinedTypeTree (rejectWildcardType(t), refinement(indentOK = true ))
19191924 })
1920- else if Feature .ccEnabled && in.isIdent(nme.UPARROW ) && isCaptureUpArrow then
1925+ else if Feature .ccEnabled && in.isIdent(nme.UPARROW ) && isCaptureUpArrow then // TODO remove
19211926 atSpan(t.span.start):
19221927 in.nextToken()
19231928 if in.token == LBRACE
@@ -1972,7 +1977,8 @@ object Parsers {
19721977
19731978 def typeBlockStats (): List [Tree ] =
19741979 val tdefs = new ListBuffer [Tree ]
1975- while in.token == TYPE do tdefs += typeBlockStat()
1980+ while (in.token == TYPE ) do
1981+ tdefs += typeBlockStat()
19761982 tdefs.toList
19771983
19781984 /** TypeBlockStat ::= ‘type’ {nl} TypeDef
@@ -2173,11 +2179,14 @@ object Parsers {
21732179 * NamesAndTypes ::= NameAndType {‘,’ NameAndType}
21742180 * NameAndType ::= id ':' Type
21752181 */
2176- def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] =
2177- def argType ( ) =
2178- val t = typ()
2182+ def argTypes (namedOK : Boolean , wildOK : Boolean , tupleOK : Boolean ): List [Tree ] = // TOOD grammar doc
2183+ def withWildCard ( gen : => Tree ) =
2184+ val t = gen
21792185 if wildOK then t else rejectWildcardType(t)
21802186
2187+ def argType () = withWildCard(typ())
2188+ def argOrCapType () = withWildCard(if in.token == LBRACE then concreteCapsType(captureSet()) else typ())
2189+
21812190 def namedArgType () =
21822191 atSpan(in.offset):
21832192 val name = ident()
@@ -2188,14 +2197,14 @@ object Parsers {
21882197 atSpan(in.offset):
21892198 val name = ident()
21902199 acceptColon()
2191- NamedArg (name, argType())
2200+ NamedArg (name, argType()) // TODO allow capsets here?
21922201
2193- if namedOK && isIdent && in.lookahead.token == EQUALS then
2194- commaSeparated(() => namedArgType())
2202+ if namedOK && isIdent && in.lookahead.token == EQUALS then // TOOD support for named cap args
2203+ commaSeparated(() => namedArgType())
21952204 else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
21962205 commaSeparated(() => namedElem())
21972206 else
2198- commaSeparated(() => argType ())
2207+ commaSeparated(() => argOrCapType ())
21992208 end argTypes
22002209
22012210 def paramTypeOf (core : () => Tree ): Tree =
@@ -2254,7 +2263,7 @@ object Parsers {
22542263 inBraces(refineStatSeq())
22552264
22562265 /** TypeBounds ::= [`>:' Type] [`<:' Type]
2257- * | `^` -- under captureChecking
2266+ * | `^` -- under captureChecking TODO remove
22582267 */
22592268 def typeBounds (): TypeBoundsTree =
22602269 atSpan(in.offset):
@@ -2264,10 +2273,29 @@ object Parsers {
22642273 else
22652274 TypeBoundsTree (bound(SUPERTYPE ), bound(SUBTYPE ))
22662275
2276+ /** CaptureSetBounds ::= [`>:' CaptureSetOrRef ] [`<:' CaptureSetOrRef ] --- under captureChecking
2277+ */
2278+ def captureSetBounds (): TypeBoundsTree =
2279+ atSpan(in.offset):
2280+ TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2281+
22672282 private def bound (tok : Int ): Tree =
22682283 if (in.token == tok) { in.nextToken(); toplevelTyp() }
22692284 else EmptyTree
22702285
2286+ private def capsBound (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2287+ if isLowerBound && refs.isEmpty then // lower bounds with empty capture sets become a pure CapSet
2288+ Select (scalaDot(nme.caps), tpnme.CapSet )
2289+ else
2290+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2291+
2292+ private def capsBound (tok : Int ): Tree =
2293+ if (in.token == tok) then
2294+ in.nextToken()
2295+ capsBound(captureSet(), isLowerBound = tok == SUPERTYPE )
2296+ else
2297+ capsBound(Nil , isLowerBound = tok == SUPERTYPE )
2298+
22712299 /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
22722300 */
22732301 def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -2277,6 +2305,15 @@ object Parsers {
22772305 else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
22782306 }
22792307
2308+ /** CaptureSetAndCtxBounds ::= CaptureSetBounds [`:` ContextBounds] -- under captureChecking
2309+ */
2310+ def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2311+ val t = captureSetBounds()
2312+ val cbs = contextBounds(pname)
2313+ if (cbs.isEmpty) t
2314+ else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2315+ }
2316+
22802317 /** ContextBound ::= Type [`as` id] */
22812318 def contextBound (pname : TypeName ): Tree =
22822319 val t = toplevelTyp(inContextBound = true )
@@ -2796,7 +2833,10 @@ object Parsers {
27962833 in.nextToken()
27972834 simpleExprRest(selectorOrMatch(t), location, canApply = true )
27982835 case LBRACKET =>
2799- val tapp = atSpan(startOffset(t), in.offset) { TypeApply (t, typeArgs(namedOK = true , wildOK = false )) }
2836+ val tapp = atSpan(startOffset(t), in.offset) {
2837+ val args = typeArgs(namedOK = true , wildOK = false )
2838+ TypeApply (t, args)
2839+ }
28002840 simpleExprRest(tapp, location, canApply = true )
28012841 case LPAREN | LBRACE | INDENT if canApply =>
28022842 val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) }
@@ -3320,6 +3360,7 @@ object Parsers {
33203360 case nme.tracked => Mod .Tracked ()
33213361 case nme.erased if in.erasedEnabled => Mod .Erased ()
33223362 case nme.mut if Feature .ccEnabled => Mod .Mut ()
3363+ case nme.cap => Mod .CaptureParam ()
33233364 }
33243365 }
33253366
@@ -3388,7 +3429,7 @@ object Parsers {
33883429 * | opaque
33893430 * LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased |
33903431 * inline | transparent | infix |
3391- * mut -- under cc
3432+ * mut | cap -- under cc
33923433 */
33933434 def modifiers (allowed : BitSet = modifierTokens, start : Modifiers = Modifiers ()): Modifiers = {
33943435 @ tailrec
@@ -3477,7 +3518,6 @@ object Parsers {
34773518 recur(numLeadParams, firstClause = true , prevIsTypeClause = false )
34783519 end typeOrTermParamClauses
34793520
3480-
34813521 /** ClsTypeParamClause::= ‘[’ ClsTypeParam {‘,’ ClsTypeParam} ‘]’
34823522 * ClsTypeParam ::= {Annotation} [‘+’ | ‘-’]
34833523 * id [HkTypeParamClause] TypeAndCtxBounds
@@ -3502,6 +3542,43 @@ object Parsers {
35023542 in.nextToken()
35033543 ok
35043544
3545+ def ensureNoHKParams () = // for cap params
3546+ if in.token == LBRACKET then
3547+ syntaxError(em " 'cap' parameters cannot have type parameters " )
3548+ in.nextToken()
3549+
3550+ def ensureNoVariance () = // for cap params
3551+ if isIdent(nme.raw.PLUS ) || isIdent(nme.raw.MINUS ) then
3552+ syntaxError(em " no `+/-` variance annotation allowed here " )
3553+ in.nextToken()
3554+
3555+ def typeOrCapParam (): TypeDef =
3556+ if isCapKw then
3557+ in.nextToken()
3558+ capParam()
3559+ else typeParam()
3560+
3561+ def capParam (): TypeDef = {
3562+ val start = in.offset
3563+ var mods = annotsAsMods() | Param
3564+ if paramOwner.isClass then
3565+ mods |= PrivateLocal
3566+ ensureNoVariance() // TODO: in the future, we might want to support variances on capture params, ruled out for now
3567+ atSpan(start, nameStart) {
3568+ val name =
3569+ if paramOwner.acceptsWildcard && in.token == USCORE then
3570+ in.nextToken()
3571+ WildcardParamName .fresh().toTypeName
3572+ else ident().toTypeName
3573+ ensureNoHKParams()
3574+ val bounds =
3575+ if paramOwner.acceptsCtxBounds then captureSetAndCtxBounds(name)
3576+ else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner .Type then captureSetAndCtxBounds(name)
3577+ else captureSetBounds()
3578+ TypeDef (name, bounds).withMods(mods)
3579+ }
3580+ }
3581+
35053582 def typeParam (): TypeDef = {
35063583 val start = in.offset
35073584 var mods = annotsAsMods() | Param
@@ -3525,11 +3602,14 @@ object Parsers {
35253602 TypeDef (name, lambdaAbstract(hkparams, bounds)).withMods(mods)
35263603 }
35273604 }
3528- commaSeparated(() => typeParam ())
3605+ commaSeparated(() => typeOrCapParam ())
35293606 }
35303607
35313608 def typeParamClauseOpt (paramOwner : ParamOwner ): List [TypeDef ] =
3532- if (in.token == LBRACKET ) typeParamClause(paramOwner) else Nil
3609+ if (in.token == LBRACKET )
3610+ typeParamClause(paramOwner)
3611+ else
3612+ Nil
35333613
35343614 /** ContextTypes ::= FunArgType {‘,’ FunArgType}
35353615 */
@@ -3871,25 +3951,29 @@ object Parsers {
38713951 * | var VarDef
38723952 * | def DefDef
38733953 * | type {nl} TypeDef
3954+ * | cap type {nl} CapDef -- under capture checking
38743955 * | TmplDef
38753956 * EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
38763957 */
3877- def defOrDcl (start : Int , mods : Modifiers ): Tree = in.token match {
3878- case VAL =>
3879- in.nextToken()
3880- patDefOrDcl(start, mods)
3881- case VAR =>
3882- val mod = atSpan(in.skipToken()) { Mod .Var () }
3883- val mod1 = addMod(mods, mod)
3884- patDefOrDcl(start, mod1)
3885- case DEF =>
3886- defDefOrDcl(start, in.skipToken(mods))
3887- case TYPE =>
3888- typeDefOrDcl(start, in.skipToken(mods))
3889- case CASE if inEnum =>
3890- enumCase(start, mods)
3891- case _ =>
3892- tmplDef(start, mods)
3958+ def defOrDcl (start : Int , mods : Modifiers ): Tree =
3959+ in.token match {
3960+ case VAL =>
3961+ in.nextToken()
3962+ patDefOrDcl(start, mods)
3963+ case VAR =>
3964+ val mod = atSpan(in.skipToken()) { Mod .Var () }
3965+ val mod1 = addMod(mods, mod)
3966+ patDefOrDcl(start, mod1)
3967+ case DEF =>
3968+ defDefOrDcl(start, in.skipToken(mods))
3969+ case TYPE if mods.is(CaptureParam ) =>
3970+ capDefOrDcl(start, in.skipToken(mods))
3971+ case TYPE =>
3972+ typeDefOrDcl(start, in.skipToken(mods))
3973+ case CASE if inEnum =>
3974+ enumCase(start, mods)
3975+ case _ =>
3976+ tmplDef(start, mods)
38933977 }
38943978
38953979 /** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
@@ -4098,6 +4182,43 @@ object Parsers {
40984182 }
40994183 }
41004184
4185+ private def concreteCapsType (refs : List [Tree ]): Tree =
4186+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, tpnme.retains)
4187+
4188+ /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSetOrRef] -- under capture checking
4189+ */
4190+ def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
4191+ newLinesOpt()
4192+ atSpan(start, nameStart) {
4193+ val nameIdent = typeIdent()
4194+ val tname = nameIdent.name.asTypeName
4195+ if in.token == LBRACKET then syntaxError(em " 'cap type' declarations cannot have type parameters " )
4196+
4197+ def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
4198+ val tdef = TypeDef (nameIdent.name.toTypeName,
4199+ refs.match
4200+ case refs : List [Tree ] => concreteCapsType(refs)
4201+ case bounds : Tree => bounds)
4202+
4203+ if (nameIdent.isBackquoted)
4204+ tdef.pushAttachment(Backquoted , ())
4205+ finalizeDef(tdef, mods, start)
4206+ }
4207+
4208+ in.token.match
4209+ case EQUALS =>
4210+ in.nextToken()
4211+ makeCapDef(captureSet())
4212+ case SUBTYPE | SUPERTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4213+ makeCapDef(captureSetAndCtxBounds(tname))
4214+ case _ if (staged & StageKind .QuotedPattern ) != 0
4215+ || sourceVersion.enablesNewGivens && in.isColon =>
4216+ makeCapDef(captureSetAndCtxBounds(tname))
4217+ case _ =>
4218+ syntaxErrorOrIncomplete(ExpectedCaptureBoundOrEquals (in.token))
4219+ return EmptyTree // return to avoid setting the span to EmptyTree
4220+ }
4221+
41014222 /** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
41024223 * | [‘case’] ‘object’ ObjectDef
41034224 * | ‘enum’ EnumDef
@@ -4691,6 +4812,7 @@ object Parsers {
46914812 * | ‘var’ VarDef
46924813 * | ‘def’ DefDef
46934814 * | ‘type’ {nl} TypeDef
4815+ * | ‘cap’ ‘type’ {nl} CapDef -- under capture checking
46944816 * (in reality we admit class defs and vars and filter them out afterwards in `checkLegal`)
46954817 */
46964818 def refineStatSeq (): List [Tree ] = {
@@ -4716,9 +4838,14 @@ object Parsers {
47164838 fail(em " this kind of definition cannot be a refinement " )
47174839
47184840 while
4841+ val mods =
4842+ if isCapTypeKw then // allow `cap type` in refinements
4843+ in.nextToken()
4844+ addMod(Modifiers (), Mod .CaptureParam ())
4845+ else Modifiers ()
47194846 val dclFound = isDclIntro
47204847 if dclFound then
4721- stats ++= checkLegal(defOrDcl(in.offset, Modifiers () ))
4848+ stats ++= checkLegal(defOrDcl(in.offset, mods ))
47224849 var what = " declaration"
47234850 if inFunReturnType then what += " (possible cause: missing `=` in front of current method body)"
47244851 statSepOrEnd(stats, noPrevStat = ! dclFound, what)
0 commit comments