Skip to content

Commit 2e8e75f

Browse files
committed
Tweak error message
1 parent da12c4f commit 2e8e75f

File tree

5 files changed

+78
-45
lines changed

5 files changed

+78
-45
lines changed

src/librustc_typeck/check/method/confirm.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,12 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
110110
self.unify_receivers(self_ty, method_sig.inputs()[0]);
111111

112112
// Add any trait/regions obligations specified on the method's type parameters.
113-
let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
114-
self.add_obligations(method_ty, all_substs, &method_predicates);
113+
// We won't add these if we encountered an illegal sized bound, so that we can use
114+
// a custom error in that case.
115+
if !rerun {
116+
let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig));
117+
self.add_obligations(method_ty, all_substs, &method_predicates);
118+
}
115119

116120
// Create the final `MethodCallee`.
117121
let callee = MethodCallee {

src/librustc_typeck/check/method/mod.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ pub enum MethodError<'tcx> {
6060

6161
// Found an applicable method, but it is not visible.
6262
PrivateMatch(Def),
63+
64+
// Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
65+
// forgotten to import a trait.
66+
IllegalSizedBound(Vec<DefId>),
6367
}
6468

6569
// 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> {
112116
Err(Ambiguity(..)) => true,
113117
Err(ClosureAmbiguity(..)) => true,
114118
Err(PrivateMatch(..)) => allow_private,
119+
Err(IllegalSizedBound(..)) => true,
115120
}
116121
}
117122

@@ -173,13 +178,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
173178
self_ty,
174179
call_expr,
175180
ProbeScope::AllTraits) {
181+
182+
// If we find a different result the caller probably forgot to import a trait.
176183
Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
177-
Err(MethodError::Ambiguity(ref sources)) => {
184+
Err(Ambiguity(ref sources)) => {
178185
sources.iter()
179186
.filter_map(|source| {
180187
match *source {
181188
// Note: this cannot come from an inherent impl,
182-
// because the first probe succeeded.
189+
// because the first probing succeeded.
183190
ImplSource(def) => self.tcx.trait_id_of_impl(def),
184191
TraitSource(_) => None,
185192
}
@@ -189,19 +196,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
189196
_ => Vec::new(),
190197
};
191198

192-
// If we find a different result, the caller probably forgot to import a trait.
193-
// We span an error with an appropriate help message.
194-
if !candidates.is_empty() {
195-
let error = MethodError::NoMatch(
196-
NoMatchData::new(Vec::new(), Vec::new(), candidates, probe::Mode::MethodCall)
197-
);
198-
self.report_method_error(span,
199-
self_ty,
200-
segment.name,
201-
Some(self_expr),
202-
error,
203-
None);
204-
}
199+
return Err(IllegalSizedBound(candidates));
205200
}
206201

207202
Ok(result.callee)

src/librustc_typeck/check/method/suggest.rs

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
315315
let msg = format!("{} `{}` is private", def.kind_name(), item_name);
316316
self.tcx.sess.span_err(span, &msg);
317317
}
318+
319+
MethodError::IllegalSizedBound(candidates) => {
320+
let msg = format!("the `{}` method cannot be invoked on a trait object", item_name);
321+
let mut err = self.sess().struct_span_err(span, &msg);
322+
if !candidates.is_empty() {
323+
let help = format!("{an}other candidate{s} {were} found in the following \
324+
trait{s}, perhaps add a `use` for {one_of_them}:",
325+
an = if candidates.len() == 1 {"an" } else { "" },
326+
s = if candidates.len() == 1 { "" } else { "s" },
327+
were = if candidates.len() == 1 { "was" } else { "were" },
328+
one_of_them = if candidates.len() == 1 {
329+
"it"
330+
} else {
331+
"one_of_them"
332+
});
333+
self.suggest_use_candidates(&mut err, help, candidates);
334+
}
335+
err.emit();
336+
}
337+
}
338+
}
339+
340+
fn suggest_use_candidates(&self,
341+
err: &mut DiagnosticBuilder,
342+
mut msg: String,
343+
candidates: Vec<DefId>) {
344+
let limit = if candidates.len() == 5 { 5 } else { 4 };
345+
for (i, trait_did) in candidates.iter().take(limit).enumerate() {
346+
msg.push_str(&format!("\ncandidate #{}: `use {};`",
347+
i + 1,
348+
self.tcx.item_path_str(*trait_did)));
349+
}
350+
if candidates.len() > limit {
351+
msg.push_str(&format!("\nand {} others", candidates.len() - limit));
318352
}
353+
err.note(&msg[..]);
319354
}
320355

321356
fn suggest_traits_to_import(&self,
@@ -330,30 +365,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
330365
candidates.sort();
331366
candidates.dedup();
332367
err.help("items from traits can only be used if the trait is in scope");
333-
let mut msg = format!("the following {traits_are} implemented but not in scope, \
334-
perhaps add a `use` for {one_of_them}:",
335-
traits_are = if candidates.len() == 1 {
336-
"trait is"
337-
} else {
338-
"traits are"
339-
},
340-
one_of_them = if candidates.len() == 1 {
341-
"it"
342-
} else {
343-
"one of them"
344-
});
345-
346-
let limit = if candidates.len() == 5 { 5 } else { 4 };
347-
for (i, trait_did) in candidates.iter().take(limit).enumerate() {
348-
msg.push_str(&format!("\ncandidate #{}: `use {};`",
349-
i + 1,
350-
self.tcx.item_path_str(*trait_did)));
351-
}
352-
if candidates.len() > limit {
353-
msg.push_str(&format!("\nand {} others", candidates.len() - limit));
354-
}
355-
err.note(&msg[..]);
356-
368+
let msg = format!("the following {traits_are} implemented but not in scope, \
369+
perhaps add a `use` for {one_of_them}:",
370+
traits_are = if candidates.len() == 1 {
371+
"trait is"
372+
} else {
373+
"traits are"
374+
},
375+
one_of_them = if candidates.len() == 1 {
376+
"it"
377+
} else {
378+
"one of them"
379+
});
380+
381+
self.suggest_use_candidates(err, msg, candidates);
357382
return;
358383
}
359384

src/test/compile-fail/issue-35976.rs renamed to src/test/ui/issue-35976.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ mod private {
2222

2323
fn bar(arg: Box<private::Future>) {
2424
arg.wait();
25-
//~^ ERROR no method named `wait` found for type `std::boxed::Box<private::Future + 'static>`
26-
//~| the following trait is implemented but not in scope
27-
//~| ERROR the trait bound `private::Future + 'static: std::marker::Sized` is not satisfied
28-
//~| `private::Future + 'static` does not have a constant size known at compile-time
25+
//~^ ERROR the `wait` method cannot be invoked on a trait object
26+
//~| another candidate was found in the following trait, perhaps add a `use` for it:
2927
}
3028

3129
fn main() {

src/test/ui/issue-35976.stderr

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: the `wait` method cannot be invoked on a trait object
2+
--> $DIR/issue-35976.rs:24:9
3+
|
4+
24 | arg.wait();
5+
| ^^^^
6+
|
7+
= note: another candidate was found in the following trait, perhaps add a `use` for it:
8+
candidate #1: `use private::Future;`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)