about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs309
-rw-r--r--src/librustc_driver/test.rs24
-rw-r--r--src/librustc_typeck/check/_match.rs27
-rw-r--r--src/librustc_typeck/check/regionck.rs10
4 files changed, 58 insertions, 312 deletions
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index 1fc52948770..6770ad41564 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -16,19 +16,16 @@ pub use self::UndoLogEntry::*;
 pub use self::CombineMapType::*;
 pub use self::RegionResolutionError::*;
 pub use self::VarValue::*;
-use self::Classification::*;
 
 use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
 
 use rustc_data_structures::graph::{self, Direction, NodeIndex};
 use middle::free_region::FreeRegionMap;
-use middle::region;
 use middle::ty::{self, Ty};
 use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
 use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
 use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
 use middle::ty::error::TypeError;
-use middle::ty::relate::RelateResult;
 use util::common::indenter;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
@@ -824,147 +821,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
           }
         }
     }
-
-    fn glb_concrete_regions(&self,
-                            free_regions: &FreeRegionMap,
-                            a: Region,
-                            b: Region)
-                            -> RelateResult<'tcx, Region>
-    {
-        debug!("glb_concrete_regions({:?}, {:?})", a, b);
-        match (a, b) {
-            (ReLateBound(..), _) |
-            (_, ReLateBound(..)) |
-            (ReEarlyBound(..), _) |
-            (_, ReEarlyBound(..)) => {
-              self.tcx.sess.bug(
-                  &format!("cannot relate bound region: GLB({:?}, {:?})",
-                          a,
-                          b));
-            }
-
-            (ReStatic, r) | (r, ReStatic) => {
-                // static lives longer than everything else
-                Ok(r)
-            }
-
-            (ReEmpty, _) | (_, ReEmpty) => {
-                // nothing lives shorter than everything else
-                Ok(ReEmpty)
-            }
-
-            (ReVar(v_id), _) |
-            (_, ReVar(v_id)) => {
-                self.tcx.sess.span_bug(
-                    (*self.var_origins.borrow())[v_id.index as usize].span(),
-                    &format!("glb_concrete_regions invoked with \
-                             non-concrete regions: {:?}, {:?}",
-                            a,
-                            b));
-            }
-
-            (ReFree(fr), ReScope(s_id)) |
-            (ReScope(s_id), ReFree(fr)) => {
-                let s = ReScope(s_id);
-                // Free region is something "at least as big as
-                // `fr.scope_id`."  If we find that the scope `fr.scope_id` is bigger
-                // than the scope `s_id`, then we can say that the GLB
-                // is the scope `s_id`.  Otherwise, as we do not know
-                // big the free region is precisely, the GLB is undefined.
-                if self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) == fr.scope ||
-                        free_regions.is_static(fr) {
-                    Ok(s)
-                } else {
-                    Err(TypeError::RegionsNoOverlap(b, a))
-                }
-            }
-
-            (ReScope(a_id), ReScope(b_id)) => {
-                self.intersect_scopes(a, b, a_id, b_id)
-            }
-
-            (ReFree(ref a_fr), ReFree(ref b_fr)) => {
-                self.glb_free_regions(free_regions, a_fr, b_fr)
-            }
-
-            // For these types, we cannot define any additional
-            // relationship:
-            (ReSkolemized(..), _) |
-            (_, ReSkolemized(..)) => {
-                if a == b {
-                    Ok(a)
-                } else {
-                    Err(TypeError::RegionsNoOverlap(b, a))
-                }
-            }
-        }
-    }
-
-    /// Computes a region that is enclosed by both free region arguments, if any. Guarantees that
-    /// if the same two regions are given as argument, in any order, a consistent result is
-    /// returned.
-    fn glb_free_regions(&self,
-                        free_regions: &FreeRegionMap,
-                        a: &FreeRegion,
-                        b: &FreeRegion)
-                        -> RelateResult<'tcx, ty::Region>
-    {
-        return match a.cmp(b) {
-            Less => helper(self, free_regions, a, b),
-            Greater => helper(self, free_regions, b, a),
-            Equal => Ok(ty::ReFree(*a))
-        };
-
-        fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
-                            free_regions: &FreeRegionMap,
-                            a: &FreeRegion,
-                            b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
-        {
-            if free_regions.sub_free_region(*a, *b) {
-                Ok(ty::ReFree(*a))
-            } else if free_regions.sub_free_region(*b, *a) {
-                Ok(ty::ReFree(*b))
-            } else {
-                this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
-                                      a.scope, b.scope)
-            }
-        }
-    }
-
-    fn intersect_scopes(&self,
-                        region_a: ty::Region,
-                        region_b: ty::Region,
-                        scope_a: region::CodeExtent,
-                        scope_b: region::CodeExtent)
-                        -> RelateResult<'tcx, Region>
-    {
-        // We want to generate the intersection of two
-        // scopes or two free regions.  So, if one of
-        // these scopes is a subscope of the other, return
-        // it. Otherwise fail.
-        debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
-               scope_a, scope_b, region_a, region_b);
-        let r_id = self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b);
-        if r_id == scope_a {
-            Ok(ReScope(scope_b))
-        } else if r_id == scope_b {
-            Ok(ReScope(scope_a))
-        } else {
-            Err(TypeError::RegionsNoOverlap(region_a, region_b))
-        }
-    }
 }
 
 // ______________________________________________________________________
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-enum Classification { Expanding, Contracting }
-
 #[derive(Copy, Clone, Debug)]
