Skip to content

Commit 2f87059

Browse files
committed
record end markers in trees and semanticdb
1 parent d2dd083 commit 2f87059

File tree

9 files changed

+336
-46
lines changed

9 files changed

+336
-46
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ object desugar {
182182
tpt = TypeTree(defn.UnitType),
183183
rhs = setterRhs
184184
).withMods((mods | Accessor) &~ (CaseAccessor | GivenOrImplicit | Lazy))
185+
.dropEndSpan
185186
Thicket(vdef1, setter)
186187
}
187188
else vdef1
@@ -874,6 +875,7 @@ object desugar {
874875
val modul = ValDef(moduleName, clsRef, New(clsRef, Nil))
875876
.withMods(mods.toTermFlags & RetainedModuleValFlags | ModuleValCreationFlags)
876877
.withSpan(mdef.span.startPos)
878+
.withEndSpan(copyFrom=mdef)
877879
val ValDef(selfName, selfTpt, _) = impl.self
878880
val selfMods = impl.self.mods
879881
if (!selfTpt.isEmpty) report.error(ObjectMayNotHaveSelfType(mdef), impl.self.srcPos)

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

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,43 @@ object Trees {
327327

328328
extension (mdef: untpd.DefTree) def mods: untpd.Modifiers = mdef.rawMods
329329

330-
abstract class NamedDefTree[-T >: Untyped](implicit @constructorOnly src: SourceFile) extends NameTree[T] with DefTree[T] {
330+
/** PackageDef | NamedDefTree */
331+
sealed trait WithEndMarker:
332+
self: Attachment.Container =>
333+
334+
import WithEndMarker.*
335+
336+
final def endToken: SimpleName = endMarker.stripModuleClassSuffix.lastPart
337+
338+
protected def endMarker: Name
339+
340+
final def withEndSpan(span: Span): self.type =
341+
self.withAttachment(EndMarker, span)
342+
343+
final def withEndSpan(copyFrom: WithEndMarker): self.type =
344+
copyFrom.endSpan.foreach(span => withEndSpan(span=span))
345+
this
346+
347+
final def dropEndSpan: self.type =
348+
self.removeAttachment(EndMarker)
349+
this
350+
351+
final def endSpan: Option[Span] = self.getAttachment(EndMarker)
352+
353+
object WithEndMarker:
354+
/** Property key for trees with an `end` marker */
355+
private val EndMarker: Property.StickyKey[Span] = Property.StickyKey()
356+
357+
end WithEndMarker
358+
359+
abstract class NamedDefTree[-T >: Untyped](implicit @constructorOnly src: SourceFile)
360+
extends NameTree[T] with DefTree[T] with WithEndMarker {
331361
type ThisTree[-T >: Untyped] <: NamedDefTree[T]
332362

363+
protected def endMarker =
364+
if name == nme.CONSTRUCTOR then nme.this_
365+
else name
366+
333367
/** The position of the name defined by this definition.
334368
* This is a point position if the definition is synthetic, or a range position
335369
* if the definition comes from source.
@@ -857,9 +891,10 @@ object Trees {
857891

858892
/** package pid { stats } */
859893
case class PackageDef[-T >: Untyped] private[ast] (pid: RefTree[T], stats: List[Tree[T]])(implicit @constructorOnly src: SourceFile)
860-
extends ProxyTree[T] {
894+
extends ProxyTree[T] with WithEndMarker {
861895
type ThisTree[-T >: Untyped] = PackageDef[T]
862896
def forwardTo: RefTree[T] = pid
897+
protected def endMarker: Name = pid.name
863898
}
864899

865900
/** arg @annot */

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,8 +1283,8 @@ object Parsers {
12831283
in.token == IDENTIFIER && in.name == nme.extension
12841284
case PackageDef(pid: RefTree, _) =>
12851285
in.isIdent && in.name == pid.name
1286-
case PatDef(_, IdPattern(id, _) :: Nil, _, _) =>
1287-
in.isIdent && in.name == id.name
1286+
case PatDef(_, IdPattern(id, _) :: Nil, _, _) => // TODO: it looks like this case is never reached
1287+
in.isIdent && in.name == id.name
12881288
case stat: MemberDef if stat.mods.is(Given) => in.token == GIVEN
12891289
case _: PatDef => in.token == VAL
12901290
case _: If => in.token == IF
@@ -1295,9 +1295,21 @@ object Parsers {
12951295
case _: (ForYield | ForDo) => in.token == FOR
12961296
case _ => false
12971297

1298+
def matchesWithUpdated(stat: Tree): Boolean = {
1299+
val didMatch = matches(stat)
1300+
if didMatch then
1301+
stat match
1302+
case stat: WithEndMarker =>
1303+
val end = in.lastCharOffset
1304+
stat.withEndSpan(span=Span(end - stat.endToken.length, end))
1305+
case _ =>
1306+
()
1307+
didMatch
1308+
}
1309+
12981310
if in.token == END then
12991311
val start = in.skipToken()
1300-
if stats.isEmpty || !matches(stats.last) then
1312+
if stats.isEmpty || !matchesWithUpdated(stats.last) then
13011313
syntaxError("misaligned end marker", Span(start, in.lastCharOffset))
13021314
in.token = IDENTIFIER // Leaving it as the original token can confuse newline insertion
13031315
in.nextToken()

compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import core._
66
import Phases._
77
import ast.tpd._
88
import ast.untpd.given
9-
import ast.Trees.mods
9+
import ast.Trees.{mods, WithEndMarker}
1010
import Contexts._
1111
import Symbols._
1212
import Flags._
@@ -139,47 +139,46 @@ class ExtractSemanticDB extends Phase:
139139
case tree => registerDefinition(tree.symbol, tree.span, Set.empty, tree.source)
140140
tree.stats.foreach(traverse)
141141
case tree: NamedDefTree =>
142-
if tree.symbol.isAllOf(ModuleValCreationFlags) then
143-
return
144-
if !excludeDef(tree.symbol)
145-
&& tree.span.hasLength then
146-
registerDefinition(tree.symbol, tree.nameSpan, symbolKinds(tree), tree.source)
147-
val privateWithin = tree.symbol.privateWithin
148-
if privateWithin.exists then
149-
registerUseGuarded(None, privateWithin, spanOfSymbol(privateWithin, tree.span, tree.source), tree.source)
150-
else if !excludeSymbol(tree.symbol) then
151-
registerSymbol(tree.symbol, symbolName(tree.symbol), symbolKinds(tree))
152-
tree match
153-
case tree: ValDef
154-
if tree.symbol.isAllOf(EnumValue) =>
155-
tree.rhs match
156-
case Block(TypeDef(_, template: Template) :: _, _) => // simple case with specialised extends clause
157-
template.parents.filter(!_.span.isZeroExtent).foreach(traverse)
158-
case _ => // calls $new
159-
case tree: ValDef
160-
if tree.symbol.isSelfSym =>
161-
if tree.tpt.span.hasLength then
162-
traverse(tree.tpt)
163-
case tree: DefDef
164-
if tree.symbol.isConstructor => // ignore typeparams for secondary ctors
165-
tree.trailingParamss.foreach(_.foreach(traverse))
166-
traverse(tree.rhs)
167-
case tree: (DefDef | ValDef)
168-
if tree.symbol.isSyntheticWithIdent =>
142+
if !tree.symbol.isAllOf(ModuleValCreationFlags) then
143+
if !excludeDef(tree.symbol)
144+
&& tree.span.hasLength then
145+
registerDefinition(tree.symbol, tree.nameSpan, symbolKinds(tree), tree.source)
146+
val privateWithin = tree.symbol.privateWithin
147+
if privateWithin.exists then
148+
registerUseGuarded(None, privateWithin, spanOfSymbol(privateWithin, tree.span, tree.source), tree.source)
149+
else if !excludeSymbol(tree.symbol) then
150+
registerSymbol(tree.symbol, symbolName(tree.symbol), symbolKinds(tree))
169151
tree match
170-
case tree: DefDef =>
171-
tree.paramss.foreach(_.foreach(param => registerSymbolSimple(param.symbol)))
172-
case tree: ValDef if tree.symbol.is(Given) => traverse(tree.tpt)
173-
case _ =>
174-
if !tree.symbol.isGlobal then
175-
localBodies(tree.symbol) = tree.rhs
176-
// ignore rhs
177-
case PatternValDef(pat, rhs) =>
178-
traverse(rhs)
179-
PatternValDef.collectPats(pat).foreach(traverse)
180-
case tree =>
181-
if !excludeChildren(tree.symbol) then
182-
traverseChildren(tree)
152+
case tree: ValDef
153+
if tree.symbol.isAllOf(EnumValue) =>
154+
tree.rhs match
155+
case Block(TypeDef(_, template: Template) :: _, _) => // simple case with specialised extends clause
156+
template.parents.filter(!_.span.isZeroExtent).foreach(traverse)
157+
case _ => // calls $new
158+
case tree: ValDef
159+
if tree.symbol.isSelfSym =>
160+
if tree.tpt.span.hasLength then
161+
traverse(tree.tpt)
162+
case tree: DefDef
163+
if tree.symbol.isConstructor => // ignore typeparams for secondary ctors
164+
tree.trailingParamss.foreach(_.foreach(traverse))
165+
traverse(tree.rhs)
166+
case tree: (DefDef | ValDef)
167+
if tree.symbol.isSyntheticWithIdent =>
168+
tree match
169+
case tree: DefDef =>
170+
tree.paramss.foreach(_.foreach(param => registerSymbolSimple(param.symbol)))
171+
case tree: ValDef if tree.symbol.is(Given) => traverse(tree.tpt)
172+
case _ =>
173+
if !tree.symbol.isGlobal then
174+
localBodies(tree.symbol) = tree.rhs
175+
// ignore rhs
176+
case PatternValDef(pat, rhs) =>
177+
traverse(rhs)
178+
PatternValDef.collectPats(pat).foreach(traverse)
179+
case tree =>
180+
if !excludeChildren(tree.symbol) then
181+
traverseChildren(tree)
183182
case tree: Template =>
184183
val ctorSym = tree.constr.symbol
185184
if !excludeDef(ctorSym) then
@@ -240,6 +239,12 @@ class ExtractSemanticDB extends Phase:
240239
case _ =>
241240
traverseChildren(tree)
242241

242+
tree match
243+
case tree: WithEndMarker =>
244+
for endSpan <- tree.endSpan do
245+
registerUseGuarded(None, tree.symbol, endSpan, tree.source)
246+
case _ =>
247+
243248
end traverse
244249

245250
private def funParamSymbol(funSym: Symbol)(using Context): Name => String =
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package endmarkers:
2+
3+
class MultiCtor/*<-endmarkers::MultiCtor#*/(val i/*<-endmarkers::MultiCtor#i.*/: Int/*->scala::Int#*/):
4+
def this()/*<-endmarkers::MultiCtor#`<init>`(+1).*/ =
5+
this(23)
6+
end this/*->endmarkers::MultiCtor#`<init>`(+1).*/
7+
end MultiCtor/*->endmarkers::MultiCtor#*/
8+
9+
/*<-endmarkers::EndMarkers$package.*/def topLevelMethod/*<-endmarkers::EndMarkers$package.topLevelMethod().*/: String/*->scala::Predef.String#*/ =
10+
"hello"
11+
end topLevelMethod/*->endmarkers::EndMarkers$package.topLevelMethod().*/
12+
13+
val topLevelVal/*<-endmarkers::EndMarkers$package.topLevelVal.*/: Int/*->scala::Int#*/ =
14+
23
15+
end topLevelVal/*->endmarkers::EndMarkers$package.topLevelVal.*/
16+
17+
var topLevelVar/*<-endmarkers::EndMarkers$package.topLevelVar().*/: String/*->scala::Predef.String#*/ =
18+
""
19+
end topLevelVar/*->endmarkers::EndMarkers$package.topLevelVar().*/
20+
21+
class Container/*<-endmarkers::Container#*/:
22+
23+
def foo/*<-endmarkers::Container#foo().*/ =
24+
(/*->scala::Tuple3.apply().*/1,2,3)
25+
end foo/*->endmarkers::Container#foo().*/
26+
27+
val bar/*<-endmarkers::Container#bar.*/ =
28+
(/*->scala::Tuple3.apply().*/4,5,6)
29+
end bar/*->endmarkers::Container#bar.*/
30+
31+
var baz/*<-endmarkers::Container#baz().*/ =
32+
15
33+
end baz/*->endmarkers::Container#baz().*/
34+
35+
end Container/*->endmarkers::Container#*/
36+
37+
def topLevelWithLocals/*<-endmarkers::EndMarkers$package.topLevelWithLocals().*/: Unit/*->scala::Unit#*/ =
38+
39+
val localVal/*<-local0*/ =
40+
37
41+
end localVal/*->local0*/
42+
43+
var localVar/*<-local1*/ =
44+
43
45+
end localVar/*->local1*/
46+
47+
def localDef/*<-local2*/ =
48+
97
49+
end localDef/*->local2*/
50+
51+
end topLevelWithLocals/*->endmarkers::EndMarkers$package.topLevelWithLocals().*/
52+
53+
object TestObj/*<-endmarkers::TestObj.*/:
54+
55+
def foo/*<-endmarkers::TestObj.foo().*/ = 23
56+
57+
end TestObj/*->endmarkers::TestObj.*/
58+
59+
end endmarkers
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package endmarkers:
2+
3+
class MultiCtor(val i: Int):
4+
def this() =
5+
this(23)
6+
end this
7+
end MultiCtor
8+
9+
def topLevelMethod: String =
10+
"hello"
11+
end topLevelMethod
12+
13+
val topLevelVal: Int =
14+
23
15+
end topLevelVal
16+
17+
var topLevelVar: String =
18+
""
19+
end topLevelVar
20+
21+
class Container:
22+
23+
def foo =
24+
(1,2,3)
25+
end foo
26+
27+
val bar =
28+
(4,5,6)
29+
end bar
30+
31+
var baz =
32+
15
33+
end baz
34+
35+
end Container
36+
37+
def topLevelWithLocals: Unit =
38+
39+
val localVal =
40+
37
41+
end localVal
42+
43+
var localVar =
44+
43
45+
end localVar
46+
47+
def localDef =
48+
97
49+
end localDef
50+
51+
end topLevelWithLocals
52+
53+
object TestObj:
54+
55+
def foo = 23
56+
57+
end TestObj
58+
59+
end endmarkers
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package object endmark/*<-endmarkers2::package.*/ers2:
2+
3+
type Foo/*<-endmarkers2::package.Foo#*/ =
4+
Unit/*->scala::Unit#*/
5+
end Foo/*->endmarkers2::package.Foo#*/
6+
7+
end endmarkers2/*->endmarkers2::package.*/
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package object endmarkers2:
2+
3+
type Foo =
4+
Unit
5+
end Foo
6+
7+
end endmarkers2

0 commit comments

Comments
 (0)