@@ -106,39 +106,59 @@ object Formatting {
106
106
107
107
private type Recorded = AnyRef /* Symbol | ParamRef | SkolemType */
108
108
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 ]] {
110
111
111
- override def default (key : String ) = Nil
112
+ override def default (key : SeenKey ) = Nil
112
113
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
+ */
114
120
def followAlias (e1 : Recorded ): Recorded = e1 match {
115
121
case e1 : Symbol if e1.isAliasType =>
116
122
val underlying = e1.typeRef.underlyingClassRef(refinementOK = false ).typeSymbol
117
123
if (underlying.name == e1.name) underlying else e1
118
124
case _ => e1
119
125
}
126
+ val key = SeenKey (str, isType)
127
+ val existing = apply(key)
120
128
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))
122
132
if (alts.isEmpty) {
123
- alts = entry :: apply(str)
124
- update(str , alts)
133
+ alts = entry :: existing
134
+ update(key , alts)
125
135
}
126
136
str + " '" * (alts.length - 1 )
127
137
}
128
138
}
129
139
130
140
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
+
131
146
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 )
134
149
135
150
override def ParamRefNameString (param : ParamRef ): String =
136
- seen.record(super .ParamRefNameString (param), param)
151
+ seen.record(super .ParamRefNameString (param), param. isInstanceOf [ TypeParamRef ], param )
137
152
138
153
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)
140
155
case _ => super .toTextRef(tp)
141
156
}
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
+ }
142
162
}
143
163
144
164
/** Create explanation for single `Recorded` type or symbol */
@@ -197,10 +217,13 @@ object Formatting {
197
217
}
198
218
199
219
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
+ }
204
227
}.sortBy(_._1)
205
228
206
229
def columnar (parts : List [(String , String )]): List [String ] = {
0 commit comments