Allows #[diagnostic::on_unimplemented]
attributes to have multiple
notes This commit extends the `#[diagnostic::on_unimplemented]` (and `#[rustc_on_unimplemented]`) attributes to allow multiple `note` options. This enables emitting multiple notes for custom error messages. For now I've opted to not change any of the existing usages of `#[rustc_on_unimplemented]` and just updated the relevant compile tests.
This commit is contained in:
parent
6d674af861
commit
160b1793b2
9 changed files with 111 additions and 23 deletions
|
@ -319,7 +319,7 @@ pub struct OnUnimplementedDirective {
|
|||
pub subcommands: Vec<OnUnimplementedDirective>,
|
||||
pub message: Option<OnUnimplementedFormatString>,
|
||||
pub label: Option<OnUnimplementedFormatString>,
|
||||
pub note: Option<OnUnimplementedFormatString>,
|
||||
pub notes: Vec<OnUnimplementedFormatString>,
|
||||
pub parent_label: Option<OnUnimplementedFormatString>,
|
||||
pub append_const_msg: Option<AppendConstMessage>,
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ pub struct OnUnimplementedDirective {
|
|||
pub struct OnUnimplementedNote {
|
||||
pub message: Option<String>,
|
||||
pub label: Option<String>,
|
||||
pub note: Option<String>,
|
||||
pub notes: Vec<String>,
|
||||
pub parent_label: Option<String>,
|
||||
// If none, should fall back to a generic message
|
||||
pub append_const_msg: Option<AppendConstMessage>,
|
||||
|
@ -399,7 +399,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
|
||||
let mut message = None;
|
||||
let mut label = None;
|
||||
let mut note = None;
|
||||
let mut notes = Vec::new();
|
||||
let mut parent_label = None;
|
||||
let mut subcommands = vec![];
|
||||
let mut append_const_msg = None;
|
||||
|
@ -415,10 +415,12 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
label = parse_value(label_)?;
|
||||
continue;
|
||||
}
|
||||
} else if item.has_name(sym::note) && note.is_none() {
|
||||
} else if item.has_name(sym::note) {
|
||||
if let Some(note_) = item.value_str() {
|
||||
note = parse_value(note_)?;
|
||||
continue;
|
||||
if let Some(note) = parse_value(note_)? {
|
||||
notes.push(note);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if item.has_name(sym::parent_label)
|
||||
&& parent_label.is_none()
|
||||
|
@ -432,7 +434,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
&& is_root
|
||||
&& message.is_none()
|
||||
&& label.is_none()
|
||||
&& note.is_none()
|
||||
&& notes.is_empty()
|
||||
&& !is_diagnostic_namespace_variant
|
||||
// FIXME(diagnostic_namespace): disallow filters for now
|
||||
{
|
||||
|
@ -487,7 +489,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
subcommands,
|
||||
message,
|
||||
label,
|
||||
note,
|
||||
notes,
|
||||
parent_label,
|
||||
append_const_msg,
|
||||
}))
|
||||
|
@ -505,12 +507,14 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
if let Some(aggr) = aggr {
|
||||
let mut subcommands = aggr.subcommands;
|
||||
subcommands.extend(directive.subcommands);
|
||||
let mut notes = aggr.notes;
|
||||
notes.extend(directive.notes);
|
||||
Ok(Some(Self {
|
||||
condition: aggr.condition.or(directive.condition),
|
||||
subcommands,
|
||||
message: aggr.message.or(directive.message),
|
||||
label: aggr.label.or(directive.label),
|
||||
note: aggr.note.or(directive.note),
|
||||
notes,
|
||||
parent_label: aggr.parent_label.or(directive.parent_label),
|
||||
append_const_msg: aggr.append_const_msg.or(directive.append_const_msg),
|
||||
}))
|
||||
|
@ -543,7 +547,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
value,
|
||||
attr.span,
|
||||
)?),
|
||||
note: None,
|
||||
notes: Vec::new(),
|
||||
parent_label: None,
|
||||
append_const_msg: None,
|
||||
}))
|
||||
|
@ -600,7 +604,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
) -> OnUnimplementedNote {
|
||||
let mut message = None;
|
||||
let mut label = None;
|
||||
let mut note = None;
|
||||
let mut notes = Vec::new();
|
||||
let mut parent_label = None;
|
||||
let mut append_const_msg = None;
|
||||
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
||||
|
@ -637,9 +641,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
label = Some(label_.clone());
|
||||
}
|
||||
|
||||
if let Some(ref note_) = command.note {
|
||||
note = Some(note_.clone());
|
||||
}
|
||||
notes.extend(command.notes.clone());
|
||||
|
||||
if let Some(ref parent_label_) = command.parent_label {
|
||||
parent_label = Some(parent_label_.clone());
|
||||
|
@ -651,7 +653,7 @@ impl<'tcx> OnUnimplementedDirective {
|
|||
OnUnimplementedNote {
|
||||
label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
|
||||
message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
|
||||
note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
|
||||
notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, &options_map)).collect(),
|
||||
parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
|
||||
append_const_msg,
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
let OnUnimplementedNote {
|
||||
message,
|
||||
label,
|
||||
note,
|
||||
notes,
|
||||
parent_label,
|
||||
append_const_msg,
|
||||
} = self.on_unimplemented_note(trait_ref, &obligation);
|
||||
|
@ -436,21 +436,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
|
||||
let is_unsize =
|
||||
Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait();
|
||||
let (message, note, append_const_msg) = if is_try_conversion {
|
||||
let (message, notes, append_const_msg) = if is_try_conversion {
|
||||
(
|
||||
Some(format!(
|
||||
"`?` couldn't convert the error to `{}`",
|
||||
trait_ref.skip_binder().self_ty(),
|
||||
)),
|
||||
Some(
|
||||
vec![
|
||||
"the question mark operation (`?`) implicitly performs a \
|
||||
conversion on the error value using the `From` trait"
|
||||
.to_owned(),
|
||||
),
|
||||
],
|
||||
Some(AppendConstMessage::Default),
|
||||
)
|
||||
} else {
|
||||
(message, note, append_const_msg)
|
||||
(message, notes, append_const_msg)
|
||||
};
|
||||
|
||||
let err_msg = self.get_standard_error_message(
|
||||
|
@ -569,9 +569,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
if let Some((msg, span)) = type_def {
|
||||
err.span_label(span, msg);
|
||||
}
|
||||
if let Some(s) = note {
|
||||
for note in notes {
|
||||
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
|
||||
err.note(s);
|
||||
err.note(note);
|
||||
}
|
||||
if let Some(s) = parent_label {
|
||||
let body = obligation.cause.body_id;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue