Skip to content

Commit 2fbc967

Browse files
committed
Add NegativePositiveConflict diagnostic to trait_selection
1 parent 7bb855a commit 2fbc967

File tree

3 files changed

+60
-30
lines changed

3 files changed

+60
-30
lines changed

compiler/rustc_error_messages/locales/en-US/trait_selection.ftl

+6
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-claus
1515
trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value
1616
.label = expected value here
1717
.note = eg `#[rustc_on_unimplemented(message="foo")]`
18+
19+
trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc}:
20+
.negative_implementation_here = negative implementation here
21+
.negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
22+
.positive_implementation_here = positive implementation here
23+
.positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`

compiler/rustc_trait_selection/src/errors.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
use rustc_errors::{fluent, ErrorGuaranteed};
12
use rustc_macros::SessionDiagnostic;
2-
use rustc_span::Span;
3+
use rustc_session::{parse::ParseSess, SessionDiagnostic};
4+
use rustc_span::{Span, Symbol};
35

46
#[derive(SessionDiagnostic)]
57
#[diag(trait_selection::dump_vtable_entries)]
@@ -54,3 +56,46 @@ pub struct NoValueInOnUnimplemented {
5456
#[label]
5557
pub span: Span,
5658
}
59+
60+
pub struct NegativePositiveConflict<'a> {
61+
pub impl_span: Span,
62+
pub trait_desc: &'a str,
63+
pub self_desc: &'a Option<String>,
64+
pub negative_impl_span: Result<Span, Symbol>,
65+
pub positive_impl_span: Result<Span, Symbol>,
66+
}
67+
68+
impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> {
69+
fn into_diagnostic(
70+
self,
71+
sess: &ParseSess,
72+
) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
73+
let mut diag = sess.struct_err(fluent::trait_selection::negative_positive_conflict);
74+
diag.set_arg("trait_desc", self.trait_desc);
75+
diag.set_arg(
76+
"self_desc",
77+
self.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty)),
78+
);
79+
diag.set_span(self.impl_span);
80+
diag.code(rustc_errors::error_code!(E0751));
81+
match self.negative_impl_span {
82+
Ok(span) => {
83+
diag.span_label(span, fluent::trait_selection::negative_implementation_here);
84+
}
85+
Err(cname) => {
86+
diag.note(fluent::trait_selection::negative_implementation_in_crate);
87+
diag.set_arg("negative_impl_cname", cname.to_string());
88+
}
89+
}
90+
match self.positive_impl_span {
91+
Ok(span) => {
92+
diag.span_label(span, fluent::trait_selection::positive_implementation_here);
93+
}
94+
Err(cname) => {
95+
diag.note(fluent::trait_selection::positive_implementation_in_crate);
96+
diag.set_arg("positive_impl_cname", cname.to_string());
97+
}
98+
}
99+
diag
100+
}
101+
}

compiler/rustc_trait_selection/src/traits/specialize/mod.rs

+8-29
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
pub mod specialization_graph;
1313
use specialization_graph::GraphExt;
1414

15+
use crate::errors::NegativePositiveConflict;
1516
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
1617
use crate::traits::select::IntercrateAmbiguityCause;
1718
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
@@ -327,35 +328,13 @@ fn report_negative_positive_conflict(
327328
positive_impl_def_id: DefId,
328329
sg: &mut specialization_graph::Graph,
329330
) {
330-
let impl_span = tcx.def_span(local_impl_def_id);
331-
332-
let mut err = struct_span_err!(
333-
tcx.sess,
334-
impl_span,
335-
E0751,
336-
"found both positive and negative implementation of trait `{}`{}:",
337-
overlap.trait_desc,
338-
overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty))
339-
);
340-
341-
match tcx.span_of_impl(negative_impl_def_id) {
342-
Ok(span) => {
343-
err.span_label(span, "negative implementation here");
344-
}
345-
Err(cname) => {
346-
err.note(&format!("negative implementation in crate `{}`", cname));
347-
}
348-
}
349-
350-
match tcx.span_of_impl(positive_impl_def_id) {
351-
Ok(span) => {
352-
err.span_label(span, "positive implementation here");
353-
}
354-
Err(cname) => {
355-
err.note(&format!("positive implementation in crate `{}`", cname));
356-
}
357-
}
358-
331+
let mut err = tcx.sess.create_err(NegativePositiveConflict {
332+
impl_span: tcx.def_span(local_impl_def_id),
333+
trait_desc: &overlap.trait_desc,
334+
self_desc: &overlap.self_desc,
335+
negative_impl_span: tcx.span_of_impl(negative_impl_def_id),
336+
positive_impl_span: tcx.span_of_impl(positive_impl_def_id),
337+
});
359338
sg.has_errored = Some(err.emit());
360339
}
361340

0 commit comments

Comments
 (0)