1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
package dotty.tools.dotc
package printing
import core._
import Texts._, Types._, Flags._, Names._, Symbols._, NameOps._, Contexts._
import collection.mutable
import scala.annotation.switch
object Disambiguation {
private class State {
var hasConflicts = false
val symString = new mutable.HashMap[Symbol, String]
val variants = new mutable.HashMap[String, mutable.ListBuffer[Symbol]]
}
def newPrinter: Context => Printer = {
val state = new State
new Printer(state)(_)
}
class Printer(state: State)(_ctx: Context) extends RefinedPrinter(_ctx) {
import state._
override def simpleNameString(sym: Symbol): String = {
if ((sym is ModuleClass) && sym.sourceModule.exists) simpleNameString(sym.sourceModule)
else symString.getOrElse(sym, recordedNameString(sym))
}
private def rawNameString(sym: Symbol) = super.simpleNameString(sym)
private def recordedNameString(sym: Symbol): String = {
val str = rawNameString(sym)
val existing = variants.getOrElse(str, new mutable.ListBuffer[Symbol])
// Dotty deviation: without a type parameter on ListBuffer, inference
// will compute ListBuffer[Symbol] | ListBuffer[Nothing] as the type of "existing"
// and then the assignment to variants below will fail.
// We need to find a way to avoid such useless inferred types.
if (!(existing contains sym)) {
hasConflicts |= existing.nonEmpty
variants(str) = (existing += sym)
}
str
}
def disambiguated(): Boolean = {
val res = hasConflicts
while (hasConflicts) disambiguate()
res
}
private def qualifiers: Stream[String] =
Stream("", "(some other)", "(some 3rd)") ++ (Stream.from(4) map (n => s"(some ${n}th)"))
private def disambiguate(): Unit = {
def update(sym: Symbol, str: String) = if (!(symString contains sym)) symString(sym) = str
def disambiguated(sym: Symbol, owner: Symbol) = s"${rawNameString(sym)}(in ${simpleNameString(owner)})"
hasConflicts = false
for ((name, vs) <- variants.toList)
if (vs.tail.nonEmpty) {
for ((owner, syms) <- vs.groupBy(_.effectiveOwner)) {
if (syms.tail.isEmpty) update(syms.head, disambiguated(syms.head, owner))
else
for {
(kind, syms1) <- syms.groupBy(kindString)
(sym, qual) <- syms1 zip qualifiers
} {
update(sym, s"$qual$kind ${disambiguated(sym, owner)}")
}
}
}
}
}
def disambiguated(op: Context => String)(implicit ctx: Context): String = {
val dctx = ctx.printer match {
case dp: Printer => ctx
case _ => ctx.fresh.setPrinterFn(newPrinter)
}
val res = op(dctx)
dctx.printer match {
case dp: Printer if dp.disambiguated() => op(dctx)
case _ => res
}
}
}
|