Tweak error message
This commit is contained in:
parent
da12c4f8e5
commit
2e8e75f50f
@ -110,8 +110,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
self.unify_receivers(self_ty, method_sig.inputs()[0]);
|
||||
|
||||
// Add any trait/regions obligations specified on the method's type parameters.
|
||||
let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
|
||||
self.add_obligations(method_ty, all_substs, &method_predicates);
|
||||
// We won't add these if we encountered an illegal sized bound, so that we can use
|
||||
// a custom error in that case.
|
||||
if !rerun {
|
||||
let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
|
||||
self.add_obligations(method_ty, all_substs, &method_predicates);
|
||||
}
|
||||
|
||||
// Create the final `MethodCallee`.
|
||||
let callee = MethodCallee {
|
||||
|
@ -60,6 +60,10 @@ pub enum MethodError<'tcx> {
|
||||
|
||||
// Found an applicable method, but it is not visible.
|
||||
PrivateMatch(Def),
|
||||
|
||||
// Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
|
||||
// forgotten to import a trait.
|
||||
IllegalSizedBound(Vec<DefId>),
|
||||
}
|
||||
|
||||
// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
|
||||
@ -112,6 +116,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
Err(Ambiguity(..)) => true,
|
||||
Err(ClosureAmbiguity(..)) => true,
|
||||
Err(PrivateMatch(..)) => allow_private,
|
||||
Err(IllegalSizedBound(..)) => true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,13 +178,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self_ty,
|
||||
call_expr,
|
||||
ProbeScope::AllTraits) {
|
||||
|
||||
// If we find a different result the caller probably forgot to import a trait.
|
||||
Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
|
||||
Err(MethodError::Ambiguity(ref sources)) => {
|
||||
Err(Ambiguity(ref sources)) => {
|
||||
sources.iter()
|
||||
.filter_map(|source| {
|
||||
match *source {
|
||||
// Note: this cannot come from an inherent impl,
|
||||
// because the first probe succeeded.
|
||||
// because the first probing succeeded.
|
||||
ImplSource(def) => self.tcx.trait_id_of_impl(def),
|
||||
TraitSource(_) => None,
|
||||
}
|
||||
@ -189,19 +196,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
_ => Vec::new(),
|
||||
};
|
||||
|
||||
// If we find a different result, the caller probably forgot to import a trait.
|
||||
// We span an error with an appropriate help message.
|
||||
if !candidates.is_empty() {
|
||||
let error = MethodError::NoMatch(
|
||||
NoMatchData::new(Vec::new(), Vec::new(), candidates, probe::Mode::MethodCall)
|
||||
);
|
||||
self.report_method_error(span,
|
||||
self_ty,
|
||||
segment.name,
|
||||
Some(self_expr),
|
||||
error,
|
||||
None);
|
||||
}
|
||||
return Err(IllegalSizedBound(candidates));
|
||||
}
|
||||
|
||||
Ok(result.callee)
|
||||
|
@ -315,9 +315,44 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let msg = format!("{} `{}` is private", def.kind_name(), item_name);
|
||||
self.tcx.sess.span_err(span, &msg);
|
||||
}
|
||||
|
||||
MethodError::IllegalSizedBound(candidates) => {
|
||||
let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
|
||||
let mut err = self.sess().struct_span_err(span, &msg);
|
||||
if !candidates.is_empty() {
|
||||
let help = format!("{an}other candidate{s} {were} found in the following \
|
||||
trait{s}, perhaps add a `use` for {one_of_them}:",
|
||||
an = if candidates.len() == 1 {"an" } else { "" },
|
||||
s = if candidates.len() == 1 { "" } else { "s" },
|
||||
were = if candidates.len() == 1 { "was" } else { "were" },
|
||||
one_of_them = if candidates.len() == 1 {
|
||||
"it"
|
||||
} else {
|
||||
"one_of_them"
|
||||
});
|
||||
self.suggest_use_candidates(&mut err, help, candidates);
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest_use_candidates(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
mut msg: String,
|
||||
candidates: Vec<DefId>) {
|
||||
let limit = if candidates.len() == 5 { 5 } else { 4 };
|
||||
for (i, trait_did) in candidates.iter().take(limit).enumerate() {
|
||||
msg.push_str(&format!("\ncandidate #{}: `use {};`",
|
||||
i + 1,
|
||||
self.tcx.item_path_str(*trait_did)));
|
||||
}
|
||||
if candidates.len() > limit {
|
||||
msg.push_str(&format!("\nand {} others", candidates.len() - limit));
|
||||
}
|
||||
err.note(&msg[..]);
|
||||
}
|
||||
|
||||
fn suggest_traits_to_import(&self,
|
||||
err: &mut DiagnosticBuilder,
|
||||
span: Span,
|
||||
@ -330,30 +365,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
candidates.sort();
|
||||
candidates.dedup();
|
||||
err.help("items from traits can only be used if the trait is in scope");
|
||||
let mut msg = format!("the following {traits_are} implemented but not in scope, \
|
||||
perhaps add a `use` for {one_of_them}:",
|
||||
traits_are = if candidates.len() == 1 {
|
||||
"trait is"
|
||||
} else {
|
||||
"traits are"
|
||||
},
|
||||
one_of_them = if candidates.len() == 1 {
|
||||
"it"
|
||||
} else {
|
||||
"one of them"
|
||||
});
|
||||
|
||||
let limit = if candidates.len() == 5 { 5 } else { 4 };
|
||||
for (i, trait_did) in candidates.iter().take(limit).enumerate() {
|
||||
msg.push_str(&format!("\ncandidate #{}: `use {};`",
|
||||
i + 1,
|
||||
self.tcx.item_path_str(*trait_did)));
|
||||
}
|
||||
if candidates.len() > limit {
|
||||
msg.push_str(&format!("\nand {} others", candidates.len() - limit));
|
||||
}
|
||||
err.note(&msg[..]);
|
||||
let msg = format!("the following {traits_are} implemented but not in scope, \
|
||||
perhaps add a `use` for {one_of_them}:",
|
||||
traits_are = if candidates.len() == 1 {
|
||||
"trait is"
|
||||
} else {
|
||||
"traits are"
|
||||
},
|
||||
one_of_them = if candidates.len() == 1 {
|
||||
"it"
|
||||
} else {
|
||||
"one of them"
|
||||
});
|
||||
|
||||
self.suggest_use_candidates(err, msg, candidates);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,8 @@ mod private {
|
||||
|
||||
fn bar(arg: Box<private::Future>) {
|
||||
arg.wait();
|
||||
//~^ ERROR no method named `wait` found for type `std::boxed::Box<private::Future + 'static>`
|
||||
//~| the following trait is implemented but not in scope
|
||||
//~| ERROR the trait bound `private::Future + 'static: std::marker::Sized` is not satisfied
|
||||
//~| `private::Future + 'static` does not have a constant size known at compile-time
|
||||
//~^ ERROR the `wait` method cannot be invoked on a trait object
|
||||
//~| another candidate was found in the following trait, perhaps add a `use` for it:
|
||||
}
|
||||
|
||||
fn main() {
|
11
src/test/ui/issue-35976.stderr
Normal file
11
src/test/ui/issue-35976.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error: the `wait` method cannot be invoked on a trait object
|
||||
--> $DIR/issue-35976.rs:24:9
|
||||
|
|
||||
24 | arg.wait();
|
||||
| ^^^^
|
||||
|
|
||||
= note: another candidate was found in the following trait, perhaps add a `use` for it:
|
||||
candidate #1: `use private::Future;`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
x
Reference in New Issue
Block a user