-pub enum VarValue { NoValue, Value(Region), ErrorValue }
+pub enum VarValue { Value(Region), ErrorValue }
 
 struct VarData {
-    classification: Classification,
     value: VarValue,
 }
 
@@ -1005,12 +869,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
     fn construct_var_data(&self) -> Vec<VarData> {
         (0..self.num_vars() as usize).map(|_| {
             VarData {
-                // All nodes are initially classified as contracting; during
-                // the expansion phase, we will shift the classification for
-                // those nodes that have a concrete region predecessor to
-                // Expanding.
-                classification: Contracting,
-                value: NoValue,
+                value: Value(ty::ReEmpty),
             }
         }).collect()
     }
@@ -1062,11 +921,11 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
               }
               ConstrainVarSubVar(a_vid, b_vid) => {
                 match var_data[a_vid.index as usize].value {
-                  NoValue | ErrorValue => false,
-                  Value(a_region) => {
-                    let b_node = &mut var_data[b_vid.index as usize];
-                    self.expand_node(free_regions, a_region, b_vid, b_node)
-                  }
+                    ErrorValue => false,
+                    Value(a_region) => {
+                        let b_node = &mut var_data[b_vid.index as usize];
+                        self.expand_node(free_regions, a_region, b_vid, b_node)
+                    }
                 }
               }
               ConstrainVarSubReg(..) => {
@@ -1100,16 +959,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             _ => { }
         }
 
