@@ -35,6 +35,8 @@ 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
39+ import dotty .tools .dotc .core .Types .AndType .make
3840
3941object Parsers {
4042
@@ -256,6 +258,7 @@ object Parsers {
256258 || defIntroTokens.contains(in.token)
257259 || allowedMods.contains(in.token)
258260 || in.isSoftModifierInModifierPosition && ! excludedSoftModifiers.contains(in.name)
261+ || Feature .ccEnabled && isIdent(nme.cap) // TODO have it as proper keyword/token instead?
259262
260263 def isStatSep : Boolean = in.isStatSep
261264
@@ -1610,6 +1613,12 @@ object Parsers {
16101613 if in.token == RBRACE then Nil else commaSeparated(captureRef)
16111614 }
16121615
1616+ /** CaptureSetOrRef ::= `{` CaptureSet `}` | CaptureRef -- under captureChecking
1617+ */
1618+ def captureSetOrRef (): List [Tree ] =
1619+ if in.token == LBRACE then captureSet()
1620+ else List (captureRef())
1621+
16131622 def capturesAndResult (core : () => Tree ): Tree =
16141623 if Feature .ccEnabled && in.token == LBRACE && in.offset == in.lastOffset
16151624 then CapturesAndResult (captureSet(), core())
@@ -1951,7 +1960,8 @@ object Parsers {
19511960
19521961 def typeBlockStats (): List [Tree ] =
19531962 val tdefs = new ListBuffer [Tree ]
1954- while in.token == TYPE do tdefs += typeBlockStat()
1963+ while (in.token == TYPE ) do
1964+ tdefs += typeBlockStat()
19551965 tdefs.toList
19561966
19571967 /** TypeBlockStat ::= ‘type’ {nl} TypeDef
@@ -2233,7 +2243,7 @@ object Parsers {
22332243 inBraces(refineStatSeq())
22342244
22352245 /** TypeBounds ::= [`>:' Type] [`<:' Type]
2236- * | `^` -- under captureChecking
2246+ * | `^` -- under captureChecking TODO remove
22372247 */
22382248 def typeBounds (): TypeBoundsTree =
22392249 atSpan(in.offset):
@@ -2247,6 +2257,19 @@ object Parsers {
22472257 if (in.token == tok) { in.nextToken(); toplevelTyp() }
22482258 else EmptyTree
22492259
2260+ private def capsType (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2261+ if isLowerBound && refs.isEmpty then
2262+ Select (scalaDot(nme.caps), tpnme.CapSet )
2263+ else
2264+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2265+
2266+ private def capsBound (tok : Int ): Tree =
2267+ if (in.token == tok) then
2268+ in.nextToken()
2269+ capsType(captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
2270+ else
2271+ capsType(Nil , isLowerBound = tok == SUPERTYPE )
2272+
22502273 /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
22512274 */
22522275 def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -2256,6 +2279,15 @@ object Parsers {
22562279 else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
22572280 }
22582281
2282+ /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds] -- under captureChecking
2283+ */
2284+ def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2285+ val t = TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2286+ val cbs = contextBounds(pname)
2287+ if (cbs.isEmpty) t
2288+ else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2289+ }
2290+
22592291 /** ContextBound ::= Type [`as` id] */
22602292 def contextBound (pname : TypeName ): Tree =
22612293 val t = toplevelTyp(inContextBound = true )
@@ -3848,25 +3880,29 @@ object Parsers {
38483880 * | var VarDef
38493881 * | def DefDef
38503882 * | type {nl} TypeDef
3883+ * | cap {nl} CapDef -- under capture checking
38513884 * | TmplDef
38523885 * EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
38533886 */
3854- def defOrDcl (start : Int , mods : Modifiers ): Tree = in.token match {
3855- case VAL =>
3856- in.nextToken()
3857- patDefOrDcl(start, mods)
3858- case VAR =>
3859- val mod = atSpan(in.skipToken()) { Mod .Var () }
3860- val mod1 = addMod(mods, mod)
3861- patDefOrDcl(start, mod1)
3862- case DEF =>
3863- defDefOrDcl(start, in.skipToken(mods))
3864- case TYPE =>
3865- typeDefOrDcl(start, in.skipToken(mods))
3866- case CASE if inEnum =>
3867- enumCase(start, mods)
3868- case _ =>
3869- tmplDef(start, mods)
3887+ def defOrDcl (start : Int , mods : Modifiers ): Tree =
3888+ in.token match {
3889+ case VAL =>
3890+ in.nextToken()
3891+ patDefOrDcl(start, mods)
3892+ case VAR =>
3893+ val mod = atSpan(in.skipToken()) { Mod .Var () }
3894+ val mod1 = addMod(mods, mod)
3895+ patDefOrDcl(start, mod1)
3896+ case DEF =>
3897+ defDefOrDcl(start, in.skipToken(mods))
3898+ case TYPE =>
3899+ typeDefOrDcl(start, in.skipToken(mods))
3900+ case CASE if inEnum =>
3901+ enumCase(start, mods)
3902+ case _ =>
3903+ if Feature .ccEnabled && isIdent(nme.cap) then // TODO do we want a dedicated CAP token? TokensCommon would need a Ctx to check if ccenabled
3904+ capDefOrDcl(start, in.skipToken(mods))
3905+ else tmplDef(start, mods)
38703906 }
38713907
38723908 /** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
@@ -4075,6 +4111,52 @@ object Parsers {
40754111 }
40764112 }
40774113
4114+ /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSet] -- under capture checking
4115+ */
4116+ def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
4117+ newLinesOpt()
4118+ atSpan(start, nameStart) {
4119+ val nameIdent = typeIdent()
4120+ val tname = nameIdent.name.asTypeName
4121+ // val tparams = typeParamClauseOpt(ParamOwner.Hk) TODO: error message: type parameters not allowed
4122+ // val vparamss = funParamClauses()
4123+
4124+ def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
4125+ val tdef = TypeDef (nameIdent.name.toTypeName,
4126+ refs.match
4127+ case refs : List [Tree ] => capsType(refs)
4128+ case bounds : Tree => bounds)
4129+
4130+ if (nameIdent.isBackquoted)
4131+ tdef.pushAttachment(Backquoted , ())
4132+ finalizeDef(tdef, mods, start)
4133+ }
4134+
4135+ in.token.match
4136+ case EQUALS =>
4137+ in.nextToken()
4138+ makeCapDef(captureSetOrRef())
4139+ case SUBTYPE | SUPERTYPE =>
4140+ captureSetAndCtxBounds(tname) match
4141+ case bounds : TypeBoundsTree if in.token == EQUALS => // TODO ask Martin: can this case even happen?
4142+ val eqOffset = in.skipToken()
4143+ var rhs = capsType(captureSetOrRef())
4144+ if mods.is(Opaque ) then
4145+ rhs = TypeBoundsTree (bounds.lo, bounds.hi, rhs)
4146+ else
4147+ syntaxError(em " cannot combine bound and alias " , eqOffset)
4148+ makeCapDef(rhs)
4149+ case bounds => makeCapDef(bounds)
4150+ case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4151+ makeCapDef(captureSetAndCtxBounds(tname))
4152+ case _ if (staged & StageKind .QuotedPattern ) != 0 // TODO not sure if we need this case for capsets
4153+ || sourceVersion.enablesNewGivens && in.isColon =>
4154+ makeCapDef(captureSetAndCtxBounds(tname))
4155+ case _ =>
4156+ syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token)) // TODO change error message
4157+ return EmptyTree // return to avoid setting the span to EmptyTree
4158+ }
4159+
40784160 /** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
40794161 * | [‘case’] ‘object’ ObjectDef
40804162 * | ‘enum’ EnumDef
0 commit comments