add enclosing_scope param to rustc_on_unimplmented

add ui test

compute enclosing_scope_span on demand

add scope test

make tidy happy

stylistic and typo fixes
This commit is contained in:
Mikhail Babenko 2019-11-22 07:34:10 +03:00
parent 582a4eaee6
commit 45aadf7ae6
5 changed files with 143 additions and 14 deletions

View File

@ -519,7 +519,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
) {
command.evaluate(self.tcx, trait_ref, &flags[..])
} else {
OnUnimplementedNote::empty()
OnUnimplementedNote::default()
}
}
@ -695,6 +695,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
fallback_has_occurred: bool,
points_at_arg: bool,
) {
let tcx = self.tcx;
let span = obligation.cause.span;
let mut err = match *error {
@ -730,6 +731,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
message,
label,
note,
enclosing_scope,
} = self.on_unimplemented_note(trait_ref, obligation);
let have_alt_message = message.is_some() || label.is_some();
let is_try = self.tcx.sess.source_map().span_to_snippet(span)
@ -794,6 +796,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
err.note(s.as_str());
}
if let Some(ref s) = enclosing_scope {
let enclosing_scope_span = tcx.def_span(
tcx.hir()
.opt_local_def_id(obligation.cause.body_id)
.unwrap_or_else(|| {
tcx.hir().body_owner_def_id(hir::BodyId {
hir_id: obligation.cause.body_id,
})
}),
);
err.span_label(enclosing_scope_span, s.as_str());
}
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg);

View File

@ -22,18 +22,15 @@ pub struct OnUnimplementedDirective {
pub message: Option<OnUnimplementedFormatString>,
pub label: Option<OnUnimplementedFormatString>,
pub note: Option<OnUnimplementedFormatString>,
pub enclosing_scope: Option<OnUnimplementedFormatString>,
}
#[derive(Default)]
pub struct OnUnimplementedNote {
pub message: Option<String>,
pub label: Option<String>,
pub note: Option<String>,
}
impl OnUnimplementedNote {
pub fn empty() -> Self {
OnUnimplementedNote { message: None, label: None, note: None }
}
pub enclosing_scope: Option<String>,
}
fn parse_error(
@ -85,24 +82,33 @@ impl<'tcx> OnUnimplementedDirective {
let mut message = None;
let mut label = None;
let mut note = None;
let mut enclosing_scope = None;
let mut subcommands = vec![];
let parse_value = |value_str| {
OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span)
.map(Some)
};
for item in item_iter {
if item.check_name(sym::message) && message.is_none() {
if let Some(message_) = item.value_str() {
message = Some(OnUnimplementedFormatString::try_parse(
tcx, trait_def_id, message_, span)?);
message = parse_value(message_)?;
continue;
}
} else if item.check_name(sym::label) && label.is_none() {
if let Some(label_) = item.value_str() {
label = Some(OnUnimplementedFormatString::try_parse(
tcx, trait_def_id, label_, span)?);
label = parse_value(label_)?;
continue;
}
} else if item.check_name(sym::note) && note.is_none() {
if let Some(note_) = item.value_str() {
note = Some(OnUnimplementedFormatString::try_parse(
tcx, trait_def_id, note_, span)?);
note = parse_value(note_)?;
continue;
}
} else if item.check_name(sym::enclosing_scope) && enclosing_scope.is_none() {
if let Some(enclosing_scope_) = item.value_str() {
enclosing_scope = parse_value(enclosing_scope_)?;
continue;
}
} else if item.check_name(sym::on) && is_root &&
@ -130,7 +136,14 @@ impl<'tcx> OnUnimplementedDirective {
if errored {
Err(ErrorReported)
} else {
Ok(OnUnimplementedDirective { condition, message, label, subcommands, note })
Ok(OnUnimplementedDirective {
condition,
subcommands,
message,
label,
note,
enclosing_scope
})
}
}
@ -157,6 +170,7 @@ impl<'tcx> OnUnimplementedDirective {
label: Some(OnUnimplementedFormatString::try_parse(
tcx, trait_def_id, value, attr.span)?),
note: None,
enclosing_scope: None,
}))
} else {
return Err(ErrorReported);
@ -174,6 +188,7 @@ impl<'tcx> OnUnimplementedDirective {
let mut message = None;
let mut label = None;
let mut note = None;
let mut enclosing_scope = None;
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
for command in self.subcommands.iter().chain(Some(self)).rev() {
@ -202,6 +217,10 @@ impl<'tcx> OnUnimplementedDirective {
if let Some(ref note_) = command.note {
note = Some(note_.clone());
}
if let Some(ref enclosing_scope_) = command.enclosing_scope {
enclosing_scope = Some(enclosing_scope_.clone());
}
}
let options: FxHashMap<Symbol, String> = options.into_iter()
@ -211,6 +230,7 @@ impl<'tcx> OnUnimplementedDirective {
label: label.map(|l| l.format(tcx, trait_ref, &options)),
message: message.map(|m| m.format(tcx, trait_ref, &options)),
note: note.map(|n| n.format(tcx, trait_ref, &options)),
enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
}
}
}

View File

@ -279,6 +279,7 @@ symbols! {
Err,
Eq,
Equal,
enclosing_scope,
except,
exclusive_range_pattern,
exhaustive_integer_patterns,

View File

@ -0,0 +1,27 @@
// Test scope annotations from `enclosing_scope` parameter
#![feature(rustc_attrs)]
#[rustc_on_unimplemented(enclosing_scope="in this scope")]
trait Trait{}
struct Foo;
fn f<T: Trait>(x: T) {}
fn main() {
let x = || {
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
let y = || {
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
};
};
{
{
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
}
}
f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied
}

View File

@ -0,0 +1,66 @@
error[E0277]: the trait bound `Foo: Trait` is not satisfied
--> $DIR/enclosing-scope.rs:14:11
|
LL | fn f<T: Trait>(x: T) {}
| - ----- required by this bound in `f`
...
LL | let x = || {
| _____________-
LL | | f(Foo{});
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
LL | | let y = || {
LL | | f(Foo{});
LL | | };
LL | | };
| |_____- in this scope
error[E0277]: the trait bound `Foo: Trait` is not satisfied
--> $DIR/enclosing-scope.rs:16:15
|
LL | fn f<T: Trait>(x: T) {}
| - ----- required by this bound in `f`
...
LL | let y = || {
| _________________-
LL | | f(Foo{});
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
LL | | };
| |_________- in this scope
error[E0277]: the trait bound `Foo: Trait` is not satisfied
--> $DIR/enclosing-scope.rs:22:15
|
LL | fn f<T: Trait>(x: T) {}
| - ----- required by this bound in `f`
LL |
LL | / fn main() {
LL | | let x = || {
LL | | f(Foo{});
LL | | let y = || {
... |
LL | | f(Foo{});
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
... |
LL | | f(Foo{});
LL | | }
| |_- in this scope
error[E0277]: the trait bound `Foo: Trait` is not satisfied
--> $DIR/enclosing-scope.rs:26:7
|
LL | fn f<T: Trait>(x: T) {}
| - ----- required by this bound in `f`
LL |
LL | / fn main() {
LL | | let x = || {
LL | | f(Foo{});
LL | | let y = || {
... |
LL | | f(Foo{});
| | ^^^^^ the trait `Trait` is not implemented for `Foo`
LL | | }
| |_- in this scope
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.