Skip to content

Commit b413f34

Browse files
committed
Auto merge of #44079 - gaurikholkar:named_conf, r=nikomatsakis
Extend E0623 for LateBound and EarlyBound Regions This is a fix for #43882 ``` fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) { x.push(y); } ``` now gives ``` error[E0623]: lifetime mismatch --> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:12 | 11 | fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) { | ------ ------ these two types are declared with different lifetimes... 12 | x.push(y); | ^ ...but data from `y` flows into `x` here ``` cc @nikomatsakis @arielb1 Please ignore the second commit. It will be merged in a separate PR.
2 parents d290dec + 88e4bf6 commit b413f34

22 files changed

+344
-178
lines changed

src/librustc/diagnostics.rs

+48-12
Original file line numberDiff line numberDiff line change
@@ -1389,30 +1389,66 @@ A lifetime of reference outlives lifetime of borrowed content.
13891389
Erroneous code example:
13901390
13911391
```compile_fail,E0312
1392-
fn make_child<'human, 'elve>(x: &mut &'human isize, y: &mut &'elve isize) {
1393-
*x = *y;
1394-
// error: lifetime of reference outlives lifetime of borrowed content
1392+
fn make_child<'tree, 'human>(
1393+
x: &'human i32,
1394+
y: &'tree i32
1395+
) -> &'human i32 {
1396+
if x > y
1397+
{ x }
1398+
else
1399+
{ y }
1400+
// error: lifetime of reference outlives lifetime of borrowed content
13951401
}
13961402
```
13971403
1398-
The compiler cannot determine if the `human` lifetime will live long enough
1399-
to keep up on the elve one. To solve this error, you have to give an
1400-
explicit lifetime hierarchy:
1404+
The function declares that it returns a reference with the `'human`
1405+
lifetime, but it may return data with the `'tree` lifetime. As neither
1406+
lifetime is declared longer than the other, this results in an
1407+
error. Sometimes, this error is because the function *body* is
1408+
incorrect -- that is, maybe you did not *mean* to return data from
1409+
`y`. In that case, you should fix the function body.
1410+
1411+
Often, however, the body is correct. In that case, the function
1412+
signature needs to be altered to match the body, so that the caller
1413+
understands that data from either `x` or `y` may be returned. The
1414+
simplest way to do this is to give both function parameters the *same*
1415+
named lifetime:
14011416
14021417
```
1403-
fn make_child<'human, 'elve: 'human>(x: &mut &'human isize,
1404-
y: &mut &'elve isize) {
1405-
*x = *y; // ok!
1418+
fn make_child<'human>(
1419+
x: &'human i32,
1420+
y: &'human i32
1421+
) -> &'human i32 {
1422+
if x > y
1423+
{ x }
1424+
else
1425+
{ y } // ok!
14061426
}
14071427
```
14081428
1409-
Or use the same lifetime for every variable:
1429+
However, in some cases, you may prefer to explicitly declare that one lifetime
1430+
outlives another using a `where` clause:
14101431
14111432
```
1412-
fn make_child<'elve>(x: &mut &'elve isize, y: &mut &'elve isize) {
1413-
*x = *y; // ok!
1433+
fn make_child<'tree, 'human>(
1434+
x: &'human i32,
1435+
y: &'tree i32
1436+
) -> &'human i32
1437+
where
1438+
'tree: 'human
1439+
{
1440+
if x > y
1441+
{ x }
1442+
else
1443+
{ y } // ok!
14141444
}
14151445
```
1446+
1447+
Here, the where clause `'tree: 'human` can be read as "the lifetime
1448+
'tree outlives the lifetime 'human" -- meaning, references with the
1449+
`'tree` lifetime live *at least as long as* references with the
1450+
`'human` lifetime. Therefore, it is safe to return data with lifetime
1451+
`'tree` when data with the lifetime `'human` is needed.
14161452
"##,
14171453

14181454
E0317: r##"

src/librustc/infer/error_reporting/anon_anon_conflict.rs src/librustc/infer/error_reporting/different_lifetimes.rs

