aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-02-08 21:19:16 +1100
committerMartin Odersky <odersky@gmail.com>2017-04-04 13:28:44 +0200
commit41d83d42650d0c0b54c47c1a9043d0b92315aa4e (patch)
tree1bf4ca65464cf3f74b10ec14f718d4b4599223d7
parent69fd9dc80e78feb35ee601a9aaac813eef331e6a (diff)
downloaddotty-41d83d42650d0c0b54c47c1a9043d0b92315aa4e.tar.gz
dotty-41d83d42650d0c0b54c47c1a9043d0b92315aa4e.tar.bz2
dotty-41d83d42650d0c0b54c47c1a9043d0b92315aa4e.zip
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.
-rw-r--r--compiler/src/dotty/tools/dotc/ast/untpd.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/parsing/Parsers.scala41
2 files changed, 34 insertions, 15 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala
index e14c6714b..7020e4dac 100644
--- a/compiler/src/dotty/tools/dotc/ast/untpd.scala
+++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala
@@ -9,6 +9,7 @@ import Decorators._
import util.Property
import language.higherKinds
import collection.mutable.ListBuffer
+import reflect.ClassTag
object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
@@ -39,9 +40,6 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def withName(name: Name)(implicit ctx: Context) = cpy.ModuleDef(this)(name.toTermName, impl)
}
- /** mods case name impl */
- case class EnumDef(name: TypeName, impl: Template) extends MemberDef
-
case class ParsedTry(expr: Tree, handler: Tree, finalizer: Tree) extends TermTree
case class SymbolLit(str: String) extends TermTree
@@ -192,6 +190,10 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def hasFlags = flags != EmptyFlags
def hasAnnotations = annotations.nonEmpty
def hasPrivateWithin = privateWithin != tpnme.EMPTY
+ def hasMod[T: ClassTag] = {
+ val cls = implicitly[ClassTag[T]].runtimeClass
+ mods.exists(mod => cls.isAssignableFrom(mod.getClass))
+ }
}
@sharable val EmptyModifiers: Modifiers = new Modifiers()
diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
index 7ec44e342..ee736179a 100644
--- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -49,6 +49,13 @@ object Parsers {
val Class, Type, TypeParam, Def = Value
}
+ private implicit class AddDeco(val buf: ListBuffer[Tree]) extends AnyVal {
+ def +++=(x: Tree) = x match {
+ case x: Thicket => buf ++= x.trees
+ case x => buf += x
+ }
+ }
+
/** The parse starting point depends on whether the source file is self-contained:
* if not, the AST will be supplemented.
*/
@@ -2061,8 +2068,9 @@ object Parsers {
case CASEOBJECT =>
objectDef(start, posMods(start, mods | Case | Module))
case ENUM =>
- val mods1 = addMod(mods, atPos(in.skipToken()) { Mod.Enum() })
- if (in.token == CLASS) tmplDef(start, mods1) else enumDef(start, mods)
+ val enumMod = atPos(in.skipToken()) { Mod.Enum() }
+ if (in.token == CLASS) tmplDef(start, addMod(mods, enumMod))
+ else enumDef(start, mods, enumMod)
case _ =>
syntaxErrorOrIncomplete("expected start of definition")
EmptyTree
@@ -2115,9 +2123,11 @@ object Parsers {
/** id ClassConstr [`extends' [ConstrApps]]
* [nl] ‘{’ EnumCaseStats ‘}’
*/
- def enumDef(start: Offset, mods: Modifiers): EnumDef = atPos(start, nameStart) {
- val name = ident().toTypeName
- val constr = classConstr(name)
+ def enumDef(start: Offset, mods: Modifiers, enumMod: Mod): Thicket = {
+ val point = nameStart
+ val modName = ident()
+ val clsName = modName.toTypeName
+ val constr = classConstr(clsName)
val parents =
if (in.token == EXTENDS) {
in.nextToken();
@@ -2125,10 +2135,17 @@ object Parsers {
if (in.token == LBRACE) Nil else tokenSeparated(WITH, constrApp)
}
else Nil
+ val clsDef = atPos(start, point) {
+ TypeDef(clsName, Template(constr, parents, EmptyValDef, Nil))
+ .withMods(addMod(mods, enumMod)).setComment(in.getDocComment(start))
+ }
newLineOptWhenFollowedBy(LBRACE)
- val body = inBraces(enumCaseStats)
- EnumDef(name, Template(constr, Nil, EmptyValDef, body))
- .withMods(mods).setComment(in.getDocComment(start)).asInstanceOf[EnumDef]
+ val modDef = atPos(in.offset) {
+ val body = inBraces(enumCaseStats)
+ ModuleDef(modName, Template(emptyConstructor, Nil, EmptyValDef, body))
+ .withMods(mods)
+ }
+ Thicket(clsDef :: modDef :: Nil)
}
/** EnumCaseStats = EnumCaseStat {semi EnumCaseStat */
@@ -2249,7 +2266,7 @@ object Parsers {
else if (in.token == IMPORT)
stats ++= importClause()
else if (in.token == AT || isTemplateIntro || isModifier)
- stats += tmplDef(in.offset, defAnnotsMods(modifierTokens))
+ stats +++= tmplDef(in.offset, defAnnotsMods(modifierTokens))
else if (!isStatSep) {
if (in.token == CASE)
syntaxErrorOrIncomplete("only `case class` or `case object` allowed")
@@ -2299,7 +2316,7 @@ object Parsers {
else if (isExprIntro)
stats += expr1()
else if (isDefIntro(modifierTokensOrCase))
- stats += defOrDcl(in.offset, defAnnotsMods(modifierTokens))
+ stats +++= defOrDcl(in.offset, defAnnotsMods(modifierTokens))
else if (!isStatSep) {
exitOnError = mustStartStat
syntaxErrorOrIncomplete("illegal start of definition")
@@ -2357,9 +2374,9 @@ object Parsers {
val start = in.offset
val imods = implicitMods()
if (isBindingIntro) stats += implicitClosure(start, Location.InBlock, imods)
- else stats += localDef(start, imods)
+ else stats +++= localDef(start, imods)
} else {
- stats += localDef(in.offset)
+ stats +++= localDef(in.offset)
}
else if (!isStatSep && (in.token != CASE)) {
exitOnError = mustStartStat