about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2019-06-03 15:54:21 -0400
committerNiko Matsakis <niko@alum.mit.edu>2019-07-02 12:15:19 -0400
commitf0eebcd02f1dd123c0ff4e8ddf04a520cc1cf2a4 (patch)
tree85aad46b166cea93b9aa023a9674922ea8c11576 /src
parent02609b85e36fd9c049e1975171f65b47e3ccdd1b (diff)
downloadrust-f0eebcd02f1dd123c0ff4e8ddf04a520cc1cf2a4.tar.gz
rust-f0eebcd02f1dd123c0ff4e8ddf04a520cc1cf2a4.zip
integrate pick constraints into lexical solver more completely
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/lexical_region_resolve/mod.rs73
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs3
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,
+        };
+
+        // 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 "bounds" -- that is, each region `b` such that
+        // 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<T> 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,