Skip to content

Commit 753b3c4

Browse files
committed
Add implicit or context param apply to synthetics
Support following synthetics - implicit and context parameters application - Anonymous context param name - Invented given Also convert TypeVar to stripped type, which may appear in synthetics
1 parent 056f4a4 commit 753b3c4

File tree

9 files changed

+385
-38
lines changed

9 files changed

+385
-38
lines changed

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

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import NameOps._
1616
import util.Spans.Span
1717
import util.{SourceFile, SourcePosition}
1818
import transform.SymUtils._
19-
import SymbolInformation.{Kind => k}
2019

2120
import scala.jdk.CollectionConverters._
2221
import scala.collection.mutable
@@ -46,12 +45,13 @@ class ExtractSemanticDB extends Phase:
4645
val unit = ctx.compilationUnit
4746
val extractor = Extractor()
4847
extractor.extract(unit.tpdTree)
49-
ExtractSemanticDB.write(unit.source, extractor.occurrences.toList, extractor.symbolInfos.toList)
48+
ExtractSemanticDB.write(unit.source, extractor.occurrences.toList, extractor.symbolInfos.toList, extractor.synthetics.toList)
5049

5150
/** Extractor of symbol occurrences from trees */
5251
class Extractor extends TreeTraverser:
53-
given s.SemanticSymbolBuilder = s.SemanticSymbolBuilder()
54-
val converter = s.TypeOps()
52+
given builder: s.SemanticSymbolBuilder = s.SemanticSymbolBuilder()
53+
val synth = SyntheticsExtractor()
54+
given converter: s.TypeOps = s.TypeOps()
5555

5656
/** The bodies of synthetic locals */
5757
private val localBodies = mutable.HashMap[Symbol, Tree]()
@@ -62,6 +62,8 @@ class ExtractSemanticDB extends Phase:
6262
/** The extracted symbol infos */
6363
val symbolInfos = new mutable.ListBuffer[SymbolInformation]()
6464

65+
val synthetics = new mutable.ListBuffer[s.Synthetic]()
66+
6567
/** A cache of localN names */
6668
val localNames = new mutable.HashSet[String]()
6769

@@ -155,11 +157,22 @@ class ExtractSemanticDB extends Phase:
155157
tree match
156158
case tree: DefDef =>
157159
tree.paramss.foreach(_.foreach(param => registerSymbolSimple(param.symbol)))
158-
case tree: ValDef if tree.symbol.is(Given) => traverse(tree.tpt)
160+
case tree: ValDef if tree.symbol.is(Given) =>
161+
synth.tryFindSynthetic(tree).foreach { synth =>
162+
synthetics += synth
163+
}
164+
traverse(tree.tpt)
159165
case _ =>
160166
if !tree.symbol.isGlobal then
161167
localBodies(tree.symbol) = tree.rhs
162168
// ignore rhs
169+
170+
// `given Int` (syntax sugar of `given given_Int: Int`)
171+
case tree: ValDef if tree.symbol.isInventedGiven =>
172+
synth.tryFindSynthetic(tree).foreach { synth =>
173+
synthetics += synth
174+
}
175+
traverse(tree.tpt)
163176
case PatternValDef(pat, rhs) =>
164177
traverse(rhs)
165178
PatternValDef.collectPats(pat).foreach(traverse)
@@ -192,6 +205,10 @@ class ExtractSemanticDB extends Phase:
192205
case tree: Apply =>
193206
@tu lazy val genParamSymbol: Name => String = tree.fun.symbol.funParamSymbol
194207
traverse(tree.fun)
208+
synth.tryFindSynthetic(tree).foreach { synth =>
209+
synthetics += synth
210+
}
211+
195212
for arg <- tree.args do
196213
arg match
197214
case tree @ NamedArg(name, arg) =>
@@ -277,12 +294,6 @@ class ExtractSemanticDB extends Phase:
277294
end PatternValDef
278295

279296

