Skip to content

Commit

Permalink
Remove regionck member constraint handling and leave it to mir borrowck
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Oct 18, 2021
1 parent 38b9e6a commit b02f298
Show file tree
Hide file tree
Showing 20 changed files with 77 additions and 482 deletions.
163 changes: 1 addition & 162 deletions compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
Expand Up @@ -2,7 +2,6 @@

use crate::infer::region_constraints::Constraint;
use crate::infer::region_constraints::GenericKind;
use crate::infer::region_constraints::MemberConstraint;
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::region_constraints::VarInfos;
use crate::infer::region_constraints::VerifyBound;
Expand Down Expand Up @@ -150,12 +149,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {

let graph = self.construct_graph();
self.expand_givens(&graph);
loop {
self.expansion(&mut var_data);
if !self.enforce_member_constraints(&graph, &mut var_data) {
break;
}
}
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
self.collect_var_errors(&var_data, &graph, errors);
var_data
Expand Down Expand Up @@ -233,133 +227,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}

/// Enforce all member constraints and return true if anything
/// changed. See `enforce_member_constraint` for more details.
fn enforce_member_constraints(
&self,
graph: &RegionGraph<'tcx>,
var_values: &mut LexicalRegionResolutions<'tcx>,
) -> bool {
// Note: we don't use the `any` combinator because we don't
// want to stop at the first constraint that makes a change.
let mut any_changed = false;
for member_constraint in &self.data.member_constraints {
any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values);
}
any_changed
}

/// Enforce a constraint like
///
/// ```
/// 'r member of ['c...]
/// ```
///
/// We look for all choice regions from the list `'c...` that:
///
/// (a) are greater than the current value of `'r` (which is a lower bound)
///
/// and
///
/// (b) are compatible with the upper bounds of `'r` that we can
/// find by traversing the graph.
///
/// From that list, we look for a *minimal* option `'c_min`. If we
/// find one, then we can enforce that `'r: 'c_min`.
#[instrument(level = "debug", skip(self, graph, member_constraint, var_values))]
fn enforce_member_constraint(
&self,
graph: &RegionGraph<'tcx>,
member_constraint: &MemberConstraint<'tcx>,
var_values: &mut LexicalRegionResolutions<'tcx>,
) -> bool {
debug!("member_constraint={:#?}", member_constraint);

// The constraint is some inference variable (`vid`) which
// must be equal to one of the options.
let member_vid = match member_constraint.member_region {
ty::ReVar(vid) => *vid,
_ => return false,
};

// The current value of `vid` is a lower bound LB -- i.e., we
// know that `LB <= vid` must be true.
let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) {
VarValue::ErrorValue => return false,
VarValue::Value(r) => r,
};

// Find all the "upper bounds" -- that is, each region `b` such that
// `r0 <= b` must hold.
let (member_upper_bounds, ..) =
self.collect_bounding_regions(graph, member_vid, OUTGOING, None);

// Get an iterator over the *available choice* -- that is,
// each choice region `c` where `lb <= c` and `c <= ub` for all the
// upper bounds `ub`.
debug!("upper_bounds={:#?}", member_upper_bounds);
let mut options = member_constraint
.choice_regions
.iter()
// If any of the regions are inference vars, resolve them, as far
// as possible.
.filter_map(|option| match option {
ty::ReVar(vid) => match var_values.value(*vid) {
VarValue::ErrorValue => None,
VarValue::Value(r) => Some(r),
},
r => Some(r),
})
.filter(|option| {
self.sub_concrete_regions(member_lower_bound, option)
&& member_upper_bounds
.iter()
.all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region))
});

// If there is more than one option, we only make a choice if
// there is a single *least* choice -- i.e., some available
// region that is `<=` all the others.
let mut least_choice: ty::Region<'tcx> = match options.next() {
Some(&r) => r,
None => return false,
};
debug!(?least_choice);
for &option in options {
debug!(?option);
if !self.sub_concrete_regions(least_choice, option) {
if self.sub_concrete_regions(option, least_choice) {
debug!("new least choice");
least_choice = option;
} else {
debug!("no least choice");
return false;
}
}
}

// (#72087) Different `ty::Regions` can be known to be equal, for
// example, we know that `'a` and `'static` are equal in a function
// with a parameter of type `&'static &'a ()`.
//
// When we have two equal regions like this `expansion` will use
// `lub_concrete_regions` to pick a canonical representative. The same
// choice is needed here so that we don't end up in a cycle of
// `expansion` changing the region one way and the code here changing
// it back.
let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
debug!(
"enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
least_choice, lub
);
if lub != member_lower_bound {
*var_values.value_mut(member_vid) = VarValue::Value(least_choice);
true
} else {
false
}
}

fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
let mut changes = Vec::new();
Expand Down Expand Up @@ -632,34 +499,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}

// Check that all member constraints are satisfied.
for member_constraint in &self.data.member_constraints {
let member_region = var_data.normalize(self.tcx(), member_constraint.member_region);
let choice_regions = member_constraint
.choice_regions
.iter()
.map(|&choice_region| var_data.normalize(self.tcx(), choice_region));
let fr = &self.region_rels.free_regions;
let sub = |a, b| {
fr.is_free_or_static(a)
&& fr.is_free_or_static(b)
&& fr.sub_free_regions(self.tcx(), a, b)
};
if !choice_regions.clone().any(|choice_region| {
// This is really checking if the regions are equal. After member constraint
// resolution, one region must be equal, or a lifetime has been leaked into
// the hidden type, but does not appear in the corresponding impl trait.
sub(member_region, choice_region) && sub(choice_region, member_region)
}) {
let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
errors.push(RegionResolutionError::MemberConstraintFailure {
span,
hidden_ty: member_constraint.hidden_ty,
member_region,
});
}
}

for verify in &self.data.verifys {
debug!("collect_errors: verify={:?}", verify);
let sub = var_data.normalize(self.tcx(), verify.region);
Expand Down
Expand Up @@ -15,7 +15,6 @@ async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> +
// Only `'a` permitted in return type, not `'b`.
async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
//~^ ERROR captures lifetime that does not appear in bounds
//~| ERROR captures lifetime that does not appear in bounds
(a, b)
}

Expand Down
Expand Up @@ -14,27 +14,14 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| -- ^^^^^^^^^^^^^^
| |
| hidden type `(&u8, &u8)` captures the lifetime `'b` as defined here
| hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
|
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
| ++++

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ret-impl-trait-one.rs:16:65
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
| -- ^^^^^^^^^^^^^^
| |
| hidden type `(&u8, &u8)` captures the lifetime `'b` as defined here
|
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
| ++++

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0623, E0700.
For more information about an error, try `rustc --explain E0623`.
29 changes: 0 additions & 29 deletions src/test/ui/impl-trait/hidden-lifetimes.nll.stderr

This file was deleted.

2 changes: 1 addition & 1 deletion src/test/ui/impl-trait/hidden-lifetimes.stderr
Expand Up @@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a {
| -- ^^^^^^^^^^^^^^
| |
| hidden type `&mut &'b T` captures the lifetime `'b` as defined here
| hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here
|
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
Expand Down

This file was deleted.

Expand Up @@ -2,13 +2,14 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
--> $DIR/ordinary-bounds-unrelated.rs:16:74
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| ^^^^^^^^^^^^^^^^^^
| -- ^^^^^^^^^^^^^^^^^^
| |
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
--> $DIR/ordinary-bounds-unrelated.rs:16:74
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| ^^^^^^^^^^^^^^^^^^
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + 'b
| ++++

error: aborting due to previous error

Expand Down

This file was deleted.

Expand Up @@ -2,13 +2,14 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
--> $DIR/ordinary-bounds-unsuited.rs:18:62
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
| -- ^^^^^^^^^^^^^^^^^^
| |
| hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here
|
note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
--> $DIR/ordinary-bounds-unsuited.rs:18:62
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + 'b
| ++++

error: aborting due to previous error

Expand Down
Expand Up @@ -59,28 +59,28 @@ LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| let's call the lifetime of this reference `'1`

error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:30:69
--> $DIR/must_outlive_least_region_or_bound.rs:29:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/must_outlive_least_region_or_bound.rs:34:61
--> $DIR/must_outlive_least_region_or_bound.rs:33:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| -- ^^^^^^^^^^^^^^^^
| |
| hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:37:5: 37:31]` captures the lifetime `'b` as defined here
| hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:35:5: 35:31]` captures the lifetime `'b` as defined here
|
help: to declare that the `impl Trait` captures 'b, you can add an explicit `'b` lifetime bound
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) + 'b {
| ++++

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:40:51
--> $DIR/must_outlive_least_region_or_bound.rs:38:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| ^^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 0 additions & 2 deletions src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs
Expand Up @@ -22,7 +22,6 @@ fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759

fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } //~ ERROR E0759
//~^ ERROR: captures lifetime that does not appear in bounds

trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}
Expand All @@ -33,7 +32,6 @@ fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERRO
// only 'a was expected.
fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
//~^ ERROR: captures lifetime that does not appear in bounds
//~| ERROR: captures lifetime that does not appear in bounds
move |_| println!("{}", y)
}

Expand Down

0 comments on commit b02f298

Please sign in to comment.