Skip to content

Commit 93d3f12

Browse files
committed
Make sure messages are lazily evaluated until report in Reporter
1 parent 28c2e04 commit 93d3f12

File tree

5 files changed

+93
-26
lines changed

5 files changed

+93
-26
lines changed

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@ trait Reporting { this: Context =>
3838
reporter.report(new Info(msg, pos))
3939

4040
def deprecationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
41-
reporter.report(msg.deprecationWarning(pos))
41+
reporter.report(new DeprecationWarning(msg, pos))
4242

4343
def migrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
44-
reporter.report(msg.migrationWarning(pos))
44+
reporter.report(new MigrationWarning(msg, pos))
4545

4646
def uncheckedWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
47-
reporter.report(msg.uncheckedWarning(pos))
47+
reporter.report(new UncheckedWarning(msg, pos))
4848

4949
def featureWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
50-
reporter.report(msg.featureWarning(pos))
50+
reporter.report(new FeatureWarning(msg, pos))
5151

5252
def featureWarning(feature: String, featureDescription: String, isScala2Feature: Boolean,
5353
featureUseSite: Symbol, required: Boolean, pos: SourcePosition): Unit = {
@@ -73,23 +73,27 @@ trait Reporting { this: Context =>
7373
}
7474

7575
def warning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
76-
reporter.report(msg.warning(pos))
76+
reporter.report(new Warning(msg, pos))
7777

7878
def strictWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
7979
if (this.settings.strict.value) error(msg, pos)
80-
else warning(msg.mapMsg(_ + "\n(This would be an error under strict mode)"), pos)
80+
else reporter.report {
81+
new ExtendMessage(() => msg)(_ + "\n(This would be an error under strict mode)").warning(pos)
82+
}
8183

8284
def error(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
83-
reporter.report(msg.error(pos))
85+
reporter.report(new Error(msg, pos))
8486

8587
def errorOrMigrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
8688
if (ctx.scala2Mode) migrationWarning(msg, pos) else error(msg, pos)
8789

8890
def restrictionError(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit =
89-
error(msg.mapMsg(m => s"Implementation restriction: $m"), pos)
91+
reporter.report {
92+
new ExtendMessage(() => msg)(m => s"Implementation restriction: $m").error(pos)
93+
}
9094

9195
def incompleteInputError(msg: Message, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit =
92-
reporter.incomplete(msg.error(pos))(ctx)
96+
reporter.incomplete(new Error(msg, pos))(ctx)
9397

9498
/** Log msg if settings.log contains the current phase.
9599
* See [[config.CompilerCommand#explainAdvanced]] for the exact meaning of
@@ -236,7 +240,7 @@ abstract class Reporter extends interfaces.ReporterResult {
236240
override def default(key: String) = 0
237241
}
238242

239-
def report(d: MessageContainer)(implicit ctx: Context): Unit =
243+
def report(d: => MessageContainer)(implicit ctx: Context): Unit =
240244
if (!isHidden(d)) {
241245
doReport(d)(ctx.addMode(Mode.Printing))
242246
d match {

src/dotty/tools/dotc/reporting/StoreReporter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class StoreReporter(outer: Reporter) extends Reporter {
3131

3232
override def flush()(implicit ctx: Context) =
3333
if (infos != null) {
34-
infos foreach ctx.reporter.report
34+
infos.foreach(ctx.reporter.report(_))
3535
infos = null
3636
}
3737

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

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package diagnostic
66
import util.SourcePosition
77
import core.Contexts.Context
88

9+
import messages._
10+
911
object Message {
1012
/** This implicit conversion provides a fallback for error messages that have
1113
* not yet been ported to the new scheme. Comment out this `implicit def` to
@@ -20,6 +22,13 @@ object Message {
2022
* into a `MessageContainer` which contains the log level and can later be
2123
* consumed by a subclass of `Reporter`.
2224
*
25+
* NOTE: you should not be persisting messages. Most messages take an implicit
26+
* `Context` and these contexts weigh in at about 4mb per instance, as such
27+
* persisting these will result in a memory leak.
28+
*
29+
* Instead use the `persist` method to create an instance that does not keep a
30+
* reference to these contexts.
31+
*
2332
* @param errorId a unique number identifying the message, this will later be
2433
* used to reference documentation online
2534
*/
@@ -47,45 +56,62 @@ abstract class Message(val errorId: Int) { self =>
4756
*/
4857
def explanation: String
4958

50-
/** It is possible to map `msg` to add details, this is at the loss of
51-
* precision since the type of the resulting `Message` won't be original
52-
* extending class
53-
*
54-
* @return a `Message` with the mapped message
59+
/** The implicit `Context` in messages is a large thing that we don't want
60+
* persisted. This method gets around that by duplicating the message
61+
* without the implicit context being passed along.
5562
*/
56-
def mapMsg(f: String => String) = new Message(errorId) {
57-
val msg = f(self.msg)
63+
def persist: Message = new Message (errorId) {
64+
val msg = self.msg
65+
val kind = self.kind
66+
val explanation = self.explanation
67+
}
68+
}
69+
70+
/** An extended message keeps the contained message from being evaluated, while
71+
* allowing for extension for the `msg` string
72+
*
73+
* This is useful when we need to add additional information to an existing
74+
* message.
75+
*/
76+
class ExtendMessage(_msg: () => Message)(f: String => String) { self =>
77+
lazy val msg = f(_msg().msg)
78+
lazy val kind = _msg().kind
79+
lazy val explanation = _msg().explanation
80+
lazy val errorId = _msg().errorId
81+
82+
private def toMessage = new Message(errorId) {
83+
val msg = self.msg
5884
val kind = self.kind
5985
val explanation = self.explanation
6086
}
6187

6288
/** Enclose this message in an `Error` container */
6389
def error(pos: SourcePosition) =
64-
new Error(self, pos)
90+
new Error(toMessage, pos)
6591

6692
/** Enclose this message in an `Warning` container */
6793
def warning(pos: SourcePosition) =
68-
new Warning(self, pos)
94+
new Warning(toMessage, pos)
6995

7096
/** Enclose this message in an `Info` container */
7197
def info(pos: SourcePosition) =
72-
new Info(self, pos)
98+
new Info(toMessage, pos)
7399

74100
/** Enclose this message in an `FeatureWarning` container */
75101
def featureWarning(pos: SourcePosition) =
76-
new FeatureWarning(self, pos)
102+
new FeatureWarning(toMessage, pos)
77103

78104
/** Enclose this message in an `UncheckedWarning` container */
79105
def uncheckedWarning(pos: SourcePosition) =
80-
new UncheckedWarning(self, pos)
106+
new UncheckedWarning(toMessage, pos)
81107

82108
/** Enclose this message in an `DeprecationWarning` container */
83109
def deprecationWarning(pos: SourcePosition) =
84-
new DeprecationWarning(self, pos)
110+
new DeprecationWarning(toMessage, pos)
85111

86112
/** Enclose this message in an `MigrationWarning` container */
87113
def migrationWarning(pos: SourcePosition) =
88-
new MigrationWarning(self, pos)
114+
new MigrationWarning(toMessage, pos)
89115
}
90116

91117
/** The fallback `Message` containing no explanation and having no `kind` */

src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ object messages {
282282
val explanation = ""
283283
}
284284

285-
case class EarlyDefinitionsNotSupported()(implicit ctx:Context)
285+
case class EarlyDefinitionsNotSupported()(implicit ctx: Context)
286286
extends Message(9) {
287287
val kind = "Syntax"
288288
val msg = "early definitions are not supported; use trait parameters instead"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dotty.tools
2+
package dotc
3+
package reporting
4+
5+
import org.junit.Assert._
6+
import org.junit.Test
7+
8+
import core.Contexts._
9+
10+
import test.DottyTest
11+
12+
import diagnostic.{ Message, MessageContainer, ExtendMessage }
13+
14+
class TestMessageLaziness extends DottyTest {
15+
ctx = ctx.fresh.setReporter(new NonchalantReporter)
16+
17+
class NonchalantReporter(implicit ctx: Context) extends Reporter
18+
with UniqueMessagePositions with HideNonSensicalMessages {
19+
def doReport(d: MessageContainer)(implicit ctx: Context) = ???
20+
21+
override def report(d: => MessageContainer)(implicit ctx: Context) = ()
22+
}
23+
24+
case class LazyError() extends Message(1000) {
25+
throw new Error("Didn't stay lazy.")
26+
27+
val kind = "Test"
28+
val msg = "Please don't blow up"
29+
val explanation = ""
30+
}
31+
32+
@Test def assureLazy =
33+
ctx.error(LazyError())
34+
35+
@Test def assureLazyExtendMessage =
36+
ctx.strictWarning(LazyError())
37+
}

0 commit comments

Comments
 (0)