introduce, but do not use, free_region_relation
computation
This duplicates, effectively, existing code in the universal regions computation.
This commit is contained in:
parent
54628c8ea8
commit
3bca170bc7
@ -104,6 +104,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
||||
None
|
||||
};
|
||||
|
||||
let universal_regions = Rc::new(universal_regions);
|
||||
|
||||
let elements = &Rc::new(RegionValueElements::new(mir));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
|
@ -206,15 +206,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// of constraints produced by the MIR type check.
|
||||
pub(crate) fn new(
|
||||
var_infos: VarInfos,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
_mir: &Mir<'tcx>,
|
||||
outlives_constraints: ConstraintSet,
|
||||
type_tests: Vec<TypeTest<'tcx>>,
|
||||
liveness_constraints: LivenessValues<RegionVid>,
|
||||
elements: &Rc<RegionValueElements>,
|
||||
) -> Self {
|
||||
let universal_regions = Rc::new(universal_regions);
|
||||
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let definitions: IndexVec<_, _> = var_infos
|
||||
.into_iter()
|
||||
|
@ -0,0 +1,225 @@
|
||||
// Copyright 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.
|
||||
|
||||
use borrow_check::location::LocationTable;
|
||||
use borrow_check::nll::facts::AllFacts;
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::type_check::constraint_conversion;
|
||||
use borrow_check::nll::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::region_constraints::GenericKind;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use rustc::traits::query::type_op::{self, TypeOp};
|
||||
use rustc::ty::{self, RegionVid, Ty};
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast;
|
||||
|
||||
#[derive(Debug)]
|
||||
crate struct UniversalRegionRelations<'tcx> {
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
|
||||
/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to
|
||||
/// be true. These encode relationships like `T: 'a` that are
|
||||
/// added via implicit bounds.
|
||||
///
|
||||
/// Each region here is guaranteed to be a key in the `indices`
|
||||
/// map. We use the "original" regions (i.e., the keys from the
|
||||
/// map, and not the values) because the code in
|
||||
/// `process_registered_region_obligations` has some special-cased
|
||||
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
|
||||
/// our special inference variable there, we would mess that up.
|
||||
crate region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
|
||||
|
||||
/// Stores the outlives relations that are known to hold from the
|
||||
/// implied bounds, in-scope where clauses, and that sort of
|
||||
/// thing.
|
||||
outlives: TransitiveRelation<RegionVid>,
|
||||
|
||||
/// This is the `<=` relation; that is, if `a: b`, then `b <= a`,
|
||||
/// and we store that here. This is useful when figuring out how
|
||||
/// to express some local region in terms of external regions our
|
||||
/// caller will understand.
|
||||
inverse_outlives: TransitiveRelation<RegionVid>,
|
||||
}
|
||||
|
||||
impl UniversalRegionRelations<'tcx> {
|
||||
crate fn create(
|
||||
infcx: &InferCtxt<'_, '_, 'tcx>,
|
||||
mir_def_id: DefId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
) -> Self {
|
||||
let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id).unwrap();
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
mir_def_id,
|
||||
mir_node_id,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
location_table,
|
||||
all_facts,
|
||||
universal_regions: universal_regions.clone(),
|
||||
relations: UniversalRegionRelations {
|
||||
universal_regions: universal_regions.clone(),
|
||||
region_bound_pairs: Vec::new(),
|
||||
outlives: TransitiveRelation::new(),
|
||||
inverse_outlives: TransitiveRelation::new(),
|
||||
},
|
||||
}.create()
|
||||
}
|
||||
|
||||
/// Records in the `outlives_relation` (and
|
||||
/// `inverse_outlives_relation`) that `fr_a: fr_b`. Invoked by the
|
||||
/// builder below.
|
||||
fn relate_universal_regions(&mut self, fr_a: RegionVid, fr_b: RegionVid) {
|
||||
debug!(
|
||||
"relate_universal_regions: fr_a={:?} outlives fr_b={:?}",
|
||||
fr_a, fr_b
|
||||
);
|
||||
self.outlives.add(fr_a, fr_b);
|
||||
self.inverse_outlives.add(fr_b, fr_a);
|
||||
}
|
||||
}
|
||||
|
||||
struct UniversalRegionRelationsBuilder<'this, 'gcx: 'tcx, 'tcx: 'this> {
|
||||
infcx: &'this InferCtxt<'this, 'gcx, 'tcx>,
|
||||
mir_def_id: DefId,
|
||||
mir_node_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
location_table: &'this LocationTable,
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
relations: UniversalRegionRelations<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
||||
all_facts: &'this mut Option<AllFacts>,
|
||||
}
|
||||
|
||||
impl UniversalRegionRelationsBuilder<'cx, 'gcx, 'tcx> {
|
||||
crate fn create(mut self) -> UniversalRegionRelations<'tcx> {
|
||||
let unnormalized_input_output_tys = self
|
||||
.universal_regions
|
||||
.unnormalized_input_tys
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(Some(self.universal_regions.unnormalized_output_ty));
|
||||
|
||||
// For each of the input/output types:
|
||||
// - Normalize the type. This will create some region
|
||||
// constraints, which we buffer up because we are
|
||||
// not ready to process them yet.
|
||||
// - Then compute the implied bounds. This will adjust
|
||||
// the `relations.region_bound_pairs` and so forth.
|
||||
// - After this is done, we'll process the constraints, once
|
||||
// the `relations` is built.
|
||||
let constraint_sets: Vec<_> = unnormalized_input_output_tys
|
||||
.flat_map(|ty| {
|
||||
debug!("build: input_or_output={:?}", ty);
|
||||
let (ty, constraints) = self
|
||||
.param_env
|
||||
.and(type_op::normalize::Normalize::new(ty))
|
||||
.fully_perform(self.infcx)
|
||||
.unwrap_or_else(|_| bug!("failed to normalize {:?}", ty));
|
||||
self.add_implied_bounds(ty);
|
||||
constraints
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Insert the facts we know from the predicates. Why? Why not.
|
||||
let param_env = self.param_env;
|
||||
self.add_outlives_bounds(outlives_bounds::explicit_outlives_bounds(param_env));
|
||||
|
||||
// Finally:
|
||||
// - outlives is reflexive, so `'r: 'r` for every region `'r`
|
||||
// - `'static: 'r` for every region `'r`
|
||||
// - `'r: 'fn_body` for every (other) universally quantified
|
||||
// region `'r`, all of which are provided by our caller
|
||||
let fr_static = self.universal_regions.fr_static;
|
||||
let fr_fn_body = self.universal_regions.fr_fn_body;
|
||||
for fr in self.universal_regions.universal_regions() {
|
||||
debug!(
|
||||
"build: relating free region {:?} to itself and to 'static",
|
||||
fr
|
||||
);
|
||||
self.relations.relate_universal_regions(fr, fr);
|
||||
self.relations.relate_universal_regions(fr_static, fr);
|
||||
self.relations.relate_universal_regions(fr, fr_fn_body);
|
||||
}
|
||||
|
||||
for data in constraint_sets {
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx.tcx,
|
||||
&self.universal_regions,
|
||||
&self.location_table,
|
||||
&self.relations.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
Locations::All,
|
||||
&mut self.constraints.outlives_constraints,
|
||||
&mut self.constraints.type_tests,
|
||||
&mut self.all_facts,
|
||||
).convert_all(&data);
|
||||
}
|
||||
|
||||
self.relations
|
||||
}
|
||||
|
||||
/// Update the type of a single local, which should represent
|
||||
/// either the return type of the MIR or one of its arguments. At
|
||||
/// the same time, compute and add any implied bounds that come
|
||||
/// from this local.
|
||||
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) {
|
||||
debug!("add_implied_bounds(ty={:?})", ty);
|
||||
let span = self.infcx.tcx.def_span(self.mir_def_id);
|
||||
let bounds = self
|
||||
.infcx
|
||||
.implied_outlives_bounds(self.param_env, self.mir_node_id, ty, span);
|
||||
self.add_outlives_bounds(bounds);
|
||||
}
|
||||
|
||||
/// Registers the `OutlivesBound` items from `outlives_bounds` in
|
||||
/// the outlives relation as well as the region-bound pairs
|
||||
/// listing.
|
||||
fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
|
||||
where
|
||||
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||
{
|
||||
for outlives_bound in outlives_bounds {
|
||||
debug!("add_outlives_bounds(bound={:?})", outlives_bound);
|
||||
|
||||
match outlives_bound {
|
||||
OutlivesBound::RegionSubRegion(r1, r2) => {
|
||||
// The bound says that `r1 <= r2`; we store `r2: r1`.
|
||||
let r1 = self.universal_regions.to_region_vid(r1);
|
||||
let r2 = self.universal_regions.to_region_vid(r2);
|
||||
self.relations.relate_universal_regions(r2, r1);
|
||||
}
|
||||
|
||||
OutlivesBound::RegionSubParam(r_a, param_b) => {
|
||||
self.relations
|
||||
.region_bound_pairs
|
||||
.push((r_a, GenericKind::Param(param_b)));
|
||||
}
|
||||
|
||||
OutlivesBound::RegionSubProjection(r_a, projection_b) => {
|
||||
self.relations
|
||||
.region_bound_pairs
|
||||
.push((r_a, GenericKind::Projection(projection_b)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -71,6 +71,7 @@ macro_rules! span_mirbug_and_err {
|
||||
}
|
||||
|
||||
mod constraint_conversion;
|
||||
mod free_region_relations;
|
||||
mod input_output;
|
||||
mod liveness;
|
||||
mod relate_tys;
|
||||
@ -110,7 +111,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
location_table: &LocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
liveness: &LivenessResults<LocalWithRegion>,
|
||||
@ -127,6 +128,17 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
type_tests: Vec::default(),
|
||||
};
|
||||
|
||||
let _urr = free_region_relations::UniversalRegionRelations::create(
|
||||
infcx,
|
||||
mir_def_id,
|
||||
param_env,
|
||||
location_table,
|
||||
Some(implicit_region_bound),
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
all_facts,
|
||||
);
|
||||
|
||||
{
|
||||
let mut borrowck_context = BorrowCheckContext {
|
||||
universal_regions,
|
||||
|
@ -14,6 +14,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||
|
||||
*/
|
||||
|
||||
#![feature(infer_outlives_requirements)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(slice_sort_by_cached_key)]
|
||||
#![feature(from_ref)]
|
||||
|
Loading…
Reference in New Issue
Block a user