From f0eebcd02f1dd123c0ff4e8ddf04a520cc1cf2a4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 3 Jun 2019 15:54:21 -0400 Subject: [PATCH] integrate pick constraints into lexical solver more completely --- .../infer/lexical_region_resolve/mod.rs | 73 ++++++++++++++----- .../multiple-lifetimes/inverse-bounds.rs | 3 - 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index a37eff82e6e..68371a0d6cb 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -118,8 +118,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let graph = self.construct_graph(); self.expand_givens(&graph); - self.enforce_pick_constraints(&graph, &mut var_data); - self.expansion(&mut var_data); + loop { + self.expansion(&mut var_data); + if !self.enforce_pick_constraints(&graph, &mut var_data) { + break; + } + } self.collect_errors(&mut var_data, errors); self.collect_var_errors(&var_data, &graph, errors); var_data @@ -204,43 +208,75 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { &self, graph: &RegionGraph<'tcx>, var_values: &mut LexicalRegionResolutions<'tcx>, - ) { + ) -> bool { + let mut any_changed = false; for pick_constraint in &self.data.pick_constraints { - let _ = self.enforce_pick_constraint(graph, pick_constraint, var_values); + if self.enforce_pick_constraint(graph, pick_constraint, var_values) { + any_changed = true; + } } + any_changed } + /// Enforce a constraint like + /// + /// ``` + /// pick 'r from ['o...] + /// ``` + /// + /// We look to see if there is a unique option `'o` from the list of options + /// that: + /// + /// (a) is greater than the current value of `'r` (which is a lower bound) + /// + /// and + /// + /// (b) is compatible with the upper bounds of `'r` that we can + /// find by traversing the graph. fn enforce_pick_constraint( &self, graph: &RegionGraph<'tcx>, pick_constraint: &PickConstraint<'tcx>, var_values: &mut LexicalRegionResolutions<'tcx>, - ) -> Result<(), ()> { + ) -> bool { debug!("enforce_pick_constraint(pick_constraint={:#?})", pick_constraint); // the constraint is some inference variable (`vid`) which // must be equal to one of the options let pick_vid = match pick_constraint.pick_region { ty::ReVar(vid) => *vid, - _ => return Err(()), + _ => return false, }; - // find all the "bounds" -- that is, each region `b` such that + // The current value of `vid` is a lower bound LB -- i.e., we + // know that `LB <= vid` must be true. + let pick_lower_bound = match var_values.value(pick_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 (pick_bounds, _) = self.collect_concrete_regions(graph, pick_vid, OUTGOING, None); + let (pick_upper_bounds, _) = self.collect_concrete_regions(graph, pick_vid, OUTGOING, None); // get an iterator over the *available options* -- that is, - // each constraint regions `o` where `o <= b` for all the - // bounds `b`. - debug!("enforce_pick_constraint: bounds={:#?}", pick_bounds); + // each constraint regions `o` where `lb <= o` and `o <= ub` for all the + // upper bounds `ub`. + debug!("enforce_pick_constraint: upper_bounds={:#?}", pick_upper_bounds); let mut options = pick_constraint.option_regions.iter().filter(|option| { - pick_bounds.iter().all(|bound| self.sub_concrete_regions(option, bound.region)) + self.sub_concrete_regions(pick_lower_bound, option) + && pick_upper_bounds + .iter() + .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region)) }); // if there >1 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 = options.next().ok_or(())?; + let mut least_choice = match options.next() { + Some(r) => r, + None => return false, + }; debug!("enforce_pick_constraint: least_choice={:?}", least_choice); for option in options { debug!("enforce_pick_constraint: option={:?}", option); @@ -250,15 +286,18 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { least_choice = option; } else { debug!("enforce_pick_constraint: no least choice"); - return Err(()); + return false; } } } debug!("enforce_pick_constraint: final least choice = {:?}", least_choice); - *var_values.value_mut(pick_vid) = VarValue::Value(least_choice); - - Ok(()) + if least_choice != pick_lower_bound { + *var_values.value_mut(pick_vid) = VarValue::Value(least_choice); + true + } else { + false + } } fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs index 41d4b59e8f0..60275ac3ab0 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs @@ -13,9 +13,6 @@ impl Trait<'_, '_> for T {} struct Invert<'a>(fn(&'a u8)); fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Invert<'a>, b: Invert<'b>) -> impl Trait<'d, 'e> -//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds -// FIXME -- we ought to be able to pick `'d` here, but our handling of in constraints -// is not smart enough where 'c: 'a, 'c: 'b,