1
Fork 0

add Locations::All as a concept

In particular, type annotations given by the user must hold at all
points in the program. This doesn't affect current analysis but
will affect fact generation later.
This commit is contained in:
Niko Matsakis 2018-05-01 10:50:05 -04:00
parent 81905a15c1
commit 53eb9e582f
4 changed files with 73 additions and 49 deletions

View file

@ -38,7 +38,6 @@ mod universal_regions;
use self::region_infer::RegionInferenceContext;
use self::universal_regions::UniversalRegions;
/// Rewrites the regions in the MIR to use NLL variables, also
/// scraping out the set of universal regions (e.g., region parameters)
/// declared on the function. That set will need to be given to

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::mir::Mir;
use rustc::mir::{Location, Mir};
use rustc::infer::region_constraints::Constraint;
use rustc::infer::region_constraints::RegionConstraintData;
use rustc::infer::region_constraints::{Verify, VerifyBound};
@ -65,7 +65,11 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
givens,
} = data;
let span = self.mir.source_info(locations.from_location).span;
let span = self.mir
.source_info(locations.from_location().unwrap_or(Location::START))
.span;
let at_location = locations.at_location().unwrap_or(Location::START);
for constraint in constraints.keys() {
debug!("generate: constraint: {:?}", constraint);
@ -83,8 +87,7 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
// reverse direction, because `regioncx` talks about
// "outlives" (`>=`) whereas the region constraints
// talk about `<=`.
self.regioncx
.add_outlives(span, b_vid, a_vid, locations.at_location);
self.regioncx.add_outlives(span, b_vid, a_vid, at_location);
}
for verify in verifys {
@ -109,7 +112,7 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
let lower_bound = self.to_region_vid(verify.region);
let point = locations.at_location;
let point = locations.at_location().unwrap_or(Location::START);
let test = self.verify_bound_to_region_test(&verify.bound);
@ -149,14 +152,6 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
}
fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid {
// Every region that we see in the constraints came from the
// MIR or from the parameter environment. If the former, it
// will be a region variable. If the latter, it will be in
// the set of universal regions *somewhere*.
if let ty::ReVar(vid) = r {
*vid
} else {
self.regioncx.to_region_vid(r)
}
self.regioncx.to_region_vid(r)
}
}

View file

