@@ -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
@@ -1617,6 +1620,12 @@ object Parsers {
16171620 if in.token == RBRACE then Nil else commaSeparated(captureRef)
16181621 }
16191622
1623+ /** CaptureSetOrRef ::= `{` CaptureSet `}` | CaptureRef -- under captureChecking
1624+ */
1625+ def captureSetOrRef (): List [Tree ] =
1626+ if in.token == LBRACE then captureSet()
1627+ else List (captureRef())
1628+
16201629 def capturesAndResult (core : () => Tree ): Tree =
16211630 if Feature .ccEnabled && in.token == LBRACE && in.offset == in.lastOffset
16221631 then CapturesAndResult (captureSet(), core())
@@ -1958,7 +1967,8 @@ object Parsers {
19581967
19591968 def typeBlockStats (): List [Tree ] =
19601969 val tdefs = new ListBuffer [Tree ]
1961- while in.token == TYPE do tdefs += typeBlockStat()
1970+ while (in.token == TYPE ) do
1971+ tdefs += typeBlockStat()
19621972 tdefs.toList
19631973
19641974 /** TypeBlockStat ::= ‘type’ {nl} TypeDef
@@ -2240,7 +2250,7 @@ object Parsers {
22402250 inBraces(refineStatSeq())
22412251
22422252 /** TypeBounds ::= [`>:' Type] [`<:' Type]
2243- * | `^` -- under captureChecking
2253+ * | `^` -- under captureChecking TODO remove
22442254 */
22452255 def typeBounds (): TypeBoundsTree =
22462256 atSpan(in.offset):
@@ -2254,6 +2264,19 @@ object Parsers {
22542264 if (in.token == tok) { in.nextToken(); toplevelTyp() }
22552265 else EmptyTree
22562266
2267+ private def capsType (refs : List [Tree ], isLowerBound : Boolean = false ): Tree =
2268+ if isLowerBound && refs.isEmpty then
2269+ Select (scalaDot(nme.caps), tpnme.CapSet )
2270+ else
2271+ makeRetaining(Select (scalaDot(nme.caps), tpnme.CapSet ), refs, if refs.isEmpty then tpnme.retainsCap else tpnme.retains)
2272+
2273+ private def capsBound (tok : Int ): Tree =
2274+ if (in.token == tok) then
2275+ in.nextToken()
2276+ capsType(captureSetOrRef(), isLowerBound = tok == SUPERTYPE )
2277+ else
2278+ capsType(Nil , isLowerBound = tok == SUPERTYPE )
2279+
22572280 /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
22582281 */
22592282 def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -2263,6 +2286,15 @@ object Parsers {
22632286 else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
22642287 }
22652288
2289+ /** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds] -- under captureChecking
2290+ */
2291+ def captureSetAndCtxBounds (pname : TypeName ): Tree = {
2292+ val t = TypeBoundsTree (capsBound(SUPERTYPE ), capsBound(SUBTYPE ))
2293+ val cbs = contextBounds(pname)
2294+ if (cbs.isEmpty) t
2295+ else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2296+ }
2297+
22662298 /** ContextBound ::= Type [`as` id] */
22672299 def contextBound (pname : TypeName ): Tree =
22682300 val t = toplevelTyp(inContextBound = true )
@@ -3855,25 +3887,29 @@ object Parsers {
38553887 * | var VarDef
38563888 * | def DefDef
38573889 * | type {nl} TypeDef
3890+ * | cap {nl} CapDef -- under capture checking
38583891 * | TmplDef
38593892 * EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
38603893 */
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)
3894+ def defOrDcl (start : Int , mods : Modifiers ): Tree =
3895+ in.token match {
3896+ case VAL =>
3897+ in.nextToken()
3898+ patDefOrDcl(start, mods)
3899+ case VAR =>
3900+ val mod = atSpan(in.skipToken()) { Mod .Var () }
3901+ val mod1 = addMod(mods, mod)
3902+ patDefOrDcl(start, mod1)
3903+ case DEF =>
3904+ defDefOrDcl(start, in.skipToken(mods))
3905+ case TYPE =>
3906+ typeDefOrDcl(start, in.skipToken(mods))
3907+ case CASE if inEnum =>
3908+ enumCase(start, mods)
3909+ case _ =>
3910+ if Feature .ccEnabled && isIdent(nme.cap) then // TODO do we want a dedicated CAP token? TokensCommon would need a Ctx to check if ccenabled
3911+ capDefOrDcl(start, in.skipToken(mods))
3912+ else tmplDef(start, mods)
38773913 }
38783914
38793915 /** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
@@ -4082,6 +4118,52 @@ object Parsers {
40824118 }
40834119 }
40844120
4121+ /** CapDef ::= id CaptureSetAndCtxBounds [‘=’ CaptureSet] -- under capture checking
4122+ */
4123+ def capDefOrDcl (start : Offset , mods : Modifiers ): Tree =
4124+ newLinesOpt()
4125+ atSpan(start, nameStart) {
4126+ val nameIdent = typeIdent()
4127+ val tname = nameIdent.name.asTypeName
4128+ // val tparams = typeParamClauseOpt(ParamOwner.Hk) TODO: error message: type parameters not allowed
4129+ // val vparamss = funParamClauses()
4130+
4131+ def makeCapDef (refs : List [Tree ] | Tree ): Tree = {
4132+ val tdef = TypeDef (nameIdent.name.toTypeName,
4133+ refs.match
4134+ case refs : List [Tree ] => capsType(refs)
4135+ case bounds : Tree => bounds)
4136+
4137+ if (nameIdent.isBackquoted)
4138+ tdef.pushAttachment(Backquoted , ())
4139+ finalizeDef(tdef, mods, start)
4140+ }
4141+
4142+ in.token.match
4143+ case EQUALS =>
4144+ in.nextToken()
4145+ makeCapDef(captureSetOrRef())
4146+ case SUBTYPE | SUPERTYPE =>
4147+ captureSetAndCtxBounds(tname) match
4148+ case bounds : TypeBoundsTree if in.token == EQUALS => // TODO ask Martin: can this case even happen?
4149+ val eqOffset = in.skipToken()
4150+ var rhs = capsType(captureSetOrRef())
4151+ if mods.is(Opaque ) then
4152+ rhs = TypeBoundsTree (bounds.lo, bounds.hi, rhs)
4153+ else
4154+ syntaxError(em " cannot combine bound and alias " , eqOffset)
4155+ makeCapDef(rhs)
4156+ case bounds => makeCapDef(bounds)
4157+ case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
4158+ makeCapDef(captureSetAndCtxBounds(tname))
4159+ case _ if (staged & StageKind .QuotedPattern ) != 0 // TODO not sure if we need this case for capsets
4160+ || sourceVersion.enablesNewGivens && in.isColon =>
4161+ makeCapDef(captureSetAndCtxBounds(tname))
4162+ case _ =>
4163+ syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals (in.token)) // TODO change error message
4164+ return EmptyTree // return to avoid setting the span to EmptyTree
4165+ }
4166+
40854167 /** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
40864168 * | [‘case’] ‘object’ ObjectDef
40874169 * | ‘enum’ EnumDef
0 commit comments