Skip to content
13 changes: 13 additions & 0 deletions src/librustc/traits/query/type_op/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ fn scrape_region_constraints<'gcx, 'tcx, R>(
) -> Fallible<(R, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
let dummy_body_id = ObligationCause::dummy().body_id;

// During NLL, we expect that nobody will register region
// obligations **except** as part of a custom type op (and, at the
// end of each custom type op, we scrape out the region
// obligations that resulted). So this vector should be empty on
// entry.
let pre_obligations = infcx.take_registered_region_obligations();
assert!(
pre_obligations.is_empty(),
"scrape_region_constraints: incoming region obligations = {:#?}",
pre_obligations,
);

let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/borrow_check/nll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@ 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.
let liveness_map = NllLivenessMap::compute(&mir);
let liveness = LivenessResults::compute(mir, &liveness_map);
let constraint_sets = type_check::type_check(
let (constraint_sets, universal_region_relations) = type_check::type_check(
infcx,
param_env,
mir,
Expand Down Expand Up @@ -153,6 +155,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
let mut regioncx = RegionInferenceContext::new(
var_origins,
universal_regions,
universal_region_relations,
mir,
outlives_constraints,
type_tests,
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 @@ -33,7 +33,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.universal_regions
.region_classification(region)
.unwrap();
let outlived_by = self.universal_regions.regions_outlived_by(region);
let outlived_by = self.universal_region_relations.regions_outlived_by(region);
writeln!(
out,
"| {r:rw$} | {c:cw$} | {ob}",
Expand Down
89 changes: 59 additions & 30 deletions src/librustc_mir/borrow_check/nll/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use borrow_check::nll::constraints::{
ConstraintIndex, ConstraintSccIndex, ConstraintSet, OutlivesConstraint,
};
use borrow_check::nll::region_infer::values::{RegionElement, ToElementIndex};
use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
use borrow_check::nll::type_check::Locations;
use rustc::hir::def_id::DefId;
use rustc::infer::canonical::QueryRegionConstraint;
Expand Down Expand Up @@ -80,8 +81,12 @@ pub struct RegionInferenceContext<'tcx> {
type_tests: Vec<TypeTest<'tcx>>,

/// Information about the universally quantified regions in scope
/// on this function and their (known) relations to one another.
/// on this function.
universal_regions: Rc<UniversalRegions<'tcx>>,

/// Information about how the universally quantified regions in
/// scope on this function relate to one another.
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
}

struct RegionDefinition<'tcx> {
Expand Down Expand Up @@ -206,15 +211,14 @@ 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>>,
universal_region_relations: Rc<UniversalRegionRelations<'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()
Expand Down Expand Up @@ -251,6 +255,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
scc_values,
type_tests,
universal_regions,
universal_region_relations,
};

result.init_free_and_bound_regions();
Expand Down Expand Up @@ -308,8 +313,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
for (external_name, variable) in self.universal_regions.named_universal_regions() {
debug!(
"init_universal_regions: region {:?} has external name {:?}",
variable,
external_name
variable, external_name
);
self.definitions[variable].external_name = Some(external_name);
}
Expand Down Expand Up @@ -419,10 +423,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
};

self.check_type_tests(
infcx, mir, mir_def_id, outlives_requirements.as_mut(), errors_buffer);
infcx,
mir,
mir_def_id,
outlives_requirements.as_mut(),
errors_buffer,
);

self.check_universal_regions(
infcx, mir, mir_def_id, outlives_requirements.as_mut(), errors_buffer);
infcx,
mir,
mir_def_id,
outlives_requirements.as_mut(),
errors_buffer,
);

let outlives_requirements = outlives_requirements.unwrap_or(vec![]);

