Skip to content

Commit 1a0908c

Browse files
committed
Drop toNoExplanation implicit conversion
`toNoExplanation` was an old-style implicit conversion. It could not be made a `Conversion` since it was defined over a call-by-name argument. It also hid important implementation details since it delayed constructing the argument. So knowing whether a string would be evaluated strictly or lazily depended on knowing how type inference would work. We replace the conversion by a combination of - an extension method `.toMessage` converting a lazy string explicitly, and - some overloading of core methods that take either a message or a lazy string. We should over time get rid of overloads and convert most strings passed as messges to proper messages. But that will take time. At least by now we see better where the work is needed.
1 parent 96d4ccd commit 1a0908c

21 files changed

+117
-65
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import scala.util.control.NonFatal
99
import Contexts._, Names._, Phases._, Symbols._
1010
import printing.{ Printer, Showable }, printing.Formatting._, printing.Texts._
1111
import transform.MegaPhase
12+
import reporting.{Message, NoExplanation}
1213

1314
/** This object provides useful implicit decorators for types defined elsewhere */
1415
object Decorators {
@@ -57,6 +58,9 @@ object Decorators {
5758
padding + s.replace("\n", "\n" + padding)
5859
end extension
5960

61+
extension (str: => String)
62+
def toMessage: Message = reporting.NoExplanation(str)
63+
6064
/** Implements a findSymbol method on iterators of Symbols that
6165
* works like find but avoids Option, replacing None with NoSymbol.
6266
*/

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ class TypeError(msg: String) extends Exception(msg) {
1818
def this() = this("")
1919
final def toMessage(using Context): Message =
2020
withMode(Mode.Printing)(produceMessage)
21-
def produceMessage(using Context): Message = super.getMessage.nn
21+
def produceMessage(using Context): Message = super.getMessage.nn.toMessage
2222
override def getMessage: String = super.getMessage.nn
2323
}
2424

2525
class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name]) extends TypeError {
2626
override def produceMessage(using Context): Message =
2727
i"malformed type: $pre is not a legal prefix for $denot because it contains abstract type member${if (absMembers.size == 1) "" else "s"} ${absMembers.mkString(", ")}"
28+
.toMessage
2829
}
2930

