Skip to content

Commit

Permalink
Rollup merge of rust-lang#67460 - estebank:named-lts, r=nikomatsakis
Browse files Browse the repository at this point in the history
Tweak impl signature mismatch errors involving `RegionKind::ReVar` lifetimes

Fix rust-lang#66406, fix rust-lang#72106.

```
error: `impl` item signature doesn't match `trait` item signature
  --> $DIR/trait-param-without-lifetime-constraint.rs:14:5
   |
LL |     fn get_relation(&self) -> To;
   |     ----------------------------- expected `fn(&Article) -> &ProofReader`
...
LL |     fn get_relation(&self) -> &ProofReader {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
   |
   = note: expected `fn(&Article) -> &ProofReader`
              found `fn(&Article) -> &ProofReader`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
  --> $DIR/trait-param-without-lifetime-constraint.rs:10:31
   |
LL |     fn get_relation(&self) -> To;
   |                               ^^ consider borrowing this type parameter in the trait
```

r? @nikomatsakis
  • Loading branch information
RalfJung authored May 29, 2020
2 parents 96dd469 + 1bd6970 commit 7823651
Show file tree
Hide file tree
Showing 40 changed files with 324 additions and 105 deletions.
15 changes: 12 additions & 3 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,18 @@ impl Diagnostic {
expected_extra: &dyn fmt::Display,
found_extra: &dyn fmt::Display,
) -> &mut Self {
let expected_label = format!("expected {}", expected_label);

let found_label = format!("found {}", found_label);
let expected_label = expected_label.to_string();
let expected_label = if expected_label.is_empty() {
"expected".to_string()
} else {
format!("expected {}", expected_label)
};
let found_label = found_label.to_string();
let found_label = if found_label.is_empty() {
"found".to_string()
} else {
format!("found {}", found_label)
};
let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
(expected_label.len() - found_label.len(), 0)
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -987,12 +987,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}

fn push_ty_ref<'tcx>(
r: &ty::Region<'tcx>,
region: &ty::Region<'tcx>,
ty: Ty<'tcx>,
mutbl: hir::Mutability,
s: &mut DiagnosticStyledString,
) {
let mut r = r.to_string();
let mut r = region.to_string();
if r == "'_" {
r.clear();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{Subtype, ValuePairs};
use crate::infer::{Subtype, TyCtxtInferExt, ValuePairs};
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
use rustc_errors::ErrorReported;
use rustc_middle::ty::Ty;
use rustc_span::Span;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::{MultiSpan, Span};

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
Expand Down Expand Up @@ -36,7 +41,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
var_origin.span(),
sub_expected_found.expected,
sub_expected_found.found,
self.tcx().def_span(*trait_item_def_id),
*trait_item_def_id,
);
return Some(ErrorReported);
}
Expand All @@ -47,14 +52,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
None
}

fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) {
fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
let tcx = self.tcx();
let trait_sp = self.tcx().def_span(trait_def_id);
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.span_label(sp, &format!("found `{:?}`", found));
err.span_label(trait_sp, &format!("expected `{:?}`", expected));

// Get the span of all the used type parameters in the method.
let assoc_item = self.tcx().associated_item(trait_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
match assoc_item.kind {
ty::AssocKind::Fn => {
let hir = self.tcx().hir();
if let Some(hir_id) = assoc_item.def_id.as_local().map(|id| hir.as_local_hir_id(id))
{
if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
visitor.visit_fn_decl(decl);
}
}
}
_ => {}
}
let mut type_param_span: MultiSpan =
visitor.types.iter().cloned().collect::<Vec<_>>().into();
for &span in &visitor.types {
type_param_span.push_span_label(
span,
"consider borrowing this type parameter in the trait".to_string(),
);
}

if let Some((expected, found)) = tcx
.infer_ctxt()
.enter(|infcx| infcx.expected_found_str_ty(&ExpectedFound { expected, found }))
{
// Highlighted the differences when showing the "expected/found" note.
err.note_expected_found(&"", expected, &"", found);
} else {
// This fallback shouldn't be necessary, but let's keep it in just in case.
err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found));
}
err.span_help(
type_param_span,
"the lifetime requirements from the `impl` do not correspond to the requirements in \
the `trait`",
);
if visitor.types.is_empty() {
err.help(
"verify the lifetime relationships in the `trait` and `impl` between the `self` \
argument, the other inputs and its output",
);
}
err.emit();
}
}

struct TypeParamSpanVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
types: Vec<Span>,
}

impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
type Map = rustc_middle::hir::map::Map<'tcx>;

fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
}

fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
match arg.kind {
hir::TyKind::Rptr(_, ref mut_ty) => {
// We don't want to suggest looking into borrowing `&T` or `&Self`.
hir::intravisit::walk_ty(self, mut_ty.ty);
return;
}
hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
[segment]
if segment
.res
.map(|res| match res {
Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
_ => false,
})
.unwrap_or(false) =>
{
self.types.push(path.span);
}
_ => {}
},
_ => {}
}
hir::intravisit::walk_ty(self, arg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ note: ...so that the expression is assignable
|
LL | bar(foo, x)
| ^
= note: expected `Type<'_>`
found `Type<'a>`
= note: expected `Type<'_>`
found `Type<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
--> $DIR/project-fn-ret-invariant.rs:48:4
|
LL | bar(foo, x)
| ^^^^^^^^^^^
= note: expected `Type<'static>`
found `Type<'_>`
= note: expected `Type<'static>`
found `Type<'_>`

error: aborting due to previous error

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/error-codes/E0490.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ note: ...so that the expression is assignable
|
LL | let x: &'a _ = &y;
| ^^
= note: expected `&'a &()`
found `&'a &'b ()`
= note: expected `&'a &()`
found `&'a &'b ()`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 1:6...
--> $DIR/E0490.rs:1:6
|
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ note: ...so that the expression is assignable
|
LL | static_val(x);
| ^
= note: expected `std::boxed::Box<dyn std::fmt::Debug>`
found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
= note: expected `std::boxed::Box<dyn std::fmt::Debug>`
found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the types are compatible
--> $DIR/dyn-trait.rs:20:5
|
LL | static_val(x);
| ^^^^^^^^^^
= note: expected `StaticTrait`
found `StaticTrait`
= note: expected `StaticTrait`
found `StaticTrait`

error: aborting due to previous error

Expand Down
6 changes: 4 additions & 2 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ error: `impl` item signature doesn't match `trait` item signature
--> $DIR/mismatched_trait_impl-2.rs:8:5
|
LL | fn deref(&self) -> &dyn Trait {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
|
::: $SRC_DIR/libcore/ops/deref.rs:LL:COL
|
LL | fn deref(&self) -> &Self::Target;
| --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static)
| --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
|
= note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
found `fn(&Struct) -> &dyn Trait`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ 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
| ---------------------------------------------- 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
|
= note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
found `fn(&i32, &u32, &u32) -> &u32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output

error: aborting due to previous error

6 changes: 4 additions & 2 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ 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
| ---------------------------------------------- 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
|
= note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
found `fn(&i32, &u32, &u32) -> &u32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output

error[E0623]: lifetime mismatch
--> $DIR/mismatched_trait_impl.rs:10:9
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-16683.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ note: ...so that the types are compatible
|
LL | self.a();
| ^
= note: expected `&'a Self`
found `&Self`
= note: expected `&'a Self`
found `&Self`

error: aborting due to previous error

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-17758.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ note: ...so that the types are compatible
|
LL | self.foo();
| ^^^
= note: expected `&'a Self`
found `&Self`
= note: expected `&'a Self`
found `&Self`

error: aborting due to previous error

Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/issues/issue-20831-debruijn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ note: ...so that the types are compatible
|
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Publisher<'_>`
found `Publisher<'_>`
= note: expected `Publisher<'_>`
found `Publisher<'_>`

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> $DIR/issue-20831-debruijn.rs:28:33
Expand Down Expand Up @@ -117,8 +117,8 @@ note: ...so that the types are compatible
|
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Publisher<'_>`
found `Publisher<'_>`
= note: expected `Publisher<'_>`
found `Publisher<'_>`

error: aborting due to 4 previous errors

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-52213.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ note: ...so that the types are compatible
|
LL | match (&t,) {
| ^^^^^
= note: expected `(&&(T,),)`
found `(&&'a (T,),)`
= note: expected `(&&(T,),)`
found `(&&'a (T,),)`
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 1:27...
--> $DIR/issue-52213.rs:1:27
|
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/issues/issue-55796.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ note: ...so that the expression is assignable
|
LL | Box::new(self.out_edges(u).map(|e| e.target()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/issue-55796.rs:21:9
Expand All @@ -45,8 +45,8 @@ note: ...so that the expression is assignable
|
LL | Box::new(self.in_edges(u).map(|e| e.target()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`
= note: expected `std::boxed::Box<(dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node> + 'static)>`
found `std::boxed::Box<dyn std::iter::Iterator<Item = <Self as Graph<'a>>::Node>>`

error: aborting due to 2 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ 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
| ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
...
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
|
= note: expected `fn(&i32, &'a i32) -> &'a i32`
found `fn(&i32, &i32) -> &i32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/nll/issue-55394.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ note: ...so that the expression is assignable
|
LL | Foo { bar }
| ^^^^^^^^^^^
= note: expected `Foo<'_>`
found `Foo<'_>`
= note: expected `Foo<'_>`
found `Foo<'_>`

error: aborting due to previous error

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/nll/normalization-bounds-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ note: ...so that the types are compatible
|
LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Visitor<'d>`
found `Visitor<'_>`
= note: expected `Visitor<'d>`
found `Visitor<'_>`

error: aborting due to previous error

Expand Down
Loading

0 comments on commit 7823651

Please sign in to comment.