@@ -35,6 +35,8 @@ import config.SourceVersion.*
35
35
import config .SourceVersion
36
36
import dotty .tools .dotc .config .MigrationVersion
37
37
import dotty .tools .dotc .util .chaining .*
38
+ import dotty .tools .dotc .config .Feature .ccEnabled
39
+ import dotty .tools .dotc .core .Types .AndType .make
38
40
39
41
object Parsers {
40
42
@@ -256,6 +258,7 @@ object Parsers {
256
258
|| defIntroTokens.contains(in.token)
257
259
|| allowedMods.contains(in.token)
258
260
|| in.isSoftModifierInModifierPosition && ! excludedSoftModifiers.contains(in.name)
261
+ || Feature .ccEnabled && isIdent(nme.cap) // TODO have it as proper keyword/token instead?
259
262
260
263
def isStatSep : Boolean = in.isStatSep
261
264
@@ -1617,6 +1620,12 @@ object Parsers {
1617
1620
if in.token == RBRACE then Nil else commaSeparated(captureRef)
1618
1621
}
1619
1622
1623
+ /** CaptureSetOrRef ::= `{` CaptureSet `}` | CaptureRef -- under captureChecking
1624
+ */
1625
+ def captureSetOrRef (): List [Tree ] =
1626
+ if in.token == LBRACE then captureSet()
1627
+ else List (captureRef())
1628
+
1620
1629
def capturesAndResult (core : () => Tree ): Tree =
1621
1630
if Feature .ccEnabled && in.token == LBRACE && in.offset == in.lastOffset
1622
1631
then CapturesAndResult (captureSet(), core())
@@ -1958,7 +1967,8 @@ object Parsers {
1958
1967
1959
1968
def typeBlockStats (): List [Tree ] =
1960
1969
val tdefs = new ListBuffer [Tree ]
1961
- while in.token == TYPE do tdefs += typeBlockStat()
1970
+ while (in.token == TYPE ) do
1971
+ tdefs += typeBlockStat()
1962
1972
tdefs.toList
1963
1973
1964
1974
/** TypeBlockStat ::= ‘type’ {nl} TypeDef
@@ -2240,7 +2250,7 @@ object Parsers {
2240
2250
inBraces(refineStatSeq())
2241
2251
2242
2252
/** TypeBounds ::= [`>:' Type] [`<:' Type]
2243
- * | `^` -- under captureChecking
2253
+ * | `^` -- under captureChecking TODO remove
2244
2254
*/
2245
2255
def typeBounds (): TypeBoundsTree =
2246
2256
atSpan(in.offset):
@@ -2254,6 +2264,19 @@ object Parsers {
2254
2264
if (in.token == tok) { in.nextToken(); toplevelTyp() }
2255
2265
else EmptyTree
2256
2266
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
+
2257
2280
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2258
2281
*/
2259
2282
def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -2263,6 +2286,15 @@ object Parsers {
2263
2286
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2264
2287
}
2265
2288
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
+
2266
2298
/** ContextBound ::= Type [`as` id] */
2267
2299
def contextBound (pname : TypeName ): Tree =
2268
2300
val t = toplevelTyp(inContextBound = true )
@@ -3855,25 +3887,29 @@ object Parsers {
3855
3887
* | var VarDef
3856
3888
* | def DefDef
3857
3889
* | type {nl} TypeDef
3890
+ * | cap {nl} CapDef -- under capture checking
3858
3891
* | TmplDef
3859
3892
* EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
3860
3893
*/
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)
3877
3913
}
3878
3914
3879
3915
/** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
@@ -4082,6 +4118,52 @@ object Parsers {
4082
4118
}
4083
4119
}
4084
4120
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
+
4085
4167
/** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
4086
4168
* | [‘case’] ‘object’ ObjectDef
4087
4169
* | ‘enum’ EnumDef
0 commit comments