about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/transform/nll/constraint_generation.rs12
-rw-r--r--src/librustc_mir/transform/nll/mod.rs1
-rw-r--r--src/librustc_mir/transform/nll/subtype.rs99
-rw-r--r--src/test/mir-opt/nll/region-subtyping-basic.rs49
4 files changed, 161 insertions, 0 deletions
diff --git a/src/librustc_mir/transform/nll/constraint_generation.rs b/src/librustc_mir/transform/nll/constraint_generation.rs
index 1fc7dbd5bd0..a7570c610d8 100644
--- a/src/librustc_mir/transform/nll/constraint_generation.rs
+++ b/src/librustc_mir/transform/nll/constraint_generation.rs
@@ -22,6 +22,7 @@ use rustc::util::common::ErrorReported;
 use rustc_data_structures::fx::FxHashSet;
 use syntax::codemap::DUMMY_SP;
 
+use super::subtype;
 use super::LivenessResults;
 use super::ToRegionIndex;
 use super::region_infer::RegionInferenceContext;
@@ -239,6 +240,9 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
                        block: BasicBlock,
                        statement: &Statement<'tcx>,
                        location: Location) {
+
+        debug!("visit_statement(statement={:?}, location={:?})", statement, location);
+
         // Look for a statement like:
         //
         //     D = & L
@@ -250,6 +254,14 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cx, 'gcx, 'tcx> {
                 self.add_borrow_constraint(location, destination_lv, region, bk, borrowed_lv);
                 self.add_reborrow_constraint(location, region, borrowed_lv);
             }
+
+            let tcx = self.infcx.tcx;
+            let destination_ty = destination_lv.ty(self.mir, tcx).to_ty(tcx);
+            let rv_ty = rv.ty(self.mir, tcx);
+
+            for (a, b) in subtype::outlives_pairs(tcx, rv_ty, destination_ty) {
+                self.regioncx.add_outlives(a, b, location.successor_within_block());
+            }
         }
 
         self.super_statement(block, statement, location);
diff --git a/src/librustc_mir/transform/nll/mod.rs b/src/librustc_mir/transform/nll/mod.rs
index 8a62533ba33..3bd4f65d0dd 100644
--- a/src/librustc_mir/transform/nll/mod.rs
+++ b/src/librustc_mir/transform/nll/mod.rs
@@ -22,6 +22,7 @@ use util as mir_util;
 use self::mir_util::PassWhere;
 
 mod constraint_generation;
+mod subtype;
 
 mod region_infer;
 use self::region_infer::RegionInferenceContext;
diff --git a/src/librustc_mir/transform/nll/subtype.rs b/src/librustc_mir/transform/nll/subtype.rs
new file mode 100644
index 00000000000..953fc0eb733
--- /dev/null
+++ b/src/librustc_mir/transform/nll/subtype.rs
@@ -0,0 +1,99 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::RegionIndex;
+use transform::nll::ToRegionIndex;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
+
+pub fn outlives_pairs<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                      a: Ty<'tcx>,
+                      b: Ty<'tcx>)
+                      -> Vec<(RegionIndex, RegionIndex)>
+{
+    let mut subtype = Subtype::new(tcx);
+    match subtype.relate(&a, &b) {
+        Ok(_) => subtype.outlives_pairs,
+
+        Err(_) => bug!("Fail to relate a = {:?} and b = {:?}", a, b)
+    }
+}
+
+struct Subtype<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    outlives_pairs: Vec<(RegionIndex, RegionIndex)>,
+    ambient_variance: ty::Variance,
+}
+
+impl<'a, 'gcx, 'tcx> Subtype<'a, 'gcx, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Subtype<'a, 'gcx, 'tcx> {
+        Subtype {
+            tcx,
+            outlives_pairs: vec![],
+            ambient_variance: ty::Covariant,
+        }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Subtype<'a, 'gcx, 'tcx> {
+    fn tag(&self) -> &'static str { "Subtype" }
+    fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.tcx }
+    fn a_is_expected(&self) -> bool { true } // irrelevant
+
+    fn relate_with_variance<T: Relate<'tcx>>(&mut self,
+                                             variance: ty::Variance,
+                                             a: &T,
+                                             b: &T)
+                                             -> RelateResult<'tcx, T>
+    {
+        let old_ambient_variance = self.ambient_variance;
+        self.ambient_variance = self.ambient_variance.xform(variance);
+
+        let result = self.relate(a, b);
+        self.ambient_variance = old_ambient_variance;
+        result
+    }
+
+    fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+        relate::super_relate_tys(self, t, t2)
+    }
+
+    fn regions(&mut self, r_a: ty::Region<'tcx>, r_b: ty::Region<'tcx>)
+               -> RelateResult<'tcx, ty::Region<'tcx>> {
+        let a = r_a.to_region_index();
+        let b = r_b.to_region_index();
+
+        match self.ambient_variance {
+            ty::Covariant => {
+                self.outlives_pairs.push((b, a));
+            },
+
+            ty::Invariant => {
+                self.outlives_pairs.push((a, b));
+                self.outlives_pairs.push((b, a));
+            },
+
+            ty::Contravariant => {
+                self.outlives_pairs.push((a, b));
+            },
+
+            ty::Bivariant => {},
+        }
+
+        Ok(r_a)
+    }
+
+    fn binders<T>(&mut self, _a: &ty::Binder<T>, _b: &ty::Binder<T>)
+                  -> RelateResult<'tcx, ty::Binder<T>>
+        where T: Relate<'tcx>
+    {
+        unimplemented!();
+    }
+}
diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs
new file mode 100644
index 00000000000..bc97858e03d
--- /dev/null
+++ b/src/test/mir-opt/nll/region-subtyping-basic.rs
@@ -0,0 +1,49 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` includes the points after `&v[0]` up to (but not
+// including) the call to `use_x`. The `else` branch is not included.
+
+// compile-flags:-Znll -Zverbose
+//                     ^^^^^^^^^ force compiler to dump more region information
+
+#![allow(warnings)]
+
+fn use_x(_: usize) -> bool { true }
+
+fn main() {
+    let mut v = [1, 2, 3];
+    let p = &v[0];
+    let q = p;
+    if true {
+        use_x(*q);
+    } else {
+        use_x(22);
+    }
+}
+
+// END RUST SOURCE
+// START rustc.node12.nll.0.mir
+// | R0: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]}
+// | R1: {bb1[1], bb1[2], bb1[3], bb1[4], bb1[5], bb1[6], bb2[0], bb2[1]}
+// | R2: {bb1[5], bb1[6], bb2[0], bb2[1]}
+// END rustc.node12.nll.0.mir
+// START rustc.node12.nll.0.mir
+// let _2: &'_#1r usize;
+// ...
+// let _6: &'_#2r usize;
+// ...
+// _2 = &'_#0r _1[_3];
+// ...
+// _7 = _2;
+// ...
+// _6 = _7;
+// END rustc.node12.nll.0.mir