@@ -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
@@ -1610,6 +1613,12 @@ object Parsers {
1610
1613
if in.token == RBRACE then Nil else commaSeparated(captureRef)
1611
1614
}
1612
1615
1616
+ /** CaptureSetOrRef ::= `{` CaptureSet `}` | CaptureRef -- under captureChecking
1617
+ */
1618
+ def captureSetOrRef (): List [Tree ] =
1619
+ if in.token == LBRACE then captureSet()
1620
+ else List (captureRef())
1621
+
1613
1622
def capturesAndResult (core : () => Tree ): Tree =
1614
1623
if Feature .ccEnabled && in.token == LBRACE && in.offset == in.lastOffset
1615
1624
then CapturesAndResult (captureSet(), core())
@@ -1951,7 +1960,8 @@ object Parsers {
1951
1960
1952
1961
def typeBlockStats (): List [Tree ] =
1953
1962
val tdefs = new ListBuffer [Tree ]
1954
- while in.token == TYPE do tdefs += typeBlockStat()
1963
+ while (in.token == TYPE ) do
1964
+ tdefs += typeBlockStat()
1955
1965
tdefs.toList
1956
1966
1957
1967
/** TypeBlockStat ::= ‘type’ {nl} TypeDef
@@ -2233,7 +2243,7 @@ object Parsers {
2233
2243
inBraces(refineStatSeq())
2234
2244
2235
2245
/** TypeBounds ::= [`>:' Type] [`<:' Type]
2236
- * | `^` -- under captureChecking
2246
+ * | `^` -- under captureChecking TODO remove
2237
2247
*/
2238
2248
def typeBounds (): TypeBoundsTree =
2239
2249
atSpan(in.offset):
@@ -2247,6 +2257,19 @@ object Parsers {
2247
2257
if (in.token == tok) { in.nextToken(); toplevelTyp() }
2248
2258
else EmptyTree
2249
2259
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
+
2250
2273
/** TypeAndCtxBounds ::= TypeBounds [`:` ContextBounds]
2251
2274
*/
2252
2275
def typeAndCtxBounds (pname : TypeName ): Tree = {
@@ -2256,6 +2279,15 @@ object Parsers {
2256
2279
else atSpan((t.span union cbs.head.span).start) { ContextBounds (t, cbs) }
2257
2280
}
2258
2281
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
+
2259
2291
/** ContextBound ::= Type [`as` id] */
2260
2292
def contextBound (pname : TypeName ): Tree =
2261
2293
val t = toplevelTyp(inContextBound = true )
@@ -3848,25 +3880,29 @@ object Parsers {
3848
3880
* | var VarDef
3849
3881
* | def DefDef
3850
3882
* | type {nl} TypeDef
3883
+ * | cap {nl} CapDef -- under capture checking
3851
3884
* | TmplDef
3852
3885
* EnumCase ::= `case' (id ClassConstr [`extends' ConstrApps]] | ids)
3853
3886
*/
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)
3870
3906
}
3871
3907
3872
3908
/** PatDef ::= ids [‘:’ Type] [‘=’ Expr]
@@ -4075,6 +4111,52 @@ object Parsers {
4075
4111
}
4076
4112
}
4077
4113
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
+
4078
4160
/** TmplDef ::= ([‘case’] ‘class’ | ‘trait’) ClassDef
4079
4161
* | [‘case’] ‘object’ ObjectDef
4080
4162
* | ‘enum’ EnumDef
0 commit comments