@@ -41,6 +41,17 @@ object Message:
41
41
i " \n $what can be rewritten automatically under -rewrite $optionStr. "
42
42
else " "
43
43
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
+
44
55
private type Recorded = Symbol | ParamRef | SkolemType | CaptureRef
45
56
46
57
private case class SeenKey (str : String , isType : Boolean )
@@ -49,7 +60,7 @@ object Message:
49
60
* adds superscripts for disambiguations, and can explain recorded symbols
50
61
* in ` where` clause
51
62
*/
52
- private class Seen (disambiguate : Boolean ):
63
+ private class Seen (disambiguate : Disambiguation ):
53
64
54
65
/** The set of lambdas that were opened at some point during printing. */
55
66
private val openedLambdas = new collection.mutable.HashSet [LambdaType ]
@@ -63,12 +74,12 @@ object Message:
63
74
var nonSensical = false
64
75
65
76
/** If false, stop all recordings */
66
- private var recordOK = disambiguate
77
+ private var disambi = disambiguate
67
78
68
79
/** Clear all entries and stop further entries to be added */
69
80
def disable () =
70
81
seen.clear()
71
- recordOK = false
82
+ disambi = Disambiguation . None
72
83
73
84
/** Record an entry `entry` with given String representation `str` and a
74
85
* type/term namespace identified by `isType`.
@@ -77,59 +88,61 @@ object Message:
77
88
* and following recordings get consecutive superscripts starting with 2.
78
89
* @return The possibly superscripted version of `str`.
79
90
*/
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
133
146
end record
134
147
135
148
/** Create explanation for single `Recorded` type or symbol */
@@ -394,13 +407,15 @@ abstract class Message(val errorId: ErrorMessageID)(using Context) { self =>
394
407
*/
395
408
def isNonSensical : Boolean = { message; myIsNonSensical }
396
409
397
- private var disambiguate : Boolean = true
410
+ private var disambiguate : Disambiguation = Disambiguation . All
398
411
399
- def withoutDisambiguation ( ): this .type =
400
- disambiguate = false
412
+ def withDisambiguation ( disambi : Disambiguation ): this .type =
413
+ disambiguate = disambi
401
414
this
402
415
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 =
404
419
if ctx eq NoContext then op
405
420
else
406
421
val msgContext = ctx.printer match
@@ -419,7 +434,7 @@ abstract class Message(val errorId: ErrorMessageID)(using Context) { self =>
419
434
420
435
/** The explanation to report. <nonsensical> tags are filtered out */
421
436
@ threadUnsafe lazy val explanation : String =
422
- inMessageContext(disambiguate = false )(explain)
437
+ inMessageContext(disambiguate = Disambiguation . None )(explain)
423
438
424
439
/** The implicit `Context` in messages is a large thing that we don't want
425
440
* persisted. This method gets around that by duplicating the message,
0 commit comments