3031
class MissingType(pre: Type, name: Name) extends TypeError {
@@ -38,6 +39,7 @@ class MissingType(pre: Type, name: Name) extends TypeError {
3839
if (ctx.debug) printStackTrace()
3940
i"""cannot resolve reference to type $pre.$name
4041
|the classfile defining the type might be missing from the classpath${otherReason(pre)}"""
42+
.toMessage
4143
}
4244
}
4345

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5296,16 +5296,18 @@ object Types {
52965296
val et = new PreviousErrorType
52975297
ctx.base.errorTypeMsg(et) = m
52985298
et
5299+
def apply(s: => String)(using Context): ErrorType =
5300+
apply(s.toMessage)
52995301
end ErrorType
53005302

53015303
class PreviousErrorType extends ErrorType:
53025304
def msg(using Context): Message =
53035305
ctx.base.errorTypeMsg.get(this) match
53045306
case Some(m) => m
5305-
case None => "error message from previous run no longer available"
5307+
case None => "error message from previous run no longer available".toMessage
53065308

53075309
object UnspecifiedErrorType extends ErrorType {
5308-
override def msg(using Context): Message = "unspecified error"
5310+
override def msg(using Context): Message = "unspecified error".toMessage
53095311
}
53105312

53115313
/* Type used to track Select nodes that could not resolve a member and their qualifier is a scala.Dynamic. */

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import printing.Texts._
2020
import printing.Printer
2121
import io.AbstractFile
2222
import util.common._
23+
import util.NoSourcePosition
2324
import typer.Checking.checkNonCyclic
2425
import typer.Nullables._
2526
import transform.SymUtils._
@@ -744,7 +745,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
744745
val anyTypes = boundSyms map (_ => defn.AnyType)
745746
val boundBounds = boundSyms map (_.info.bounds.hi)
746747
val tp2 = tp1.subst(boundSyms, boundBounds).subst(boundSyms, anyTypes)
747-
report.warning(FailureToEliminateExistential(tp, tp1, tp2, boundSyms, classRoot.symbol))
748+
report.warning(FailureToEliminateExistential(tp, tp1, tp2, boundSyms, classRoot.symbol), NoSourcePosition)
748749
tp2
749750
}
750751
else tp1

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ object Inlines:
155155
tree,
156156
i"""|Maximal number of $reason (${setting.value}) exceeded,
157157
|Maybe this is caused by a recursive inline method?
158-
|You can use ${setting.name} to change the limit.""",
158+
|You can use ${setting.name} to change the limit.""".toMessage,
159159
(tree :: enclosingInlineds).last.srcPos
160160
)
161161
if ctx.base.stopInlining && enclosingInlineds.isEmpty then

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

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,22 @@ object Parsers {
142142
val length = if offset == in.offset && in.name != null then in.name.show.length else 0
143143
syntaxError(msg, Span(offset, offset + length))
144144
lastErrorOffset = in.offset
145-
end if
145+
146+
def syntaxError(msg: => String, offset: Int): Unit =
147+
syntaxError(msg.toMessage, offset)
148+
149+
def syntaxError(msg: => String): Unit =
150+
syntaxError(msg, in.offset)
146151

147152
/** Unconditionally issue an error at given span, without
148153
* updating lastErrorOffset.
149154
*/
150155
def syntaxError(msg: Message, span: Span): Unit =
151156
report.error(msg, source.atSpan(span))
152157

158+
def syntaxError(msg: => String, span: Span): Unit =
159+
syntaxError(msg.toMessage, span)
160+
153161
def unimplementedExpr(using Context): Select =
154162
Select(Select(rootDot(nme.scala), nme.Predef), nme.???)
155163
}
@@ -259,9 +267,6 @@ object Parsers {
259267
in.skip()
260268
lastErrorOffset = in.offset
261269

262-
def warning(msg: Message, sourcePos: SourcePosition): Unit =
263-
report.warning(msg, sourcePos)
264-
265270
def warning(msg: Message, offset: Int = in.offset): Unit =
266271
report.warning(msg, source.atSpan(Span(offset)))
267272

@@ -283,6 +288,9 @@ object Parsers {
283288
syntaxError(msg, offset)
284289
skip()
285290

291+
def syntaxErrorOrIncomplete(msg: => String): Unit =
292+
syntaxErrorOrIncomplete(msg.toMessage, in.offset)
293+
286294
def syntaxErrorOrIncomplete(msg: Message, span: Span): Unit =
287295
if in.token == EOF then
288296
incompleteInputError(msg)
@@ -350,7 +358,7 @@ object Parsers {
350358
val statFollows = mustStartStatTokens.contains(found)
351359
syntaxError(
352360
if noPrevStat then IllegalStartOfStatement(what, isModifier, statFollows)
353-
else i"end of $what expected but ${showToken(found)} found")
361+
else i"end of $what expected but ${showToken(found)} found".toMessage)
354362
if mustStartStatTokens.contains(found) then
355363
false // it's a statement that might be legal in an outer context
356364
else
@@ -610,11 +618,11 @@ object Parsers {
610618
if in.isNewLine && !(nextIndentWidth < startIndentWidth) then
611619
warning(
612620
if startIndentWidth <= nextIndentWidth then
613-
i"""Line is indented too far to the right, or a `{` is missing before:
621+
i"""Line is indented too far to the right, or a `{` is missing before:
614622
|
615-
|${t.tryToShow}"""
623+
|${t.tryToShow}""".toMessage
616624
else
617-
in.spaceTabMismatchMsg(startIndentWidth, nextIndentWidth),
625+
in.spaceTabMismatchMsg(startIndentWidth, nextIndentWidth).toMessage,
618626
in.next.offset
619627
)
620628
t
@@ -627,7 +635,7 @@ object Parsers {
627635
if in.isNewLine then
628636
val nextIndentWidth = in.indentWidth(in.next.offset)
629637
if in.currentRegion.indentWidth < nextIndentWidth then
630-
warning(i"Line is indented too far to the right, or a `{` or `:` is missing", in.next.offset)
638+
warning(i"Line is indented too far to the right, or a `{` or `:` is missing".toMessage, in.next.offset)
631639

632640
/* -------- REWRITES ----------------------------------------------------------- */
633641

@@ -1732,7 +1740,7 @@ object Parsers {
17321740
Ident(tpnme.USCOREkw).withSpan(Span(start, in.lastOffset, start))
17331741
else
17341742
if sourceVersion.isAtLeast(future) then
1735-
deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead")
1743+
deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead".toMessage)
17361744
patch(source, Span(in.offset, in.offset + 1), "?")
17371745
val start = in.skipToken()
17381746
typeBounds().withSpan(Span(start, in.lastOffset, start))
@@ -2171,10 +2179,11 @@ object Parsers {
21712179
else Literal(Constant(())) // finally without an expression
21722180
}
21732181
else {
2174-
if (handler.isEmpty) warning(
2175-
EmptyCatchAndFinallyBlock(body),
2176-
source.atSpan(Span(tryOffset, endOffset(body)))
2177-
)
2182+
if handler.isEmpty then
2183+
report.warning(
2184+
EmptyCatchAndFinallyBlock(body),
2185+
source.atSpan(Span(tryOffset, endOffset(body)))
2186+
)
21782187
EmptyTree
21792188
}
21802189
ParsedTry(body, handler, finalizer)
@@ -2768,7 +2777,7 @@ object Parsers {
27682777
warning(i"""Misleading indentation: this expression forms part of the preceding catch case.
27692778
|If this is intended, it should be indented for clarity.
27702779
|Otherwise, if the handler is intended to be empty, use a multi-line catch with
2771-
|an indented case.""")
2780+
|an indented case.""".toMessage)
27722781
expr()
27732782
else block()
27742783
})
@@ -2989,7 +2998,8 @@ object Parsers {
29892998
inBrackets {
29902999
if in.token == THIS then
29913000
if sourceVersion.isAtLeast(future) then
2992-
deprecationWarning("The [this] qualifier will be deprecated in the future; it should be dropped.")
3001+
deprecationWarning(
3002+
"The [this] qualifier will be deprecated in the future; it should be dropped.".toMessage)
29933003
in.nextToken()
29943004
mods | Local
29953005
else mods.withPrivateWithin(ident().toTypeName)
@@ -3471,7 +3481,8 @@ object Parsers {
34713481
if sourceVersion.isAtLeast(future) then
34723482
deprecationWarning(
34733483
em"""`= _` has been deprecated; use `= uninitialized` instead.
3474-
|`uninitialized` can be imported with `scala.compiletime.uninitialized`.""", rhsOffset)
3484+
|`uninitialized` can be imported with `scala.compiletime.uninitialized`.""".toMessage,
3485+
rhsOffset)
34753486
placeholderParams = placeholderParams.tail
34763487
atSpan(rhs0.span) { Ident(nme.WILDCARD) }
34773488
case rhs0 => rhs0

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ object Scanners {
112112

113113
/** signal an error where the input ended in the middle of a token */
114114
def incompleteInputError(msg: String): Unit = {
115-
report.incompleteInputError(msg, sourcePos())
115+
report.incompleteInputError(msg.toMessage, sourcePos())
116116
token = EOF
117117
errOffset = offset
118118
}

compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Parsers._
1313
import util.Spans._
1414
import core._
1515
import Constants._
16+
import Decorators.toMessage
1617
import util.SourceFile
1718
import Utility._
1819

@@ -379,7 +380,7 @@ object MarkupParsers {
379380
ts(0)
380381
}
381382
},
382-
msg => parser.incompleteInputError(msg)
383+
msg => parser.incompleteInputError(msg.toMessage)
383384
)
384385

385386
/** @see xmlPattern. resynchronizes after successful parse

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

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,35 @@ object report:
1818
if ctx.settings.verbose.value then echo(msg, pos)
1919

2020
def echo(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit =
21-
ctx.reporter.report(new Info(msg, pos.sourcePos))
21+
ctx.reporter.report(new Info(msg.toMessage, pos.sourcePos))
2222

2323
private def issueWarning(warning: Warning)(using Context): Unit =
2424
ctx.reporter.report(warning)
2525

26-
def deprecationWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit =
26+
def deprecationWarning(msg: Message, pos: SrcPos)(using Context): Unit =
2727
issueWarning(new DeprecationWarning(msg, pos.sourcePos))
2828

29-
def migrationWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit =
29+
def deprecationWarning(msg: => String, pos: SrcPos)(using Context): Unit =
30+
deprecationWarning(msg.toMessage, pos)
31+
32+
def migrationWarning(msg: Message, pos: SrcPos)(using Context): Unit =
3033
issueWarning(new MigrationWarning(msg, pos.sourcePos))
3134

32-
def uncheckedWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit =
35+
def migrationWarning(msg: => String, pos: SrcPos)(using Context): Unit =
36+
migrationWarning(msg.toMessage, pos)
37+
38+
def uncheckedWarning(msg: Message, pos: SrcPos)(using Context): Unit =
3339
issueWarning(new UncheckedWarning(msg, pos.sourcePos))
3440

35-
def featureWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit =
41+
def uncheckedWarning(msg: => String, pos: SrcPos)(using Context): Unit =
42+
uncheckedWarning(msg.toMessage, pos)
43+
44+
def featureWarning(msg: Message, pos: SrcPos)(using Context): Unit =
3645
issueWarning(new FeatureWarning(msg, pos.sourcePos))
3746

47+
def featureWarning(msg: => String, pos: SrcPos)(using Context): Unit =
48+
featureWarning(msg.toMessage, pos)
49+
3850
def featureWarning(feature: String, featureDescription: => String,
3951
featureUseSite: Symbol, required: Boolean, pos: SrcPos)(using Context): Unit = {
4052
val req = if (required) "needs to" else "should"
@@ -52,30 +64,43 @@ object report:
5264
|by adding the import clause 'import $fqname'
5365
|or by setting the compiler option -language:$feature.$explain""".stripMargin
5466
if (required) error(msg, pos)
55-
else issueWarning(new FeatureWarning(msg, pos.sourcePos))
67+
else issueWarning(new FeatureWarning(msg.toMessage, pos.sourcePos))
5668
}
5769

58-
def warning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit =
70+
def warning(msg: Message, pos: SrcPos)(using Context): Unit =
5971
issueWarning(new Warning(msg, addInlineds(pos)))
6072

61-
def error(msg: Message, pos: SrcPos = NoSourcePosition, sticky: Boolean = false)(using Context): Unit =
73+
def warning(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit =
74+
warning(msg.toMessage, pos)
75+
76+
def error(msg: Message, pos: SrcPos)(using Context): Unit =
6277
val fullPos = addInlineds(pos)
63-
ctx.reporter.report(if (sticky) new StickyError(msg, fullPos) else new Error(msg, fullPos))
78+
ctx.reporter.report(new Error(msg, fullPos))
6479
if ctx.settings.YdebugError.value then Thread.dumpStack()
6580

81+
def error(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit =
82+
error(msg.toMessage, pos)
83+
6684
def error(ex: TypeError, pos: SrcPos)(using Context): Unit =
67-
error(ex.toMessage, pos, sticky = true)
68-
if ctx.settings.YdebugTypeError.value then ex.printStackTrace()
85+
val fullPos = addInlineds(pos)
86+
ctx.reporter.report(new StickyError(ex.toMessage, fullPos))
87+
if ctx.settings.YdebugError.value then Thread.dumpStack()
6988

70-
def errorOrMigrationWarning(msg: Message, pos: SrcPos = NoSourcePosition, from: SourceVersion)(using Context): Unit =
89+
def errorOrMigrationWarning(msg: Message, pos: SrcPos, from: SourceVersion)(using Context): Unit =
7190
if sourceVersion.isAtLeast(from) then
7291
if sourceVersion.isMigrating && sourceVersion.ordinal <= from.ordinal then migrationWarning(msg, pos)
7392
else error(msg, pos)
7493

75-
def gradualErrorOrMigrationWarning(msg: Message, pos: SrcPos = NoSourcePosition, warnFrom: SourceVersion, errorFrom: SourceVersion)(using Context): Unit =
94+
def errorOrMigrationWarning(msg: => String, pos: SrcPos, from: SourceVersion)(using Context): Unit =
95+
errorOrMigrationWarning(msg.toMessage, pos, from)
96+
97+
def gradualErrorOrMigrationWarning(msg: Message, pos: SrcPos, warnFrom: SourceVersion, errorFrom: SourceVersion)(using Context): Unit =
7698
if sourceVersion.isAtLeast(errorFrom) then errorOrMigrationWarning(msg, pos, errorFrom)
7799
else if sourceVersion.isAtLeast(warnFrom) then warning(msg, pos)
78100

101+
def gradualErrorOrMigrationWarning(msg: => String, pos: SrcPos, warnFrom: SourceVersion, errorFrom: SourceVersion)(using Context): Unit =
102+
gradualErrorOrMigrationWarning(msg.toMessage, pos, warnFrom, errorFrom)
103+
79104
def restrictionError(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit =
80105
error(msg.mapMsg("Implementation restriction: " + _), pos)
81106

compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import dotty.tools.dotc.util.SourcePosition
1111

1212
import java.util.Optional
1313
import scala.util.chaining._
14+
import core.Decorators.toMessage
1415

1516
object Diagnostic:
1617

@@ -23,7 +24,8 @@ object Diagnostic:
2324
class Error(
2425
msg: Message,
2526
pos: SourcePosition
26-
) extends Diagnostic(msg, pos, ERROR)
27+
) extends Diagnostic(msg, pos, ERROR):
28+
def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos)
2729

2830
/** A sticky error is an error that should not be hidden by backtracking and
2931
* trying some alternative path. Typically, errors issued after catching
@@ -46,7 +48,8 @@ object Diagnostic:
4648
class Info(
4749
msg: Message,
4850
pos: SourcePosition
49-
) extends Diagnostic(msg, pos, INFO)
51+
) extends Diagnostic(msg, pos, INFO):
52+
def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos)
5053

5154
abstract class ConditionalWarning(
5255
msg: Message,

compiler/src/dotty/tools/dotc/reporting/Message.scala

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ object Message {
1313
val nonSensicalStartTag: String = "<nonsensical>"
1414
val nonSensicalEndTag: String = "</nonsensical>"
1515

16-
/** This implicit conversion provides a fallback for error messages that have
17-
* not yet been ported to the new scheme. Comment out this `implicit def` to
18-
* see where old errors still exist
19-
*/
20-
implicit def toNoExplanation(str: => String): Message = NoExplanation(str)
21-
2216
def rewriteNotice(what: String, version: SourceVersion | Null = null, options: String = "")(using Context): String =
2317
if !ctx.mode.is(Mode.Interactive) then
2418
val sourceStr = if version != null then i"-source $version" else ""

compiler/src/dotty/tools/dotc/reporting/Reporter.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import dotty.tools.dotc.util.NoSourcePosition
1414
import java.io.{BufferedReader, PrintWriter}
1515
import scala.annotation.internal.sharable
1616
import scala.collection.mutable
17+
import core.Decorators.toMessage
1718

1819
object Reporter {
1920
/** Convert a SimpleReporter into a real Reporter */
@@ -218,7 +219,7 @@ abstract class Reporter extends interfaces.ReporterResult {
218219
for (settingName, count) <- unreportedWarnings do
219220
val were = if count == 1 then "was" else "were"
220221
val msg = s"there $were ${countString(count, settingName.tail + " warning")}; re-run with $settingName for details"
221-
report(Warning(msg, NoSourcePosition))
222+
report(Warning(msg.toMessage, NoSourcePosition))
222223

223224
/** Print the summary of warnings and errors */
224225
def printSummary()(using Context): Unit = {

0 commit comments

Comments
 (0)