Skip to content

Commit 40da850

Browse files
authored
Merge pull request #1608 from dotty-staging/modifiers
Record syntactic information about modifiers
2 parents 133fbb3 + 24a725d commit 40da850

File tree

3 files changed

+260
-41
lines changed

3 files changed

+260
-41
lines changed

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

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,51 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
9494
class InfixOpBlock(leftOperand: Tree, rightOp: Tree) extends Block(leftOperand :: Nil, rightOp)
9595

9696
// ----- Modifiers -----------------------------------------------------
97+
/** Mod is intended to record syntactic information about modifiers, it's
98+
* NOT a replacement of FlagSet.
99+
*
100+
* For any query about semantic information, check `flags` instead.
101+
*/
102+
sealed abstract class Mod(val flags: FlagSet) extends Positioned
97103

98-
/** Modifiers and annotations for definitions
99-
* @param flags The set flags
104+
object Mod {
105+
case class Private() extends Mod(Flags.Private)
106+
107+
case class Protected() extends Mod(Flags.Protected)
108+
109+
case class Val() extends Mod(Flags.EmptyFlags)
110+
111+
case class Var() extends Mod(Flags.Mutable)
112+
113+
case class Implicit(flag: FlagSet = Flags.ImplicitCommon) extends Mod(flag)
114+
115+
case class Final() extends Mod(Flags.Final)
116+
117+
case class Sealed() extends Mod(Flags.Sealed)
118+
119+
case class Override() extends Mod(Flags.Override)
120+
121+
case class Abstract() extends Mod(Flags.Abstract)
122+
123+
case class Lazy() extends Mod(Flags.Lazy)
124+
125+
case class Inline() extends Mod(Flags.Inline)
126+
127+
case class Type() extends Mod(Flags.EmptyFlags)
128+
}
129+
130+
/** Modifiers and annotations for definitions
131+
*
132+
* @param flags The set flags
100133
* @param privateWithin If a private or protected has is followed by a
101134
* qualifier [q], the name q, "" as a typename otherwise.
102135
* @param annotations The annotations preceding the modifiers
103136
*/
104137
case class Modifiers (
105138
flags: FlagSet = EmptyFlags,
106139
privateWithin: TypeName = tpnme.EMPTY,
107-
annotations: List[Tree] = Nil) extends Positioned with Cloneable {
140+
annotations: List[Tree] = Nil,
141+
mods: List[Mod] = Nil) extends Positioned with Cloneable {
108142

109143
def is(fs: FlagSet): Boolean = flags is fs
110144
def is(fc: FlagConjunction): Boolean = flags is fc
@@ -120,7 +154,15 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
120154
if (this.flags == flags) this
121155
else copy(flags = flags)
122156

123-
def withAddedAnnotation(annot: Tree): Modifiers =
157+
def withAddedMod(mod: Mod): Modifiers =
158+
if (mods.exists(_ eq mod)) this
159+
else withMods(mods :+ mod)
160+
161+
def withMods(ms: List[Mod]): Modifiers =
162+
if (mods eq ms) this
163+
else copy(mods = ms)
164+
165+
def withAddedAnnotation(annot: Tree): Modifiers =
124166
if (annotations.exists(_ eq annot)) this
125167
else withAnnotations(annotations :+ annot)
126168

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

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,8 +1097,9 @@ object Parsers {
10971097
/** Expr ::= implicit Id `=>' Expr
10981098
* BlockResult ::= implicit Id [`:' InfixType] `=>' Block
10991099
*/
1100-
def implicitClosure(start: Int, location: Location.Value): Tree = {
1101-
val mods = atPos(start) { Modifiers(Implicit) }
1100+
def implicitClosure(start: Int, location: Location.Value, implicitMod: Option[Mod] = None): Tree = {
1101+
var mods = atPos(start) { Modifiers(Implicit) }
1102+
if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get)
11021103
val id = termIdent()
11031104
val paramExpr =
11041105
if (location == Location.InBlock && in.token == COLON)
@@ -1464,19 +1465,19 @@ object Parsers {
14641465

14651466
/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
14661467

1467-
private def flagOfToken(tok: Int): FlagSet = tok match {
1468-
case ABSTRACT => Abstract
1469-
case FINAL => Final
1470-
case IMPLICIT => ImplicitCommon
1471-
case INLINE => Inline
1472-
case LAZY => Lazy
1473-
case OVERRIDE => Override
1474-
case PRIVATE => Private
1475-
case PROTECTED => Protected
1476-
case SEALED => Sealed
1468+
private def modOfToken(tok: Int): Mod = tok match {
1469+
case ABSTRACT => Mod.Abstract()
1470+
case FINAL => Mod.Final()
1471+
case IMPLICIT => Mod.Implicit(ImplicitCommon)
1472+
case INLINE => Mod.Inline()
1473+
case LAZY => Mod.Lazy()
1474+
case OVERRIDE => Mod.Override()
1475+
case PRIVATE => Mod.Private()
1476+
case PROTECTED => Mod.Protected()
1477+
case SEALED => Mod.Sealed()
14771478
}
14781479

1479-
/** Drop `private' modifier when followed by a qualifier.
1480+
/** Drop `private' modifier when followed by a qualifier.
14801481
* Contract `abstract' and `override' to ABSOVERRIDE
14811482
*/
14821483
private def normalize(mods: Modifiers): Modifiers =
@@ -1488,11 +1489,11 @@ object Parsers {
14881489
mods
14891490

14901491
private def addModifier(mods: Modifiers): Modifiers = {
1491-
val flag = flagOfToken(in.token)
1492-
if (mods is flag) syntaxError(RepeatedModifier(flag.toString))
1493-
val res = addFlag(mods, flag)
1494-
in.nextToken()
1495-
res
1492+
val tok = in.token
1493+
val mod = atPos(in.skipToken()) { modOfToken(tok) }
1494+
1495+
if (mods is mod.flags) syntaxError(RepeatedModifier(mod.flags.toString))
1496+
addMod(mods, mod)
14961497
}
14971498

14981499
private def compatible(flags1: FlagSet, flags2: FlagSet): Boolean = (
@@ -1518,6 +1519,11 @@ object Parsers {
15181519
}
15191520
}
15201521

1522+
/** Always add the syntactic `mod`, but check and conditionally add semantic `mod.flags`
1523+
*/
1524+
def addMod(mods: Modifiers, mod: Mod): Modifiers =
1525+
addFlag(mods, mod.flags).withAddedMod(mod)
1526+
15211527
/** AccessQualifier ::= "[" (Id | this) "]"
15221528
*/
15231529
def accessQualifierOpt(mods: Modifiers): Modifiers =
@@ -1614,8 +1620,8 @@ object Parsers {
16141620
mods =
16151621
atPos(start, in.offset) {
16161622
if (in.token == TYPE) {
1617-
in.nextToken()
1618-
mods | Param | ParamAccessor
1623+
val mod = atPos(in.skipToken()) { Mod.Type() }
1624+
(mods | Param | ParamAccessor).withAddedMod(mod)
16191625
} else {
16201626
if (mods.hasFlags) syntaxError("`type' expected")
16211627
mods | Param | PrivateLocal
@@ -1659,7 +1665,7 @@ object Parsers {
16591665
* Param ::= id `:' ParamType [`=' Expr]
16601666
*/
16611667
def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = {
1662-
var implicitFlag = EmptyFlags
1668+
var implicitMod: Mod = null
16631669
var firstClauseOfCaseClass = ofCaseClass
16641670
var implicitOffset = -1 // use once
16651671
def param(): ValDef = {
@@ -1670,11 +1676,11 @@ object Parsers {
16701676
mods =
16711677
atPos(start, in.offset) {
16721678
if (in.token == VAL) {
1673-
in.nextToken()
1674-
mods
1679+
val mod = atPos(in.skipToken()) { Mod.Val() }
1680+
mods.withAddedMod(mod)
16751681
} else if (in.token == VAR) {
1676-
in.nextToken()
1677-
addFlag(mods, Mutable)
1682+
val mod = atPos(in.skipToken()) { Mod.Var() }
1683+
addMod(mods, mod)
16781684
} else {
16791685
if (!(mods.flags &~ (ParamAccessor | Inline)).isEmpty)
16801686
syntaxError("`val' or `var' expected")
@@ -1696,7 +1702,7 @@ object Parsers {
16961702
if (in.token == ARROW) {
16971703
if (owner.isTypeName && !(mods is Local))
16981704
syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name")
1699-
else if (!implicitFlag.isEmpty)
1705+
else if (implicitMod != null)
17001706
syntaxError("implicit parameters may not be call-by-name")
17011707
}
17021708
paramType()
@@ -1708,15 +1714,16 @@ object Parsers {
17081714
mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset)))
17091715
implicitOffset = -1
17101716
}
1711-
ValDef(name, tpt, default).withMods(addFlag(mods, implicitFlag))
1717+
if (implicitMod != null) mods = addMod(mods, implicitMod)
1718+
ValDef(name, tpt, default).withMods(mods)
17121719
}
17131720
}
17141721
def paramClause(): List[ValDef] = inParens {
17151722
if (in.token == RPAREN) Nil
17161723
else {
17171724
if (in.token == IMPLICIT) {
1718-
implicitOffset = in.skipToken()
1719-
implicitFlag = Implicit
1725+
implicitOffset = in.offset
1726+
implicitMod = atPos(in.skipToken()) { Mod.Implicit(Implicit) }
17201727
}
17211728
commaSeparated(param)
17221729
}
@@ -1726,7 +1733,7 @@ object Parsers {
17261733
if (in.token == LPAREN)
17271734
paramClause() :: {
17281735
firstClauseOfCaseClass = false
1729-
if (implicitFlag.isEmpty) clauses() else Nil
1736+
if (implicitMod == null) clauses() else Nil
17301737
}
17311738
else Nil
17321739
}
@@ -1819,9 +1826,13 @@ object Parsers {
18191826
*/
18201827
def defOrDcl(start: Int, mods: Modifiers): Tree = in.token match {
18211828
case VAL =>
1822-
patDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
1829+
val mod = atPos(in.skipToken()) { Mod.Val() }
1830+
val mods1 = mods.withAddedMod(mod)
1831+
patDefOrDcl(start, mods1, in.getDocComment(start))
18231832
case VAR =>
1824-
patDefOrDcl(start, posMods(start, addFlag(mods, Mutable)), in.getDocComment(start))
1833+
val mod = atPos(in.skipToken()) { Mod.Var() }
1834+
val mod1 = addMod(mods, mod)
1835+
patDefOrDcl(start, mod1, in.getDocComment(start))
18251836
case DEF =>
18261837
defDefOrDcl(start, posMods(start, mods), in.getDocComment(start))
18271838
case TYPE =>
@@ -2184,8 +2195,11 @@ object Parsers {
21842195
stats.toList
21852196
}
21862197

2187-
def localDef(start: Int, implicitFlag: FlagSet): Tree =
2188-
defOrDcl(start, addFlag(defAnnotsMods(localModifierTokens), implicitFlag))
2198+
def localDef(start: Int, implicitFlag: FlagSet, implicitMod: Option[Mod] = None): Tree = {
2199+
var mods = addFlag(defAnnotsMods(localModifierTokens), implicitFlag)
2200+
if (implicitMod.nonEmpty) mods = mods.withAddedMod(implicitMod.get)
2201+
defOrDcl(start, mods)
2202+
}
21892203

21902204
/** BlockStatSeq ::= { BlockStat semi } [ResultExpr]
21912205
* BlockStat ::= Import
@@ -2205,9 +2219,10 @@ object Parsers {
22052219
stats += expr(Location.InBlock)
22062220
else if (isDefIntro(localModifierTokens))
22072221
if (in.token == IMPLICIT) {
2208-
val start = in.skipToken()
2209-
if (isIdent) stats += implicitClosure(start, Location.InBlock)
2210-
else stats += localDef(start, ImplicitCommon)
2222+
val start = in.offset
2223+
val mod = atPos(in.skipToken()) { Mod.Implicit(ImplicitCommon) }
2224+
if (isIdent) stats += implicitClosure(start, Location.InBlock, Some(mod))
2225+
else stats += localDef(start, ImplicitCommon, Some(mod))
22112226
} else {
22122227
stats += localDef(in.offset, EmptyFlags)
22132228
}

0 commit comments

Comments
 (0)