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:
parent
81905a15c1
commit
53eb9e582f
4 changed files with 73 additions and 49 deletions
|
@ -38,7 +38,6 @@ mod universal_regions;
|
||||||
use self::region_infer::RegionInferenceContext;
|
use self::region_infer::RegionInferenceContext;
|
||||||
use self::universal_regions::UniversalRegions;
|
use self::universal_regions::UniversalRegions;
|
||||||
|
|
||||||
|
|
||||||
/// Rewrites the regions in the MIR to use NLL variables, also
|
/// Rewrites the regions in the MIR to use NLL variables, also
|
||||||
/// scraping out the set of universal regions (e.g., region parameters)
|
/// scraping out the set of universal regions (e.g., region parameters)
|
||||||
/// declared on the function. That set will need to be given to
|
/// declared on the function. That set will need to be given to
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// 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::Constraint;
|
||||||
use rustc::infer::region_constraints::RegionConstraintData;
|
use rustc::infer::region_constraints::RegionConstraintData;
|
||||||
use rustc::infer::region_constraints::{Verify, VerifyBound};
|
use rustc::infer::region_constraints::{Verify, VerifyBound};
|
||||||
|
@ -65,7 +65,11 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
||||||
givens,
|
givens,
|
||||||
} = data;
|
} = 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() {
|
for constraint in constraints.keys() {
|
||||||
debug!("generate: constraint: {:?}", constraint);
|
debug!("generate: constraint: {:?}", constraint);
|
||||||
|
@ -83,8 +87,7 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
||||||
// reverse direction, because `regioncx` talks about
|
// reverse direction, because `regioncx` talks about
|
||||||
// "outlives" (`>=`) whereas the region constraints
|
// "outlives" (`>=`) whereas the region constraints
|
||||||
// talk about `<=`.
|
// talk about `<=`.
|
||||||
self.regioncx
|
self.regioncx.add_outlives(span, b_vid, a_vid, at_location);
|
||||||
.add_outlives(span, b_vid, a_vid, locations.at_location);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for verify in verifys {
|
for verify in verifys {
|
||||||
|
@ -109,7 +112,7 @@ impl<'cx, 'tcx> SubtypeConstraintGenerator<'cx, 'tcx> {
|
||||||
|
|
||||||
let lower_bound = self.to_region_vid(verify.region);
|
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);
|
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 {
|
fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid {
|
||||||
// Every region that we see in the constraints came from the
|
self.regioncx.to_region_vid(r)
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ use rustc::traits::PredicateObligations;
|
||||||
|
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
|
||||||
use super::{AtLocation, TypeChecker};
|
use super::{Locations, TypeChecker};
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
pub(super) fn equate_inputs_and_outputs(
|
pub(super) fn equate_inputs_and_outputs(
|
||||||
|
@ -47,26 +47,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
} = universal_regions;
|
} = universal_regions;
|
||||||
let infcx = self.infcx;
|
let infcx = self.infcx;
|
||||||
|
|
||||||
let start_position = Location {
|
|
||||||
block: START_BLOCK,
|
|
||||||
statement_index: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Equate expected input tys with those in the MIR.
|
// Equate expected input tys with those in the MIR.
|
||||||
let argument_locals = (1..).map(Local::new);
|
let argument_locals = (1..).map(Local::new);
|
||||||
for (&unnormalized_input_ty, local) in unnormalized_input_tys.iter().zip(argument_locals) {
|
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;
|
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!(
|
assert!(
|
||||||
mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
|
mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
|
||||||
mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
|
mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
|
||||||
);
|
);
|
||||||
if let Some(mir_yield_ty) = mir.yield_ty {
|
if let Some(mir_yield_ty) = mir.yield_ty {
|
||||||
let ur_yield_ty = universal_regions.yield_ty.unwrap();
|
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`
|
// 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={:?}",
|
"equate_inputs_and_outputs: unnormalized_output_ty={:?}",
|
||||||
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!(
|
debug!(
|
||||||
"equate_inputs_and_outputs: normalized output_ty={:?}",
|
"equate_inputs_and_outputs: normalized output_ty={:?}",
|
||||||
output_ty
|
output_ty
|
||||||
);
|
);
|
||||||
let mir_output_ty = mir.local_decls[RETURN_PLACE].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 mut obligations = ObligationAccumulator::default();
|
||||||
|
|
||||||
let (output_ty, anon_type_map) = obligations.add(infcx.instantiate_anon_types(
|
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
|
// prove that `T: Iterator` where `T` is the type we
|
||||||
// instantiated it with).
|
// instantiated it with).
|
||||||
if let Some(anon_type_map) = anon_type_map {
|
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);
|
infcx.constrain_anon_types(&anon_type_map, universal_regions);
|
||||||
Ok(InferOk {
|
Ok(InferOk {
|
||||||
value: (),
|
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);
|
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!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
location,
|
Location::START,
|
||||||
"equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
|
"equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
|
||||||
a,
|
a,
|
||||||
b,
|
b,
|
||||||
|
|
|
@ -619,16 +619,35 @@ pub struct OutlivesSet<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Locations {
|
pub enum Locations {
|
||||||
/// The location in the MIR that generated these constraints.
|
All,
|
||||||
/// This is intended for error reporting and diagnosis; the
|
Pair {
|
||||||
/// constraints may *take effect* at a distinct spot.
|
/// The location in the MIR that generated these constraints.
|
||||||
pub from_location: Location,
|
/// 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
|
/// The constraints must be met at this location. In terms of the
|
||||||
/// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
|
/// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
|
||||||
/// is the `P` value.
|
/// is the `P` value.
|
||||||
pub at_location: Location,
|
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> {
|
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={:?}",
|
"check_stmt: user_assert_ty ty={:?} local_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!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
stmt,
|
stmt,
|
||||||
|
@ -820,7 +839,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
let place_ty = location.ty(mir, tcx).to_ty(tcx);
|
let place_ty = location.ty(mir, tcx).to_ty(tcx);
|
||||||
let rv_ty = value.ty(mir, tcx);
|
let rv_ty = value.ty(mir, tcx);
|
||||||
|
|
||||||
let locations = Locations {
|
let locations = Locations::Pair {
|
||||||
from_location: term_location,
|
from_location: term_location,
|
||||||
at_location: target.start_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
|
// *both* blocks, so we need to ensure that it holds
|
||||||
// at both locations.
|
// at both locations.
|
||||||
if let Some(unwind) = unwind {
|
if let Some(unwind) = unwind {
|
||||||
let locations = Locations {
|
let locations = Locations::Pair {
|
||||||
from_location: term_location,
|
from_location: term_location,
|
||||||
at_location: unwind.start_location(),
|
at_location: unwind.start_location(),
|
||||||
};
|
};
|
||||||
|
@ -971,7 +990,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
match *destination {
|
match *destination {
|
||||||
Some((ref dest, target_block)) => {
|
Some((ref dest, target_block)) => {
|
||||||
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
|
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
|
||||||
let locations = Locations {
|
let locations = Locations::Pair {
|
||||||
from_location: term_location,
|
from_location: term_location,
|
||||||
at_location: target_block.start_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);
|
let operand_ty = operand.ty(mir, tcx);
|
||||||
if let Err(terr) =
|
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!(
|
span_mirbug!(
|
||||||
self,
|
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
|
where
|
||||||
T: fmt::Debug + TypeFoldable<'tcx>,
|
T: fmt::Debug + TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("normalize(value={:?}, location={:?})", value, location);
|
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
|
let Normalized { value, obligations } = this.infcx
|
||||||
.at(&this.misc(this.last_span), this.param_env)
|
.at(&this.misc(this.last_span), this.param_env)
|
||||||
.normalize(value)
|
.normalize(value)
|
||||||
|
@ -1585,16 +1604,32 @@ trait AtLocation {
|
||||||
|
|
||||||
impl AtLocation for Location {
|
impl AtLocation for Location {
|
||||||
fn at_self(self) -> Locations {
|
fn at_self(self) -> Locations {
|
||||||
Locations {
|
Locations::Pair {
|
||||||
from_location: self,
|
from_location: self,
|
||||||
at_location: self,
|
at_location: self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn at_successor_within_block(self) -> Locations {
|
fn at_successor_within_block(self) -> Locations {
|
||||||
Locations {
|
Locations::Pair {
|
||||||
from_location: self,
|
from_location: self,
|
||||||
at_location: self.successor_within_block(),
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue