665 lines
33 KiB
HTML
665 lines
33 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="light sidebar-visible" dir="ltr">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>Diagnostic and subdiagnostic structs - Rust Compiler Development Guide</title>
|
|
|
|
|
|
<!-- Custom HTML head -->
|
|
|
|
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="#ffffff">
|
|
|
|
<link rel="icon" href="../favicon.svg">
|
|
<link rel="shortcut icon" href="../favicon.png">
|
|
<link rel="stylesheet" href="../css/variables.css">
|
|
<link rel="stylesheet" href="../css/general.css">
|
|
<link rel="stylesheet" href="../css/chrome.css">
|
|
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
|
|
<!-- Fonts -->
|
|
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
<!-- Provide site root and default themes to javascript -->
|
|
<script>
|
|
const path_to_root = "../";
|
|
const default_light_theme = "light";
|
|
const default_dark_theme = "navy";
|
|
</script>
|
|
<!-- Start loading toc.js asap -->
|
|
<script src="../toc.js"></script>
|
|
</head>
|
|
<body>
|
|
<div id="body-container">
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
<script>
|
|
try {
|
|
let theme = localStorage.getItem('mdbook-theme');
|
|
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
}
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
}
|
|
} catch (e) { }
|
|
</script>
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
<script>
|
|
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
let theme;
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
const html = document.documentElement;
|
|
html.classList.remove('light')
|
|
html.classList.add(theme);
|
|
html.classList.add("js");
|
|
</script>
|
|
|
|
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
<script>
|
|
let sidebar = null;
|
|
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
if (document.body.clientWidth >= 1080) {
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
sidebar = sidebar || 'visible';
|
|
} else {
|
|
sidebar = 'hidden';
|
|
}
|
|
sidebar_toggle.checked = sidebar === 'visible';
|
|
html.classList.remove('sidebar-visible');
|
|
html.classList.add("sidebar-" + sidebar);
|
|
</script>
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
<!-- populated by js -->
|
|
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
<noscript>
|
|
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
</noscript>
|
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
<div class="sidebar-resize-indicator"></div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
<div class="page">
|
|
<div id="menu-bar-hover-placeholder"></div>
|
|
<div id="menu-bar" class="menu-bar sticky">
|
|
<div class="left-buttons">
|
|
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
<i class="fa fa-bars"></i>
|
|
</label>
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
<i class="fa fa-paint-brush"></i>
|
|
</button>
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
</ul>
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<h1 class="menu-title">Rust Compiler Development Guide</h1>
|
|
|
|
<div class="right-buttons">
|
|
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
<i id="print-button" class="fa fa-print"></i>
|
|
</a>
|
|
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
|
|
<i id="git-repository-button" class="fa fa-github"></i>
|
|
</a>
|
|
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/master/src/diagnostics/diagnostic-structs.md" title="Suggest an edit" aria-label="Suggest an edit">
|
|
<i id="git-edit-button" class="fa fa-edit"></i>
|
|
</a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
</form>
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
<ul id="searchresults">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
<script>
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
});
|
|
</script>
|
|
|
|
<div id="content" class="content">
|
|
<main>
|
|
<h1 id="diagnostic-and-subdiagnostic-structs"><a class="header" href="#diagnostic-and-subdiagnostic-structs">Diagnostic and subdiagnostic structs</a></h1>
|
|
<p>rustc has three diagnostic traits that can be used to create diagnostics:
|
|
<code>Diagnostic</code>, <code>LintDiagnostic</code>, and <code>Subdiagnostic</code>. For simple diagnostics,
|
|
instead of using the <code>Diag</code> API to create and emit diagnostics,
|
|
derived impls can be used. They are only suitable for simple diagnostics that
|
|
don't require much logic in deciding whether or not to add additional
|
|
subdiagnostics.</p>
|
|
<p>Such diagnostic can be translated into
|
|
different languages and each has a slug that uniquely identifies the
|
|
diagnostic.</p>
|
|
<h2 id="derivediagnostic-and-derivelintdiagnostic"><a class="header" href="#derivediagnostic-and-derivelintdiagnostic"><code>#[derive(Diagnostic)]</code> and <code>#[derive(LintDiagnostic)]</code></a></h2>
|
|
<p>Consider the <a href="https://github.com/rust-lang/rust/blob/6201eabde85db854c1ebb57624be5ec699246b50/compiler/rustc_hir_analysis/src/errors.rs#L68-L77">definition</a> of the "field already declared" diagnostic
|
|
shown below:</p>
|
|
<pre><code class="language-rust ignore">#[derive(Diagnostic)]
|
|
#[diag(hir_analysis_field_already_declared, code = E0124)]
|
|
pub struct FieldAlreadyDeclared {
|
|
pub field_name: Ident,
|
|
#[primary_span]
|
|
#[label]
|
|
pub span: Span,
|
|
#[label(previous_decl_label)]
|
|
pub prev_span: Span,
|
|
}</code></pre>
|
|
<p><code>Diagnostic</code> can only be derived on structs and enums.
|
|
Attributes that are placed on the type for structs are placed on each
|
|
variants for enums (or vice versa). Each <code>Diagnostic</code> has to have one
|
|
attribute, <code>#[diag(...)]</code>, applied to the struct or each enum variant.</p>
|
|
<p>If an error has an error code (e.g. "E0624"), then that can be specified using
|
|
the <code>code</code> sub-attribute. Specifying a <code>code</code> isn't mandatory, but if you are
|
|
porting a diagnostic that uses <code>Diag</code> to use <code>Diagnostic</code>
|
|
then you should keep the code if there was one.</p>
|
|
<p><code>#[diag(..)]</code> must provide a slug as the first positional argument (a path to an
|
|
item in <code>rustc_errors::fluent::*</code>). A slug uniquely identifies the diagnostic
|
|
and is also how the compiler knows what error message to emit (in the default
|
|
locale of the compiler, or in the locale requested by the user). See
|
|
<a href="./translation.html">translation documentation</a> to learn more about how
|
|
translatable error messages are written and how slug items are generated.</p>
|
|
<p>In our example, the Fluent message for the "field already declared" diagnostic
|
|
looks like this:</p>
|
|
<pre><code class="language-fluent">hir_analysis_field_already_declared =
|
|
field `{$field_name}` is already declared
|
|
.label = field already declared
|
|
.previous_decl_label = `{$field_name}` first declared here
|
|
</code></pre>
|
|
<p><code>hir_analysis_field_already_declared</code> is the slug from our example and is followed
|
|
by the diagnostic message.</p>
|
|
<p>Every field of the <code>Diagnostic</code> which does not have an annotation is
|
|
available in Fluent messages as a variable, like <code>field_name</code> in the example
|
|
above. Fields can be annotated <code>#[skip_arg]</code> if this is undesired.</p>
|
|
<p>Using the <code>#[primary_span]</code> attribute on a field (that has type <code>Span</code>)
|
|
indicates the primary span of the diagnostic which will have the main message
|
|
of the diagnostic.</p>
|
|
<p>Diagnostics are more than just their primary message, they often include
|
|
labels, notes, help messages and suggestions, all of which can also be
|
|
specified on a <code>Diagnostic</code>.</p>
|
|
<p><code>#[label]</code>, <code>#[help]</code>, <code>#[warning]</code> and <code>#[note]</code> can all be applied to fields which have the
|
|
type <code>Span</code>. Applying any of these attributes will create the corresponding
|
|
subdiagnostic with that <code>Span</code>. These attributes will look for their
|
|
diagnostic message in a Fluent attribute attached to the primary Fluent
|
|
message. In our example, <code>#[label]</code> will look for
|
|
<code>hir_analysis_field_already_declared.label</code> (which has the message "field already
|
|
declared"). If there is more than one subdiagnostic of the same type, then
|
|
these attributes can also take a value that is the attribute name to look for
|
|
(e.g. <code>previous_decl_label</code> in our example).</p>
|
|
<p>Other types have special behavior when used in a <code>Diagnostic</code> derive:</p>
|
|
<ul>
|
|
<li>Any attribute applied to an <code>Option<T></code> will only emit a
|
|
subdiagnostic if the option is <code>Some(..)</code>.</li>
|
|
<li>Any attribute applied to a <code>Vec<T></code> will be repeated for each element of the
|
|
vector.</li>
|
|
</ul>
|
|
<p><code>#[help]</code>, <code>#[warning]</code> and <code>#[note]</code> can also be applied to the struct itself, in which case
|
|
they work exactly like when applied to fields except the subdiagnostic won't
|
|
have a <code>Span</code>. These attributes can also be applied to fields of type <code>()</code> for
|
|
the same effect, which when combined with the <code>Option</code> type can be used to
|
|
represent optional <code>#[note]</code>/<code>#[help]</code>/<code>#[warning]</code> subdiagnostics.</p>
|
|
<p>Suggestions can be emitted using one of four field attributes:</p>
|
|
<ul>
|
|
<li><code>#[suggestion(slug, code = "...", applicability = "...")]</code></li>
|
|
<li><code>#[suggestion_hidden(slug, code = "...", applicability = "...")]</code></li>
|
|
<li><code>#[suggestion_short(slug, code = "...", applicability = "...")]</code></li>
|
|
<li><code>#[suggestion_verbose(slug, code = "...", applicability = "...")]</code></li>
|
|
</ul>
|
|
<p>Suggestions must be applied on either a <code>Span</code> field or a <code>(Span, MachineApplicability)</code> field. Similarly to other field attributes, the slug
|
|
specifies the Fluent attribute with the message and defaults to the equivalent
|
|
of <code>.suggestion</code>. <code>code</code> specifies the code that should be suggested as a
|
|
replacement and is a format string (e.g. <code>{field_name}</code> would be replaced by
|
|
the value of the <code>field_name</code> field of the struct), not a Fluent identifier.
|
|
<code>applicability</code> can be used to specify the applicability in the attribute, it
|
|
cannot be used when the field's type contains an <code>Applicability</code>.</p>
|
|
<p>In the end, the <code>Diagnostic</code> derive will generate an implementation of
|
|
<code>Diagnostic</code> that looks like the following:</p>
|
|
<pre><code class="language-rust ignore">impl<'a, G: EmissionGuarantee> Diagnostic<'a> for FieldAlreadyDeclared {
|
|
fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
|
|
let mut diag = Diag::new(dcx, level, fluent::hir_analysis_field_already_declared);
|
|
diag.set_span(self.span);
|
|
diag.span_label(
|
|
self.span,
|
|
fluent::hir_analysis_label
|
|
);
|
|
diag.span_label(
|
|
self.prev_span,
|
|
fluent::hir_analysis_previous_decl_label
|
|
);
|
|
diag
|
|
}
|
|
}</code></pre>
|
|
<p>Now that we've defined our diagnostic, how do we <a href="https://github.com/rust-lang/rust/blob/f1112099eba41abadb6f921df7edba70affe92c5/compiler/rustc_hir_analysis/src/collect.rs#L823-L827">use it</a>? It's quite
|
|
straightforward, just create an instance of the struct and pass it to
|
|
<code>emit_err</code> (or <code>emit_warning</code>):</p>
|
|
<pre><code class="language-rust ignore">tcx.dcx().emit_err(FieldAlreadyDeclared {
|
|
field_name: f.ident,
|
|
span: f.span,
|
|
prev_span,
|
|
});</code></pre>
|
|
<h3 id="reference"><a class="header" href="#reference">Reference</a></h3>
|
|
<p><code>#[derive(Diagnostic)]</code> and <code>#[derive(LintDiagnostic)]</code> support the
|
|
following attributes:</p>
|
|
<ul>
|
|
<li><code>#[diag(slug, code = "...")]</code>
|
|
<ul>
|
|
<li><em>Applied to struct or enum variant.</em></li>
|
|
<li><em>Mandatory</em></li>
|
|
<li>Defines the text and error code to be associated with the diagnostic.</li>
|
|
<li>Slug (<em>Mandatory</em>)
|
|
<ul>
|
|
<li>Uniquely identifies the diagnostic and corresponds to its Fluent message,
|
|
mandatory.</li>
|
|
<li>A path to an item in <code>rustc_errors::fluent</code>, e.g.
|
|
<code>rustc_errors::fluent::hir_analysis_field_already_declared</code>
|
|
(<code>rustc_errors::fluent</code> is implicit in the attribute, so just
|
|
<code>hir_analysis_field_already_declared</code>).</li>
|
|
<li>See <a href="./translation.html">translation documentation</a>.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>code = "..."</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li>Specifies the error code.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[note]</code> or <code>#[note(slug)]</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to struct or struct fields of type <code>Span</code>, <code>Option<()></code> or <code>()</code>.</em></li>
|
|
<li>Adds a note subdiagnostic.</li>
|
|
<li>Value is a path to an item in <code>rustc_errors::fluent</code> for the note's
|
|
message.
|
|
<ul>
|
|
<li>Defaults to equivalent of <code>.note</code>.</li>
|
|
</ul>
|
|
</li>
|
|
<li>If applied to a <code>Span</code> field, creates a spanned note.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[help]</code> or <code>#[help(slug)]</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to struct or struct fields of type <code>Span</code>, <code>Option<()></code> or <code>()</code>.</em></li>
|
|
<li>Adds a help subdiagnostic.</li>
|
|
<li>Value is a path to an item in <code>rustc_errors::fluent</code> for the note's
|
|
message.
|
|
<ul>
|
|
<li>Defaults to equivalent of <code>.help</code>.</li>
|
|
</ul>
|
|
</li>
|
|
<li>If applied to a <code>Span</code> field, creates a spanned help.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[label]</code> or <code>#[label(slug)]</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to <code>Span</code> fields.</em></li>
|
|
<li>Adds a label subdiagnostic.</li>
|
|
<li>Value is a path to an item in <code>rustc_errors::fluent</code> for the note's
|
|
message.
|
|
<ul>
|
|
<li>Defaults to equivalent of <code>.label</code>.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[warning]</code> or <code>#[warning(slug)]</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to struct or struct fields of type <code>Span</code>, <code>Option<()></code> or <code>()</code>.</em></li>
|
|
<li>Adds a warning subdiagnostic.</li>
|
|
<li>Value is a path to an item in <code>rustc_errors::fluent</code> for the note's
|
|
message.
|
|
<ul>
|
|
<li>Defaults to equivalent of <code>.warn</code>.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]</code>
|
|
(<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to <code>(Span, MachineApplicability)</code> or <code>Span</code> fields.</em></li>
|
|
<li>Adds a suggestion subdiagnostic.</li>
|
|
<li>Slug (<em>Mandatory</em>)
|
|
<ul>
|
|
<li>A path to an item in <code>rustc_errors::fluent</code>, e.g.
|
|
<code>rustc_errors::fluent::hir_analysis_field_already_declared</code>
|
|
(<code>rustc_errors::fluent</code> is implicit in the attribute, so just
|
|
<code>hir_analysis_field_already_declared</code>). Fluent attributes for all messages
|
|
exist as top-level items in that module (so <code>hir_analysis_message.attr</code> is just
|
|
<code>attr</code>).</li>
|
|
<li>See <a href="./translation.html">translation documentation</a>.</li>
|
|
<li>Defaults to <code>rustc_errors::fluent::_subdiag::suggestion</code> (or</li>
|
|
<li><code>.suggestion</code> in Fluent).</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>code = "..."</code>/<code>code("...", ...)</code> (<em>Mandatory</em>)
|
|
<ul>
|
|
<li>One or multiple format strings indicating the code to be suggested as a
|
|
replacement. Multiple values signify multiple possible replacements.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>applicability = "..."</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li>String which must be one of <code>machine-applicable</code>, <code>maybe-incorrect</code>,
|
|
<code>has-placeholders</code> or <code>unspecified</code>.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[subdiagnostic]</code>
|
|
<ul>
|
|
<li><em>Applied to a type that implements <code>Subdiagnostic</code> (from
|
|
<code>#[derive(Subdiagnostic)]</code>).</em></li>
|
|
<li>Adds the subdiagnostic represented by the subdiagnostic struct.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[primary_span]</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to <code>Span</code> fields on <code>Subdiagnostic</code>s. Not used for <code>LintDiagnostic</code>s.</em></li>
|
|
<li>Indicates the primary span of the diagnostic.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[skip_arg]</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to any field.</em></li>
|
|
<li>Prevents the field from being provided as a diagnostic argument.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
<h2 id="derivesubdiagnostic"><a class="header" href="#derivesubdiagnostic"><code>#[derive(Subdiagnostic)]</code></a></h2>
|
|
<p>It is common in the compiler to write a function that conditionally adds a
|
|
specific subdiagnostic to an error if it is applicable. Oftentimes these
|
|
subdiagnostics could be represented using a diagnostic struct even if the
|
|
overall diagnostic could not. In this circumstance, the <code>Subdiagnostic</code>
|
|
derive can be used to represent a partial diagnostic (e.g a note, label, help or
|
|
suggestion) as a struct.</p>
|
|
<p>Consider the <a href="https://github.com/rust-lang/rust/blob/f1112099eba41abadb6f921df7edba70affe92c5/compiler/rustc_hir_analysis/src/errors.rs#L221-L234">definition</a> of the "expected return type" label
|
|
shown below:</p>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>#[derive(Subdiagnostic)]
|
|
pub enum ExpectedReturnTypeLabel<'tcx> {
|
|
#[label(hir_analysis_expected_default_return_type)]
|
|
Unit {
|
|
#[primary_span]
|
|
span: Span,
|
|
},
|
|
#[label(hir_analysis_expected_return_type)]
|
|
Other {
|
|
#[primary_span]
|
|
span: Span,
|
|
expected: Ty<'tcx>,
|
|
},
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<p>Like <code>Diagnostic</code>, <code>Subdiagnostic</code> can be derived for structs or
|
|
enums. Attributes that are placed on the type for structs are placed on each
|
|
variants for enums (or vice versa). Each <code>Subdiagnostic</code> should have one
|
|
attribute applied to the struct or each variant, one of:</p>
|
|
<ul>
|
|
<li><code>#[label(..)]</code> for defining a label</li>
|
|
<li><code>#[note(..)]</code> for defining a note</li>
|
|
<li><code>#[help(..)]</code> for defining a help</li>
|
|
<li><code>#[warning(..)]</code> for defining a warning</li>
|
|
<li><code>#[suggestion{,_hidden,_short,_verbose}(..)]</code> for defining a suggestion</li>
|
|
</ul>
|
|
<p>All of the above must provide a slug as the first positional argument (a path
|
|
to an item in <code>rustc_errors::fluent::*</code>). A slug uniquely identifies the
|
|
diagnostic and is also how the compiler knows what error message to emit (in
|
|
the default locale of the compiler, or in the locale requested by the user).
|
|
See <a href="./translation.html">translation documentation</a> to learn more about how
|
|
translatable error messages are written and how slug items are generated.</p>
|
|
<p>In our example, the Fluent message for the "expected return type" label
|
|
looks like this:</p>
|
|
<pre><code class="language-fluent">hir_analysis_expected_default_return_type = expected `()` because of default return type
|
|
|
|
hir_analysis_expected_return_type = expected `{$expected}` because of return type
|
|
</code></pre>
|
|
<p>Using the <code>#[primary_span]</code> attribute on a field (with type <code>Span</code>) will denote
|
|
the primary span of the subdiagnostic. A primary span is only necessary for a
|
|
label or suggestion, which can not be spanless.</p>
|
|
<p>Every field of the type/variant which does not have an annotation is available
|
|
in Fluent messages as a variable. Fields can be annotated <code>#[skip_arg]</code> if this
|
|
is undesired.</p>
|
|
<p>Like <code>Diagnostic</code>, <code>Subdiagnostic</code> supports <code>Option<T></code> and
|
|
<code>Vec<T></code> fields.</p>
|
|
<p>Suggestions can be emitted using one of four attributes on the type/variant:</p>
|
|
<ul>
|
|
<li><code>#[suggestion(..., code = "...", applicability = "...")]</code></li>
|
|
<li><code>#[suggestion_hidden(..., code = "...", applicability = "...")]</code></li>
|
|
<li><code>#[suggestion_short(..., code = "...", applicability = "...")]</code></li>
|
|
<li><code>#[suggestion_verbose(..., code = "...", applicability = "...")]</code></li>
|
|
</ul>
|
|
<p>Suggestions require <code>#[primary_span]</code> be set on a field and can have the
|
|
following sub-attributes:</p>
|
|
<ul>
|
|
<li>The first positional argument specifies the path to a item in
|
|
<code>rustc_errors::fluent</code> corresponding to the Fluent attribute with the message
|
|
and defaults to the equivalent of <code>.suggestion</code>.</li>
|
|
<li><code>code</code> specifies the code that should be suggested as a replacement and is a
|
|
format string (e.g. <code>{field_name}</code> would be replaced by the value of the
|
|
<code>field_name</code> field of the struct), not a Fluent identifier.</li>
|
|
<li><code>applicability</code> can be used to specify the applicability in the attribute, it
|
|
cannot be used when the field's type contains an <code>Applicability</code>.</li>
|
|
</ul>
|
|
<p>Applicabilities can also be specified as a field (of type <code>Applicability</code>)
|
|
using the <code>#[applicability]</code> attribute.</p>
|
|
<p>In the end, the <code>Subdiagnostic</code> derive will generate an implementation
|
|
of <code>Subdiagnostic</code> that looks like the following:</p>
|
|
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
|
|
</span><span class="boring">fn main() {
|
|
</span>impl<'tcx> Subdiagnostic for ExpectedReturnTypeLabel<'tcx> {
|
|
fn add_to_diag(self, diag: &mut rustc_errors::Diagnostic) {
|
|
use rustc_errors::{Applicability, IntoDiagArg};
|
|
match self {
|
|
ExpectedReturnTypeLabel::Unit { span } => {
|
|
diag.span_label(span, rustc_errors::fluent::hir_analysis_expected_default_return_type)
|
|
}
|
|
ExpectedReturnTypeLabel::Other { span, expected } => {
|
|
diag.set_arg("expected", expected);
|
|
diag.span_label(span, rustc_errors::fluent::hir_analysis_expected_return_type)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
<span class="boring">}</span></code></pre></pre>
|
|
<p>Once defined, a subdiagnostic can be used by passing it to the <code>subdiagnostic</code>
|
|
function (<a href="https://github.com/rust-lang/rust/blob/f1112099eba41abadb6f921df7edba70affe92c5/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs#L670-L674">example</a> and <a href="https://github.com/rust-lang/rust/blob/f1112099eba41abadb6f921df7edba70affe92c5/compiler/rustc_hir_analysis/src/check/fn_ctxt/suggestions.rs#L704-L707">example</a>) on a
|
|
diagnostic or by assigning it to a <code>#[subdiagnostic]</code>-annotated field of a
|
|
diagnostic struct.</p>
|
|
<h3 id="reference-1"><a class="header" href="#reference-1">Reference</a></h3>
|
|
<p><code>#[derive(Subdiagnostic)]</code> supports the following attributes:</p>
|
|
<ul>
|
|
<li><code>#[label(slug)]</code>, <code>#[help(slug)]</code>, <code>#[warning(slug)]</code> or <code>#[note(slug)]</code>
|
|
<ul>
|
|
<li><em>Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes.</em></li>
|
|
<li><em>Mandatory</em></li>
|
|
<li>Defines the type to be representing a label, help or note.</li>
|
|
<li>Slug (<em>Mandatory</em>)
|
|
<ul>
|
|
<li>Uniquely identifies the diagnostic and corresponds to its Fluent message,
|
|
mandatory.</li>
|
|
<li>A path to an item in <code>rustc_errors::fluent</code>, e.g.
|
|
<code>rustc_errors::fluent::hir_analysis_field_already_declared</code>
|
|
(<code>rustc_errors::fluent</code> is implicit in the attribute, so just
|
|
<code>hir_analysis_field_already_declared</code>).</li>
|
|
<li>See <a href="./translation.html">translation documentation</a>.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[suggestion{,_hidden,_short,_verbose}(slug, code = "...", applicability = "...")]</code>
|
|
<ul>
|
|
<li><em>Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes.</em></li>
|
|
<li><em>Mandatory</em></li>
|
|
<li>Defines the type to be representing a suggestion.</li>
|
|
<li>Slug (<em>Mandatory</em>)
|
|
<ul>
|
|
<li>A path to an item in <code>rustc_errors::fluent</code>, e.g.
|
|
<code>rustc_errors::fluent::hir_analysis_field_already_declared</code>
|
|
(<code>rustc_errors::fluent</code> is implicit in the attribute, so just
|
|
<code>hir_analysis::field_already_declared</code>). Fluent attributes for all messages
|
|
exist as top-level items in that module (so <code>hir_analysis_message.attr</code> is just
|
|
<code>hir_analysis::attr</code>).</li>
|
|
<li>See <a href="./translation.html">translation documentation</a>.</li>
|
|
<li>Defaults to <code>rustc_errors::fluent::_subdiag::suggestion</code> (or</li>
|
|
<li><code>.suggestion</code> in Fluent).</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>code = "..."</code>/<code>code("...", ...)</code> (<em>Mandatory</em>)
|
|
<ul>
|
|
<li>One or multiple format strings indicating the code to be suggested as a
|
|
replacement. Multiple values signify multiple possible replacements.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>applicability = "..."</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Mutually exclusive with <code>#[applicability]</code> on a field.</em></li>
|
|
<li>Value is the applicability of the suggestion.</li>
|
|
<li>String which must be one of:
|
|
<ul>
|
|
<li><code>machine-applicable</code></li>
|
|
<li><code>maybe-incorrect</code></li>
|
|
<li><code>has-placeholders</code></li>
|
|
<li><code>unspecified</code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[multipart_suggestion{,_hidden,_short,_verbose}(slug, applicability = "...")]</code>
|
|
<ul>
|
|
<li><em>Applied to struct or enum variant. Mutually exclusive with struct/enum variant attributes.</em></li>
|
|
<li><em>Mandatory</em></li>
|
|
<li>Defines the type to be representing a multipart suggestion.</li>
|
|
<li>Slug (<em>Mandatory</em>): see <code>#[suggestion]</code></li>
|
|
<li><code>applicability = "..."</code> (<em>Optional</em>): see <code>#[suggestion]</code></li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[primary_span]</code> (<em>Mandatory</em> for labels and suggestions; <em>optional</em> otherwise; not applicable
|
|
to multipart suggestions)
|
|
<ul>
|
|
<li><em>Applied to <code>Span</code> fields.</em></li>
|
|
<li>Indicates the primary span of the subdiagnostic.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[suggestion_part(code = "...")]</code> (<em>Mandatory</em>; only applicable to multipart suggestions)
|
|
<ul>
|
|
<li><em>Applied to <code>Span</code> fields.</em></li>
|
|
<li>Indicates the span to be one part of the multipart suggestion.</li>
|
|
<li><code>code = "..."</code> (<em>Mandatory</em>)
|
|
<ul>
|
|
<li>Value is a format string indicating the code to be suggested as a
|
|
replacement.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[applicability]</code> (<em>Optional</em>; only applicable to (simple and multipart) suggestions)
|
|
<ul>
|
|
<li><em>Applied to <code>Applicability</code> fields.</em></li>
|
|
<li>Indicates the applicability of the suggestion.</li>
|
|
</ul>
|
|
</li>
|
|
<li><code>#[skip_arg]</code> (<em>Optional</em>)
|
|
<ul>
|
|
<li><em>Applied to any field.</em></li>
|
|
<li>Prevents the field from being provided as a diagnostic argument.</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
<a rel="prev" href="../diagnostics.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
<a rel="next prefetch" href="../diagnostics/translation.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
<a rel="prev" href="../diagnostics.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
<a rel="next prefetch" href="../diagnostics/translation.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
window.playground_copyable = true;
|
|
</script>
|
|
|
|
|
|
<script src="../elasticlunr.min.js"></script>
|
|
<script src="../mark.min.js"></script>
|
|
<script src="../searcher.js"></script>
|
|
|
|
<script src="../clipboard.min.js"></script>
|
|
<script src="../highlight.js"></script>
|
|
<script src="../book.js"></script>
|
|
|
|
<!-- Custom JS scripts -->
|
|
<script src="../mermaid.min.js"></script>
|
|
<script src="../mermaid-init.js"></script>
|
|
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|