280-
private def range(span: Span, treeSource: SourceFile)(using Context): Option[Range] =
281-
def lineCol(offset: Int) = (treeSource.offsetToLine(offset), treeSource.column(offset))
282-
val (startLine, startCol) = lineCol(span.start)
283-
val (endLine, endCol) = lineCol(span.end)
284-
Some(Range(startLine, startCol, endLine, endCol))
285-
286297

287298
private def registerSymbol(sym: Symbol, symkinds: Set[SymbolKind])(using Context): Unit =
288299
val sname = sym.symbolName
@@ -448,7 +459,12 @@ object ExtractSemanticDB:
448459

449460
val name: String = "extractSemanticDB"
450461

451-
def write(source: SourceFile, occurrences: List[SymbolOccurrence], symbolInfos: List[SymbolInformation])(using Context): Unit =
462+
def write(
463+
source: SourceFile,
464+
occurrences: List[SymbolOccurrence],
465+
symbolInfos: List[SymbolInformation],
466+
synthetics: List[Synthetic],
467+
)(using Context): Unit =
452468
def absolutePath(path: Path): Path = path.toAbsolutePath.normalize
453469
val semanticdbTarget =
454470
val semanticdbTargetSetting = ctx.settings.semanticdbTarget.value
@@ -470,7 +486,8 @@ object ExtractSemanticDB:
470486
text = "",
471487
md5 = internal.MD5.compute(String(source.content)),
472488
symbols = symbolInfos,
473-
occurrences = occurrences
489+
occurrences = occurrences,
490+
synthetics = synthetics,
474491
)
475492
val docs = TextDocuments(List(doc))
476493
val out = Files.newOutputStream(outpath)

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

Lines changed: 116 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import dotty.tools.dotc.{semanticdb => s}
55
import scala.collection.mutable
66
import dotty.tools.dotc.semanticdb.Scala3.{_, given}
77
import SymbolInformation.Kind._
8-
9-
class SymbolInfomationPrinter (symtab: PrinterSymtab):
8+
import dotty.tools.dotc.util.SourceFile
9+
class SymbolInformationPrinter (symtab: PrinterSymtab):
1010
val notes = InfoNotes()
1111
val infoPrinter = InfoPrinter(notes)
1212

@@ -28,8 +28,9 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
2828
val displayName = if sym.isGlobal then sym.desc.value else sym
2929
SymbolInformation(symbol = sym, displayName = displayName)
3030
}
31+
end InfoNotes
3132