+81-45
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
4646
};
4747

4848
// Determine whether the sub and sup consist of both anonymous (elided) regions.
49-
let anon_reg_sup = or_false!(self.is_suitable_anonymous_region(sup));
49+
let anon_reg_sup = or_false!(self.is_suitable_region(sup));
5050

51-
let anon_reg_sub = or_false!(self.is_suitable_anonymous_region(sub));
51+
let anon_reg_sub = or_false!(self.is_suitable_region(sub));
5252
let scope_def_id_sup = anon_reg_sup.def_id;
5353
let bregion_sup = anon_reg_sup.boundregion;
5454
let scope_def_id_sub = anon_reg_sub.def_id;
@@ -57,10 +57,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
5757
let ty_sup = or_false!(self.find_anon_type(sup, &bregion_sup));
5858

5959
let ty_sub = or_false!(self.find_anon_type(sub, &bregion_sub));
60+
debug!("try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}",
61+
ty_sub,
62+
sup,
63+
bregion_sup);
64+
debug!("try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}",
65+
ty_sup,
66+
sub,
67+
bregion_sub);
6068

6169
let (main_label, label1, label2) = if let (Some(sup_arg), Some(sub_arg)) =
62-
(self.find_arg_with_anonymous_region(sup, sup),
63-
self.find_arg_with_anonymous_region(sub, sub)) {
70+
(self.find_arg_with_region(sup, sup), self.find_arg_with_region(sub, sub)) {
6471

6572
let (anon_arg_sup, is_first_sup, anon_arg_sub, is_first_sub) =
6673
(sup_arg.arg, sup_arg.is_first, sub_arg.arg, sub_arg.is_first);
@@ -97,6 +104,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
97104
(span_label, span_label_var1, span_label_var2)
98105
}
99106
} else {
107+
debug!("no arg with anon region found");
108+
debug!("try_report_anon_anon_conflict: is_suitable(sub) = {:?}",
109+
self.is_suitable_region(sub));
110+
debug!("try_report_anon_anon_conflict: is_suitable(sup) = {:?}",
111+
self.is_suitable_region(sup));
100112
return false;
101113
};
102114

