Skip to content

Commit

Permalink
For named lifetimes point only at method signature
Browse files Browse the repository at this point in the history
When refering to named lifetime conflict, point only at the method's
signature span instead of the entire method.

When the expected and found sup and sub traces are the same, avoid
redundant text.
  • Loading branch information
estebank committed Jan 28, 2018
1 parent ee06559 commit 6c02699
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 44 deletions.
65 changes: 45 additions & 20 deletions src/librustc/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,25 +175,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
ty::ReEarlyBound(_) |
ty::ReFree(_) => {
let scope = region.free_region_binding_scope(self);
let prefix = match *region {
ty::ReEarlyBound(ref br) => {
format!("the lifetime {} as defined on", br.name)
}
ty::ReFree(ref fr) => {
match fr.bound_region {
ty::BrAnon(idx) => {
format!("the anonymous lifetime #{} defined on", idx + 1)
}
ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
_ => {
format!("the lifetime {} as defined on",
fr.bound_region)
}
}
}
_ => bug!()
};

let node = self.hir.as_local_node_id(scope)
.unwrap_or(DUMMY_NODE_ID);
let unknown;
Expand All @@ -218,7 +199,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
&unknown
}
};
let (msg, opt_span) = explain_span(self, tag, self.hir.span(node));
let (prefix, span) = match *region {
ty::ReEarlyBound(ref br) => {
(format!("the lifetime {} as defined on", br.name),
self.sess.codemap().def_span(self.hir.span(node)))
}
ty::ReFree(ref fr) => {
match fr.bound_region {
ty::BrAnon(idx) => {
(format!("the anonymous lifetime #{} defined on", idx + 1),
self.hir.span(node))
}
ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(),
self.hir.span(node)),
_ => (format!("the lifetime {} as defined on", fr.bound_region),
self.sess.codemap().def_span(self.hir.span(node))),
}
}
_ => bug!()
};
let (msg, opt_span) = explain_span(self, tag, span);
(format!("{} {}", prefix, msg), opt_span)
}

Expand Down Expand Up @@ -1075,6 +1075,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
sup_region,
"...");

match (&sup_origin, &sub_origin) {
(&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
if let (Some((sup_expected, sup_found)),
Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values),
self.values_str(&sub_trace.values)) {
if sub_expected == sup_expected && sub_found == sup_found {
self.tcx.note_and_explain_region(
region_scope_tree,
&mut err,
"...but the lifetime must also be valid for ",
sub_region,
"...",
);
err.note(&format!("...so that the {}:\nexpected {}\n found {}",
sup_trace.cause.as_requirement_str(),
sup_expected.content(),
sup_found.content()));
err.emit();
return;
}
}
}
_ => {}
}

self.note_region_origin(&mut err, &sup_origin);

self.tcx.note_and_explain_region(region_scope_tree, &mut err,
Expand Down
52 changes: 52 additions & 0 deletions src/test/ui/borrowck/regions-bound-missing-bound-in-impl.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration
--> $DIR/regions-bound-missing-bound-in-impl.rs:28:5
|
28 | / fn no_bound<'b:'a>(self, b: Inv<'b>) {
29 | | //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
30 | | }
| |_____^ lifetimes do not match trait

error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration
--> $DIR/regions-bound-missing-bound-in-impl.rs:32:5
|
32 | / fn has_bound<'b>(self, b: Inv<'b>) {
33 | | //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
34 | | }
| |_____^ lifetimes do not match trait

error[E0308]: method not compatible with trait
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
|
36 | / fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
37 | | //~^ ERROR method not compatible with trait
38 | | //
39 | | // Note: This is a terrible error message. It is caused
... |
47 | | // cases.
48 | | }
| |_____^ lifetime mismatch
|
= note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)`
found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)`
note: the lifetime 'c as defined on the method body at 36:5...
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
|
36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 36:5
--> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
|
36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0276]: impl has stricter requirements than trait
--> $DIR/regions-bound-missing-bound-in-impl.rs:53:5
|
24 | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
| ------------------------------------------------------- definition of `another_bound` from trait
...
53 | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't`

error: aborting due to 4 previous errors

Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,8 @@ note: the anonymous lifetime #2 defined on the body at 47:29...
note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
--> $DIR/expect-region-supply-region.rs:42:1
|
42 | / fn expect_bound_supply_named<'x>() {
43 | | let mut f: Option<&u32> = None;
44 | |
45 | | // Here we give a type annotation that `x` should be free. We get
... |
54 | | });
55 | | }
| |_^
42 | fn expect_bound_supply_named<'x>() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
--> $DIR/expect-region-supply-region.rs:47:33
Expand All @@ -61,14 +55,8 @@ error[E0308]: mismatched types
note: the lifetime 'x as defined on the function body at 42:1...
--> $DIR/expect-region-supply-region.rs:42:1
|
42 | / fn expect_bound_supply_named<'x>() {
43 | | let mut f: Option<&u32> = None;
44 | |
45 | | // Here we give a type annotation that `x` should be free. We get
... |
54 | | });
55 | | }
| |_^
42 | fn expect_bound_supply_named<'x>() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
--> $DIR/expect-region-supply-region.rs:47:29
|
Expand Down
22 changes: 22 additions & 0 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ops::Deref;
trait Trait {}

struct Struct;

impl Deref for Struct {
type Target = Trait;
fn deref(&self) -> &Trait {
unimplemented!();
}
}
//~^^^^ ERROR cannot infer an appropriate lifetime for lifetime parameter
24 changes: 24 additions & 0 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error[E0601]: main function not found

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
--> $DIR/mismatched_trait_impl-2.rs:18:5
|
18 | / fn deref(&self) -> &Trait {
19 | | unimplemented!();
20 | | }
| |_____^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
--> $DIR/mismatched_trait_impl-2.rs:18:5
|
18 | / fn deref(&self) -> &Trait {
19 | | unimplemented!();
20 | | }
| |_____^
= 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) -> &Trait + 'static
found fn(&Struct) -> &Trait

error: aborting due to 2 previous errors

11 changes: 3 additions & 8 deletions src/test/ui/in-band-lifetimes/mismatched_trait_impl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,11 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th
20 | | x
21 | | }
| |_____^
= 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: but, the lifetime must be valid for the lifetime 'a as defined on the method body at 19:5...
note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 19:5...
--> $DIR/mismatched_trait_impl.rs:19:5
|
19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
20 | | x
21 | | }
| |_____^
19 | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the method type is compatible with trait:
expected fn(&i32, &'a u32, &u32) -> &'a u32
found fn(&i32, &u32, &u32) -> &u32
Expand Down

0 comments on commit 6c02699

Please sign in to comment.