@@ -41,6 +41,17 @@ object Message:
4141 i " \n $what can be rewritten automatically under -rewrite $optionStr. "
4242 else " "
4343
44+ enum Disambiguation :
45+ case All
46+ case AllExcept (strs : List [String ])
47+ case None
48+
49+ def recordOK (str : String ): Boolean = this match
50+ case All => true
51+ case AllExcept (strs) => ! strs.contains(str)
52+ case None => false
53+ end Disambiguation
54+
4455 private type Recorded = Symbol | ParamRef | SkolemType | CaptureRef
4556
4657 private case class SeenKey (str : String , isType : Boolean )
@@ -49,7 +60,7 @@ object Message:
4960 * adds superscripts for disambiguations, and can explain recorded symbols
5061 * in ` where` clause
5162 */
52- private class Seen (disambiguate : Boolean ):
63+ private class Seen (disambiguate : Disambiguation ):
5364
5465 /** The set of lambdas that were opened at some point during printing. */
5566 private val openedLambdas = new collection.mutable.HashSet [LambdaType ]
@@ -63,12 +74,12 @@ object Message:
6374 var nonSensical = false
6475
6576 /** If false, stop all recordings */
66- private var recordOK = disambiguate
77+ private var disambi = disambiguate
6778
6879 /** Clear all entries and stop further entries to be added */
6980 def disable () =
7081 seen.clear()
71- recordOK = false
82+ disambi = Disambiguation . None
7283
7384 /** Record an entry `entry` with given String representation `str` and a
7485 * type/term namespace identified by `isType`.
@@ -77,59 +88,61 @@ object Message:
7788 * and following recordings get consecutive superscripts starting with 2.
7889 * @return The possibly superscripted version of `str`.
7990 */
80- def record (str : String , isType : Boolean , entry : Recorded )(using Context ): String = if ! recordOK then str else
81- // println(s"recording $str, $isType, $entry")
82-
83- /** If `e1` is an alias of another class of the same name, return the other
84- * class symbol instead. This normalization avoids recording e.g. scala.List
85- * and scala.collection.immutable.List as two different types
86- */
87- def followAlias (e1 : Recorded ): Recorded = e1 match {
88- case e1 : Symbol if e1.isAliasType =>
89- val underlying = e1.typeRef.underlyingClassRef(refinementOK = false ).typeSymbol
90- if (underlying.name == e1.name) underlying else e1.namedType.dealias.typeSymbol
91- case _ => e1
92- }
93- val key = SeenKey (str, isType)
94- val existing = seen(key)
95- lazy val dealiased = followAlias(entry)
96-
97- /** All lambda parameters with the same name are given the same superscript as
98- * long as their corresponding binder has been printed.
99- * See tests/neg/lambda-rename.scala for test cases.
100- */
101- def sameSuperscript (cur : Recorded , existing : Recorded ) =
102- (cur eq existing) ||
103- (cur, existing).match
104- case (cur : ParamRef , existing : ParamRef ) =>
105- (cur.paramName eq existing.paramName) &&
106- openedLambdas.contains(cur.binder) &&
107- openedLambdas.contains(existing.binder)
108- case _ =>
109- false
110-
111- // The length of alts corresponds to the number of superscripts we need to print.
112- var alts = existing.dropWhile(alt => ! sameSuperscript(dealiased, followAlias(alt)))
113- if alts.isEmpty then
114- alts = entry :: existing
115- seen(key) = alts
116-
117- val suffix = alts.length match {
118- case 1 => " "
119- case n => n.toString.toCharArray.map {
120- case '0' => '⁰'
121- case '1' => '¹'
122- case '2' => '²'
123- case '3' => '³'
124- case '4' => '⁴'
125- case '5' => '⁵'
126- case '6' => '⁶'
127- case '7' => '⁷'
128- case '8' => '⁸'
129- case '9' => '⁹'
130- }.mkString
131- }
132- str + suffix
91+ def record (str : String , isType : Boolean , entry : Recorded )(using Context ): String =
92+ if disambi.recordOK(str) then
93+ // println(s"recording $str, $isType, $entry")
94+
95+ /** If `e1` is an alias of another class of the same name, return the other
96+ * class symbol instead. This normalization avoids recording e.g. scala.List
97+ * and scala.collection.immutable.List as two different types
98+ */
99+ def followAlias (e1 : Recorded ): Recorded = e1 match {
100+ case e1 : Symbol if e1.isAliasType =>
101+ val underlying = e1.typeRef.underlyingClassRef(refinementOK = false ).typeSymbol
102+ if (underlying.name == e1.name) underlying else e1.namedType.dealias.typeSymbol
103+ case _ => e1
104+ }
105+ val key = SeenKey (str, isType)
106+ val existing = seen(key)
107+ lazy val dealiased = followAlias(entry)
108+
109+ /** All lambda parameters with the same name are given the same superscript as
110+ * long as their corresponding binder has been printed.
111+ * See tests/neg/lambda-rename.scala for test cases.
112+ */
113+ def sameSuperscript (cur : Recorded , existing : Recorded ) =
114+ (cur eq existing) ||
115+ (cur, existing).match
116+ case (cur : ParamRef , existing : ParamRef ) =>
117+ (cur.paramName eq existing.paramName) &&
118+ openedLambdas.contains(cur.binder) &&
119+ openedLambdas.contains(existing.binder)
120+ case _ =>
121+ false
122+
123+ // The length of alts corresponds to the number of superscripts we need to print.
124+ var alts = existing.dropWhile(alt => ! sameSuperscript(dealiased, followAlias(alt)))
125+ if alts.isEmpty then
126+ alts = entry :: existing
127+ seen(key) = alts
128+
129+ val suffix = alts.length match {
130+ case 1 => " "
131+ case n => n.toString.toCharArray.map {
132+ case '0' => '⁰'
133+ case '1' => '¹'
134+ case '2' => '²'
135+ case '3' => '³'
136+ case '4' => '⁴'
137+ case '5' => '⁵'
138+ case '6' => '⁶'
139+ case '7' => '⁷'
140+ case '8' => '⁸'
141+ case '9' => '⁹'
142+ }.mkString
143+ }
144+ str + suffix
145+ else str
133146 end record
134147
135148 /** Create explanation for single `Recorded` type or symbol */
@@ -394,13 +407,15 @@ abstract class Message(val errorId: ErrorMessageID)(using Context) { self =>
394407 */
395408 def isNonSensical : Boolean = { message; myIsNonSensical }
396409
397- private var disambiguate : Boolean = true
410+ private var disambiguate : Disambiguation = Disambiguation . All
398411
399- def withoutDisambiguation ( ): this .type =
400- disambiguate = false
412+ def withDisambiguation ( disambi : Disambiguation ): this .type =
413+ disambiguate = disambi
401414 this
402415
403- private def inMessageContext (disambiguate : Boolean )(op : Context ?=> String ): String =
416+ def withoutDisambiguation (): this .type = withDisambiguation(Disambiguation .None )
417+
418+ private def inMessageContext (disambiguate : Disambiguation )(op : Context ?=> String ): String =
404419 if ctx eq NoContext then op
405420 else
406421 val msgContext = ctx.printer match
@@ -419,7 +434,7 @@ abstract class Message(val errorId: ErrorMessageID)(using Context) { self =>
419434
420435 /** The explanation to report. <nonsensical> tags are filtered out */
421436 @ threadUnsafe lazy val explanation : String =
422- inMessageContext(disambiguate = false )(explain)
437+ inMessageContext(disambiguate = Disambiguation . None )(explain)
423438
424439 /** The implicit `Context` in messages is a large thing that we don't want
425440 * persisted. This method gets around that by duplicating the message,
0 commit comments