From 3ca1c5d5b5e0d19f55570f5d49d97100e9b524b3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Esteban=20K=C3=BCber?= Date: Thu, 30 Jan 2020 20:12:46 -0800 Subject: [PATCH] Point at `Sized` requirements Make #47990 easier to understand --- src/librustc_typeck/check/method/confirm.rs | 24 ++++++++++++------- src/librustc_typeck/check/method/mod.rs | 6 ++--- src/librustc_typeck/check/method/suggest.rs | 3 ++- src/test/ui/issues/issue-35976.stderr | 3 +++ .../suggestions/imm-ref-trait-object.stderr | 5 ++++ .../by-value-trait-object-safety.stderr | 3 +++ 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 832aa9f62ff..eee9dc99d35 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -32,7 +32,7 @@ fn deref(&self) -> &Self::Target { pub struct ConfirmResult<'tcx> { pub callee: MethodCallee<'tcx>, - pub illegal_sized_bound: bool, + pub illegal_sized_bound: Option, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -112,7 +112,7 @@ fn confirm( // Add any trait/regions obligations specified on the method's type parameters. // We won't add these if we encountered an illegal sized bound, so that we can use // a custom error in that case. - if !illegal_sized_bound { + if illegal_sized_bound.is_none() { let method_ty = self.tcx.mk_fn_ptr(ty::Binder::bind(method_sig)); self.add_obligations(method_ty, all_substs, &method_predicates); } @@ -561,23 +561,31 @@ fn convert_place_op_to_mutable( fn predicates_require_illegal_sized_bound( &self, predicates: &ty::InstantiatedPredicates<'tcx>, - ) -> bool { + ) -> Option { let sized_def_id = match self.tcx.lang_items().sized_trait() { Some(def_id) => def_id, - None => return false, + None => return None, }; traits::elaborate_predicates(self.tcx, predicates.predicates.clone()) .filter_map(|predicate| match predicate { ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => { - Some(trait_pred) + let span = predicates + .predicates + .iter() + .zip(predicates.spans.iter()) + .filter_map(|(p, span)| if *p == predicate { Some(*span) } else { None }) + .next() + .unwrap_or(rustc_span::DUMMY_SP); + Some((trait_pred, span)) } _ => None, }) - .any(|trait_pred| match trait_pred.skip_binder().self_ty().kind { - ty::Dynamic(..) => true, - _ => false, + .filter_map(|(trait_pred, span)| match trait_pred.skip_binder().self_ty().kind { + ty::Dynamic(..) => Some(span), + _ => None, }) + .next() } fn enforce_illegal_method_limitations(&self, pick: &probe::Pick<'_>) { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index c1cf3522b5d..e90c2ef5e43 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -58,7 +58,7 @@ pub enum MethodError<'tcx> { // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have // forgotten to import a trait. - IllegalSizedBound(Vec, bool), + IllegalSizedBound(Vec, bool, Span), // Found a match, but the return type is wrong BadReturnType, @@ -204,7 +204,7 @@ pub fn lookup_method( let result = self.confirm_method(span, self_expr, call_expr, self_ty, pick.clone(), segment); - if result.illegal_sized_bound { + if let Some(span) = result.illegal_sized_bound { let mut needs_mut = false; if let ty::Ref(region, t_type, mutability) = self_ty.kind { let trait_type = self @@ -249,7 +249,7 @@ pub fn lookup_method( _ => Vec::new(), }; - return Err(IllegalSizedBound(candidates, needs_mut)); + return Err(IllegalSizedBound(candidates, needs_mut, span)); } Ok(result.callee) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 490c69b5536..789bac2705b 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -640,9 +640,10 @@ macro_rules! report_function { err.emit(); } - MethodError::IllegalSizedBound(candidates, needs_mut) => { + MethodError::IllegalSizedBound(candidates, needs_mut, bound_span) => { let msg = format!("the `{}` method cannot be invoked on a trait object", item_name); let mut err = self.sess().struct_span_err(span, &msg); + err.span_label(bound_span, "this has a `Sized` requirement"); if !candidates.is_empty() { let help = format!( "{an}other candidate{s} {were} found in the following trait{s}, perhaps \ diff --git a/src/test/ui/issues/issue-35976.stderr b/src/test/ui/issues/issue-35976.stderr index 99b243a0777..f9b9b7dbd34 100644 --- a/src/test/ui/issues/issue-35976.stderr +++ b/src/test/ui/issues/issue-35976.stderr @@ -1,6 +1,9 @@ error: the `wait` method cannot be invoked on a trait object --> $DIR/issue-35976.rs:14:9 | +LL | fn wait(&self) where Self: Sized; + | ----- this has a `Sized` requirement +... LL | arg.wait(); | ^^^^ | diff --git a/src/test/ui/suggestions/imm-ref-trait-object.stderr b/src/test/ui/suggestions/imm-ref-trait-object.stderr index 9185eaa65c0..37c20535229 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object.stderr @@ -3,6 +3,11 @@ error: the `min` method cannot be invoked on a trait object | LL | t.min().unwrap() | ^^^ + | + ::: $SRC_DIR/libcore/iter/traits/iterator.rs:LL:COL + | +LL | Self: Sized, + | ----- this has a `Sized` requirement | = note: you need `&mut dyn std::iter::Iterator` instead of `&dyn std::iter::Iterator` diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr b/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr index 7e9a2316be2..4cd2098eef2 100644 --- a/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr +++ b/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr @@ -1,6 +1,9 @@ error: the `foo` method cannot be invoked on a trait object --> $DIR/by-value-trait-object-safety.rs:18:7 | +LL | fn foo(self) -> String where Self: Sized; + | ----- this has a `Sized` requirement +... LL | x.foo(); | ^^^ -- 2.44.0