diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs index 1edb1c601bf1a..cd003aa8dab70 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/mod.rs @@ -12,6 +12,7 @@ mod named_anon_conflict; mod placeholder_error; mod outlives_closure; mod static_impl_trait; +mod trait_impl_difference; mod util; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { @@ -73,6 +74,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { .or_else(|| self.try_report_anon_anon_conflict()) .or_else(|| self.try_report_outlives_closure()) .or_else(|| self.try_report_static_impl_trait()) + .or_else(|| self.try_report_impl_not_conforming_to_trait()) } pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) { diff --git a/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs new file mode 100644 index 0000000000000..0194300c50721 --- /dev/null +++ b/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -0,0 +1,59 @@ +//! Error Reporting for `impl` items that do not match the obligations from their `trait`. + +use syntax_pos::Span; +use crate::ty::Ty; +use crate::infer::{ValuePairs, Subtype}; +use crate::infer::error_reporting::nice_region_error::NiceRegionError; +use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::util::common::ErrorReported; +use crate::traits::ObligationCauseCode::CompareImplMethodObligation; + +impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { + /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. + pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option { + if let Some(ref error) = self.error { + debug!("try_report_impl_not_conforming_to_trait {:?}", error); + if let RegionResolutionError::SubSupConflict( + _, + var_origin, + sub_origin, + _sub, + sup_origin, + _sup, + ) = error.clone() { + match (&sup_origin, &sub_origin) { + (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) => { + if let ( + ValuePairs::Types(sub_expected_found), + ValuePairs::Types(sup_expected_found), + CompareImplMethodObligation { trait_item_def_id, .. }, + ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) { + if sup_expected_found == sub_expected_found { + self.emit_err( + var_origin.span(), + sub_expected_found.expected, + sub_expected_found.found, + self.tcx().def_span(*trait_item_def_id), + ); + return Some(ErrorReported); + } + } + } + _ => {} + } + } + } + None + } + + fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) { + let mut err = self.tcx().sess.struct_span_err( + sp, + "`impl` item signature doesn't match `trait` item signature", + ); + err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); + err.span_label(sp, &format!("found {:?}", found)); + err.span_label(impl_sp, &format!("expected {:?}", expected)); + err.emit(); + } +} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs index d131a944721d0..eca9a67fcb387 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs @@ -1,3 +1,5 @@ +// ignore-x86 +// ^ due to stderr output differences use std::ops::Deref; trait Trait {} @@ -6,9 +8,9 @@ struct Struct; impl Deref for Struct { type Target = dyn Trait; fn deref(&self) -> &dyn Trait { + //~^ ERROR `impl` item signature doesn't match `trait` item signature unimplemented!(); } } -//~^^^^ ERROR cannot infer an appropriate lifetime for lifetime parameter fn main() {} diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr index c1ec536ef4362..d3862e3d4df60 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr @@ -1,21 +1,16 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements - --> $DIR/mismatched_trait_impl-2.rs:8:5 +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/mismatched_trait_impl-2.rs:10:5 | LL | fn deref(&self) -> &dyn Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait + | + ::: $SRC_DIR/libcore/ops/deref.rs:LL:COL | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5... - --> $DIR/mismatched_trait_impl-2.rs:8:5 +LL | fn deref(&self) -> &Self::Target; + | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static) | -LL | / fn deref(&self) -> &dyn Trait { -LL | | unimplemented!(); -LL | | } - | |_____^ - = note: ...but the lifetime must also be valid for the static lifetime... - = note: ...so that the method type is compatible with trait: - expected fn(&Struct) -> &(dyn Trait + 'static) - found fn(&Struct) -> &dyn Trait + = note: expected `fn(&Struct) -> &(dyn Trait + 'static)` + found `fn(&Struct) -> &dyn Trait` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr index b5287f32a5045..c245d78ae828f 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr @@ -1,25 +1,14 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements +error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl.rs:9:5 | +LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; + | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32 +... LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 9:5... - --> $DIR/mismatched_trait_impl.rs:9:5 - | -LL | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { -LL | | x -LL | | } - | |_____^ -note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the method body at 9:32... - --> $DIR/mismatched_trait_impl.rs:9:32 - | -LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^ - = note: ...so that the method type is compatible with trait: - expected fn(&i32, &'a u32, &u32) -> &'a u32 - found fn(&i32, &u32, &u32) -> &u32 + = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` + found `fn(&i32, &u32, &u32) -> &u32` error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs index f2ba81af9b638..b9e02e967c126 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs @@ -6,7 +6,7 @@ trait Get { } impl Get for i32 { - fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer + fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR `impl` item signature doesn't match x //~ ERROR lifetime mismatch } } diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr index 734ca0819e416..bc302e91c1c51 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr @@ -1,24 +1,14 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements +error: `impl` item signature doesn't match `trait` item signature --> $DIR/mismatched_trait_impl.rs:9:5 | +LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32; + | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32 +... LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32 | -note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 9:5... - --> $DIR/mismatched_trait_impl.rs:9:5 - | -LL | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { -LL | | x -LL | | } - | |_____^ -note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the method body at 9:32... - --> $DIR/mismatched_trait_impl.rs:9:32 - | -LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { - | ^^ - = note: ...so that the method type is compatible with trait: - expected fn(&i32, &'a u32, &u32) -> &'a u32 - found fn(&i32, &u32, &u32) -> &u32 + = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32` + found `fn(&i32, &u32, &u32) -> &u32` error[E0623]: lifetime mismatch --> $DIR/mismatched_trait_impl.rs:10:9 @@ -32,4 +22,3 @@ LL | x error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0495`. diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.rs b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.rs new file mode 100644 index 0000000000000..2ce1a0f454651 --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.rs @@ -0,0 +1,12 @@ +trait Foo { + fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32; +} + +impl Foo for () { + fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + //~^ ERROR `impl` item signature doesn't match `trait` item signature + if x > y { x } else { y } + } +} + +fn main() {} diff --git a/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr new file mode 100644 index 0000000000000..d07f305954b6e --- /dev/null +++ b/src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.stderr @@ -0,0 +1,14 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5 + | +LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32; + | ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32 +... +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32 + | + = note: expected `fn(&i32, &'a i32) -> &'a i32` + found `fn(&i32, &i32) -> &i32` + +error: aborting due to previous error + diff --git a/src/test/ui/reject-specialized-drops-8142.rs b/src/test/ui/reject-specialized-drops-8142.rs index f047e16bc0b94..b3cb83f94e053 100644 --- a/src/test/ui/reject-specialized-drops-8142.rs +++ b/src/test/ui/reject-specialized-drops-8142.rs @@ -52,6 +52,6 @@ impl Drop for V { fn drop(&mut self) { } } // REJECT //~^ ERROR Implementations of Drop cannot be specialized impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT -//~^ ERROR cannot infer an appropriate lifetime +//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'lw` pub fn main() { }