Skip to content

Commit 6fdaab6

Browse files
committed
Refactor error message handling
- Revise string interpolators; `em` and `exm` nor produce messages, whereas `i`, `e`, and `ex` produce strings. - Use Message intead of () => String in some places.
1 parent 2992589 commit 6fdaab6

31 files changed

+1046
-1016
lines changed

compiler/src/dotty/tools/backend/sjs/JSExportsGen.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,7 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
135135

136136
for ((info, _) <- tups.tail) {
137137
report.error(
138-
em"export overload conflicts with export of $firstSym: " +
139-
"a field may not share its exported name with another export",
138+
em"export overload conflicts with export of $firstSym: a field may not share its exported name with another export",
140139
info.pos)
141140
}
142141

@@ -264,8 +263,8 @@ final class JSExportsGen(jsCodeGen: JSCodeGen)(using Context) {
264263
.alternatives
265264

266265
assert(!alts.isEmpty,
267-
em"Ended up with no alternatives for ${classSym.fullName}::$name. " +
268-
em"Original set was ${alts} with types ${alts.map(_.info)}")
266+
em"""Ended up with no alternatives for ${classSym.fullName}::$name.
267+
|Original set was ${alts} with types ${alts.map(_.info)}""")
269268

270269
val (jsName, isProp) = exportNameInfo(name)
271270

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ object desugar {
11371137
def errorOnGivenBinding(bind: Bind)(using Context): Boolean =
11381138
report.error(
11391139
em"""${hl("given")} patterns are not allowed in a ${hl("val")} definition,
1140-
|please bind to an identifier and use an alias given.""".stripMargin, bind)
1140+
|please bind to an identifier and use an alias given.""", bind)
11411141
false
11421142

11431143
def isTuplePattern(arity: Int): Boolean = pat match {

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
428428
else
429429
val res = Select(TypeTree(pre), tp)
430430
if needLoad && !res.symbol.isStatic then
431-
throw new TypeError(em"cannot establish a reference to $res")
431+
throw new TypeError(e"cannot establish a reference to $res")
432432
res
433433

434434
def ref(sym: Symbol)(using Context): Tree =
@@ -1296,7 +1296,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
12961296
else if (tree.tpe.widen isRef numericCls)
12971297
tree
12981298
else {
1299-
report.warning(i"conversion from ${tree.tpe.widen} to ${numericCls.typeRef} will always fail at runtime.")
1299+
report.warning(em"conversion from ${tree.tpe.widen} to ${numericCls.typeRef} will always fail at runtime.")
13001300
Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)).withSpan(tree.span)
13011301
}
13021302
}

compiler/src/dotty/tools/dotc/cc/CaptureSet.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ object CaptureSet:
559559
// elements from variable sources in contra- and non-variant positions. In essence,
560560
// we approximate types resulting from such maps by returning a possible super type
561561
// from the actual type. But this is neither sound nor complete.
562-
report.warning(i"trying to add elems ${CaptureSet(newElems)} from unrecognized source $origin of mapped set $this$whereCreated")
562+
report.warning(em"trying to add elems ${CaptureSet(newElems)} from unrecognized source $origin of mapped set $this$whereCreated")
563563
CompareResult.fail(this)
564564
else
565565
CompareResult.OK

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ object Contexts {
255255
file
256256
catch
257257
case ex: InvalidPathException =>
258-
report.error(s"invalid file path: ${ex.getMessage}")
258+
report.error(em"invalid file path: ${ex.getMessage}")
259259
NoAbstractFile
260260

261261
/** AbstractFile with given path, memoized */

compiler/src/dotty/tools/dotc/core/Decorators.scala

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ object Decorators {
5959
end extension
6060

6161
extension (str: => String)
62-
def toMessage: Message = reporting.NoExplanation(str)
62+
def toMessage: Message = NoExplanation(str)
6363

6464
/** Implements a findSymbol method on iterators of Symbols that
6565
* works like find but avoids Option, replacing None with NoSymbol.
@@ -291,17 +291,41 @@ object Decorators {
291291
def derivedCons(x1: T, xs1: List[T]) =
292292
if (xs.head eq x1) && (xs.tail eq xs1) then xs else x1 :: xs1
293293

294+
/* This extension defines the following string formatters:
295+
* i, e, ex, em, exm
296+
* String formatters ending in `m` produce a message, the others produce a string.
297+
* Details are as follows:
298+
*
299+
* i : Gneral purpose string interpolator that uses Formtting.show to print compiler data
300+
* e : Like `i`, but with logic that limits the size of messages and that
301+
* filters out nonsensical messages after the first error is reported.
302+
* `e` or its variants should be used for error messages and warnings instead of `i`.
303+
* ex : Like `e`, but it assembles additional info on type variables and for
304+
* disambiguating symbols.
305+
* em : Like `e`, but producing a message
306+
* exm: Like `ex`, but producing a message
307+
*/
294308
extension (sc: StringContext)
295309
/** General purpose string formatting */
296310
def i(args: Shown*)(using Context): String =
297311
new StringFormatter(sc).assemble(args)
298312

299-
/** Formatting for error messages: Like `i` but suppress follow-on
300-
* error messages after the first one if some of their arguments are "non-sensical".
313+
/** Formatting for error messages: Like `i`, with two modifications
314+
* - limit size of messages
315+
* - mark some parts of messages with <nonsensical> tags, so that
316+
* error messages after the first one are filtered out if some of
317+
* their arguments are "non-sensical".
301318
*/
302-
def em(args: Shown*)(using Context): String =
319+
def e(args: Shown*)(using Context): String =
303320
forErrorMessages(new StringFormatter(sc).assemble(args))
304321

322+
/** A NoExplanation message formatted with `e` */
323+
def em(args: Shown*)(using Context): NoExplanation =
324+
NoExplanation(e(args*))
325+
326+
def exm(args: Shown*)(using Context): NoExplanation =
327+
NoExplanation(ex(args*))
328+
305329
/** Formatting with added explanations: Like `em`, but add explanations to
306330
* give more info about type variables and to disambiguate where needed.
307331
*/

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,9 +1268,9 @@ object Denotations {
12681268
if sd1.exists then
12691269
if sd2.exists then
12701270
throw TypeError(
1271-
em"""Failure to disambiguate overloaded reference with
1272-
| ${denot1.symbol.showLocated}: ${denot1.info} and
1273-
| ${denot2.symbol.showLocated}: ${denot2.info}""")
1271+
e"""Failure to disambiguate overloaded reference with
1272+
| ${denot1.symbol.showLocated}: ${denot1.info} and
1273+
| ${denot2.symbol.showLocated}: ${denot2.info}""")
12741274
else sd1
12751275
else sd2
12761276
}

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,10 +2438,10 @@ object SymDenotations {
24382438
val youngest = assocFiles.filter(_.lastModified == lastModDate)
24392439
val chosen = youngest.head
24402440
def ambiguousFilesMsg(f: AbstractFile) =
2441-
em"""Toplevel definition $name is defined in
2442-
| $chosen
2443-
|and also in
2444-
| $f"""
2441+
e"""Toplevel definition $name is defined in
2442+
| $chosen
2443+
|and also in
2444+
| $f"""
24452445
if youngest.size > 1 then
24462446
throw TypeError(i"""${ambiguousFilesMsg(youngest.tail.head)}
24472447
|One of these files should be removed from the classpath.""")
@@ -2454,8 +2454,8 @@ object SymDenotations {
24542454
try f.container == chosen.container catch case NonFatal(ex) => true
24552455
if !ambiguityWarningIssued then
24562456
for conflicting <- assocFiles.find(!sameContainer(_)) do
2457-
report.warning(i"""${ambiguousFilesMsg(conflicting.nn)}
2458-
|Keeping only the definition in $chosen""")
2457+
report.warning(em"""${ambiguousFilesMsg(conflicting.nn)}
2458+
|Keeping only the definition in $chosen""")
24592459
ambiguityWarningIssued = true
24602460
multi.filterWithPredicate(_.symbol.associatedFile == chosen)
24612461
end dropStale

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ class ClassfileParser(
326326
if (isEnum) {
327327
val enumClass = sym.owner.linkedClass
328328
if (!enumClass.exists)
329-
report.warning(s"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.")
329+
report.warning(em"no linked class for java enum $sym in ${sym.owner}. A referencing class file might be missing an InnerClasses entry.")
330330
else {
331331
if (!enumClass.is(Flags.Sealed)) enumClass.setFlag(Flags.AbstractSealed)
332332
enumClass.addAnnotation(Annotation.Child(sym, NoSpan))
@@ -656,7 +656,7 @@ class ClassfileParser(
656656
case tp: TypeRef if tp.denot.infoOrCompleter.isInstanceOf[StubInfo] =>
657657
// Silently ignore missing annotation classes like javac
658658
if ctx.debug then
659-
report.warning(i"Error while parsing annotations in ${classfile}: annotation class $tp not present on classpath")
659+
report.warning(em"Error while parsing annotations in ${classfile}: annotation class $tp not present on classpath")
660660
None
661661
case _ =>
662662
if (hasError || skip) None
@@ -671,7 +671,7 @@ class ClassfileParser(
671671
// the classpath would *not* end up here. A class not found is signaled
672672
// with a `FatalError` exception, handled above. Here you'd end up after a NPE (for example),
673673
// and that should never be swallowed silently.
674-
report.warning("Caught: " + ex + " while parsing annotations in " + classfile)
674+
report.warning(em"Caught: $ex while parsing annotations in $classfile")
675675
if (ctx.debug) ex.printStackTrace()
676676

677677
None // ignore malformed annotations
@@ -753,7 +753,7 @@ class ClassfileParser(
753753
case tpnme.ConstantValueATTR =>
754754
val c = pool.getConstant(in.nextChar)
755755
if (c ne null) res.constant = c
756-
else report.warning(s"Invalid constant in attribute of ${sym.showLocated} while parsing ${classfile}")
756+
else report.warning(em"Invalid constant in attribute of ${sym.showLocated} while parsing ${classfile}")
757757

758758
case tpnme.MethodParametersATTR =>
759759
val paramCount = in.nextByte
@@ -967,15 +967,15 @@ class ClassfileParser(
967967
}
968968
}
969969
else {
970-
report.error(s"Could not find $path in ${classfile.underlyingSource}")
970+
report.error(em"Could not find $path in ${classfile.underlyingSource}")
971971
Array.empty
972972
}
973973
case _ =>
974974
val dir = classfile.container
975975
val name = classfile.name.stripSuffix(".class") + ".tasty"
976976
val tastyFileOrNull = dir.lookupName(name, false)
977977
if (tastyFileOrNull == null) {
978-
report.error(s"Could not find TASTY file $name under $dir")
978+
report.error(em"Could not find TASTY file $name under $dir")
979979
Array.empty
980980
} else
981981
tastyFileOrNull.toByteArray

compiler/src/dotty/tools/dotc/core/tasty/PositionPickler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import core._
1414
import Annotations._, Decorators._
1515
import collection.mutable
1616
import util.Spans._
17+
import reporting.Message
1718

1819
class PositionPickler(
1920
pickler: TastyPickler,
@@ -33,7 +34,7 @@ class PositionPickler(
3334
(addrDelta << 3) | (toInt(hasStartDelta) << 2) | (toInt(hasEndDelta) << 1) | toInt(hasPoint)
3435
}
3536

36-
def picklePositions(source: SourceFile, roots: List[Tree], warnings: mutable.ListBuffer[String]): Unit = {
37+
def picklePositions(source: SourceFile, roots: List[Tree], warnings: mutable.ListBuffer[Message]): Unit = {
3738
/** Pickle the number of lines followed by the length of each line */
3839
def pickleLineOffsets(): Unit = {
3940
val content = source.content()

0 commit comments

Comments
 (0)