@@ -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
- import ast ._
9
+ import ast ._ , tpd . *
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,62 @@ 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
+ extension (tree : Tree ) def summaryString : String = tree match
145
+ case Literal (const) => s " Literal( $const) "
146
+ case Ident (name) => s " Ident( ${name.decode}) "
147
+ case Select (qual, name) => s " Select( ${qual.summaryString}, ${name.decode}) "
148
+ case tree : NameTree => (if tree.isType then " type " else " " ) + tree.name.decode
149
+ case tree => s " ${tree.className}${if tree.symbol.exists then s " ( ${tree.symbol}) " else " " }"
150
+
151
+ val info1 = formatExplain(List (
152
+ " while compiling" -> ctx.compilationUnit,
153
+ " during phase" -> ctx.phase.prevMega,
154
+ " mode" -> ctx.mode,
155
+ " library version" -> scala.util.Properties .versionString,
156
+ " compiler version" -> dotty.tools.dotc.config.Properties .versionString,
157
+ " settings" -> settings.map(s => if s.value == " " then s " ${s.name} \"\" " else s " ${s.name} ${s.value}" ).mkString(" " ),
158
+ ))
159
+ val symbolInfos = if sym eq NoSymbol then List (" symbol" -> sym) else List (
160
+ " symbol" -> sym.showLocated,
161
+ " symbol definition" -> s " ${sym.showDcl} (a ${sym.className}) " ,
162
+ " symbol package" -> sym.enclosingPackageClass.fullName,
163
+ " symbol owners" -> sym.showExtendedLocation,
164
+ )
165
+ val info2 = formatExplain(List (
166
+ " tree" -> tree.summaryString,
167
+ " tree position" -> (if pos.exists then s " $path: ${pos.line + 1 }: ${pos.column}" else s " $path:<unknown> " ),
168
+ " tree type" -> tree.typeOpt.show,
169
+ ) ::: symbolInfos ::: List (
170
+ " call site" -> s " ${site.showLocated} in ${site.enclosingPackageClass}"
171
+ ))
172
+ val context_s = try
173
+ s """ == Source file context for tree position ==
174
+ |
175
+ | ${messageRendering.messageAndPos(Diagnostic .Error (" " , pos))}""" .stripMargin
176
+ catch case _ : Exception => " <Cannot read source file>"
177
+ s """
178
+ | $errorMessage
179
+ |
180
+ | An unhandled exception was thrown in the compiler. Please file a crash
181
+ | report here: https://github.com/lampepfl/dotty/issues/new/choose
182
+ |
183
+ | $info1
184
+ |
185
+ | $info2
186
+ |
187
+ | $context_s""" .stripMargin
188
+ } catch case _ : Throwable => errorMessage // don't introduce new errors trying to report errors, so swallow exceptions
132
189
end report
0 commit comments