Skip to content

Commit 5125bfd

Browse files
nikomatsakiscramertj
authored andcommitted
force all regions to be the least region, error if no such region
1 parent 64a6fde commit 5125bfd

File tree

2 files changed

+56
-30
lines changed

2 files changed

+56
-30
lines changed

src/librustc/middle/free_region.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> {
8484
(&ty::ReFree(_), &ty::ReEarlyBound(_)) |
8585
(&ty::ReEarlyBound(_), &ty::ReFree(_)) |
8686
(&ty::ReFree(_), &ty::ReFree(_)) =>
87-
self.free_regions.relation.contains(&sub_region, &super_region),
87+
self.free_regions.sub_free_regions(&sub_region, &super_region),
8888

8989
_ =>
9090
false,
@@ -158,14 +158,29 @@ impl<'tcx> FreeRegionMap<'tcx> {
158158
}
159159
}
160160

161-
// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
162-
// (with the exception that `'static: 'x` is not notable)
161+
/// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
162+
/// (with the exception that `'static: 'x` is not notable)
163163
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
164164
if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
165165
self.relation.add(sub, sup)
166166
}
167167
}
168168

169+
/// True if `r_a <= r_b` is known to hold. Both `r_a` and `r_b`
170+
/// must be free regions from the function header.
171+
pub fn sub_free_regions<'a, 'gcx>(&self,
172+
r_a: Region<'tcx>,
173+
r_b: Region<'tcx>)
174+
-> bool {
175+
assert!(is_free(r_a));
176+
assert!(is_free(r_b));
177+
self.relation.contains(&r_a, &r_b)
178+
}
179+
180+
/// Compute the least-upper-bound of two free regions. In some
181+
/// cases, this is more conservative than necessary, in order to
182+
/// avoid making arbitrary choices. See
183+
/// `TransitiveRelation::postdom_upper_bound` for more details.
169184
pub fn lub_free_regions<'a, 'gcx>(&self,
170185
tcx: TyCtxt<'a, 'gcx, 'tcx>,
171186
r_a: Region<'tcx>,

src/librustc_typeck/check/regionck.rs

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -473,12 +473,14 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
473473

474474
let abstract_type_generics = self.tcx.generics_of(def_id);
475475

476+
let span = self.tcx.def_span(def_id);
477+
476478
// Go through all the regions used as arguments to the
477479
// abstract type. These are the parameters to the abstract
478480
// type; so in our example above, `substs` would contain
479481
// `['a]` for the first impl trait and `'b` for the
480482
// second.
481-
let mut bound_region = None;
483+
let mut least_region = None;
482484
for region_def in &abstract_type_generics.regions {
483485
// Find the index of this region in the list of substitutions.
484486
let index = region_def.index as usize;
@@ -487,39 +489,48 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
487489
let subst_arg = anon_defn.substs[index].as_region().unwrap();
488490

489491
// Compute the least upper bound of it with the other regions.
490-
debug!("constrain_anon_types: bound_region={:?}", bound_region);
492+
debug!("constrain_anon_types: least_region={:?}", least_region);
491493
debug!("constrain_anon_types: subst_arg={:?}", subst_arg);
492-
if let Some(r) = bound_region {
493-
let lub = self.free_region_map.lub_free_regions(self.tcx,
494-
r,
495-
subst_arg);
496-
bound_region = Some(lub);
497-
498-
if let ty::ReStatic = *lub {
499-
// If LUB results in `'static`, we might as well
500-
// stop iterating here.
501-
//
502-
// FIXME: We might consider issuing an error
503-
// here. `'static` is too strict to be useful,
504-
// most likely, and the resulting errors may
505-
// well be rather confusing.
506-
break;
494+
match least_region {
495+
None => least_region = Some(subst_arg),
496+
Some(lr) => {
497+
if self.free_region_map.sub_free_regions(lr, subst_arg) {
498+
// keep the current least region
499+
} else if self.free_region_map.sub_free_regions(subst_arg, lr) {
500+
// switch to `subst_arg`
501+
least_region = Some(subst_arg);
502+
} else {
503+
// There are two regions (`lr` and
504+
// `subst_arg`) which are not relatable. We can't
505+
// find a best choice.
506+
507+
// FIXME We don't need to issue an error
508+
// if there is a lifetime bound in the
509+
// `impl Trait` already (e.g., `impl Foo +
510+
// 'a`). `required_region_bounds` could be
511+
// applied during the instantiation phase
512+
// to find this, I suspect.
513+
self.tcx
514+
.sess
515+
.struct_span_err(span, "ambiguous lifetime bound in `impl Trait`")
516+
.span_label(span,
517+
format!("neither `{}` nor `{}` outlives the other",
518+
lr, subst_arg))
519+
.emit();
520+
521+
least_region = Some(self.tcx.mk_region(ty::ReEmpty));
522+
break;
523+
}
507524
}
508-
} else {
509-
bound_region = Some(subst_arg);
510525
}
511526
}
512-
debug!("constrain_anon_types: bound_region={:?}", bound_region);
513527

514-
// If we don't find any arguments in the interface, then
515-
// the only valid region that can appear in the resulting
516-
// type is `'static`.
517-
let bound_region = bound_region.unwrap_or(self.tcx.types.re_static);
528+
let least_region = least_region.unwrap_or(self.tcx.types.re_static);
529+
debug!("constrain_anon_types: least_region={:?}", least_region);
518530

519-
// Require that all regions outlive `bound_region`
520-
let span = self.tcx.def_span(def_id);
531+
// Require that all regions outlive `least_region`
521532
self.tcx.for_each_free_region(&concrete_ty, |region| {
522-
self.sub_regions(infer::CallReturn(span), bound_region, region);
533+
self.sub_regions(infer::CallReturn(span), least_region, region);
523534
});
524535
}
525536
}

0 commit comments

Comments
 (0)