Skip to content

make MIR type checker handle a number of other cases #46582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Dec 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d6772cb
Check Repeat Rvalue
spastorino Nov 28, 2017
7f20b91
fix universal regions to handle constant expressions like `[T; 22]`
nikomatsakis Nov 27, 2017
c915926
Check NullaryOp Rvalue
spastorino Nov 20, 2017
5010496
Check Aggregate predicates
spastorino Nov 26, 2017
688ab5a
Check functions predicates
spastorino Nov 27, 2017
4449240
Add more debug logs
spastorino Nov 28, 2017
8635548
Restructure a bit check_aggregate_rvalue code
spastorino Nov 28, 2017
7d56131
Mir typeck Cast for ReifyFnPtr value
spastorino Nov 29, 2017
900d4d5
Mir typeck Cast for UnsafeFnPtr value
spastorino Nov 30, 2017
ae035cb
Extract coerce_closure_fn_ty function
spastorino Nov 30, 2017
14700e5
Mir typeck Cast for ClosureFnPtr value
spastorino Nov 30, 2017
0c26d8f
Mir typeck Cast for Unsize value
spastorino Nov 30, 2017
d5cff07
normalize fn sig as part of reification
nikomatsakis Dec 1, 2017
decbbb3
when reifying a safe fn as an unsafe fn ptr, insert two casts
nikomatsakis Dec 2, 2017
a30e225
fix closure tests now that MIR typeck works properly
nikomatsakis Dec 7, 2017
77663a6
refactor region value bitmatrix
nikomatsakis Dec 1, 2017
7a20a3f
change to use an O(1) data structure for looking up point indices
nikomatsakis Dec 1, 2017
f6723a9
improve comments on `safe_to_unsafe_fn_ty` and `coerce_closure_fn_ty`
nikomatsakis Dec 12, 2017
75ac071
document return value of `add_live_point`
nikomatsakis Dec 12, 2017
abd6d0d
comments for `defining_ty` and `compute_indices`
nikomatsakis Dec 13, 2017
51847a1
add FIXME related to constant well-formedness
nikomatsakis Dec 13, 2017
237dd41
correct comment in test
nikomatsakis Dec 13, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// translate them into the form that the NLL solver
/// understands. See the NLL module for mode details.
pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
assert!(self.region_obligations.borrow().is_empty(),
"region_obligations not empty: {:#?}",
self.region_obligations.borrow());

self.borrow_region_constraints().take_and_reset_data()
}

Expand Down
16 changes: 15 additions & 1 deletion src/librustc/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,12 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
body_id: ast::NodeId,
obligation: RegionObligation<'tcx>,
) {
debug!("register_region_obligation({:?}, {:?})", body_id, obligation);
debug!(
"register_region_obligation(body_id={:?}, obligation={:?})",
body_id,
obligation
);

self.region_obligations
.borrow_mut()
.push((body_id, obligation));
Expand Down Expand Up @@ -139,6 +144,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
"cannot process registered region obligations in a snapshot"
);

debug!("process_registered_region_obligations()");

// pull out the region obligations with the given `body_id` (leaving the rest)
let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len());
{
Expand All @@ -157,6 +164,13 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
cause,
} in my_region_obligations
{
debug!(
"process_registered_region_obligations: sup_type={:?} sub_region={:?} cause={:?}",
sup_type,
sub_region,
cause
);

let origin = SubregionOrigin::from_obligation_cause(
&cause,
|| infer::RelateParamBound(cause.span, sup_type),
Expand Down
28 changes: 27 additions & 1 deletion src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1708,7 +1708,9 @@ slice_interners!(
);

impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Create an unsafe fn ty based on a safe fn ty.
/// Given a `fn` type, returns an equivalent `unsafe fn` type;
/// that is, a `fn` type that is equivalent in every way for being
/// unsafe.
pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig {
Expand All @@ -1717,6 +1719,30 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}))
}

/// Given a closure signature `sig`, returns an equivalent `fn`
/// type with the same signature. Detuples and so forth -- so
/// e.g. if we have a sig with `Fn<(u32, i32)>` then you would get
/// a `fn(u32, i32)`.
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
let converted_sig = sig.map_bound(|s| {
let params_iter = match s.inputs()[0].sty {
ty::TyTuple(params, _) => {
params.into_iter().cloned()
}
_ => bug!(),
};
self.mk_fn_sig(
params_iter,
s.output(),
s.variadic,
hir::Unsafety::Normal,
abi::Abi::Rust,
)
});

