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 or the MIT license +// , 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>(&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(&mut self, _a: &ty::Binder, _b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + 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 or the MIT license +// , 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