add basic region subtyping inference
This commit is contained in:
parent
b8615f3bea
commit
dde61f3855
@ -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);
|
||||
|
@ -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;
|
||||
|
99
src/librustc_mir/transform/nll/subtype.rs
Normal file
99
src/librustc_mir/transform/nll/subtype.rs
Normal 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!();
|
||||
}
|
||||
}
|
49
src/test/mir-opt/nll/region-subtyping-basic.rs
Normal file
49
src/test/mir-opt/nll/region-subtyping-basic.rs
Normal 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
|
Loading…
Reference in New Issue
Block a user