-        b_data.classification = Expanding;
         match b_data.value {
-          NoValue => {
-            debug!("Setting initial value of {:?} to {:?}",
-                   b_vid, a_region);
-
-            b_data.value = Value(a_region);
-            return true;
-          }
-
           Value(cur_region) => {
             let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
             if lub == cur_region {
@@ -1148,7 +998,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
               }
               ConstrainVarSubVar(a_vid, b_vid) => {
                 match var_data[b_vid.index as usize].value {
-                  NoValue | ErrorValue => false,
+                  ErrorValue => false,
                   Value(b_region) => {
                     let a_data = &mut var_data[a_vid.index as usize];
                     self.contract_node(free_regions, a_vid, a_data, b_region)
@@ -1169,27 +1019,12 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                      a_data: &mut VarData,
                      b_region: Region)
                      -> bool {
-        debug!("contract_node({:?} == {:?}/{:?}, {:?})",
-               a_vid, a_data.value,
-               a_data.classification, b_region);
+        debug!("contract_node({:?} == {:?}, {:?})",
+               a_vid, a_data.value, b_region);
 
         return match a_data.value {
-            NoValue => {
-                assert_eq!(a_data.classification, Contracting);
-                a_data.value = Value(b_region);
-                true // changed
-            }
-
             ErrorValue => false, // no change
-
-            Value(a_region) => {
-                match a_data.classification {
-                    Expanding =>
-                        check_node(self, free_regions, a_vid, a_data, a_region, b_region),
-                    Contracting =>
-                        adjust_node(self, free_regions, a_vid, a_data, a_region, b_region),
-                }
-            }
+            Value(a_region) => check_node(self, free_regions, a_vid, a_data, a_region, b_region),
         };
 
         fn check_node(this: &RegionVarBindings,
@@ -1209,37 +1044,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             }
             false
         }
-
-        fn adjust_node(this: &RegionVarBindings,
-                       free_regions: &FreeRegionMap,
-                       a_vid: RegionVid,
-                       a_data: &mut VarData,
-                       a_region: Region,
-                       b_region: Region)
-                       -> bool {
-            match this.glb_concrete_regions(free_regions, a_region, b_region) {
-                Ok(glb) => {
-                    if glb == a_region {
-                        false
-                    } else {
-                        debug!("Contracting value of {:?} from {:?} to {:?}",
-                               a_vid,
-                               a_region,
-                               glb);
-                        a_data.value = Value(glb);
-                        true
-                    }
-                }
-                Err(_) => {
-                    debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
-                           a_vid,
-                           a_region,
-                           b_region);
-                    a_data.value = ErrorValue;
-                    false
-                }
-            }
-        }
     }
 
     fn collect_concrete_region_errors(&self,
@@ -1308,12 +1112,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 Value(_) => {
                     /* Inference successful */
                 }
-                NoValue => {
-                    /* Unconstrained inference: do not report an error
-                       until the value of this variable is requested.
-                       After all, sometimes we make region variables but never
-                       really use their values. */
-                }
                 ErrorValue => {
                     /* Inference impossible, this value contains
                        inconsistent constraints.
@@ -1339,18 +1137,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                        this portion of the code and think hard about it. =) */
 
                     let node_vid = RegionVid { index: idx as u32 };
-                    match var_data[idx].classification {
-                        Expanding => {
-                            self.collect_error_for_expanding_node(
-                                free_regions, graph, var_data, &mut dup_vec,
-                                node_vid, errors);
-                        }
-                        Contracting => {
-                            self.collect_error_for_contracting_node(
-                                free_regions, graph, var_data, &mut dup_vec,
-                                node_vid, errors);
-                        }
-                    }
+                    self.collect_error_for_expanding_node(
+                        free_regions, graph, &mut dup_vec, node_vid, errors);
                 }
             }
         }
@@ -1396,7 +1184,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
     fn collect_error_for_expanding_node(&self,
                                         free_regions: &FreeRegionMap,
                                         graph: &RegionGraph,
-                                        var_data: &[VarData],
                                         dup_vec: &mut [u32],
                                         node_idx: RegionVid,
                                         errors: &mut Vec<RegionResolutionError<'tcx>>)
@@ -1404,11 +1191,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
         // Errors in expanding nodes result from a lower-bound that is
         // not contained by an upper-bound.
         let (mut lower_bounds, lower_dup) =
-            self.collect_concrete_regions(graph, var_data, node_idx,
-                                          graph::INCOMING, dup_vec);
+            self.collect_concrete_regions(graph, node_idx, graph::INCOMING, dup_vec);
         let (mut upper_bounds, upper_dup) =
-            self.collect_concrete_regions(graph, var_data, node_idx,
-                                          graph::OUTGOING, dup_vec);
+            self.collect_concrete_regions(graph, node_idx, graph::OUTGOING, dup_vec);
 
         if lower_dup || upper_dup {
             return;
@@ -1459,59 +1244,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                     upper_bounds));
     }
 
-    fn collect_error_for_contracting_node(
-        &self,
-        free_regions: &FreeRegionMap,
-        graph: &RegionGraph,
-        var_data: &[VarData],
-        dup_vec: &mut [u32],
-        node_idx: RegionVid,
-        errors: &mut Vec<RegionResolutionError<'tcx>>)
-    {
-        // Errors in contracting nodes result from two upper-bounds
-        // that have no intersection.
-        let (upper_bounds, dup_found) =
-            self.collect_concrete_regions(graph, var_data, node_idx,
-                                          graph::OUTGOING, dup_vec);
-
-        if dup_found {
-            return;
-        }
-
-        for upper_bound_1 in &upper_bounds {
-            for upper_bound_2 in &upper_bounds {
-                match self.glb_concrete_regions(free_regions,
-                                                upper_bound_1.region,
-                                                upper_bound_2.region) {
-                    Ok(_) => {}
-                    Err(_) => {
-                        let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone();
-                        debug!("region inference error at {:?} for {:?}: \
-                                SupSupConflict sub: {:?} sup: {:?}",
-                               origin, node_idx, upper_bound_1.region, upper_bound_2.region);
-                        errors.push(SupSupConflict(
-                            origin,
-                            upper_bound_1.origin.clone(),
-                            upper_bound_1.region,
-                            upper_bound_2.origin.clone(),
-                            upper_bound_2.region));
-                        return;
-                    }
-                }
-            }
-        }
-
-        self.tcx.sess.span_bug(
-            (*self.var_origins.borrow())[node_idx.index as usize].span(),
-            &format!("collect_error_for_contracting_node() could not find error \
-                     for var {:?}, upper_bounds={:?}",
-                    node_idx,
-                    upper_bounds));
-    }
-
     fn collect_concrete_regions(&self,
                                 graph: &RegionGraph,
-                                var_data: &[VarData],
                                 orig_node_idx: RegionVid,
                                 dir: Direction,
                                 dup_vec: &mut [u32])
@@ -1536,7 +1270,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 
         while !state.stack.is_empty() {
             let node_idx = state.stack.pop().unwrap();
-            let classification = var_data[node_idx.index as usize].classification;
 
             // check whether we've visited this node on some previous walk
             if dup_vec[node_idx.index as usize] == u32::MAX {
@@ -1545,17 +1278,12 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 state.dup_found = true;
             }
 
-            debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
-                    classification={:?})",
-                   orig_node_idx, node_idx, classification);
+            debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
+                   orig_node_idx, node_idx);
 
             // figure out the direction from which this node takes its
             // values, and search for concrete regions etc in that direction
