Skip to content

Commit 66da254

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 73ed7f2 commit 66da254

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()

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@ class TreeUnpickler(reader: TastyReader,
127127
if f == null then "" else s" in $f"
128128
if ctx.settings.YdebugUnpickling.value then throw ex
129129
else throw TypeError(
130-
em"""Could not read definition of $denot$where
131-
|An exception was encountered:
132-
| $ex
133-
|Run with -Ydebug-unpickling to see full stack trace.""")
130+
e"""Could not read definition of $denot$where
131+
|An exception was encountered:
132+
| $ex
133+
|Run with -Ydebug-unpickling to see full stack trace.""")
134134
treeAtAddr(currentAddr) =
135135
try
136136
atPhaseBeforeTransforms {

compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ReadTasty extends Phase {
2929
val className = unit.className.toTypeName
3030

3131
def cannotUnpickle(reason: String): None.type = {
32-
report.error(s"class $className cannot be unpickled because $reason")
32+
report.error(em"class $className cannot be unpickled because $reason")
3333
None
3434
}
3535

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,7 +1743,7 @@ object Parsers {
17431743
Ident(tpnme.USCOREkw).withSpan(Span(start, in.lastOffset, start))
17441744
else
17451745
if sourceVersion.isAtLeast(future) then
1746-
deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead".toMessage)
1746+
deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead")
17471747
patch(source, Span(in.offset, in.offset + 1), "?")
17481748
val start = in.skipToken()
17491749
typeBounds().withSpan(Span(start, in.lastOffset, start))
@@ -3488,7 +3488,7 @@ object Parsers {
34883488
if sourceVersion.isAtLeast(future) then
34893489
deprecationWarning(
34903490
em"""`= _` has been deprecated; use `= uninitialized` instead.
3491-
|`uninitialized` can be imported with `scala.compiletime.uninitialized`.""".toMessage,
3491+
|`uninitialized` can be imported with `scala.compiletime.uninitialized`.""",
34923492
rhsOffset)
34933493
placeholderParams = placeholderParams.tail
34943494
atSpan(rhs0.span) { Ident(nme.WILDCARD) }

compiler/src/dotty/tools/dotc/quoted/Interpreter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ abstract class Interpreter(pos: SrcPos, classLoader: ClassLoader)(using Context)
6060
case tree: Ident if tree.symbol.is(Inline, butNot = Method) =>
6161
tree.tpe.widenTermRefExpr match
6262
case ConstantType(c) => c.value.asInstanceOf[Object]
63-
case _ => throw new StopInterpretation(em"${tree.symbol} could not be inlined", tree.srcPos)
63+
case _ => throw new StopInterpretation(e"${tree.symbol} could not be inlined", tree.srcPos)
6464

6565
// TODO disallow interpreted method calls as arguments
6666
case Call(fn, args) =>
@@ -231,7 +231,7 @@ abstract class Interpreter(pos: SrcPos, classLoader: ClassLoader)(using Context)
231231
try clazz.getMethod(name.toString, paramClasses: _*)
232232
catch {
233233
case _: NoSuchMethodException =>
234-
val msg = em"Could not find method ${clazz.getCanonicalName}.$name with parameters ($paramClasses%, %)"
234+
val msg = e"Could not find method ${clazz.getCanonicalName}.$name with parameters ($paramClasses%, %)"
235235
throw new StopInterpretation(msg, pos)
236236
case MissingClassDefinedInCurrentRun(sym) if ctx.compilationUnit.isSuspendable =>
237237
if (ctx.settings.XprintSuspension.value)

compiler/src/dotty/tools/dotc/quoted/PickledQuotes.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import dotty.tools.dotc.core.tasty.{ PositionPickler, TastyPickler, TastyPrinter
1212
import dotty.tools.dotc.core.tasty.DottyUnpickler
1313
import dotty.tools.dotc.core.tasty.TreeUnpickler.UnpickleMode
1414
import dotty.tools.dotc.report
15-
15+
import dotty.tools.dotc.reporting.Message
1616

1717
import scala.quoted.Quotes
1818
import scala.quoted.runtime.impl._
@@ -220,7 +220,7 @@ object PickledQuotes {
220220
treePkl.pickle(tree :: Nil)
221221
treePkl.compactify()
222222
if tree.span.exists then
223-
val positionWarnings = new mutable.ListBuffer[String]()
223+
val positionWarnings = new mutable.ListBuffer[Message]()
224224
val reference = ctx.settings.sourceroot.value
225225
new PositionPickler(pickler, treePkl.buf.addrOfTree, treePkl.treeAnnots, reference)
226226
.picklePositions(ctx.compilationUnit.source, tree :: Nil, positionWarnings)

compiler/src/dotty/tools/dotc/report.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ object report:
7070
def warning(msg: Message, pos: SrcPos)(using Context): Unit =
7171
issueWarning(new Warning(msg, addInlineds(pos)))
7272

73+
def warning(msg: Message)(using Context): Unit =
74+
warning(msg, NoSourcePosition)
75+
7376
def warning(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit =
7477
warning(msg.toMessage, pos)
7578

@@ -78,6 +81,9 @@ object report:
7881
ctx.reporter.report(new Error(msg, fullPos))
7982
if ctx.settings.YdebugError.value then Thread.dumpStack()
8083

84+
def error(msg: Message)(using Context): Unit =
85+
error(msg, NoSourcePosition)
86+
8187
def error(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit =
8288
error(msg.toMessage, pos)
8389

0 commit comments

Comments
 (0)