Skip to content

Commit 1b3f335

Browse files
Merge pull request #6476 from dotty-staging/change-explaining-printer
Change explaining printer
2 parents 78ff696 + efe720a commit 1b3f335

File tree

4 files changed

+43
-20
lines changed

4 files changed

+43
-20
lines changed

compiler/src/dotty/tools/dotc/printing/Formatting.scala

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,39 +106,59 @@ object Formatting {
106106

107107
private type Recorded = AnyRef /*Symbol | ParamRef | SkolemType */
108108

109-
private class Seen extends mutable.HashMap[String, List[Recorded]] {
109+
private case class SeenKey(str: String, isType: Boolean)
110+
private class Seen extends mutable.HashMap[SeenKey, List[Recorded]] {
110111

111-
override def default(key: String) = Nil
112+
override def default(key: SeenKey) = Nil
112113

113-
def record(str: String, entry: Recorded)(implicit ctx: Context): String = {
114+
def record(str: String, isType: Boolean, entry: Recorded)(implicit ctx: Context): String = {
115+
116+
/** If `e1` is an alias of another class of the same name, return the other
117+
* class symbol instead. This normalization avoids recording e.g. scala.List
118+
* and scala.collection.immutable.List as two different types
119+
*/
114120
def followAlias(e1: Recorded): Recorded = e1 match {
115121
case e1: Symbol if e1.isAliasType =>
116122
val underlying = e1.typeRef.underlyingClassRef(refinementOK = false).typeSymbol
117123
if (underlying.name == e1.name) underlying else e1
118124
case _ => e1
119125
}
126+
val key = SeenKey(str, isType)
127+
val existing = apply(key)
120128
lazy val dealiased = followAlias(entry)
121-
var alts = apply(str).dropWhile(alt => dealiased ne followAlias(alt))
129+
130+
// alts: The alternatives in `existing` that are equal, or follow (an alias of) `entry`
131+
var alts = existing.dropWhile(alt => dealiased ne followAlias(alt))
122132
if (alts.isEmpty) {
123-
alts = entry :: apply(str)
124-
update(str, alts)
133+
alts = entry :: existing
134+
update(key, alts)
125135
}
126136
str + "'" * (alts.length - 1)
127137
}
128138
}
129139

130140
private class ExplainingPrinter(seen: Seen)(_ctx: Context) extends RefinedPrinter(_ctx) {
141+
142+
/** True if printer should a source module instead of its module class */
143+
private def useSourceModule(sym: Symbol): Boolean =
144+
sym.is(ModuleClass, butNot = Package) && sym.sourceModule.exists && !_ctx.settings.YdebugNames.value
145+
131146
override def simpleNameString(sym: Symbol): String =
132-
if ((sym is ModuleClass) && sym.sourceModule.exists) simpleNameString(sym.sourceModule)
133-
else seen.record(super.simpleNameString(sym), sym)
147+
if (useSourceModule(sym)) simpleNameString(sym.sourceModule)
148+
else seen.record(super.simpleNameString(sym), sym.isType, sym)
134149

135150
override def ParamRefNameString(param: ParamRef): String =
136-
seen.record(super.ParamRefNameString(param), param)
151+
seen.record(super.ParamRefNameString(param), param.isInstanceOf[TypeParamRef], param)
137152

138153
override def toTextRef(tp: SingletonType): Text = tp match {
139-
case tp: SkolemType => seen.record(tp.repr.toString, tp)
154+
case tp: SkolemType => seen.record(tp.repr.toString, isType = true, tp)
140155
case _ => super.toTextRef(tp)
141156
}
157+
158+
override def toText(tp: Type): Text = tp match {
159+
case tp: TypeRef if useSourceModule(tp.symbol) => Str("object ") ~ super.toText(tp)
160+
case _ => super.toText(tp)
161+
}
142162
}
143163

144164
/** Create explanation for single `Recorded` type or symbol */
@@ -197,10 +217,13 @@ object Formatting {
197217
}
198218

199219
val toExplain: List[(String, Recorded)] = seen.toList.flatMap {
200-
case (str, entry :: Nil) =>
201-
if (needsExplanation(entry)) (str, entry) :: Nil else Nil
202-
case (str, entries) =>
203-
entries.map(alt => (seen.record(str, alt), alt))
220+
case (key, entry :: Nil) =>
221+
if (needsExplanation(entry)) (key.str, entry) :: Nil else Nil
222+
case (key, entries) =>
223+
for (alt <- entries) yield {
224+
val tickedString = seen.record(key.str, key.isType, alt)
225+
(tickedString, alt)
226+
}
204227
}.sortBy(_._1)
205228

206229
def columnar(parts: List[(String, String)]): List[String] = {

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
298298
}
299299
}
300300

301-
/** The string representation of this type used as a prefix */
301+
/** The string representation of this type used as a prefix, including separator */
302302
protected def toTextPrefix(tp: Type): Text = controlled {
303303
homogenize(tp) match {
304304
case NoPrefix => ""

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
7878
if (ctx.settings.YdebugNames.value) name.debugString else NameTransformer.decodeIllegalChars(name.toString)
7979

8080
override protected def simpleNameString(sym: Symbol): String =
81-
nameString(if (ctx.property(XprintMode).isEmpty) sym.originalName else sym.name)
81+
nameString(if (ctx.property(XprintMode).isEmpty) sym.initial.name else sym.name)
8282

8383
override def fullNameString(sym: Symbol): String =
8484
if (isEmptyPrefix(sym.maybeOwner)) nameString(sym)

language-server/test/dotty/tools/languageserver/CompletionTest.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class CompletionTest {
7979
withSources(
8080
code"""object O { object MyObject }""",
8181
code"""import O.My${m1}"""
82-
).completion(m1, Set(("MyObject", Module, "O.MyObject")))
82+
).completion(m1, Set(("MyObject", Module, "O.MyObject$")))
8383
}
8484

8585
@Test def importCompleteWithClassAndCompanion: Unit = {
@@ -114,7 +114,7 @@ class CompletionTest {
114114
).completion(m1, Set(("myVal", Field, "Int"),
115115
("myDef", Method, "=> Int"),
116116
("myVar", Variable, "Int"),
117-
("myObject", Module, "MyObject.myObject"),
117+
("myObject", Module, "MyObject.myObject$"),
118118
("myClass", Class, "MyObject.myClass"),
119119
("myTrait", Class, "MyObject.myTrait")))
120120
}
@@ -138,7 +138,7 @@ class CompletionTest {
138138
code"""object O {
139139
val out = java.io.FileDesc${m1}
140140
}""".withSource
141-
.completion(m1, Set(("FileDescriptor", Module, "java.io.FileDescriptor")))
141+
.completion(m1, Set(("FileDescriptor", Module, "java.io.FileDescriptor$")))
142142
}
143143

144144
@Test def importRename: Unit = {
@@ -197,7 +197,7 @@ class CompletionTest {
197197
| object bat
198198
| val bizz: ba${m1}
199199
|}""".withSource
200-
.completion(m1, Set(("bar", Field, "Bar"), ("bat", Module, "Foo.bat")))
200+
.completion(m1, Set(("bar", Field, "Bar"), ("bat", Module, "Foo.bat$")))
201201
}
202202

203203
@Test def completionOnRenamedImport: Unit = {

0 commit comments

Comments
 (0)