Expand Down Expand Up @@ -581,13 +595,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let Some(lower_bound_region) = lower_bound_region {
let region_scope_tree = &tcx.region_scope_tree(mir_def_id);
let type_test_span = type_test.locations.span(mir);
infcx.construct_generic_bound_failure(
region_scope_tree,
type_test_span,
None,
type_test.generic_kind,
lower_bound_region,
).buffer(errors_buffer);
infcx
.construct_generic_bound_failure(
region_scope_tree,
type_test_span,
None,
type_test.generic_kind,
lower_bound_region,
)
.buffer(errors_buffer);
} else {
// FIXME. We should handle this case better. It
// indicates that we have e.g. some region variable
Expand All @@ -599,10 +615,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// iterating over the universal regions and reporting
// an error that multiple bounds are required.
let type_test_span = type_test.locations.span(mir);
tcx.sess.struct_span_err(
type_test_span,
&format!("`{}` does not live long enough", type_test.generic_kind,),
).buffer(errors_buffer);
tcx.sess
.struct_span_err(
type_test_span,
&format!("`{}` does not live long enough", type_test.generic_kind,),
)
.buffer(errors_buffer);
}
}
}
Expand Down Expand Up @@ -654,8 +672,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// region, which ensures it can be encoded in a `ClosureOutlivesRequirement`.
let lower_bound_plus = self.non_local_universal_upper_bound(*lower_bound);
assert!(self.universal_regions.is_universal_region(lower_bound_plus));
assert!(!self.universal_regions
.is_local_free_region(lower_bound_plus));
assert!(
!self
.universal_regions
.is_local_free_region(lower_bound_plus)
);

propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject,
Expand Down Expand Up @@ -768,7 +789,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {

// Grow further to get smallest universal region known to
// creator.
let non_local_lub = self.universal_regions.non_local_upper_bound(lub);
let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);

debug!(
"non_local_universal_upper_bound: non_local_lub={:?}",
Expand Down Expand Up @@ -804,7 +825,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let mut lub = self.universal_regions.fr_fn_body;
let r_scc = self.constraint_sccs.scc(r);
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
lub = self.universal_regions.postdom_upper_bound(lub, ur);
lub = self.universal_region_relations.postdom_upper_bound(lub, ur);
}

debug!("universal_upper_bound: r={:?} lub={:?}", r, lub);
Expand Down Expand Up @@ -872,7 +893,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.all(|r1| {
self.scc_values
.universal_regions_outlived_by(sup_region_scc)
.any(|r2| self.universal_regions.outlives(r2, r1))
.any(|r2| self.universal_region_relations.outlives(r2, r1))
});

if !universal_outlives {
Expand All @@ -887,7 +908,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
return true;
}

self.scc_values.contains_points(sup_region_scc, sub_region_scc)
self.scc_values
.contains_points(sup_region_scc, sub_region_scc)
}

/// Once regions have been propagated, this method is used to see
Expand Down Expand Up @@ -977,7 +999,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// (because `fr` includes `end(o)`).
for shorter_fr in self.scc_values.universal_regions_outlived_by(longer_fr_scc) {
// If it is known that `fr: o`, carry on.
if self.universal_regions.outlives(longer_fr, shorter_fr) {
if self
.universal_region_relations
.outlives(longer_fr, shorter_fr)
{
continue;
}

Expand All @@ -991,14 +1016,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
// Shrink `fr` until we find a non-local region (if we do).
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
if let Some(fr_minus) = self.universal_regions.non_local_lower_bound(longer_fr) {
if let Some(fr_minus) = self
.universal_region_relations
.non_local_lower_bound(longer_fr)
{
debug!("check_universal_region: fr_minus={:?}", fr_minus);

// Grow `shorter_fr` until we find a non-local
// region. (We always will.) We'll call that
// `shorter_fr+` -- it's ever so slightly larger than
// `fr`.
let shorter_fr_plus = self.universal_regions.non_local_upper_bound(shorter_fr);
let shorter_fr_plus = self
.universal_region_relations
.non_local_upper_bound(shorter_fr);
debug!(
"check_universal_region: shorter_fr_plus={:?}",
shorter_fr_plus
Expand All @@ -1021,8 +1051,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// Note: in this case, we use the unapproximated regions
// to report the error. This gives better error messages
// in some cases.
self.report_error(
mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
self.report_error(mir, infcx, mir_def_id, longer_fr, shorter_fr, errors_buffer);
}
}

Expand Down
Loading