diff options
| -rw-r--r-- | src/librustc_typeck/check/expr.rs | 36 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 111 | ||||
| -rw-r--r-- | src/test/ui/impl-trait/trait_type.stderr | 2 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-3344.stderr | 2 | ||||
| -rw-r--r-- | src/test/ui/missing/missing-items/m2.stderr | 6 | ||||
| -rw-r--r-- | src/test/ui/span/impl-wrong-item-for-trait.stderr | 2 | ||||
| -rw-r--r-- | src/test/ui/span/issue-23729.stderr | 2 | ||||
| -rw-r--r-- | src/test/ui/span/issue-23827.stderr | 2 | ||||
| -rw-r--r-- | src/test/ui/span/issue-24356.stderr | 2 | ||||
| -rw-r--r-- | src/test/ui/suggestions/missing-trait-item.fixed | 20 | ||||
| -rw-r--r-- | src/test/ui/suggestions/missing-trait-item.rs | 16 | ||||
| -rw-r--r-- | src/test/ui/suggestions/missing-trait-item.stderr | 25 |
12 files changed, 192 insertions, 34 deletions
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 35870abbaef..f8d3c055087 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -592,20 +592,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause.span, target_id, ); - let val = match ty.kind { - ty::Bool => "true", - ty::Char => "'a'", - ty::Int(_) | ty::Uint(_) => "42", - ty::Float(_) => "3.14159", - ty::Error | ty::Never => return, - _ => "value", - }; - let msg = "give it a value of the expected type"; - let label = destination.label - .map(|l| format!(" {}", l.ident)) - .unwrap_or_else(String::new); - let sugg = format!("break{} {}", label, val); - err.span_suggestion(expr.span, msg, sugg, Applicability::HasPlaceholders); + if let Some(val) = ty_kind_suggestion(ty) { + let label = destination.label + .map(|l| format!(" {}", l.ident)) + .unwrap_or_else(String::new); + err.span_suggestion( + expr.span, + "give it a value of the expected type", + format!("break{} {}", label, val), + Applicability::HasPlaceholders, + ); + } }, false); } } else { @@ -1725,3 +1722,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.mk_unit() } } + +crate fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { + Some(match ty.kind { + ty::Bool => "true", + ty::Char => "'a'", + ty::Int(_) | ty::Uint(_) => "42", + ty::Float(_) => "3.14159", + ty::Error | ty::Never => return None, + _ => "value", + }) +} diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 26f04081046..3b5a6be1989 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1800,12 +1800,12 @@ fn check_specialization_validity<'tcx>( fn check_impl_items_against_trait<'tcx>( tcx: TyCtxt<'tcx>, - impl_span: Span, + full_impl_span: Span, impl_id: DefId, impl_trait_ref: ty::TraitRef<'tcx>, impl_item_refs: &[hir::ImplItemRef], ) { - let impl_span = tcx.sess.source_map().def_span(impl_span); + let impl_span = tcx.sess.source_map().def_span(full_impl_span); // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` @@ -1934,12 +1934,22 @@ fn check_impl_items_against_trait<'tcx>( missing_items.iter() .map(|trait_item| trait_item.ident.to_string()) .collect::<Vec<_>>().join("`, `"))); + + // `Span` before impl block closing brace. + let hi = full_impl_span.hi() - BytePos(1); + let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); + let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0); + let padding: String = (0..indentation).map(|_| " ").collect(); for trait_item in missing_items { + let snippet = suggestion_signature(&trait_item, tcx); + let code = format!("{}{}\n{}", padding, snippet, padding); + let msg = format!("implement the missing item: `{}`", snippet); + let appl = Applicability::HasPlaceholders; if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { err.span_label(span, format!("`{}` from trait", trait_item.ident)); + err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); } else { - err.note_trait_signature(trait_item.ident.to_string(), - trait_item.signature(tcx)); + err.span_suggestion_hidden(sugg_sp, &msg, code, appl); } } err.emit(); @@ -1947,13 +1957,92 @@ fn check_impl_items_against_trait<'tcx>( if !invalidated_items.is_empty() { let invalidator = overridden_associated_type.unwrap(); - span_err!(tcx.sess, invalidator.span, E0399, - "the following trait items need to be reimplemented \ - as `{}` was overridden: `{}`", - invalidator.ident, - invalidated_items.iter() - .map(|name| name.to_string()) - .collect::<Vec<_>>().join("`, `")) + span_err!( + tcx.sess, + invalidator.span, + E0399, + "the following trait items need to be reimplemented as `{}` was overridden: `{}`", + invalidator.ident, + invalidated_items.iter() + .map(|name| name.to_string()) + .collect::<Vec<_>>().join("`, `")) + } +} + +/// Given a `ty::AssocItem` and a `TyCtxt`, return placeholder code for that associated item. +/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a +/// structured suggestion. +fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { + match assoc.kind { + ty::AssocKind::Method => { + // We skip the binder here because the binder would deanonymize all + // late-bound regions, and we don't want method signatures to show up + // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound + // regions just fine, showing `fn(&MyType)`. + let sig = tcx.fn_sig(assoc.def_id); + let unsafety = match sig.unsafety() { + hir::Unsafety::Unsafe => "unsafe ", + _ => "", + }; + let args = sig.inputs() + .skip_binder() + .iter() + .map(|ty| Some(match ty.kind { + ty::Param(param) if param.name == kw::SelfUpper => { + "self".to_string() + } + ty::Ref(reg, ref_ty, mutability) => { + let mutability = match mutability { + hir::Mutability::MutMutable => "mut ", + _ => "", + }; + let mut reg = format!("{}", reg); + if ®[..] == "'_" { + reg = "".to_string(); + } + if ®[..] != "" { + reg = format!("{} ", reg); + } + match ref_ty.kind { + ty::Param(param) + if param.name == kw::SelfUpper => { + format!("&{}{}self", reg, mutability) + } + _ => format!("_: {:?}", ty), + } + + } + _ => format!("_: {:?}", ty), + })) + .chain(std::iter::once(if sig.c_variadic() { + Some("...".to_string()) + } else { + None + })) + .filter_map(|arg| arg) + .collect::<Vec<String>>() + .join(", "); + let output = sig.output(); + let output = if !output.skip_binder().is_unit() { + format!(" -> {:?}", output.skip_binder()) + } else { + String::new() + }; + // FIXME: this is not entirely correct, as the lifetimes from borrowed params will + // not be present in the `fn` definition, not will we account for renamed + // lifetimes between the `impl` and the `trait`, but this should be good enough to + // fill in a significant portion of the missing code, and other subsequent + // suggestions can help the user fix the code. + format!("{}fn {}({}){} {{ unimplemented!() }}", unsafety, assoc.ident, args, output) + } + ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), + // FIXME(type_alias_impl_trait): we should print bounds here too. + ty::AssocKind::OpaqueTy => format!("type {} = Type;", assoc.ident), + ty::AssocKind::Const => { + let ty = tcx.type_of(assoc.def_id); + let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); + format!("const {}: {:?} = {};", assoc.ident, ty, val) + } } } diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 129d7ef5783..151dc681621 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -29,7 +29,7 @@ error[E0046]: not all trait items implemented, missing: `fmt` LL | impl std::fmt::Display for MyType4 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation | - = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { unimplemented!() }` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-3344.stderr b/src/test/ui/issues/issue-3344.stderr index 6593e07b189..271fbb6c874 100644 --- a/src/test/ui/issues/issue-3344.stderr +++ b/src/test/ui/issues/issue-3344.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `partial_cmp` LL | impl PartialOrd for Thing { | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `partial_cmp` in implementation | - = note: `partial_cmp` from trait: `fn(&Self, &Rhs) -> std::option::Option<std::cmp::Ordering>` + = help: implement the missing item: `fn partial_cmp(&self, _: &Rhs) -> std::option::Option<std::cmp::Ordering> { unimplemented!() }` error: aborting due to previous error diff --git a/src/test/ui/missing/missing-items/m2.stderr b/src/test/ui/missing/missing-items/m2.stderr index d2dac4ca645..f8243528d72 100644 --- a/src/test/ui/missing/missing-items/m2.stderr +++ b/src/test/ui/missing/missing-items/m2.stderr @@ -4,9 +4,9 @@ error[E0046]: not all trait items implemented, missing: `CONSTANT`, `Type`, `met LL | impl m1::X for X { | ^^^^^^^^^^^^^^^^ missing `CONSTANT`, `Type`, `method` in implementation | - = note: `CONSTANT` from trait: `const CONSTANT: u32;` - = note: `Type` from trait: `type Type;` - = note: `method` from trait: `fn(&Self, std::string::String) -> <Self as m1::X>::Type` + = help: implement the missing item: `const CONSTANT: u32 = 42;` + = help: implement the missing item: `type Type = Type;` + = help: implement the missing item: `fn method(&self, _: std::string::String) -> <Self as m1::X>::Type { unimplemented!() }` error: aborting due to previous error diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index 81409aac289..f23f421edc7 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -64,7 +64,7 @@ error[E0046]: not all trait items implemented, missing: `fmt` LL | impl Debug for FooTypeForMethod { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation | - = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { unimplemented!() }` error: aborting due to 8 previous errors diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr index 865fae917c5..f88ce6c88db 100644 --- a/src/test/ui/span/issue-23729.stderr +++ b/src/test/ui/span/issue-23729.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Item` LL | impl Iterator for Recurrence { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Item` in implementation | - = note: `Item` from trait: `type Item;` + = help: implement the missing item: `type Item = Type;` error: aborting due to previous error diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr index a8e3e9b6b9a..46a820f1b76 100644 --- a/src/test/ui/span/issue-23827.stderr +++ b/src/test/ui/span/issue-23827.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Output` LL | impl<C: Component> FnOnce<(C,)> for Prototype { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Output` in implementation | - = note: `Output` from trait: `type Output;` + = help: implement the missing item: `type Output = Type;` error: aborting due to previous error diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr index 4827e9ddd50..a1f9b255020 100644 --- a/src/test/ui/span/issue-24356.stderr +++ b/src/test/ui/span/issue-24356.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `Target` LL | impl Deref for Thing { | ^^^^^^^^^^^^^^^^^^^^ missing `Target` in implementation | - = note: `Target` from trait: `type Target;` + = help: implement the missing item: `type Target = Type;` error: aborting due to previous error diff --git a/src/test/ui/suggestions/missing-trait-item.fixed b/src/test/ui/suggestions/missing-trait-item.fixed new file mode 100644 index 00000000000..42f579a665e --- /dev/null +++ b/src/test/ui/suggestions/missing-trait-item.fixed @@ -0,0 +1,20 @@ +// run-rustfix + +trait T { + unsafe fn foo(a: &usize, b: &usize) -> usize; + fn bar(&self, a: &usize, b: &usize) -> usize; +} + +mod foo { + use super::T; + impl T for () { fn bar(&self, _: &usize, _: &usize) -> usize { unimplemented!() } + unsafe fn foo(_: &usize, _: &usize) -> usize { unimplemented!() } + } //~ ERROR not all trait items + + impl T for usize { //~ ERROR not all trait items + fn bar(&self, _: &usize, _: &usize) -> usize { unimplemented!() } + unsafe fn foo(_: &usize, _: &usize) -> usize { unimplemented!() } + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-trait-item.rs b/src/test/ui/suggestions/missing-trait-item.rs new file mode 100644 index 00000000000..b4fca25ba2f --- /dev/null +++ b/src/test/ui/suggestions/missing-trait-item.rs @@ -0,0 +1,16 @@ +// run-rustfix + +trait T { + unsafe fn foo(a: &usize, b: &usize) -> usize; + fn bar(&self, a: &usize, b: &usize) -> usize; +} + +mod foo { + use super::T; + impl T for () {} //~ ERROR not all trait items + + impl T for usize { //~ ERROR not all trait items + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-trait-item.stderr b/src/test/ui/suggestions/missing-trait-item.stderr new file mode 100644 index 00000000000..4a9d7b472c9 --- /dev/null +++ b/src/test/ui/suggestions/missing-trait-item.stderr @@ -0,0 +1,25 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar` + --> $DIR/missing-trait-item.rs:10:5 + | +LL | unsafe fn foo(a: &usize, b: &usize) -> usize; + | --------------------------------------------- `foo` from trait +LL | fn bar(&self, a: &usize, b: &usize) -> usize; + | --------------------------------------------- `bar` from trait +... +LL | impl T for () {} + | ^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + +error[E0046]: not all trait items implemented, missing: `foo`, `bar` + --> $DIR/missing-trait-item.rs:12:5 + | +LL | unsafe fn foo(a: &usize, b: &usize) -> usize; + | --------------------------------------------- `foo` from trait +LL | fn bar(&self, a: &usize, b: &usize) -> usize; + | --------------------------------------------- `bar` from trait +... +LL | impl T for usize { + | ^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0046`. |
