Skip to content

Commit

Permalink
Rollup merge of rust-lang#65068 - estebank:trait-impl-lt-mismatch, r=…
Browse files Browse the repository at this point in the history
…nikomatsakis

Custom lifetime error for `impl` item doesn't conform to `trait`

Partly addresses rust-lang#42706, rust-lang#41343, fix rust-lang#40900.
  • Loading branch information
tmandry committed Oct 30, 2019
2 parents aa69777 + 213fd1f commit ab9b789
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 53 deletions.
2 changes: 2 additions & 0 deletions src/librustc/infer/error_reporting/nice_region_error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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>) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ErrorReported> {
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();
}
}
4 changes: 3 additions & 1 deletion src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore-x86
// ^ due to stderr output differences
use std::ops::Deref;
trait Trait {}

Expand All @@ -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() {}
23 changes: 9 additions & 14 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
Original file line number Diff line number Diff line change
@@ -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`.
25 changes: 7 additions & 18 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl.nll.stderr
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion src/test/ui/in-band-lifetimes/mismatched_trait_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
25 changes: 7 additions & 18 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -32,4 +22,3 @@ LL | x

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0495`.
12 changes: 12 additions & 0 deletions src/test/ui/lifetimes/lifetime-mismatch-between-trait-and-impl.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion src/test/ui/reject-specialized-drops-8142.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ impl<One> Drop for V<One,One> { 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() { }

0 comments on commit ab9b789

Please sign in to comment.