-            let dir = match classification {
-                Expanding => graph::INCOMING,
-                Contracting => graph::OUTGOING,
-            };
-
+            let dir = graph::INCOMING;
             process_edges(self, &mut state, graph, node_idx, dir);
         }
 
@@ -1638,7 +1366,6 @@ fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
 fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
     match values[rid.index as usize] {
         Value(r) => r,
-        NoValue => ReEmpty, // No constraints, return ty::ReEmpty
         ErrorValue => ReStatic, // Previously reported error.
     }
 }
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 0c83851ba00..4bbc22ef1a2 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -351,6 +351,11 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
                                    self.tcx().types.isize)
     }
 
+    pub fn t_rptr_empty(&self) -> Ty<'tcx> {
+        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty),
+                                   self.tcx().types.isize)
+    }
+
     pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
         infer::TypeTrace::dummy(self.tcx())
     }
@@ -593,16 +598,15 @@ fn lub_free_free() {
 
 #[test]
 fn lub_returning_scope() {
-    test_env(EMPTY_SOURCE_STR,
-             errors(&["cannot infer an appropriate lifetime"]), |env| {
-                 env.create_simple_region_hierarchy();
-                 let t_rptr_scope10 = env.t_rptr_scope(10);
-                 let t_rptr_scope11 = env.t_rptr_scope(11);
-
-                 // this should generate an error when regions are resolved
-                 env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
-                                 env.t_fn(&[], t_rptr_scope11));
-             })
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        env.create_simple_region_hierarchy();
+        let t_rptr_scope10 = env.t_rptr_scope(10);
+        let t_rptr_scope11 = env.t_rptr_scope(11);
+        let t_rptr_empty = env.t_rptr_empty();
+        env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize),
+                      env.t_fn(&[t_rptr_scope11], env.tcx().types.isize),
+                      env.t_fn(&[t_rptr_empty], env.tcx().types.isize));
+    });
 }
 
 #[test]
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index db5dd19c923..d89e5ee6006 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -259,17 +259,30 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
             }
         }
         hir::PatRegion(ref inner, mutbl) => {
-            let inner_ty = fcx.infcx().next_ty_var();
-
-            let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
-            let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
-            let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
-
+            let expected = fcx.infcx().shallow_resolve(expected);
             if check_dereferencable(pcx, pat.span, expected, &**inner) {
                 // `demand::subtype` would be good enough, but using
                 // `eqtype` turns out to be equally general. See (*)
                 // below for details.
-                demand::eqtype(fcx, pat.span, expected, rptr_ty);
+
+                // Take region, inner-type from expected type if we
+                // can, to avoid creating needless variables.  This
+                // also helps with the bad interactions of the given
+                // hack detailed in (*) below.
+                let (rptr_ty, inner_ty) = match expected.sty {
+                    ty::TyRef(_, mt) if mt.mutbl == mutbl => {
+                        (expected, mt.ty)
+                    }
+                    _ => {
+                        let inner_ty = fcx.infcx().next_ty_var();
+                        let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
+                        let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+                        let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
+                        demand::eqtype(fcx, pat.span, expected, rptr_ty);
+                        (rptr_ty, inner_ty)
+                    }
+                };
+
                 fcx.write_ty(pat.id, rptr_ty);
                 check_pat(pcx, &**inner, inner_ty);
             } else {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 31e6c942dc6..7c6417e61d4 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -1182,9 +1182,10 @@ fn link_fn_args(rcx: &Rcx, body_scope: CodeExtent, args: &[hir::Arg]) {
         let arg_ty = rcx.fcx.node_ty(arg.id);
         let re_scope = ty::ReScope(body_scope);
         let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
-        debug!("arg_ty={:?} arg_cmt={:?}",
+        debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
                arg_ty,
-               arg_cmt);
+               arg_cmt,
+               arg);
         link_pattern(rcx, mc, arg_cmt, &*arg.pat);
     }
 }
@@ -1527,9 +1528,10 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
 {
     let ty = rcx.resolve_type(ty);
 
-    debug!("type_must_outlive(ty={:?}, region={:?})",
+    debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})",
            ty,
-           region);
+           region,
+           origin);
 
     assert!(!ty.has_escaping_regions());