@ -29,7 +29,7 @@ use rustc::traits::PredicateObligations;
use rustc_data_structures::indexed_vec::Idx;
use super::{AtLocation, TypeChecker};
use super::{Locations, TypeChecker};
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
pub(super) fn equate_inputs_and_outputs(
@ -47,26 +47,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
} = universal_regions;
let infcx = self.infcx;
let start_position = Location {
block: START_BLOCK,
statement_index: 0,
};
// Equate expected input tys with those in the MIR.
let argument_locals = (1..).map(Local::new);
for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) {
let input_ty = self.normalize(&unnormalized_input_ty, start_position);
let input_ty = self.normalize(&unnormalized_input_ty, Locations::All);
let mir_input_ty = mir.local_decls[local].ty;
self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty);
self.equate_normalized_input_or_output(input_ty, mir_input_ty);
}
assert!(
mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
);
);
if let Some(mir_yield_ty) = mir.yield_ty {
let ur_yield_ty = universal_regions.yield_ty.unwrap();
self.equate_normalized_input_or_output(start_position, ur_yield_ty, mir_yield_ty);
self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty);
}
// Return types are a bit more complex. They may contain existential `impl Trait`
@ -75,13 +70,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
"equate_inputs_and_outputs: unnormalized_output_ty={:?}",
unnormalized_output_ty
);
let output_ty = self.normalize(&unnormalized_output_ty, start_position);
let output_ty = self.normalize(&unnormalized_output_ty, Locations::All);
debug!(
"equate_inputs_and_outputs: normalized output_ty={:?}",
output_ty
);
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
let anon_type_map = self.fully_perform_op(start_position.at_self(), |cx| {
let anon_type_map = self.fully_perform_op(Locations::All, |cx| {
let mut obligations = ObligationAccumulator::default();
let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
@ -148,7 +143,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// prove that `T: Iterator` where `T` is the type we
// instantiated it with).
if let Some(anon_type_map) = anon_type_map {
self.fully_perform_op(start_position.at_self(), |_cx| {
self.fully_perform_op(Locations::All, |_cx| {
infcx.constrain_anon_types(&anon_type_map, universal_regions);
Ok(InferOk {
value: (),
@ -158,13 +153,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
fn equate_normalized_input_or_output(&mut self, location: Location, a: Ty<'tcx>, b: Ty<'tcx>) {
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);
if let Err(terr) = self.eq_types(a, b, location.at_self()) {
if let Err(terr) = self.eq_types(a, b, Locations::All) {
span_mirbug!(
self,
location,
Location::START,
"equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
a,
b,

View file

@ -619,16 +619,35 @@ pub struct OutlivesSet<'tcx> {
}
#[derive(Copy, Clone, Debug)]
pub struct Locations {
/// The location in the MIR that generated these constraints.
/// This is intended for error reporting and diagnosis; the
/// constraints may *take effect* at a distinct spot.
pub from_location: Location,
pub enum Locations {
All,
Pair {
/// The location in the MIR that generated these constraints.
/// This is intended for error reporting and diagnosis; the
/// constraints may *take effect* at a distinct spot.
from_location: Location,
/// The constraints must be met at this location. In terms of the
/// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
/// is the `P` value.
pub at_location: Location,
/// The constraints must be met at this location. In terms of the
/// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
/// is the `P` value.
at_location: Location,
}
}
impl Locations {
pub fn from_location(&self) -> Option<Location> {
match self {
Locations::All => None,
Locations::Pair { from_location, .. } => Some(*from_location),
}
}
pub fn at_location(&self) -> Option<Location> {
match self {
Locations::All => None,
Locations::Pair { at_location, .. } => Some(*at_location),
}
}
}
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
@ -770,7 +789,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
"check_stmt: user_assert_ty ty={:?} local_ty={:?}",
ty, local_ty
);
if let Err(terr) = self.eq_types(ty, local_ty, location.at_self()) {
if let Err(terr) = self.eq_types(ty, local_ty, Locations::All) {
span_mirbug!(
self,
stmt,
@ -820,7 +839,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let place_ty = location.ty(mir, tcx).to_ty(tcx);
let rv_ty = value.ty(mir, tcx);
let locations = Locations {
let locations = Locations::Pair {
from_location: term_location,
at_location: target.start_location(),
};
@ -839,7 +858,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// *both* blocks, so we need to ensure that it holds
// at both locations.
if let Some(unwind) = unwind {
let locations = Locations {
let locations = Locations::Pair {
from_location: term_location,
at_location: unwind.start_location(),
};
@ -971,7 +990,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
match *destination {
Some((ref dest, target_block)) => {
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
let locations = Locations {
let locations = Locations::Pair {
from_location: term_location,
at_location: target_block.start_location(),
};
@ -1375,7 +1394,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
};
let operand_ty = operand.ty(mir, tcx);
if let Err(terr) =
self.sub_types(operand_ty, field_ty, location.at_successor_within_block())
self.sub_types(operand_ty, field_ty, location.at_self())
{
span_mirbug!(
self,
@ -1514,12 +1533,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
fn normalize<T>(&mut self, value: &T, location: Location) -> T
fn normalize<T>(&mut self, value: &T, location: impl ToLocations) -> T
where
T: fmt::Debug + TypeFoldable<'tcx>,
{
debug!("normalize(value={:?}, location={:?})", value, location);
self.fully_perform_op(location.at_self(), |this| {
self.fully_perform_op(location.to_locations(), |this| {
let Normalized { value, obligations } = this.infcx
.at(&this.misc(this.last_span), this.param_env)
.normalize(value)
@ -1585,16 +1604,32 @@ trait AtLocation {
impl AtLocation for Location {
fn at_self(self) -> Locations {
Locations {
Locations::Pair {
from_location: self,
at_location: self,
}
}
fn at_successor_within_block(self) -> Locations {
Locations {
Locations::Pair {
from_location: self,
at_location: self.successor_within_block(),
}
}
}
trait ToLocations: fmt::Debug + Copy {
fn to_locations(self) -> Locations;
}
impl ToLocations for Locations {
fn to_locations(self) -> Locations {
self
}
}
impl ToLocations for Location {
fn to_locations(self) -> Locations {
self.at_self()
}
}