32-
class InfoPrinter(notes: InfoNotes) {
33+
class InfoPrinter(notes: InfoNotes):
3334
private enum SymbolStyle:
3435
case Reference, Definition
3536
def pprint(info: SymbolInformation): String =
@@ -78,7 +79,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
7879
private def pprintDef(info: SymbolInformation) =
7980
notes.enter(info)
8081
pprint(info.symbol, SymbolStyle.Definition)
81-
private def pprintRef(sym: String): String = pprint(sym, SymbolStyle.Reference)
82+
def pprintRef(sym: String): String = pprint(sym, SymbolStyle.Reference)
8283
private def pprintDef(sym: String): String = pprint(sym, SymbolStyle.Definition)
8384
private def pprint(sym: String, style: SymbolStyle): String =
8485
val info = notes.visit(sym)
@@ -134,7 +135,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
134135
case _ =>
135136
"<?>"
136137

137-
private def pprint(tpe: Type): String = {
138+
protected def pprint(tpe: Type): String = {
138139
def prefix(tpe: Type): String = tpe match
139140
case TypeRef(pre, sym, args) =>
140141
val preStr = pre match {
@@ -201,7 +202,7 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
201202
case tpe => s"@${pprint(tpe)}"
202203
}
203204

204-
private def pprint(const: Constant): String = const match {
205+
protected def pprint(const: Constant): String = const match {
205206
case Constant.Empty =>
206207
"<?>"
207208
case UnitConstant() =>
@@ -242,7 +243,6 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
242243
s"private[${ssym}] "
243244
case ProtectedWithinAccess(ssym) =>
244245
s"protected[${ssym}] "
245-
246246
extension (scope: Scope)
247247
private def infos: List[SymbolInformation] =
248248
if (scope.symlinks.nonEmpty)
@@ -255,8 +255,8 @@ class SymbolInfomationPrinter (symtab: PrinterSymtab):
255255
case Some(s) => s.infos
256256
case None => Nil
257257
}
258-
}
259-
end SymbolInfomationPrinter
258+
end InfoPrinter
259+
end SymbolInformationPrinter
260260

261261
extension (info: SymbolInformation)
262262
def prefixBeforeTpe: String = {
@@ -277,3 +277,110 @@ object PrinterSymtab:
277277
new PrinterSymtab {
278278
override def info(symbol: String): Option[SymbolInformation] = map.get(symbol)
279279
}
280+
281+
def processRange(sb: StringBuilder, range: Range): Unit =
282+
sb.append('[')
283+
.append(range.startLine).append(':').append(range.startCharacter)
284+
.append("..")
285+
.append(range.endLine).append(':').append(range.endCharacter)
286+
.append("):")
287+
288+
289+
290+
class SyntheticPrinter(symtab: PrinterSymtab, source: SourceFile) extends SymbolInformationPrinter(symtab):
291+
292+
def pprint(synth: Synthetic): String =
293+
val sb = new StringBuilder()
294+
val notes = InfoNotes()
295+
val treePrinter = TreePrinter(source, synth.range, notes)
296+
297+
synth.range match
298+
case Some(range) =>
299+
processRange(sb, range)
300+
sb.append(source.substring(range))
301+
case None =>
302+
sb.append("[):")
303+
sb.append(" => ")
304+
sb.append(treePrinter.pprint(synth.tree))
305+
sb.toString
306+
307+
extension (source: SourceFile)
308+
private def substring(range: Option[s.Range]): String =
309+
range match
310+
case Some(range) => source.substring(range)
311+
case None => ""
312+
private def substring(range: s.Range): String =
313+
/** get the line length of a given line */
314+
def lineLength(line: Int): Int =
315+
val isLastLine = source.lineToOffsetOpt(line).nonEmpty && source.lineToOffsetOpt(line + 1).isEmpty
316+
if isLastLine then source.content.length - source.lineToOffset(line) - 1
317+
else source.lineToOffset(line + 1) - source.lineToOffset(line) - 1 // -1 for newline char
318+
319+
val start = source.lineToOffset(range.startLine) +
320+
math.min(range.startCharacter, lineLength(range.startLine))
321+
val end = source.lineToOffset(range.endLine) +
322+
math.min(range.endCharacter, lineLength(range.endLine))
323+
new String(source.content, start, end - start)
324+
325+
326+
// def pprint(tree: s.Tree, range: Option[Range]): String =
327+
class TreePrinter(source: SourceFile, originalRange: Option[Range], notes: InfoNotes) extends InfoPrinter(notes):
328+
def pprint(tree: Tree): String =
329+
val sb = new StringBuilder()
330+
processTree(tree)(using sb)
331+
sb.toString
332+
333+
334+
private def rep[T](xs: Seq[T], seq: String)(f: T => Unit)(using sb: StringBuilder): Unit =
335+
xs.zipWithIndex.foreach { (x, i) =>
336+
if i != 0 then sb.append(seq)
337+
f(x)
338+
}
339+
340+
private def processTree(tree: Tree)(using sb: StringBuilder): Unit =
341+
tree match {
342+
case tree: ApplyTree =>
343+
processTree(tree.function)
344+
sb.append("(")
345+
rep(tree.arguments, ", ")(processTree)
346+
sb.append(")")
347+
case tree: FunctionTree =>
348+
sb.append("{")
349+
sb.append("(")
350+
rep(tree.parameters, ", ")(processTree)
351+
sb.append(") =>")
352+
processTree(tree.body)
353+
sb.append("}")
354+
case tree: IdTree =>
355+
sb.append(pprintRef(tree.symbol))
356+
case tree: LiteralTree =>
357+
sb.append(pprint(tree.constant))
358+
case tree: MacroExpansionTree =>
359+
sb.append("(`macro-expandee` : `")
360+
sb.append(pprint(tree.tpe))
361+
sb.append(")")
362+
case tree: OriginalTree =>
363+
if (tree.range == originalRange && originalRange.nonEmpty) then
364+
sb.append("*")
365+
else
366+
sb.append("orig(")
367+
sb.append(source.substring(tree.range))
368+
sb.append(")")
369+
case tree: SelectTree =>
370+
processTree(tree.qualifier)
371+
sb.append(".")
372+
tree.id match
373+
case Some(tree) => processTree(tree)
374+
case None => ()
375+
case tree: TypeApplyTree =>
376+
processTree(tree.function)
377+
sb.append("[")
378+
rep(tree.typeArguments, ", ")((t) => sb.append(pprint(t)))
379+
sb.append("]")
380+
381+
case _ =>
382+
sb.append("<?>")
383+
}
384+
385+
386+
end SyntheticPrinter

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import core.Flags._
1010
import core.NameKinds
1111
import core.StdNames.nme
1212
import SymbolInformation.{Kind => k}
13+
import dotty.tools.dotc.util.SourceFile
14+
import dotty.tools.dotc.util.Spans.Span
15+
import dotty.tools.dotc.ast.tpd
16+
import dotty.tools.dotc.{semanticdb => s}
1317

1418
import java.lang.Character.{isJavaIdentifierPart, isJavaIdentifierStart}
1519

@@ -26,6 +30,12 @@ object Scala3:
2630

2731
private val WILDCARDTypeName = nme.WILDCARD.toTypeName
2832

33+
def range(span: Span, treeSource: SourceFile)(using Context): Option[Range] =
34+
def lineCol(offset: Int) = (treeSource.offsetToLine(offset), treeSource.column(offset))
35+
val (startLine, startCol) = lineCol(span.start)
36+
val (endLine, endCol) = lineCol(span.end)
37+
Some(Range(startLine, startCol, endLine, endCol))
38+
2939
sealed trait FakeSymbol {
3040
private[Scala3] var sname: Option[String] = None
3141
}
@@ -220,6 +230,12 @@ object Scala3:
220230
def isSyntheticWithIdent(using Context): Boolean =
221231
sym.is(Synthetic) && !sym.isAnonymous && !sym.name.isEmptyNumbered
222232

233+
/** Check if the symbol is invented by Desugar.inventGivenOrExtensionName
234+
* return true if the symbol is defined as `given Int = ...` and name is invented as "given_Int"
235+
*/
236+
def isInventedGiven(using Context): Boolean =
237+
sym.is(Given) && sym.name.startsWith("given_")
238+
223239
/** The semanticdb name of the given symbol */
224240
def symbolName(using builder: SemanticSymbolBuilder)(using Context): String =
225241
builder.symbolName(sym)
@@ -419,20 +435,22 @@ object Scala3:
419435
def hasLength = range.endLine > range.startLine || range.endCharacter > range.startCharacter
420436
end RangeOps
421437

422-
/** Sort symbol occurrences by their start position. */
423-
given OccurrenceOrdering: Ordering[SymbolOccurrence] = (x, y) =>
424-
x.range -> y.range match
438+
private def compareRange(x: Option[Range], y: Option[Range]): Int = x -> y match
425439
case None -> _ | _ -> None => 0
426440
case Some(a) -> Some(b) =>
427441
val byLine = Integer.compare(a.startLine, b.startLine)
428442
if (byLine != 0)
429443
byLine
430444
else // byCharacter
431445
Integer.compare(a.startCharacter, b.startCharacter)
432-
end OccurrenceOrdering
446+
447+
/** Sort symbol occurrences by their start position. */
448+
given Ordering[SymbolOccurrence] = (x, y) => compareRange(x.range, y.range)
433449

434450
given Ordering[SymbolInformation] = Ordering.by[SymbolInformation, String](_.symbol)(IdentifierOrdering())
435451

452+
given Ordering[Synthetic] = (x, y) => compareRange(x.range, y.range)
453+
436454
/**
437455
* A comparator for identifier like "Predef" or "Function10".
438456
*

0 commit comments

Comments
 (0)