Skip to content

Commit d691126

Browse files
committed
Change handling of enum defs.
The previous scheme did not work because desugaring cannot deal with repeated expansions. We now sidestep the issue by doing the expansion in the parser. Luckily, positions work out perfectly, so that one can reconstruct the source precisely from the parsed untyped trees.
1 parent f04a07d commit d691126

File tree

2 files changed

+34
-15
lines changed

2 files changed

+34
-15
lines changed

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Decorators._
99
import util.Property
1010
import language.higherKinds
1111
import collection.mutable.ListBuffer
12+
import reflect.ClassTag
1213

1314
object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
1415

@@ -39,9 +40,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
3940
def withName(name: Name)(implicit ctx: Context) = cpy.ModuleDef(this)(name.toTermName, impl)
4041
}
4142

42-
/** mods case name impl */
43-
case class EnumDef(name: TypeName, impl: Template) extends MemberDef
44-
4543
case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree
4644

4745
case class SymbolLit(str: String) extends TermTree
@@ -191,6 +189,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
191189
def hasFlags = flags != EmptyFlags
192190
def hasAnnotations = annotations.nonEmpty
193191
def hasPrivateWithin = privateWithin != tpnme.EMPTY
192+
def hasMod[T: ClassTag] = {
193+
val cls = implicitly[ClassTag[T]].runtimeClass
194+
mods.exists(mod => cls.isAssignableFrom(mod.getClass))
195+
}
194196
}
195197

196198
@sharable val EmptyModifiers: Modifiers = new Modifiers()

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ object Parsers {
4848
val Class, Type, TypeParam, Def = Value
4949
}
5050

51+
private implicit class AddDeco(val buf: ListBuffer[Tree]) extends AnyVal {
52+
def +++=(x: Tree) = x match {
53+
case x: Thicket => buf ++= x.trees
54+
case x => buf += x
55+
}
56+
}
57+
5158
/** The parse starting point depends on whether the source file is self-contained:
5259
* if not, the AST will be supplemented.
5360
*/
@@ -2049,8 +2056,9 @@ object Parsers {
20492056
case CASEOBJECT =>
20502057
objectDef(start, posMods(start, mods | Case | Module))
20512058
case ENUM =>
2052-
val mods1 = addMod(mods, atPos(in.skipToken()) { Mod.Enum() })
2053-
if (in.token == CLASS) tmplDef(start, mods1) else enumDef(start, mods)
2059+
val enumMod = atPos(in.skipToken()) { Mod.Enum() }
2060+
if (in.token == CLASS) tmplDef(start, addMod(mods, enumMod))
2061+
else enumDef(start, mods, enumMod)
20542062
case _ =>
20552063
syntaxErrorOrIncomplete("expected start of definition")
20562064
EmptyTree
@@ -2103,20 +2111,29 @@ object Parsers {
21032111
/** id ClassConstr [`extends' [ConstrApps]]
21042112
* [nl] ‘{’ EnumCaseStats ‘}’
21052113
*/
2106-
def enumDef(start: Offset, mods: Modifiers): EnumDef = atPos(start, nameStart) {
2107-
val name = ident().toTypeName
2108-
val constr = classConstr(name)
2114+
def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): Thicket = {
2115+
val point = nameStart
2116+
val modName = ident()
2117+
val clsName = modName.toTypeName
2118+
val constr = classConstr(clsName)
21092119
val parents =
21102120
if (in.token == EXTENDS) {
21112121
in.nextToken();
21122122
newLineOptWhenFollowedBy(LBRACE)
21132123
if (in.token == LBRACE) Nil else tokenSeparated(WITH, constrApp)
21142124
}
21152125
else Nil
2126+
val clsDef = atPos(start, point) {
2127+
TypeDef(clsName, Template(constr, parents, EmptyValDef, Nil))
2128+
.withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start))
2129+
}
21162130
newLineOptWhenFollowedBy(LBRACE)
2117-
val body = inBraces(enumCaseStats)
2118-
EnumDef(name, Template(constr, Nil, EmptyValDef, body))
2119-
.withMods(mods).setComment(in.getDocComment(start)).asInstanceOf[EnumDef]
2131+
val modDef = atPos(in.offset) {
2132+
val body = inBraces(enumCaseStats)
2133+
ModuleDef(modName, Template(emptyConstructor, Nil, EmptyValDef, body))
2134+
.withMods(mods)
2135+
}
2136+
Thicket(clsDef :: modDef :: Nil)
21202137
}
21212138

21222139
/** EnumCaseStats = EnumCaseStat {semi EnumCaseStat */
@@ -2237,7 +2254,7 @@ object Parsers {
22372254
else if (in.token == IMPORT)
22382255
stats ++= importClause()
22392256
else if (in.token == AT || isTemplateIntro || isModifier)
2240-
stats += tmplDef(in.offset, defAnnotsMods(modifierTokens))
2257+
stats +++= tmplDef(in.offset, defAnnotsMods(modifierTokens))
22412258
else if (!isStatSep) {
22422259
if (in.token == CASE)
22432260
syntaxErrorOrIncomplete("only `case class` or `case object` allowed")
@@ -2287,7 +2304,7 @@ object Parsers {
22872304
else if (isExprIntro)
22882305
stats += expr1()
22892306
else if (isDefIntro(modifierTokensOrCase))
2290-
stats += defOrDcl(in.offset, defAnnotsMods(modifierTokens))
2307+
stats +++= defOrDcl(in.offset, defAnnotsMods(modifierTokens))
22912308
else if (!isStatSep) {
22922309
exitOnError = mustStartStat
22932310
syntaxErrorOrIncomplete("illegal start of definition")
@@ -2345,9 +2362,9 @@ object Parsers {
23452362
val start = in.offset
23462363
val imods = implicitMods()
23472364
if (isBindingIntro) stats += implicitClosure(start, Location.InBlock, imods)
2348-
else stats += localDef(start, imods)
2365+
else stats +++= localDef(start, imods)
23492366
} else {
2350-
stats += localDef(in.offset)
2367+
stats +++= localDef(in.offset)
23512368
}
23522369
else if (!isStatSep && (in.token != CASE)) {
23532370
exitOnError = mustStartStat

0 commit comments

Comments
 (0)