Skip to content

Commit

Permalink
add basic region subtyping inference
Browse files Browse the repository at this point in the history
  • Loading branch information
spastorino authored and nikomatsakis committed Oct 31, 2017
1 parent b8615f3 commit dde61f3
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/librustc_mir/transform/nll/constraint_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/transform/nll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
99 changes: 99 additions & 0 deletions src/librustc_mir/transform/nll/subtype.rs
Original file line number Diff line number Diff line change
@@ -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!();
}
}
49 changes: 49 additions & 0 deletions src/test/mir-opt/nll/region-subtyping-basic.rs
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit dde61f3

Please sign in to comment.