@@ -124,35 +136,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
124136
/// The function returns the nested type corresponding to the anonymous region
125137
/// for e.g. `&u8` and Vec<`&u8`.
126138
pub fn find_anon_type(&self, region: Region<'tcx>, br: &ty::BoundRegion) -> Option<&hir::Ty> {
127-
if let Some(anon_reg) = self.is_suitable_anonymous_region(region) {
139+
if let Some(anon_reg) = self.is_suitable_region(region) {
128140
let def_id = anon_reg.def_id;
129141
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
130-
let ret_ty = self.tcx.type_of(def_id);
131-
if let ty::TyFnDef(_, _) = ret_ty.sty {
132-
let inputs: &[_] =
133-
match self.tcx.hir.get(node_id) {
134-
hir_map::NodeItem(&hir::Item {
135-
node: hir::ItemFn(ref fndecl, ..), ..
136-
}) => &fndecl.inputs,
137-
hir_map::NodeTraitItem(&hir::TraitItem {
138-
node: hir::TraitItemKind::Method(ref fndecl, ..),
139-
..
140-
}) => &fndecl.decl.inputs,
141-
hir_map::NodeImplItem(&hir::ImplItem {
142-
node: hir::ImplItemKind::Method(ref fndecl, ..),
143-
..
144-
}) => &fndecl.decl.inputs,
142+
let inputs: &[_] = match self.tcx.hir.get(node_id) {
143+
hir_map::NodeItem(&hir::Item { node: hir::ItemFn(ref fndecl, ..), .. }) => {
144+
&fndecl.inputs
145+
}
146+
hir_map::NodeTraitItem(&hir::TraitItem {
147+
node: hir::TraitItemKind::Method(ref fndecl, ..), ..
148+
}) => &fndecl.decl.inputs,
149+
hir_map::NodeImplItem(&hir::ImplItem {
150+
node: hir::ImplItemKind::Method(ref fndecl, ..), ..
151+
}) => &fndecl.decl.inputs,
145152

146-
_ => &[],
147-
};
153+
_ => &[],
154+
};
148155

149-
return inputs
150-
.iter()
151-
.filter_map(|arg| {
152-
self.find_component_for_bound_region(&**arg, br)
153-
})
154-
.next();
155-
}
156+
return inputs
157+
.iter()
158+
.filter_map(|arg| self.find_component_for_bound_region(&**arg, br))
159+
.next();
156160
}
157161
}
158162
None
@@ -199,30 +203,62 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> {
199203
}
200204

201205
fn visit_ty(&mut self, arg: &'gcx hir::Ty) {
202-
// Find the index of the anonymous region that was part of the
203-
// error. We will then search the function parameters for a bound
204-
// region at the right depth with the same index.
205-
let br_index = match self.bound_region {
206-
ty::BrAnon(index) => index,
207-
_ => return,
208-
};
209-
210206
match arg.node {
211207
hir::TyRptr(ref lifetime, _) => {
208+
// the lifetime of the TyRptr
212209
let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
213-
match self.infcx.tcx.named_region(hir_id) {
214-
// the lifetime of the TyRptr
215-
Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
210+
match (self.infcx.tcx.named_region(hir_id), self.bound_region) {
211+
// Find the index of the anonymous region that was part of the
212+
// error. We will then search the function parameters for a bound
213+
// region at the right depth with the same index
214+
(Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)),
215+
ty::BrAnon(br_index)) => {
216+
debug!("LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}",
217+
debruijn_index.depth,
218+
anon_index,
219+
br_index);
216220
if debruijn_index.depth == 1 && anon_index == br_index {
217221
self.found_type = Some(arg);
218222
return; // we can stop visiting now
219223
}
220224
}
221-
Some(rl::Region::Static) |
222-
Some(rl::Region::EarlyBound(_, _)) |
223-
Some(rl::Region::LateBound(_, _)) |
224-
Some(rl::Region::Free(_, _)) |
225-
None => {
225+
226+
// Find the index of the named region that was part of the
227+
// error. We will then search the function parameters for a bound
228+
// region at the right depth with the same index
229+
(Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
230+
debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \
231+
def_id={:?}",
232+
self.infcx.tcx.hir.local_def_id(id),
233+
def_id);
234+
if self.infcx.tcx.hir.local_def_id(id) == def_id {
235+
self.found_type = Some(arg);
236+
return; // we can stop visiting now
237+
}
238+
}
239+
240+
// Find the index of the named region that was part of the
241+
// error. We will then search the function parameters for a bound
242+
// region at the right depth with the same index
243+
(Some(rl::Region::LateBound(debruijn_index, id)), ty::BrNamed(def_id, _)) => {
244+
debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
245+
debruijn_index.depth);
246+
debug!("self.infcx.tcx.hir.local_def_id(id)={:?}",
247+
self.infcx.tcx.hir.local_def_id(id));
248+
debug!("def_id={:?}", def_id);
249+
if debruijn_index.depth == 1 &&
250+
self.infcx.tcx.hir.local_def_id(id) == def_id {
251+
self.found_type = Some(arg);
252+
return; // we can stop visiting now
253+
}
254+
}
255+
256+
(Some(rl::Region::Static), _) |
257+
(Some(rl::Region::Free(_, _)), _) |
258+
(Some(rl::Region::EarlyBound(_, _)), _) |
259+
(Some(rl::Region::LateBound(_, _)), _) |
260+
(Some(rl::Region::LateBoundAnon(_, _)), _) |
261+
(None, _) => {
226262
debug!("no arg found");
227263
}
228264
}

src/librustc/infer/error_reporting/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ mod need_type_info;
7979
mod named_anon_conflict;
8080
#[macro_use]
8181
mod util;
82-
mod anon_anon_conflict;
82+
mod different_lifetimes;
8383

8484
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
8585
pub fn note_and_explain_region(self,

src/librustc/infer/error_reporting/named_anon_conflict.rs

+39-11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use infer::InferCtxt;
1414
use infer::region_inference::RegionResolutionError::*;
1515
use infer::region_inference::RegionResolutionError;
16+
use ty;
1617

1718
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
1819
// This method generates the error message for the case when
@@ -24,39 +25,68 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
2425
_ => return false, // inapplicable
2526
};
2627

28+
debug!("try_report_named_anon_conflict(sub={:?}, sup={:?})",
29+
sub,
30+
sup);
31+
2732
// Determine whether the sub and sup consist of one named region ('a)
2833
// and one anonymous (elided) region. If so, find the parameter arg
2934
// where the anonymous region appears (there must always be one; we
3035
// only introduced anonymous regions in parameters) as well as a
3136
// version new_ty of its type where the anonymous region is replaced
3237
// with the named one.//scope_def_id
3338
let (named, anon_arg_info, region_info) =
34-
if sub.is_named_region() && self.is_suitable_anonymous_region(sup).is_some() {
39+
if self.is_named_region(sub) && self.is_suitable_region(sup).is_some() &&
40+
self.find_arg_with_region(sup, sub).is_some() {
3541
(sub,
36-
self.find_arg_with_anonymous_region(sup, sub).unwrap(),
37-
self.is_suitable_anonymous_region(sup).unwrap())
38-
} else if sup.is_named_region() && self.is_suitable_anonymous_region(sub).is_some() {
42+
self.find_arg_with_region(sup, sub).unwrap(),
43+
self.is_suitable_region(sup).unwrap())
44+
} else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some() &&
45+
self.find_arg_with_region(sub, sup).is_some() {
3946
(sup,
40-
self.find_arg_with_anonymous_region(sub, sup).unwrap(),
41-
self.is_suitable_anonymous_region(sub).unwrap())
47+
self.find_arg_with_region(sub, sup).unwrap(),
48+
self.is_suitable_region(sub).unwrap())
4249
} else {
4350
return false; // inapplicable
4451
};
4552

53+
debug!("try_report_named_anon_conflict: named = {:?}", named);
54+
debug!("try_report_named_anon_conflict: anon_arg_info = {:?}",
55+
anon_arg_info);
56+
debug!("try_report_named_anon_conflict: region_info = {:?}",
57+
region_info);
58+
4659
let (arg, new_ty, br, is_first, scope_def_id, is_impl_item) = (anon_arg_info.arg,
4760
anon_arg_info.arg_ty,
4861
anon_arg_info.bound_region,
4962
anon_arg_info.is_first,
5063
region_info.def_id,
5164
region_info.is_impl_item);
65+
match br {
66+
ty::BrAnon(_) => {}
67+
_ => {
68+
/* not an anonymous region */
69+
debug!("try_report_named_anon_conflict: not an anonymous region");
70+
return false;
71+
}
72+
}
73+
5274
if is_impl_item {
75+
debug!("try_report_named_anon_conflict: impl item, bail out");
5376
return false;
5477
}
5578

56-
if self.is_return_type_anon(scope_def_id, br) || self.is_self_anon(is_first, scope_def_id) {
79+
if self.is_return_type_anon(scope_def_id, br) {
80+
debug!("try_report_named_anon_conflict: is_return_type_anon({:?}, {:?}) = true",
81+
scope_def_id,
82+
br);
83+
return false;
84+
} else if self.is_self_anon(is_first, scope_def_id) {
85+
debug!("try_report_named_anon_conflict: is_self_anon({:?}, {:?}) = true",
86+
is_first,
87+
scope_def_id);
5788
return false;
5889
} else {
59-
6090
let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() {
6191
(format!("the type of `{}`", simple_name), format!("the type of `{}`", simple_name))
6292
} else {
@@ -72,9 +102,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
72102
format!("consider changing {} to `{}`", span_label_var, new_ty))
73103
.span_label(span, format!("lifetime `{}` required", named))
74104
.emit();
75-
76-
105+
return true;
77106
}
78-
return true;
79107
}
80108
}

0 commit comments

Comments
 (0)