self.mk_fn_ptr(converted_sig)
}

// Interns a type/name combination, stores the resulting box in cx.interners,
// and returns the box as cast to an unsafe ptr (see comments for Ty above).
pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/borrow_check/nll/region_infer/dump_mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
with_msg: &mut FnMut(&str) -> io::Result<()>,
) -> io::Result<()> {
for region in self.definitions.indices() {
let value = self.region_value_str_from_matrix(&self.liveness_constraints, region);
let value = self.liveness_constraints.region_value_str(region);
if value != "{}" {
with_msg(&format!("{:?} live at {}", region, value))?;
}
Expand Down
149 changes: 38 additions & 111 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ use rustc::mir::{ClosureOutlivesRequirement, ClosureRegionRequirements, Location
use rustc::ty::{self, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::bitvec::BitMatrix;
use rustc_data_structures::indexed_vec::Idx;
use std::collections::BTreeMap;
use std::fmt;
use std::rc::Rc;
use syntax_pos::Span;

mod annotation;
mod dump_mir;
mod graphviz;
mod values;
use self::values::{RegionValueElements, RegionValues};

pub struct RegionInferenceContext<'tcx> {
/// Contains the definition for every region variable. Region
Expand All @@ -36,27 +36,22 @@ pub struct RegionInferenceContext<'tcx> {
/// from as well as its final inferred value.
definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,

/// Maps from points/universal-regions to a `RegionElementIndex`.
elements: Rc<RegionValueElements>,

/// The liveness constraints added to each region. For most
/// regions, these start out empty and steadily grow, though for
/// each universally quantified region R they start out containing
/// the entire CFG and `end(R)`.
///
/// In this `BitMatrix` representation, the rows are the region
/// variables and the columns are the free regions and MIR locations.
liveness_constraints: BitMatrix,
liveness_constraints: RegionValues,

/// The final inferred values of the inference variables; `None`
/// until `solve` is invoked.
inferred_values: Option<BitMatrix>,
inferred_values: Option<RegionValues>,

/// The constraints we have accumulated and used during solving.
constraints: Vec<Constraint>,

/// A map from each MIR Location to its column index in
/// `liveness_constraints`/`inferred_values`. (The first N columns are
/// the free regions.)
point_indices: BTreeMap<Location, usize>,

/// Information about the universally quantified regions in scope
/// on this function and their (known) relations to one another.
universal_regions: UniversalRegions<'tcx>,
Expand Down Expand Up @@ -112,19 +107,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let num_region_variables = var_origins.len();
let num_universal_regions = universal_regions.len();

let mut num_points = 0;
let mut point_indices = BTreeMap::new();

for (block, block_data) in mir.basic_blocks().iter_enumerated() {
for statement_index in 0..block_data.statements.len() + 1 {
let location = Location {
block,
statement_index,
};
point_indices.insert(location, num_universal_regions + num_points);
num_points += 1;
}
}
let elements = &Rc::new(RegionValueElements::new(mir, num_universal_regions));

// Create a RegionDefinition for each inference variable.
let definitions = var_origins
Expand All @@ -134,13 +117,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {

let mut result = Self {
definitions,
liveness_constraints: BitMatrix::new(
num_region_variables,
num_universal_regions + num_points,
),
elements: elements.clone(),
liveness_constraints: RegionValues::new(elements, num_region_variables),
inferred_values: None,
constraints: Vec::new(),
point_indices,
universal_regions,
};

Expand Down Expand Up @@ -186,14 +166,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.definitions[variable].is_universal = true;

// Add all nodes in the CFG to liveness constraints
for (_location, point_index) in &self.point_indices {
self.liveness_constraints
.add(variable.index(), *point_index);
for point_index in self.elements.all_point_indices() {
self.liveness_constraints.add(variable, point_index);
}

// Add `end(X)` into the set for X.
self.liveness_constraints
.add(variable.index(), variable.index());
self.liveness_constraints.add(variable, variable);
}
}

Expand All @@ -217,32 +195,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let inferred_values = self.inferred_values
.as_ref()
.expect("region values not yet inferred");
self.region_contains_point_in_matrix(inferred_values, r, p)
}

/// True if given region `r` contains the point `p`, when
/// evaluated in the set of region values `matrix`.
fn region_contains_point_in_matrix(
&self,
matrix: &BitMatrix,
r: RegionVid,
p: Location,
) -> bool {
let point_index = self.point_indices
.get(&p)
.expect("point index should be known");
matrix.contains(r.index(), *point_index)
}

/// True if given region `r` contains the `end(s)`, when
/// evaluated in the set of region values `matrix`.
fn region_contains_region_in_matrix(
&self,
matrix: &BitMatrix,
r: RegionVid,
s: RegionVid,
) -> bool {
matrix.contains(r.index(), s.index())
inferred_values.contains(r, p)
}

/// Returns access to the value of `r` for debugging purposes.
Expand All @@ -251,43 +204,24 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.as_ref()
.expect("region values not yet inferred");

self.region_value_str_from_matrix(inferred_values, r)
}

fn region_value_str_from_matrix(&self,
matrix: &BitMatrix,
r: RegionVid) -> String {
let mut result = String::new();
result.push_str("{");
let mut sep = "";

for &point in self.point_indices.keys() {
if self.region_contains_point_in_matrix(matrix, r, point) {
result.push_str(&format!("{}{:?}", sep, point));
sep = ", ";
}
}

for fr in (0..self.universal_regions.len()).map(RegionVid::new) {
if self.region_contains_region_in_matrix(matrix, r, fr) {
result.push_str(&format!("{}{:?}", sep, fr));
sep = ", ";
}
}

result.push_str("}");

result
inferred_values.region_value_str(r)
}

/// Indicates that the region variable `v` is live at the point `point`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer more documentation about the sense of the boolean - e.g. "returns true if the region had changed"

///
/// Returns `true` if this constraint is new and `false` is the
/// constraint was already present.
pub(super) fn add_live_point(&mut self, v: RegionVid, point: Location) -> bool {
debug!("add_live_point({:?}, {:?})", v, point);
assert!(self.inferred_values.is_none(), "values already inferred");
let point_index = self.point_indices
.get(&point)
.expect("point index should be known");
self.liveness_constraints.add(v.index(), *point_index)
debug!("add_live_point: @{:?}", point);

let element = self.elements.index(point);
if self.liveness_constraints.add(v, element) {
true
} else {
false
}
}

/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
Expand Down Expand Up @@ -386,16 +320,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
outlives_requirements: &mut Vec<ClosureOutlivesRequirement>,
) {
let inferred_values = self.inferred_values.as_ref().unwrap();
let longer_value = inferred_values.iter(longer_fr.index());

debug!("check_universal_region(fr={:?})", longer_fr);

// Find every region `o` such that `fr: o`
// (because `fr` includes `end(o)`).
let shorter_frs = longer_value
.take_while(|&i| i < self.universal_regions.len())
.map(RegionVid::new);
for shorter_fr in shorter_frs {
for shorter_fr in inferred_values.universal_regions_outlived_by(longer_fr) {
// If it is known that `fr: o`, carry on.
if self.universal_regions.outlives(longer_fr, shorter_fr) {
continue;
Expand Down Expand Up @@ -512,20 +442,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {

fn copy(
&self,
inferred_values: &mut BitMatrix,
inferred_values: &mut RegionValues,
mir: &Mir<'tcx>,
from_region: RegionVid,
to_region: RegionVid,
start_point: Location,
constraint_point: Location,
) -> bool {
let mut changed = false;

let mut stack = vec![];
let mut visited = FxHashSet();

stack.push(start_point);
stack.push(constraint_point);
while let Some(p) = stack.pop() {
if !self.region_contains_point_in_matrix(inferred_values, from_region, p) {
let point_index = self.elements.index(p);

if !inferred_values.contains(from_region, point_index) {
debug!(" not in from-region");
continue;
}
Expand All @@ -535,8 +467,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
continue;
}

let point_index = self.point_indices.get(&p).unwrap();
changed |= inferred_values.add(to_region.index(), *point_index);
let new = inferred_values.add(to_region, point_index);
changed |= new;

let block_data = &mir[p.block];
let successor_points = if p.statement_index < block_data.statements.len() {
Expand Down Expand Up @@ -564,13 +496,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// If we reach the END point in the graph, then copy
// over any skolemized end points in the `from_region`
// and make sure they are included in the `to_region`.
let universal_region_indices = inferred_values
.iter(from_region.index())
.take_while(|&i| i < self.universal_regions.len())
.collect::<Vec<_>>();
for fr in &universal_region_indices {
changed |= inferred_values.add(to_region.index(), *fr);
}
changed |=
inferred_values.add_universal_regions_outlived_by(from_region, to_region);
} else {
stack.extend(successor_points);
}
Expand Down
Loading