Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c45f295

Browse files
committed
span: move MultiSpan
`MultiSpan` contains labels, which are more complicated with the introduction of diagnostic translation and will use types from `rustc_errors` - however, `rustc_errors` depends on `rustc_span` so `rustc_span` cannot use types like `DiagnosticMessage` without dependency cycles. Introduce a new `rustc_error_messages` crate that can contain `DiagnosticMessage` and `MultiSpan`. Signed-off-by: David Wood <david.wood@huawei.com>
1 parent 8c68456 commit c45f295

File tree

66 files changed

+354
-293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+354
-293
lines changed

Cargo.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3645,13 +3645,23 @@ dependencies = [
36453645
name = "rustc_error_codes"
36463646
version = "0.0.0"
36473647

3648+
[[package]]
3649+
name = "rustc_error_messages"
3650+
version = "0.0.0"
3651+
dependencies = [
3652+
"rustc_macros",
3653+
"rustc_serialize",
3654+
"rustc_span",
3655+
]
3656+
36483657
[[package]]
36493658
name = "rustc_errors"
36503659
version = "0.0.0"
36513660
dependencies = [
36523661
"annotate-snippets",
36533662
"atty",
36543663
"rustc_data_structures",
3664+
"rustc_error_messages",
36553665
"rustc_lint_defs",
36563666
"rustc_macros",
36573667
"rustc_serialize",
@@ -3708,6 +3718,7 @@ dependencies = [
37083718
"odht",
37093719
"rustc_ast",
37103720
"rustc_data_structures",
3721+
"rustc_error_messages",
37113722
"rustc_feature",
37123723
"rustc_index",
37133724
"rustc_macros",
@@ -3864,6 +3875,7 @@ version = "0.0.0"
38643875
dependencies = [
38653876
"rustc_ast",
38663877
"rustc_data_structures",
3878+
"rustc_error_messages",
38673879
"rustc_hir",
38683880
"rustc_macros",
38693881
"rustc_serialize",

compiler/rustc_borrowck/src/borrowck_errors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
1+
use rustc_errors::{struct_span_err, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed, MultiSpan};
22
use rustc_middle::ty::{self, Ty, TyCtxt};
3-
use rustc_span::{MultiSpan, Span};
3+
use rustc_span::Span;
44

55
impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
66
crate fn cannot_move_when_borrowed(

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use either::Either;
22
use rustc_const_eval::util::CallKind;
33
use rustc_data_structures::fx::FxHashSet;
4-
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
4+
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
55
use rustc_hir as hir;
66
use rustc_hir::def_id::DefId;
77
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
@@ -15,7 +15,7 @@ use rustc_middle::mir::{
1515
use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
1616
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
1717
use rustc_span::symbol::sym;
18-
use rustc_span::{BytePos, MultiSpan, Span};
18+
use rustc_span::{BytePos, Span};
1919
use rustc_trait_selection::infer::InferCtxtExt;
2020
use rustc_trait_selection::traits::TraitEngineExt as _;
2121

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use rustc_ast::tokenstream::TokenStream;
77
use rustc_ast::visit::{self, Visitor};
88
use rustc_ast::{token, BlockCheckMode, UnsafeSource};
99
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
10-
use rustc_errors::{pluralize, Applicability, PResult};
10+
use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
1111
use rustc_expand::base::{self, *};
1212
use rustc_parse_format as parse;
1313
use rustc_span::symbol::{sym, Ident, Symbol};
14-
use rustc_span::{InnerSpan, MultiSpan, Span};
14+
use rustc_span::{InnerSpan, Span};
1515
use smallvec::SmallVec;
1616

1717
use std::borrow::Cow;
@@ -446,7 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
446446
.iter()
447447
.filter(|fmt| fmt.precision_span.is_some())
448448
.count();
449-
e.span_label(span, &format!(
449+
e.span_label(
450+
span,
451+
&format!(
450452
"this precision flag adds an extra required argument at position {}, \
451453
which is why there {} expected",
452454
pos,
@@ -455,7 +457,8 @@ impl<'a, 'b> Context<'a, 'b> {
455457
} else {
456458
format!("are {} arguments", count)
457459
},
458-
));
460+
),
461+
);
459462
if let Some(arg) = self.args.get(pos) {
460463
e.span_label(
461464
arg.span,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "rustc_error_messages"
3+
version = "0.0.0"
4+
edition = "2021"
5+
6+
[lib]
7+
doctest = false
8+
9+
[dependencies]
10+
rustc_serialize = { path = "../rustc_serialize" }
11+
rustc_span = { path = "../rustc_span" }
12+
rustc_macros = { path = "../rustc_macros" }
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
use rustc_macros::{Decodable, Encodable};
2+
use rustc_span::Span;
3+
4+
/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
5+
/// diagnostic messages.
6+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
7+
pub enum DiagnosticMessage {
8+
/// Non-translatable diagnostic message.
9+
Str(String),
10+
/// Identifier for a Fluent message corresponding to the diagnostic message.
11+
FluentIdentifier(String),
12+
}
13+
14+
impl DiagnosticMessage {
15+
/// Convert `DiagnosticMessage` to a `&str`.
16+
pub fn as_str(&self) -> &str {
17+
match self {
18+
DiagnosticMessage::Str(msg) => msg,
19+
DiagnosticMessage::FluentIdentifier(..) => unimplemented!(),
20+
}
21+
}
22+
23+
/// Convert `DiagnosticMessage` to an owned `String`.
24+
pub fn to_string(self) -> String {
25+
match self {
26+
DiagnosticMessage::Str(msg) => msg,
27+
DiagnosticMessage::FluentIdentifier(..) => unimplemented!(),
28+
}
29+
}
30+
}
31+
32+
/// A span together with some additional data.
33+
#[derive(Clone, Debug)]
34+
pub struct SpanLabel {
35+
/// The span we are going to include in the final snippet.
36+
pub span: Span,
37+
38+
/// Is this a primary span? This is the "locus" of the message,
39+
/// and is indicated with a `^^^^` underline, versus `----`.
40+
pub is_primary: bool,
41+
42+
/// What label should we attach to this span (if any)?
43+
pub label: Option<DiagnosticMessage>,
44+
}
45+
46+
/// A collection of `Span`s.
47+
///
48+
/// Spans have two orthogonal attributes:
49+
///
50+
/// - They can be *primary spans*. In this case they are the locus of
51+
/// the error, and would be rendered with `^^^`.
52+
/// - They can have a *label*. In this case, the label is written next
53+
/// to the mark in the snippet when we render.
54+
#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
55+
pub struct MultiSpan {
56+
primary_spans: Vec<Span>,
57+
span_labels: Vec<(Span, DiagnosticMessage)>,
58+
}
59+
60+
impl MultiSpan {
61+
#[inline]
62+
pub fn new() -> MultiSpan {
63+
MultiSpan { primary_spans: vec![], span_labels: vec![] }
64+
}
65+
66+
pub fn from_span(primary_span: Span) -> MultiSpan {
67+
MultiSpan { primary_spans: vec![primary_span], span_labels: vec![] }
68+
}
69+
70+
pub fn from_spans(mut vec: Vec<Span>) -> MultiSpan {
71+
vec.sort();
72+
MultiSpan { primary_spans: vec, span_labels: vec![] }
73+
}
74+
75+
pub fn push_span_label(&mut self, span: Span, label: String) {
76+
self.span_labels.push((span, DiagnosticMessage::Str(label)));
77+
}
78+
79+
pub fn push_span_message(&mut self, span: Span, message: DiagnosticMessage) {
80+
self.span_labels.push((span, message));
81+
}
82+
83+
/// Selects the first primary span (if any).
84+
pub fn primary_span(&self) -> Option<Span> {
85+
self.primary_spans.first().cloned()
86+
}
87+
88+
/// Returns all primary spans.
89+
pub fn primary_spans(&self) -> &[Span] {
90+
&self.primary_spans
91+
}
92+
93+
/// Returns `true` if any of the primary spans are displayable.
94+
pub fn has_primary_spans(&self) -> bool {
95+
self.primary_spans.iter().any(|sp| !sp.is_dummy())
96+
}
97+
98+
/// Returns `true` if this contains only a dummy primary span with any hygienic context.
99+
pub fn is_dummy(&self) -> bool {
100+
let mut is_dummy = true;
101+
for span in &self.primary_spans {
102+
if !span.is_dummy() {
103+
is_dummy = false;
104+
}
105+
}
106+
is_dummy
107+
}
108+
109+
/// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
110+
/// display well (like std macros). Returns whether replacements occurred.
111+
pub fn replace(&mut self, before: Span, after: Span) -> bool {
112+
let mut replacements_occurred = false;
113+
for primary_span in &mut self.primary_spans {
114+
if *primary_span == before {
115+
*primary_span = after;
116+
replacements_occurred = true;
117+
}
118+
}
119+
for span_label in &mut self.span_labels {
120+
if span_label.0 == before {
121+
span_label.0 = after;
122+
replacements_occurred = true;
123+
}
124+
}
125+
replacements_occurred
126+
}
127+
128+
/// Returns the strings to highlight. We always ensure that there
129+
/// is an entry for each of the primary spans -- for each primary
130+
/// span `P`, if there is at least one label with span `P`, we return
131+
/// those labels (marked as primary). But otherwise we return
132+
/// `SpanLabel` instances with empty labels.
133+
pub fn span_labels(&self) -> Vec<SpanLabel> {
134+
let is_primary = |span| self.primary_spans.contains(&span);
135+
136+
let mut span_labels = self
137+
.span_labels
138+
.iter()
139+
.map(|&(span, ref label)| SpanLabel {
140+
span,
141+
is_primary: is_primary(span),
142+
label: Some(label.clone()),
143+
})
144+
.collect::<Vec<_>>();
145+
146+
for &span in &self.primary_spans {
147+
if !span_labels.iter().any(|sl| sl.span == span) {
148+
span_labels.push(SpanLabel { span, is_primary: true, label: None });
149+
}
150+
}
151+
152+
span_labels
153+
}
154+
155+
/// Returns `true` if any of the span labels is displayable.
156+
pub fn has_span_labels(&self) -> bool {
157+
self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
158+
}
159+
}
160+
161+
impl From<Span> for MultiSpan {
162+
fn from(span: Span) -> MultiSpan {
163+
MultiSpan::from_span(span)
164+
}
165+
}
166+
167+
impl From<Vec<Span>> for MultiSpan {
168+
fn from(spans: Vec<Span>) -> MultiSpan {
169+
MultiSpan::from_spans(spans)
170+
}
171+
}

compiler/rustc_errors/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ doctest = false
88

99
[dependencies]
1010
tracing = "0.1"
11+
rustc_error_messages = { path = "../rustc_error_messages" }
1112
rustc_serialize = { path = "../rustc_serialize" }
1213
rustc_span = { path = "../rustc_span" }
1314
rustc_macros = { path = "../rustc_macros" }

compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
88
use crate::emitter::FileWithAnnotatedLines;
99
use crate::snippet::Line;
10-
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, SubDiagnostic};
10+
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Emitter, Level, MultiSpan, SubDiagnostic};
1111
use annotate_snippets::display_list::{DisplayList, FormatOptions};
1212
use annotate_snippets::snippet::*;
1313
use rustc_data_structures::sync::Lrc;
1414
use rustc_span::source_map::SourceMap;
15-
use rustc_span::{MultiSpan, SourceFile};
15+
use rustc_span::SourceFile;
1616

1717
/// Generates diagnostics using annotate-snippet
1818
pub struct AnnotateSnippetEmitterWriter {

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
use crate::snippet::Style;
2-
use crate::CodeSuggestion;
3-
use crate::Level;
4-
use crate::Substitution;
5-
use crate::SubstitutionPart;
6-
use crate::SuggestionStyle;
7-
use crate::ToolMetadata;
2+
use crate::{
3+
CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart,
4+
SuggestionStyle, ToolMetadata,
5+
};
86
use rustc_data_structures::stable_map::FxHashMap;
97
use rustc_lint_defs::{Applicability, LintExpectationId};
108
use rustc_serialize::json::Json;
119
use rustc_span::edition::LATEST_STABLE_EDITION;
12-
use rustc_span::{MultiSpan, Span, DUMMY_SP};
10+
use rustc_span::{Span, DUMMY_SP};
1311
use std::fmt;
1412
use std::hash::{Hash, Hasher};
1513

@@ -18,34 +16,6 @@ use std::hash::{Hash, Hasher};
1816
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
1917
pub struct SuggestionsDisabled;
2018

21-
/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
22-
/// diagnostic messages.
23-
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
24-
pub enum DiagnosticMessage {
25-
/// Non-translatable diagnostic message.
26-
Str(String),
27-
/// Identifier for a Fluent message corresponding to the diagnostic message.
28-
FluentIdentifier(String),
29-
}
30-
31-
impl DiagnosticMessage {
32-
/// Convert `DiagnosticMessage` to a `&str`.
33-
pub fn as_str(&self) -> &str {
34-
match self {
35-
DiagnosticMessage::Str(msg) => msg,
36-
DiagnosticMessage::FluentIdentifier(..) => unimplemented!(),
37-
}
38-
}
39-
40-
/// Convert `DiagnosticMessage` to an owned `String`.
41-
pub fn to_string(self) -> String {
42-
match self {
43-
DiagnosticMessage::Str(msg) => msg,
44-
DiagnosticMessage::FluentIdentifier(..) => unimplemented!(),
45-
}
46-
}
47-
}
48-
4919
#[must_use]
5020
#[derive(Clone, Debug, Encodable, Decodable)]
5121
pub struct Diagnostic {
@@ -262,7 +232,7 @@ impl Diagnostic {
262232
self.set_span(after);
263233
for span_label in before.span_labels() {
264234
if let Some(label) = span_label.label {
265-
self.span_label(after, label);
235+
self.span.push_span_message(after, label);
266236
}
267237
}
268238
self

compiler/rustc_errors/src/diagnostic_builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{Diagnostic, DiagnosticId, DiagnosticStyledString, ErrorGuaranteed};
2-
use crate::{Handler, Level, StashKey};
2+
use crate::{Handler, Level, MultiSpan, StashKey};
33
use rustc_lint_defs::Applicability;
44

5-
use rustc_span::{MultiSpan, Span};
5+
use rustc_span::Span;
66
use std::fmt::{self, Debug};
77
use std::marker::PhantomData;
88
use std::ops::{Deref, DerefMut};

0 commit comments

Comments
 (0)