Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions compiler/src/dotty/tools/dotc/cc/SepCheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -461,10 +461,19 @@ class SepCheck(checker: CheckCaptures.CheckerAPI) extends tpd.TreeTraverser:
*/
def consumeError(ref: Capability, loc: (SrcPos, TypeRole), pos: SrcPos)(using Context): Unit =
val (locPos, role) = loc
report.error(
em"""Separation failure: Illegal access to $ref, which was ${role.howConsumed}
|on line ${locPos.line + 1} and therefore is no longer available.""",
pos)
val parts = List(
reporting.Diagnostic.DiagnosticPart(
"The capability was consumed here.",
locPos.sourcePos,
isPrimary = false
),
reporting.Diagnostic.DiagnosticPart(
"Then, it was used here",
pos.sourcePos,
isPrimary = true
)
)
report.error(reporting.UseAfterConsume(ref, role.howConsumed), pos, parts)

/** Report a failure where a capability is consumed in a loop.
* @param ref the capability
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/report.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ object report:
ctx.reporter.report(new Error(msg, fullPos))
if ctx.settings.YdebugError.value then Thread.dumpStack()

/** Report an error with multi-span messages. */
def error(msg: Message, pos: SrcPos, parts: List[Diagnostic.DiagnosticPart])(using Context): Unit =
val fullPos = addInlineds(pos)
ctx.reporter.report(new Error(msg, fullPos, parts))
if ctx.settings.YdebugError.value then Thread.dumpStack()

def error(msg: => String, pos: SrcPos)(using Context): Unit =
error(msg.toMessage, pos)

Expand Down
66 changes: 41 additions & 25 deletions compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import core.Decorators.toMessage

object Diagnostic:

/** A part of a multi-span diagnostic, associating text with a source position.
* @param text the message text for this part
* @param srcPos the source position where this part applies
* @param isPrimary whether this is the primary message (true) or a secondary note (false)
*/
case class DiagnosticPart(text: String, srcPos: SourcePosition, isPrimary: Boolean)

def shouldExplain(dia: Diagnostic)(using Context): Boolean =
ctx.settings.explain.value && dia.msg.canExplain
|| ctx.settings.explainTypes.value && dia.msg.isInstanceOf[TypeMismatchMsg]
Expand All @@ -21,8 +28,9 @@ object Diagnostic:
// `Diagnostics to be consumed by `Reporter` ---------------------- //
class Error(
msg: Message,
pos: SourcePosition
) extends Diagnostic(msg, pos, ERROR):
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends Diagnostic(msg, pos, ERROR, parts):
def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos)

/** A sticky error is an error that should not be hidden by backtracking and
Expand All @@ -31,8 +39,9 @@ object Diagnostic:
*/
class StickyError(
msg: Message,
pos: SourcePosition
) extends Error(msg, pos)
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends Error(msg, pos, parts)

/** A Warning with an origin. The semantics of `origin` depend on the warning.
* For example, an unused import warning has an origin that specifies the unused selector.
Expand All @@ -45,65 +54,72 @@ object Diagnostic:

/** Lints are likely to be filtered. Provide extra axes for filtering by `-Wconf`.
*/
class LintWarning(msg: Message, pos: SourcePosition, origin: String = OriginWarning.NoOrigin)
extends Warning(msg, pos), OriginWarning(origin)
class LintWarning(msg: Message, pos: SourcePosition, origin: String = OriginWarning.NoOrigin, parts: List[DiagnosticPart] = Nil)
extends Warning(msg, pos, parts), OriginWarning(origin)

class Warning(
msg: Message,
pos: SourcePosition
) extends Diagnostic(msg, pos, WARNING) {
def toError: Error = new Error(msg, pos).tap(e => if isVerbose then e.setVerbose())
def toInfo: Info = new Info(msg, pos).tap(e => if isVerbose then e.setVerbose())
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends Diagnostic(msg, pos, WARNING, parts) {
def toError: Error = new Error(msg, pos, parts).tap(e => if isVerbose then e.setVerbose())
def toInfo: Info = new Info(msg, pos, parts).tap(e => if isVerbose then e.setVerbose())
def isSummarizedConditional(using Context): Boolean = false
}

class Info(
msg: Message,
pos: SourcePosition
) extends Diagnostic(msg, pos, INFO):
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends Diagnostic(msg, pos, INFO, parts):
def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos)

abstract class ConditionalWarning(
msg: Message,
pos: SourcePosition
) extends Warning(msg, pos) {
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends Warning(msg, pos, parts) {
def enablingOption(using Context): Setting[Boolean]
override def isSummarizedConditional(using Context): Boolean = !enablingOption.value
}

class FeatureWarning(
msg: Message,
pos: SourcePosition
) extends ConditionalWarning(msg, pos) {
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends ConditionalWarning(msg, pos, parts) {
def enablingOption(using Context): Setting[Boolean] = ctx.settings.feature
}

class UncheckedWarning(
msg: Message,
pos: SourcePosition
) extends ConditionalWarning(msg, pos) {
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends ConditionalWarning(msg, pos, parts) {
def enablingOption(using Context): Setting[Boolean] = ctx.settings.unchecked
}

class DeprecationWarning(msg: Message, pos: SourcePosition, origin: String)
extends ConditionalWarning(msg, pos), OriginWarning(origin):
class DeprecationWarning(msg: Message, pos: SourcePosition, origin: String, parts: List[DiagnosticPart] = Nil)
extends ConditionalWarning(msg, pos, parts), OriginWarning(origin):
def enablingOption(using Context): Setting[Boolean] = ctx.settings.deprecation

class ConfigurationWarning(msg: Message, pos: SourcePosition) extends ConditionalWarning(msg, pos):
class ConfigurationWarning(msg: Message, pos: SourcePosition, parts: List[DiagnosticPart] = Nil) extends ConditionalWarning(msg, pos, parts):
def enablingOption(using Context): Setting[Boolean] = ConfigurationWarning.setting
override def isSummarizedConditional(using Context): Boolean = false
object ConfigurationWarning:
private val setting = Setting.internal("-configuration", value = true)

class MigrationWarning(
msg: Message,
pos: SourcePosition
) extends Warning(msg, pos)
pos: SourcePosition,
parts: List[DiagnosticPart] = Nil
) extends Warning(msg, pos, parts)

class Diagnostic(
val msg: Message,
val pos: SourcePosition,
val level: Int
val level: Int,
val parts: List[Diagnostic.DiagnosticPart] = Nil
) extends interfaces.Diagnostic:
private var verbose: Boolean = false
def isVerbose: Boolean = verbose
Expand All @@ -117,6 +133,6 @@ class Diagnostic(
msg.message.replaceAll("\u001B\\[[;\\d]*m", "")
override def diagnosticRelatedInformation: JList[interfaces.DiagnosticRelatedInformation] =
Collections.emptyList()

override def toString: String = s"$getClass at $pos L${pos.line+1}: $message"
end Diagnostic

Loading
Loading