add basic region subtyping inference

This commit is contained in:
Santiago Pastorino 2017-10-25 18:04:57 -04:00 committed by Niko Matsakis
parent b8615f3bea
commit dde61f3855
4 changed files with 161 additions and 0 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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!();
}
}

View File

@ -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