Skip to content

Commit 49ca74b

Browse files
committed
Diagnostic: only compute the stack trace when needed
Diagnostic extends Exception, but the stack trace is only used for debugging purposes in combination with ThrowingReporter when using either -Ycheck, -Ytest-pickler or scala3-staging. We make this explicit by adding Reporter#computeStackTraces which is queried in the constructor of Diagnostic.
1 parent 263eada commit 49ca74b

File tree

7 files changed

+36
-19
lines changed

7 files changed

+36
-19
lines changed

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

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import java.util.Optional
1313
import scala.util.chaining._
1414
import core.Decorators.toMessage
1515

16+
import scala.annotation.constructorOnly
17+
1618
object Diagnostic:
1719

1820
def shouldExplain(dia: Diagnostic)(using Context): Boolean =
@@ -24,8 +26,8 @@ object Diagnostic:
2426
class Error(
2527
msg: Message,
2628
pos: SourcePosition
27-
) extends Diagnostic(msg, pos, ERROR):
28-
def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos)
29+
)(using @constructorOnly ictx: Context) extends Diagnostic(msg, pos, ERROR):
30+
def this(str: => String, pos: SourcePosition)(using Context) = this(str.toMessage, pos)
2931

3032
/** A sticky error is an error that should not be hidden by backtracking and
3133
* trying some alternative path. Typically, errors issued after catching
@@ -34,62 +36,68 @@ object Diagnostic:
3436
class StickyError(
3537
msg: Message,
3638
pos: SourcePosition
37-
) extends Error(msg, pos)
39+
)(using @constructorOnly ictx: Context) extends Error(msg, pos)
3840

3941
class Warning(
4042
msg: Message,
4143
pos: SourcePosition
42-
) extends Diagnostic(msg, pos, WARNING) {
43-
def toError: Error = new Error(msg, pos).tap(e => if isVerbose then e.setVerbose())
44-
def toInfo: Info = new Info(msg, pos).tap(e => if isVerbose then e.setVerbose())
44+
)(using @constructorOnly ictx: Context) extends Diagnostic(msg, pos, WARNING) {
45+
def toError(using Context): Error = new Error(msg, pos).tap(e => if isVerbose then e.setVerbose())
46+
def toInfo(using Context): Info = new Info(msg, pos).tap(e => if isVerbose then e.setVerbose())
4547
def isSummarizedConditional(using Context): Boolean = false
4648
}
4749

4850
class Info(
4951
msg: Message,
5052
pos: SourcePosition
51-
) extends Diagnostic(msg, pos, INFO):
52-
def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos)
53+
)(using @constructorOnly ictx: Context) extends Diagnostic(msg, pos, INFO):
54+
def this(str: => String, pos: SourcePosition)(using Context) = this(str.toMessage, pos)
5355

5456
abstract class ConditionalWarning(
5557
msg: Message,
5658
pos: SourcePosition
57-
) extends Warning(msg, pos) {
59+
)(using @constructorOnly ictx: Context) extends Warning(msg, pos) {
5860
def enablingOption(using Context): Setting[Boolean]
5961
override def isSummarizedConditional(using Context): Boolean = !enablingOption.value
6062
}
6163

6264
class FeatureWarning(
6365
msg: Message,
6466
pos: SourcePosition
65-
) extends ConditionalWarning(msg, pos) {
67+
)(using @constructorOnly ictx: Context) extends ConditionalWarning(msg, pos) {
6668
def enablingOption(using Context): Setting[Boolean] = ctx.settings.feature
6769
}
6870

6971
class UncheckedWarning(
7072
msg: Message,
7173
pos: SourcePosition
72-
) extends ConditionalWarning(msg, pos) {
74+
)(using @constructorOnly ictx: Context) extends ConditionalWarning(msg, pos) {
7375
def enablingOption(using Context): Setting[Boolean] = ctx.settings.unchecked
7476
}
7577

7678
class DeprecationWarning(
7779
msg: Message,
7880
pos: SourcePosition
79-
) extends ConditionalWarning(msg, pos) {
81+
)(using @constructorOnly ictx: Context) extends ConditionalWarning(msg, pos) {
8082
def enablingOption(using Context): Setting[Boolean] = ctx.settings.deprecation
8183
}
8284

8385
class MigrationWarning(
8486
msg: Message,
8587
pos: SourcePosition
86-
) extends Warning(msg, pos)
88+
)(using @constructorOnly ictx: Context) extends Warning(msg, pos)
8789

8890
class Diagnostic(
8991
val msg: Message,
9092
val pos: SourcePosition,
9193
val level: Int
92-
) extends Exception with interfaces.Diagnostic:
94+
)(using @constructorOnly ictx: Context) extends Exception(
95+
// These are just the default values
96+
/*message =*/ null, /*cause =*/ null, /*enableSuppression =*/ true,
97+
98+
// Performance optimization: don't compute the stack trace unless requested by the reporter.
99+
/*writableStackTrace =*/ ictx.reporter.computeStackTraces
100+
) with interfaces.Diagnostic:
93101
private var verbose: Boolean = false
94102
def isVerbose: Boolean = verbose
95103
def setVerbose(): this.type =

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,4 +265,9 @@ abstract class Reporter extends interfaces.ReporterResult {
265265

266266
/** If this reporter buffers messages, all buffered messages, otherwise Nil */
267267
def pendingMessages(using Context): List[Diagnostic] = Nil
268+
269+
/** If true, Diagnostics created when `ctx.reporter eq this` will have their
270+
* stack traces filled in.
271+
*/
272+
def computeStackTraces: Boolean = false
268273
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import Diagnostic.Error
88
/**
99
* This class implements a Reporter that throws all errors and sends warnings and other
1010
* info to the underlying reporter.
11+
*
12+
* @param computeStackTraces If true, the thrown errors will have their stack traces filled in.
1113
*/
12-
class ThrowingReporter(reportInfo: Reporter) extends Reporter {
14+
class ThrowingReporter(reportInfo: Reporter, override val computeStackTraces: Boolean) extends Reporter {
1315
def doReport(dia: Diagnostic)(using Context): Unit = dia match {
1416
case _: Error => throw dia
1517
case _ => reportInfo.doReport(dia)

compiler/src/dotty/tools/dotc/transform/Pickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class Pickler extends Phase {
119119
testUnpickler(
120120
using ctx2
121121
.setPeriod(Period(ctx.runId + 1, ctx.base.typerPhase.id))
122-
.setReporter(new ThrowingReporter(ctx.reporter))
122+
.setReporter(new ThrowingReporter(ctx.reporter, computeStackTraces = true))
123123
.addMode(Mode.ReadPositions)
124124
.addMode(Mode.PrintShowExceptions))
125125
result

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class TreeChecker extends Phase with SymTransformer {
135135
val checkingCtx = ctx
136136
.fresh
137137
.addMode(Mode.ImplicitsEnabled)
138-
.setReporter(new ThrowingReporter(ctx.reporter))
138+
.setReporter(new ThrowingReporter(ctx.reporter, computeStackTraces = true))
139139

140140
val checker = inContext(ctx) {
141141
new Checker(previousPhases(phasesToRun.toList))

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2390,7 +2390,9 @@ trait Applications extends Compatibility {
23902390
val methodRefTree = ref(methodRef, needLoad = false)
23912391
val truncatedSym = methodRef.symbol.asTerm.copy(info = truncateExtension(methodRef.info))
23922392
val truncatedRefTree = untpd.TypedSplice(ref(truncatedSym)).withSpan(receiver.span)
2393-
val newCtx = ctx.fresh.setNewScope.setReporter(new reporting.ThrowingReporter(ctx.reporter))
2393+
val newCtx = ctx.fresh.setNewScope.setReporter(
2394+
// No need to compute stack traces since we discard all exceptions below.
2395+
new reporting.ThrowingReporter(ctx.reporter, computeStackTraces = false))
23942396

23952397
try
23962398
val appliedTree = inContext(newCtx) {

staging/src/scala/quoted/staging/QuoteDriver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ private class QuoteDriver(appClassloader: ClassLoader) extends Driver:
6666
private def setCompilerSettings(ctx: FreshContext, settings: Compiler.Settings): ctx.type =
6767
// An error in the generated code is a bug in the compiler
6868
// Setting the throwing reporter however will report any exception
69-
ctx.setReporter(new ThrowingReporter(ctx.reporter))
69+
ctx.setReporter(new ThrowingReporter(ctx.reporter, computeStackTraces = true))
7070

7171
end QuoteDriver

0 commit comments

Comments
 (0)