diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 45f0672f1c0b4e80fc1f5ce6f66c7bbdb1807660..f7e05f4777ecce97d554d17c4f93bd0370079f5c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1131,7 +1131,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, if !is_implemented { if !is_provided { - missing_items.push(trait_item.name()); + missing_items.push(trait_item); } else if associated_type_overridden { invalidated_items.push(trait_item.name()); } @@ -1139,16 +1139,25 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } if !missing_items.is_empty() { - struct_span_err!(tcx.sess, impl_span, E0046, + let mut err = struct_span_err!(tcx.sess, impl_span, E0046, "not all trait items implemented, missing: `{}`", missing_items.iter() - .map(|name| name.to_string()) - .collect::>().join("`, `")) - .span_label(impl_span, &format!("missing `{}` in implementation", + .map(|trait_item| trait_item.name().to_string()) + .collect::>().join("`, `")); + err.span_label(impl_span, &format!("missing `{}` in implementation", missing_items.iter() - .map(|name| name.to_string()) - .collect::>().join("`, `")) - ).emit(); + .map(|trait_item| trait_item.name().to_string()) + .collect::>().join("`, `"))); + for trait_item in missing_items { + if let Some(span) = tcx.map.span_if_local(trait_item.def_id()) { + err.span_label(span, &format!("`{}` from trait", trait_item.name())); + } else { + err.note(&format!("`{}` from trait: `{}`", + trait_item.name(), + signature(trait_item))); + } + } + err.emit(); } if !invalidated_items.is_empty() { @@ -1163,6 +1172,14 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } +fn signature<'a, 'tcx>(item: &ty::ImplOrTraitItem) -> String { + match *item { + ty::MethodTraitItem(ref item) => format!("{}", item.fty.sig.0), + ty::TypeTraitItem(ref item) => format!("type {};", item.name.to_string()), + ty::ConstTraitItem(ref item) => format!("const {}: {:?};", item.name.to_string(), item.ty), + } +} + /// Checks a constant with a given type. fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, diff --git a/src/test/run-make/missing-items/Makefile b/src/test/run-make/missing-items/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bcc9cdf2d65274404235126fb67183ca83bda50c --- /dev/null +++ b/src/test/run-make/missing-items/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +all: + $(RUSTC) m1.rs -C prefer-dynamic + $(RUSTC) m2.rs 2>&1 | grep "error\[E0046\]: not all trait items implemented, missing: .*" + $(RUSTC) m2.rs 2>&1 | grep " --> m2.rs:18:1" + $(RUSTC) m2.rs 2>&1 | grep " | ^ missing .CONSTANT., .Type., .method. in implementation" + $(RUSTC) m2.rs 2>&1 | grep " = note: .CONSTANT. from trait: .const CONSTANT: u32;." + $(RUSTC) m2.rs 2>&1 | grep " = note: .Type. from trait: .type Type;." + $(RUSTC) m2.rs 2>&1 | grep " = note: .method. from trait: .fn(&Self, std::string::String) -> ::Type." diff --git a/src/test/run-make/missing-items/m1.rs b/src/test/run-make/missing-items/m1.rs new file mode 100644 index 0000000000000000000000000000000000000000..060c7a9571b7b61ffb4f9f1b8bac300fc94323fa --- /dev/null +++ b/src/test/run-make/missing-items/m1.rs @@ -0,0 +1,17 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] +#![crate_type = "dylib"] +pub trait X { + const CONSTANT: u32; + type Type; + fn method(&self, s: String) -> Self::Type; +} diff --git a/src/test/run-make/missing-items/m2.rs b/src/test/run-make/missing-items/m2.rs new file mode 100644 index 0000000000000000000000000000000000000000..7055673acc9a91db82dff223b8d7c4b24aecb37a --- /dev/null +++ b/src/test/run-make/missing-items/m2.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_consts)] +#![crate_type = "dylib"] +extern crate m1; + +struct X { +} + +impl m1::X for X { +} diff --git a/src/test/compile-fail/E0046.rs b/src/test/ui/span/E0046.rs similarity index 95% rename from src/test/compile-fail/E0046.rs rename to src/test/ui/span/E0046.rs index a8b56b2b9ab37248a596f3f37df0d5e15290ff34..9e757860a857b3f96309eb8a721b3c3ea94c637a 100644 --- a/src/test/compile-fail/E0046.rs +++ b/src/test/ui/span/E0046.rs @@ -10,6 +10,7 @@ trait Foo { fn foo(); + //~^ NOTE `foo` from trait } struct Bar; diff --git a/src/test/ui/span/E0046.stderr b/src/test/ui/span/E0046.stderr new file mode 100644 index 0000000000000000000000000000000000000000..729a515612463396cf588abc8c38f174ed0c092f --- /dev/null +++ b/src/test/ui/span/E0046.stderr @@ -0,0 +1,11 @@ +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/E0046.rs:18:1 + | +12 | fn foo(); + | --------- `foo` from trait +... +18 | impl Foo for Bar {} + | ^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error: aborting due to previous error + diff --git a/src/test/compile-fail/impl-wrong-item-for-trait.rs b/src/test/ui/span/impl-wrong-item-for-trait.rs similarity index 92% rename from src/test/compile-fail/impl-wrong-item-for-trait.rs rename to src/test/ui/span/impl-wrong-item-for-trait.rs index 388c9a1729cca08e5a8a510807bcf516b87fd1ba..54ed42af5d582028bd4b241ddbc32daebfddb9ae 100644 --- a/src/test/compile-fail/impl-wrong-item-for-trait.rs +++ b/src/test/ui/span/impl-wrong-item-for-trait.rs @@ -10,11 +10,11 @@ #![feature(associated_consts)] +use std::fmt::Debug; + trait Foo { fn bar(&self); - //~^ NOTE item in trait - //~| NOTE item in trait - const MY_CONST: u32; //~ NOTE item in trait + const MY_CONST: u32; } pub struct FooConstForMethod; @@ -50,4 +50,7 @@ impl Foo for FooTypeForMethod { const MY_CONST: u32 = 1; } +impl Debug for FooTypeForMethod { +} + fn main () {} diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr new file mode 100644 index 0000000000000000000000000000000000000000..244285e358453ee9737d9a238c5b612072b0407a --- /dev/null +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -0,0 +1,64 @@ +error[E0323]: item `bar` is an associated const, which doesn't match its trait `` + --> $DIR/impl-wrong-item-for-trait.rs:25:5 + | +16 | fn bar(&self); + | -------------- item in trait +... +25 | const bar: u64 = 1; + | ^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0046]: not all trait items implemented, missing: `bar` + --> $DIR/impl-wrong-item-for-trait.rs:22:1 + | +16 | fn bar(&self); + | -------------- `bar` from trait +... +22 | impl Foo for FooConstForMethod { + | ^ missing `bar` in implementation + +error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `` + --> $DIR/impl-wrong-item-for-trait.rs:37:5 + | +17 | const MY_CONST: u32; + | -------------------- item in trait +... +37 | fn MY_CONST() {} + | ^^^^^^^^^^^^^^^^ does not match trait + +error[E0046]: not all trait items implemented, missing: `MY_CONST` + --> $DIR/impl-wrong-item-for-trait.rs:33:1 + | +17 | const MY_CONST: u32; + | -------------------- `MY_CONST` from trait +... +33 | impl Foo for FooMethodForConst { + | ^ missing `MY_CONST` in implementation + +error[E0325]: item `bar` is an associated type, which doesn't match its trait `` + --> $DIR/impl-wrong-item-for-trait.rs:47:5 + | +16 | fn bar(&self); + | -------------- item in trait +... +47 | type bar = u64; + | ^^^^^^^^^^^^^^^ does not match trait + +error[E0046]: not all trait items implemented, missing: `bar` + --> $DIR/impl-wrong-item-for-trait.rs:44:1 + | +16 | fn bar(&self); + | -------------- `bar` from trait +... +44 | impl Foo for FooTypeForMethod { + | ^ missing `bar` in implementation + +error[E0046]: not all trait items implemented, missing: `fmt` + --> $DIR/impl-wrong-item-for-trait.rs:53:1 + | +53 | impl Debug for FooTypeForMethod { + | ^ missing `fmt` in implementation + | + = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + +error: aborting due to 7 previous errors + diff --git a/src/test/compile-fail/issue-23729.rs b/src/test/ui/span/issue-23729.rs similarity index 96% rename from src/test/compile-fail/issue-23729.rs rename to src/test/ui/span/issue-23729.rs index b1047ce18cccdf552ce6bd2ceee305fe78fe5a81..66134a03baf41319a72d8af61edd68e9c0f663fc 100644 --- a/src/test/compile-fail/issue-23729.rs +++ b/src/test/ui/span/issue-23729.rs @@ -20,6 +20,7 @@ struct Recurrence { impl Iterator for Recurrence { //~^ ERROR E0046 //~| NOTE missing `Item` in implementation + //~| NOTE `Item` from trait: `type Item;` #[inline] fn next(&mut self) -> Option { if self.pos < 2 { diff --git a/src/test/ui/span/issue-23729.stderr b/src/test/ui/span/issue-23729.stderr new file mode 100644 index 0000000000000000000000000000000000000000..493ca01778bc15de42d55ce7865f1e381bc2f9cf --- /dev/null +++ b/src/test/ui/span/issue-23729.stderr @@ -0,0 +1,10 @@ +error[E0046]: not all trait items implemented, missing: `Item` + --> $DIR/issue-23729.rs:20:9 + | +20 | impl Iterator for Recurrence { + | ^ missing `Item` in implementation + | + = note: `Item` from trait: `type Item;` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-23827.rs b/src/test/ui/span/issue-23827.rs similarity index 96% rename from src/test/compile-fail/issue-23827.rs rename to src/test/ui/span/issue-23827.rs index 2062e2373129bd77d698d0aa555743dd85d0494d..a5ab443597b9b71b059e0b365faaa28cd70bae05 100644 --- a/src/test/compile-fail/issue-23827.rs +++ b/src/test/ui/span/issue-23827.rs @@ -36,6 +36,7 @@ extern "rust-call" fn call_mut(&mut self, (comp,): (C,)) -> Prototype { impl FnOnce<(C,)> for Prototype { //~^ ERROR E0046 //~| NOTE missing `Output` in implementation + //~| NOTE `Output` from trait: `type Output;` extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype { Fn::call(&self, (comp,)) } diff --git a/src/test/ui/span/issue-23827.stderr b/src/test/ui/span/issue-23827.stderr new file mode 100644 index 0000000000000000000000000000000000000000..5130bb53a198bf2bb9ce01bd883ac44d1dbdb450 --- /dev/null +++ b/src/test/ui/span/issue-23827.stderr @@ -0,0 +1,10 @@ +error[E0046]: not all trait items implemented, missing: `Output` + --> $DIR/issue-23827.rs:36:1 + | +36 | impl FnOnce<(C,)> for Prototype { + | ^ missing `Output` in implementation + | + = note: `Output` from trait: `type Output;` + +error: aborting due to previous error + diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/ui/span/issue-24356.rs similarity index 94% rename from src/test/compile-fail/issue-24356.rs rename to src/test/ui/span/issue-24356.rs index d39fd539dcebc301350cc85ba5e606408c774f20..0997dc802f88bfc7a9cc70c8959e278ea2576416 100644 --- a/src/test/compile-fail/issue-24356.rs +++ b/src/test/ui/span/issue-24356.rs @@ -30,6 +30,7 @@ fn deref(&self) -> &i8 { &self.0 } impl Deref for Thing { //~^ ERROR E0046 //~| NOTE missing `Target` in implementation + //~| NOTE `Target` from trait: `type Target;` fn deref(&self) -> i8 { self.0 } } diff --git a/src/test/ui/span/issue-24356.stderr b/src/test/ui/span/issue-24356.stderr new file mode 100644 index 0000000000000000000000000000000000000000..906ef25ca0e10b4d3d405ab839df60ffb2b6d4ac --- /dev/null +++ b/src/test/ui/span/issue-24356.stderr @@ -0,0 +1,10 @@ +error[E0046]: not all trait items implemented, missing: `Target` + --> $DIR/issue-24356.rs:30:9 + | +30 | impl Deref for Thing { + | ^ missing `Target` in implementation + | + = note: `Target` from trait: `type Target;` + +error: aborting due to previous error +