@@ -77,10 +77,11 @@ trait MessageRendering {
7777 * -- Error: source.scala ---------------------
7878 * ```
7979 */
80- private def boxTitle (title : String )(using Context , Level , Offset ): String =
80+ private def boxTitle (title : String , isSubtitle : Boolean = false )(using Context , Level , Offset ): String =
8181 val pageWidth = ctx.settings.pageWidth.value
8282 val line = " -" * (pageWidth - title.length - 4 )
83- hl(s " -- $title $line" )
83+ val starter = if isSubtitle then " .." else " --"
84+ hl(s " $starter $title $line" )
8485
8586 /** The position markers aligned under the error
8687 *
@@ -169,7 +170,8 @@ trait MessageRendering {
169170 private def posStr (
170171 pos : SourcePosition ,
171172 message : Message ,
172- diagnosticString : String
173+ diagnosticString : String ,
174+ isSubdiag : Boolean = false
173175 )(using Context , Level , Offset ): String =
174176 assert(
175177 message.errorId.isActive,
@@ -191,7 +193,7 @@ trait MessageRendering {
191193 val title =
192194 if fileAndPos.isEmpty then s " $errId$kind: " // this happens in dotty.tools.repl.ScriptedTests // TODO add name of source or remove `:` (and update test files)
193195 else s " $errId$kind: $fileAndPos"
194- boxTitle(title)
196+ boxTitle(title, isSubtitle = isSubdiag )
195197 })
196198 else " "
197199 end posStr
@@ -232,6 +234,18 @@ trait MessageRendering {
232234 if origin.nonEmpty then
233235 addHelp(" origin=" )(origin)
234236
237+ // adjust a pos at EOF if preceded by newline
238+ private def adjust (pos : SourcePosition ): SourcePosition =
239+ if pos.span.isSynthetic
240+ && pos.span.isZeroExtent
241+ && pos.span.exists
242+ && pos.span.start == pos.source.length
243+ && pos.source(pos.span.start - 1 ) == '\n '
244+ then
245+ pos.withSpan(pos.span.shift(- 1 ))
246+ else
247+ pos
248+
235249 /** The whole message rendered from `dia.msg`.
236250 *
237251 * For a position in an inline expansion, choose `pos1`
@@ -252,17 +266,6 @@ trait MessageRendering {
252266 *
253267 */
254268 def messageAndPos (dia : Diagnostic )(using Context ): String =
255- // adjust a pos at EOF if preceded by newline
256- def adjust (pos : SourcePosition ): SourcePosition =
257- if pos.span.isSynthetic
258- && pos.span.isZeroExtent
259- && pos.span.exists
260- && pos.span.start == pos.source.length
261- && pos.source(pos.span.start - 1 ) == '\n '
262- then
263- pos.withSpan(pos.span.shift(- 1 ))
264- else
265- pos
266269 val msg = dia.msg
267270 val pos = dia.pos
268271 val pos1 = adjust(pos.nonInlined) // innermost pos contained by call.pos
@@ -296,6 +299,9 @@ trait MessageRendering {
296299 sb.append(EOL ).append(endBox)
297300 end if
298301 else sb.append(msg.message)
302+
303+ dia.getSubdiags.foreach(addSubdiagnostic(sb, _))
304+
299305 if dia.isVerbose then
300306 appendFilterHelp(dia, sb)
301307
@@ -313,6 +319,20 @@ trait MessageRendering {
313319 sb.toString
314320 end messageAndPos
315321
322+ private def addSubdiagnostic (sb : StringBuilder , subdiag : Subdiagnostic )(using Context , Level , Offset ): Unit =
323+ val pos1 = adjust(subdiag.pos)
324+ val msg = subdiag.msg
325+ assert(pos1.exists && pos1.source.file.exists)
326+
327+ val posString = posStr(pos1, msg, " Note" , isSubdiag = true )
328+ val (srcBefore, srcAfter, offset) = sourceLines(pos1)
329+ val marker = positionMarker(pos1)
330+ val err = errorMsg(pos1, msg.message)
331+
332+ val diagText = (posString :: srcBefore ::: marker :: err :: srcAfter).mkString(EOL )
333+ sb.append(EOL )
334+ sb.append(diagText)
335+
316336 private def hl (str : String )(using Context , Level ): String =
317337 summon[Level ].value match
318338 case interfaces.Diagnostic .ERROR => Red (str).show
0 commit comments