@@ -4,13 +4,12 @@ import reporting._
4
4
import Diagnostic ._
5
5
import util .{SourcePosition , NoSourcePosition , SrcPos }
6
6
import core ._
7
- import Contexts ._ , Symbols ._ , Decorators ._
7
+ import Contexts ._ , Flags . * , Symbols ._ , Decorators ._
8
8
import config .SourceVersion
9
9
import ast ._
10
10
import config .Feature .sourceVersion
11
11
import java .lang .System .currentTimeMillis
12
12
13
-
14
13
object report :
15
14
16
15
/** For sending messages that are printed only if -verbose is set */
@@ -129,4 +128,64 @@ object report:
129
128
case Nil => pos
130
129
recur(pos.sourcePos, tpd.enclosingInlineds)
131
130
131
+ private object messageRendering extends MessageRendering
132
+
133
+ // Should only be called from Run#enrichErrorMessage.
134
+ def enrichErrorMessage (errorMessage : String )(using Context ): String = try {
135
+ def formatExplain (pairs : List [(String , Any )]) = pairs.map((k, v) => f " $k%20s: $v" ).mkString(" \n " )
136
+
137
+ val settings = ctx.settings.userSetSettings(ctx.settingsState).sortBy(_.name)
138
+ val tree = ctx.tree
139
+ val sym = tree.symbol
140
+ val pos = tree.sourcePos
141
+ val path = pos.source.path
142
+ val site = ctx.outersIterator.map(_.owner).filter(sym => ! sym.exists || sym.isClass || sym.is(Method )).next()
143
+
144
+ import untpd .*
145
+ extension (tree : Tree ) def summaryString : String = tree match
146
+ case Literal (const) => s " Literal( $const) "
147
+ case Ident (name) => s " Ident( ${name.decode}) "
148
+ case Select (qual, name) => s " Select( ${qual.summaryString}, ${name.decode}) "
149
+ case tree : NameTree => (if tree.isType then " type " else " " ) + tree.name.decode
150
+ case tree => s " ${tree.className}${if tree.symbol.exists then s " ( ${tree.symbol}) " else " " }"
151
+
152
+ val info1 = formatExplain(List (
153
+ " while compiling" -> ctx.compilationUnit,
154
+ " during phase" -> ctx.phase.prevMega,
155
+ " mode" -> ctx.mode,
156
+ " library version" -> scala.util.Properties .versionString,
157
+ " compiler version" -> dotty.tools.dotc.config.Properties .versionString,
158
+ " settings" -> settings.map(s => if s.value == " " then s " ${s.name} \"\" " else s " ${s.name} ${s.value}" ).mkString(" " ),
159
+ ))
160
+ val symbolInfos = if sym eq NoSymbol then List (" symbol" -> sym) else List (
161
+ " symbol" -> sym.showLocated,
162
+ " symbol definition" -> s " ${sym.showDcl} (a ${sym.className}) " ,
163
+ " symbol package" -> sym.enclosingPackageClass.fullName,
164
+ " symbol owners" -> sym.showExtendedLocation,
165
+ )
166
+ val info2 = formatExplain(List (
167
+ " tree" -> tree.summaryString,
168
+ " tree position" -> (if pos.exists then s " $path: ${pos.line + 1 }: ${pos.column}" else s " $path:<unknown> " ),
169
+ " tree type" -> tree.typeOpt.show,
170
+ ) ::: symbolInfos ::: List (
171
+ " call site" -> s " ${site.showLocated} in ${site.enclosingPackageClass}"
172
+ ))
173
+ val context_s = try
174
+ s """ == Source file context for tree position ==
175
+ |
176
+ | ${messageRendering.messageAndPos(Diagnostic .Error (" " , pos))}""" .stripMargin
177
+ catch case _ : Exception => " <Cannot read source file>"
178
+ s """
179
+ | $errorMessage
180
+ |
181
+ | An unhandled exception was thrown in the compiler.
182
+ | Please file a crash report here:
183
+ | https://github.com/lampepfl/dotty/issues/new/choose
184
+ |
185
+ | $info1
186
+ |
187
+ | $info2
188
+ |
189
+ | $context_s""" .stripMargin
190
+ } catch case _ : Throwable => errorMessage // don't introduce new errors trying to report errors, so swallow exceptions
132
191
end report
0 commit comments