preliminary integration of "pick constraints" into nll solver
This commit is contained in:
parent
3b5a7276d2
commit
ec48b4ebe2
src
librustc/infer
librustc_mir/borrow_check/nll
@ -385,13 +385,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
option_regions: _,
|
||||
} => {
|
||||
let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
|
||||
opaque_types::report_unexpected_hidden_region(
|
||||
opaque_types::unexpected_hidden_region_diagnostic(
|
||||
self.tcx,
|
||||
Some(region_scope_tree),
|
||||
opaque_type_def_id,
|
||||
hidden_ty,
|
||||
pick_region,
|
||||
);
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use crate::ty::subst::{InternalSubsts, Kind, SubstsRef, UnpackedKind};
|
||||
use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt};
|
||||
use crate::util::nodemap::DefIdMap;
|
||||
use errors::DiagnosticBuilder;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -499,13 +500,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_unexpected_hidden_region(
|
||||
pub fn unexpected_hidden_region_diagnostic(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_scope_tree: Option<®ion::ScopeTree>,
|
||||
opaque_type_def_id: DefId,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
hidden_region: ty::Region<'tcx>,
|
||||
) {
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let span = tcx.def_span(opaque_type_def_id);
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
@ -573,7 +574,7 @@ pub fn report_unexpected_hidden_region(
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
err
|
||||
}
|
||||
|
||||
// Visitor that requires that (almost) all regions in the type visited outlive
|
||||
@ -724,13 +725,13 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
|
||||
None => {
|
||||
if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
|
||||
if let Some(hidden_ty) = self.hidden_ty.take() {
|
||||
report_unexpected_hidden_region(
|
||||
unexpected_hidden_region_diagnostic(
|
||||
self.tcx,
|
||||
None,
|
||||
self.opaque_type_def_id,
|
||||
hidden_ty,
|
||||
r,
|
||||
);
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
self.tcx.lifetimes.re_empty
|
||||
|
@ -71,10 +71,12 @@ impl<'tcx> PickConstraintSet<'tcx, ty::RegionVid> {
|
||||
p_c: &PickConstraint<'tcx>,
|
||||
mut to_region_vid: impl FnMut(ty::Region<'tcx>) -> ty::RegionVid,
|
||||
) {
|
||||
debug!("push_constraint(p_c={:?})", p_c);
|
||||
let pick_region_vid: ty::RegionVid = to_region_vid(p_c.pick_region);
|
||||
let next_constraint = self.first_constraints.get(&pick_region_vid).cloned();
|
||||
let start_index = self.option_regions.len();
|
||||
let end_index = start_index + p_c.option_regions.len();
|
||||
debug!("push_constraint: pick_region_vid={:?}", pick_region_vid);
|
||||
let constraint_index = self.constraints.push(NllPickConstraint {
|
||||
next_constraint,
|
||||
pick_region_vid,
|
||||
@ -136,6 +138,12 @@ impl<'tcx, R> PickConstraintSet<'tcx, R>
|
||||
where
|
||||
R: Copy + Hash + Eq,
|
||||
{
|
||||
crate fn all_indices(
|
||||
&self,
|
||||
) -> impl Iterator<Item = NllPickConstraintIndex> {
|
||||
self.constraints.indices()
|
||||
}
|
||||
|
||||
/// Iterate down the constraint indices associated with a given
|
||||
/// peek-region. You can then use `option_regions` and other
|
||||
/// methods to access data.
|
||||
|
@ -1,20 +1,23 @@
|
||||
use super::universal_regions::UniversalRegions;
|
||||
use crate::borrow_check::nll::constraints::graph::NormalConstraintGraph;
|
||||
use crate::borrow_check::nll::constraints::{ConstraintSccIndex, OutlivesConstraintSet, OutlivesConstraint};
|
||||
use crate::borrow_check::nll::constraints::{
|
||||
ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
|
||||
};
|
||||
use crate::borrow_check::nll::pick_constraints::PickConstraintSet;
|
||||
use crate::borrow_check::nll::region_infer::values::{
|
||||
PlaceholderIndices, RegionElement, ToElementIndex
|
||||
PlaceholderIndices, RegionElement, ToElementIndex,
|
||||
};
|
||||
use crate::borrow_check::Upvar;
|
||||
use crate::borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::borrow_check::nll::type_check::Locations;
|
||||
use crate::borrow_check::Upvar;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::canonical::QueryOutlivesConstraint;
|
||||
use rustc::infer::opaque_types;
|
||||
use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
|
||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc::mir::{
|
||||
ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
ConstraintCategory, Local, Location, Body,
|
||||
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
ConstraintCategory, Local, Location,
|
||||
};
|
||||
use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::util::common::{self, ErrorReported};
|
||||
@ -61,6 +64,9 @@ pub struct RegionInferenceContext<'tcx> {
|
||||
/// compute the values of each region.
|
||||
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
|
||||
|
||||
/// The "pick R0 from [R1..Rn]" constraints, indexed by SCC.
|
||||
pick_constraints: Rc<PickConstraintSet<'tcx, ConstraintSccIndex>>,
|
||||
|
||||
/// Map closure bounds to a `Span` that should be used for error reporting.
|
||||
closure_bounds_mapping:
|
||||
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
|
||||
@ -188,7 +194,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
|
||||
_body: &Body<'tcx>,
|
||||
outlives_constraints: OutlivesConstraintSet,
|
||||
pick_constraints: PickConstraintSet<'tcx, RegionVid>,
|
||||
pick_constraints_in: PickConstraintSet<'tcx, RegionVid>,
|
||||
closure_bounds_mapping: FxHashMap<
|
||||
Location,
|
||||
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
|
||||
@ -220,9 +226,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
let scc_representatives = Self::compute_scc_representatives(&constraint_sccs, &definitions);
|
||||
|
||||
let _pick_constraints_scc = pick_constraints.into_mapped( // TODO
|
||||
|r| constraint_sccs.scc(r),
|
||||
);
|
||||
let pick_constraints = Rc::new(pick_constraints_in.into_mapped(|r| constraint_sccs.scc(r)));
|
||||
|
||||
let mut result = Self {
|
||||
definitions,
|
||||
@ -230,6 +234,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
constraints,
|
||||
constraint_graph,
|
||||
constraint_sccs,
|
||||
pick_constraints,
|
||||
closure_bounds_mapping,
|
||||
scc_universes,
|
||||
scc_representatives,
|
||||
@ -347,9 +352,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
debug!(
|
||||
"init_free_and_bound_regions: placeholder {:?} is \
|
||||
not compatible with universe {:?} of its SCC {:?}",
|
||||
placeholder,
|
||||
scc_universe,
|
||||
scc,
|
||||
placeholder, scc_universe, scc,
|
||||
);
|
||||
self.add_incompatible_universe(scc);
|
||||
}
|
||||
@ -434,11 +437,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// to store those. Otherwise, we'll pass in `None` to the
|
||||
// functions below, which will trigger them to report errors
|
||||
// eagerly.
|
||||
let mut outlives_requirements = if infcx.tcx.is_closure(mir_def_id) {
|
||||
Some(vec![])
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut outlives_requirements =
|
||||
if infcx.tcx.is_closure(mir_def_id) { Some(vec![]) } else { None };
|
||||
|
||||
self.check_type_tests(
|
||||
infcx,
|
||||
@ -457,16 +457,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
errors_buffer,
|
||||
);
|
||||
|
||||
self.check_pick_constraints(infcx, mir_def_id, errors_buffer);
|
||||
|
||||
let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
|
||||
|
||||
if outlives_requirements.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let num_external_vids = self.universal_regions.num_global_and_external_regions();
|
||||
Some(ClosureRegionRequirements {
|
||||
num_external_vids,
|
||||
outlives_requirements,
|
||||
})
|
||||
Some(ClosureRegionRequirements { num_external_vids, outlives_requirements })
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,6 +495,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the value of the SCC `scc_a` if it has not already
|
||||
/// been computed. The `visited` parameter is a bitset
|
||||
#[inline]
|
||||
fn propagate_constraint_sccs_if_new(
|
||||
&mut self,
|
||||
@ -507,6 +508,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the value of the SCC `scc_a`, which has not yet been
|
||||
/// computed. This works by first computing all successors of the
|
||||
/// SCC (if they haven't been computed already) and then unioning
|
||||
/// together their elements.
|
||||
fn propagate_constraint_sccs_new(
|
||||
&mut self,
|
||||
scc_a: ConstraintSccIndex,
|
||||
@ -516,10 +521,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
// Walk each SCC `B` such that `A: B`...
|
||||
for &scc_b in constraint_sccs.successors(scc_a) {
|
||||
debug!(
|
||||
"propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}",
|
||||
scc_a, scc_b
|
||||
);
|
||||
debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b);
|
||||
|
||||
// ...compute the value of `B`...
|
||||
self.propagate_constraint_sccs_if_new(scc_b, visited);
|
||||
@ -537,6 +539,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// Now take pick constraints into account
|
||||
let pick_constraints = self.pick_constraints.clone();
|
||||
for p_c_i in pick_constraints.indices(scc_a) {
|
||||
self.apply_pick_constraint(scc_a, pick_constraints.option_regions(p_c_i));
|
||||
}
|
||||
|
||||
debug!(
|
||||
"propagate_constraint_sccs: scc_a = {:?} has value {:?}",
|
||||
scc_a,
|
||||
@ -544,6 +552,114 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
/// Invoked for each `pick R0 from [R1..Rn]` constraint.
|
||||
///
|
||||
/// `scc` is the SCC containing R0, and `option_regions` are the
|
||||
/// `R1..Rn` regions -- they are always known to be universal
|
||||
/// regions (and if that's not true, we just don't attempt to
|
||||
/// enforce the constraint).
|
||||
///
|
||||
/// The current value of `scc` at the time the method is invoked
|
||||
/// is considered a *lower bound*. If possible, we will modify
|
||||
/// the constraint to set it equal to one of the option regions.
|
||||
/// If we make any changes, returns true, else false.
|
||||
fn apply_pick_constraint(
|
||||
&mut self,
|
||||
scc: ConstraintSccIndex,
|
||||
option_regions: &[ty::RegionVid],
|
||||
) -> bool {
|
||||
debug!("apply_pick_constraint(scc={:?}, option_regions={:#?})", scc, option_regions,);
|
||||
|
||||
if let Some(uh_oh) =
|
||||
option_regions.iter().find(|&&r| !self.universal_regions.is_universal_region(r))
|
||||
{
|
||||
debug!("apply_pick_constraint: option region `{:?}` is not a universal region", uh_oh);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a mutable vector of the options. We'll try to winnow
|
||||
// them down.
|
||||
let mut option_regions: Vec<ty::RegionVid> = option_regions.to_vec();
|
||||
|
||||
// The 'pick-region' in a pick-constraint is part of the
|
||||
// hidden type, which must be in the root universe. Therefore,
|
||||
// it cannot have any placeholders in its value.
|
||||
assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT);
|
||||
debug_assert!(
|
||||
self.scc_values.placeholders_contained_in(scc).next().is_none(),
|
||||
"scc {:?} in a pick-constraint has placeholder value: {:?}",
|
||||
scc,
|
||||
self.scc_values.region_value_str(scc),
|
||||
);
|
||||
|
||||
// The existing value for `scc` is a lower-bound. This will
|
||||
// consist of some set {P} + {LB} of points {P} and
|
||||
// lower-bound free regions {LB}. As each option region O is a
|
||||
// free region, it will outlive the points. But we can only
|
||||
// consider the option O if O: LB.
|
||||
option_regions.retain(|&o_r| {
|
||||
self.scc_values
|
||||
.universal_regions_outlived_by(scc)
|
||||
.all(|lb| self.universal_region_relations.outlives(o_r, lb))
|
||||
});
|
||||
|
||||
// Now find all the *upper bounds* -- that is, each UB is a free
|
||||
// region that must outlive pick region R0 (`UB: R0`). Therefore,
|
||||
// we need only keep an option O if `UB: O`.
|
||||
//
|
||||
// TODO -- need to implement the reverse graph construction for this
|
||||
//
|
||||
// let mut upper_bounds = ...;
|
||||
// option_regions.retain(|&o_r| {
|
||||
// upper_bounds
|
||||
// .all(|ub| self.universal_region_relations.outlives(
|
||||
// ub,
|
||||
// o_r,
|
||||
// })
|
||||
// });
|
||||
|
||||
// If we ruled everything out, we're done.
|
||||
if option_regions.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, we need to find the minimum option, if any, and take that.
|
||||
debug!("apply_pick_constraint: option_regions remaining are {:#?}", option_regions);
|
||||
let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option<ty::RegionVid> {
|
||||
let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2);
|
||||
let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1);
|
||||
if r1_outlives_r2 && r2_outlives_r1 {
|
||||
Some(r1.min(r2))
|
||||
} else if r1_outlives_r2 {
|
||||
Some(r2)
|
||||
} else if r2_outlives_r1 {
|
||||
Some(r1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
let mut best_option = option_regions[0];
|
||||
for &other_option in &option_regions[1..] {
|
||||
debug!(
|
||||
"apply_pick_constraint: best_option={:?} other_option={:?}",
|
||||
best_option, other_option,
|
||||
);
|
||||
match min(best_option, other_option) {
|
||||
Some(m) => best_option = m,
|
||||
None => {
|
||||
debug!(
|
||||
"apply_pick_constraint: {:?} and {:?} are incomparable --> no best choice",
|
||||
best_option, other_option,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("apply_pick_constraint: best_choice={:?}", best_option);
|
||||
self.scc_values.add_element(scc, best_option)
|
||||
}
|
||||
|
||||
/// Returns `true` if all the elements in the value of `scc_b` are nameable
|
||||
/// in `scc_a`. Used during constraint propagation, and only once
|
||||
/// the value of `scc_b` has been computed.
|
||||
@ -560,9 +676,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// Otherwise, we have to iterate over the universe elements in
|
||||
// B's value, and check whether all of them are nameable
|
||||
// from universe_a
|
||||
self.scc_values
|
||||
.placeholders_contained_in(scc_b)
|
||||
.all(|p| universe_a.can_name(p.universe))
|
||||
self.scc_values.placeholders_contained_in(scc_b).all(|p| universe_a.can_name(p.universe))
|
||||
}
|
||||
|
||||
/// Extend `scc` so that it can outlive some placeholder region
|
||||
@ -737,12 +851,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
) -> bool {
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
let TypeTest {
|
||||
generic_kind,
|
||||
lower_bound,
|
||||
locations,
|
||||
verify_bound: _,
|
||||
} = type_test;
|
||||
let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test;
|
||||
|
||||
let generic_ty = generic_kind.to_ty(tcx);
|
||||
let subject = match self.try_promote_type_test_subject(infcx, generic_ty) {
|
||||
@ -892,11 +1001,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// except that it converts further takes the non-local upper
|
||||
/// bound of `'y`, so that the final result is non-local.
|
||||
fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
debug!(
|
||||
"non_local_universal_upper_bound(r={:?}={})",
|
||||
r,
|
||||
self.region_value_str(r)
|
||||
);
|
||||
debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
|
||||
|
||||
let lub = self.universal_upper_bound(r);
|
||||
|
||||
@ -904,10 +1009,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// creator.
|
||||
let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);
|
||||
|
||||
debug!(
|
||||
"non_local_universal_upper_bound: non_local_lub={:?}",
|
||||
non_local_lub
|
||||
);
|
||||
debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub);
|
||||
|
||||
non_local_lub
|
||||
}
|
||||
@ -927,11 +1029,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding
|
||||
/// a result `'y`.
|
||||
fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
|
||||
debug!(
|
||||
"universal_upper_bound(r={:?}={})",
|
||||
r,
|
||||
self.region_value_str(r)
|
||||
);
|
||||
debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
|
||||
|
||||
// Find the smallest universal region that contains all other
|
||||
// universal regions within `region`.
|
||||
@ -956,10 +1054,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
lower_bound: RegionVid,
|
||||
verify_bound: &VerifyBound<'tcx>,
|
||||
) -> bool {
|
||||
debug!(
|
||||
"eval_verify_bound(lower_bound={:?}, verify_bound={:?})",
|
||||
lower_bound, verify_bound
|
||||
);
|
||||
debug!("eval_verify_bound(lower_bound={:?}, verify_bound={:?})", lower_bound, verify_bound);
|
||||
|
||||
match verify_bound {
|
||||
VerifyBound::IfEq(test_ty, verify_bound1) => {
|
||||
@ -968,7 +1063,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
||||
VerifyBound::OutlivedBy(r) => {
|
||||
let r_vid = self.to_region_vid(r);
|
||||
self.eval_outlives(body, r_vid, lower_bound)
|
||||
self.eval_outlives(r_vid, lower_bound)
|
||||
}
|
||||
|
||||
VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
|
||||
@ -1041,23 +1136,17 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
// Evaluate whether `sup_region: sub_region @ point`.
|
||||
fn eval_outlives(
|
||||
&self,
|
||||
_body: &Body<'tcx>,
|
||||
sup_region: RegionVid,
|
||||
sub_region: RegionVid,
|
||||
) -> bool {
|
||||
// Evaluate whether `sup_region == sub_region`.
|
||||
fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool {
|
||||
self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1)
|
||||
}
|
||||
|
||||
// Evaluate whether `sup_region: sub_region`.
|
||||
fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
|
||||
debug!("eval_outlives({:?}: {:?})", sup_region, sub_region);
|
||||
|
||||
debug!(
|
||||
"eval_outlives: sup_region's value = {:?}",
|
||||
self.region_value_str(sup_region),
|
||||
);
|
||||
debug!(
|
||||
"eval_outlives: sub_region's value = {:?}",
|
||||
self.region_value_str(sub_region),
|
||||
);
|
||||
debug!("eval_outlives: sup_region's value = {:?}", self.region_value_str(sup_region),);
|
||||
debug!("eval_outlives: sub_region's value = {:?}", self.region_value_str(sub_region),);
|
||||
|
||||
let sub_region_scc = self.constraint_sccs.scc(sub_region);
|
||||
let sup_region_scc = self.constraint_sccs.scc(sup_region);
|
||||
@ -1068,9 +1157,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// now). Therefore, the sup-region outlives the sub-region if,
|
||||
// for each universal region R1 in the sub-region, there
|
||||
// exists some region R2 in the sup-region that outlives R1.
|
||||
let universal_outlives = self.scc_values
|
||||
.universal_regions_outlived_by(sub_region_scc)
|
||||
.all(|r1| {
|
||||
let universal_outlives =
|
||||
self.scc_values.universal_regions_outlived_by(sub_region_scc).all(|r1| {
|
||||
self.scc_values
|
||||
.universal_regions_outlived_by(sup_region_scc)
|
||||
.any(|r2| self.universal_region_relations.outlives(r2, r1))
|
||||
@ -1088,8 +1176,7 @@ 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
|
||||
@ -1171,12 +1258,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// Because this free region must be in the ROOT universe, we
|
||||
// know it cannot contain any bound universes.
|
||||
assert!(self.scc_universes[longer_fr_scc] == ty::UniverseIndex::ROOT);
|
||||
debug_assert!(
|
||||
self.scc_values
|
||||
.placeholders_contained_in(longer_fr_scc)
|
||||
.next()
|
||||
.is_none()
|
||||
);
|
||||
debug_assert!(self.scc_values.placeholders_contained_in(longer_fr_scc).next().is_none());
|
||||
|
||||
// Only check all of the relations for the main representative of each
|
||||
// SCC, otherwise just check that we outlive said representative. This
|
||||
@ -1230,9 +1312,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> Option<ErrorReported> {
|
||||
// If it is known that `fr: o`, carry on.
|
||||
if self.universal_region_relations
|
||||
.outlives(longer_fr, shorter_fr)
|
||||
{
|
||||
if self.universal_region_relations.outlives(longer_fr, shorter_fr) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -1246,9 +1326,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// We'll call it `fr-` -- it's ever so slightly smaller than
|
||||
// `longer_fr`.
|
||||
|
||||
if let Some(fr_minus) = self
|
||||
.universal_region_relations
|
||||
.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);
|
||||
|
||||
@ -1258,12 +1336,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// Grow `shorter_fr` until we find some non-local regions. (We
|
||||
// always will.) We'll call them `shorter_fr+` -- they're ever
|
||||
// so slightly larger than `shorter_fr`.
|
||||
let shorter_fr_plus = self.universal_region_relations
|
||||
.non_local_upper_bounds(&shorter_fr);
|
||||
debug!(
|
||||
"check_universal_region: shorter_fr_plus={:?}",
|
||||
shorter_fr_plus
|
||||
);
|
||||
let shorter_fr_plus =
|
||||
self.universal_region_relations.non_local_upper_bounds(&shorter_fr);
|
||||
debug!("check_universal_region: shorter_fr_plus={:?}", shorter_fr_plus);
|
||||
for &&fr in &shorter_fr_plus {
|
||||
// Push the constraint `fr-: shorter_fr+`
|
||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
@ -1295,28 +1370,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
longer_fr: RegionVid,
|
||||
placeholder: ty::PlaceholderRegion,
|
||||
) {
|
||||
debug!(
|
||||
"check_bound_universal_region(fr={:?}, placeholder={:?})",
|
||||
longer_fr, placeholder,
|
||||
);
|
||||
debug!("check_bound_universal_region(fr={:?}, placeholder={:?})", longer_fr, placeholder,);
|
||||
|
||||
let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
|
||||
debug!(
|
||||
"check_bound_universal_region: longer_fr_scc={:?}",
|
||||
longer_fr_scc,
|
||||
);
|
||||
debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,);
|
||||
|
||||
// If we have some bound universal region `'a`, then the only
|
||||
// elements it can contain is itself -- we don't know anything
|
||||
// else about it!
|
||||
let error_element = match {
|
||||
self.scc_values
|
||||
.elements_contained_in(longer_fr_scc)
|
||||
.find(|element| match element {
|
||||
RegionElement::Location(_) => true,
|
||||
RegionElement::RootUniversalRegion(_) => true,
|
||||
RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
|
||||
})
|
||||
self.scc_values.elements_contained_in(longer_fr_scc).find(|element| match element {
|
||||
RegionElement::Location(_) => true,
|
||||
RegionElement::RootUniversalRegion(_) => true,
|
||||
RegionElement::PlaceholderRegion(placeholder1) => placeholder != *placeholder1,
|
||||
})
|
||||
} {
|
||||
Some(v) => v,
|
||||
None => return,
|
||||
@ -1327,7 +1394,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
let error_region = match error_element {
|
||||
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
|
||||
RegionElement::RootUniversalRegion(r) => r,
|
||||
RegionElement::PlaceholderRegion(error_placeholder) => self.definitions
|
||||
RegionElement::PlaceholderRegion(error_placeholder) => self
|
||||
.definitions
|
||||
.iter_enumerated()
|
||||
.filter_map(|(r, definition)| match definition.origin {
|
||||
NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
|
||||
@ -1345,12 +1413,44 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
// the AST-based checker uses a more conservative check,
|
||||
// so to even see this error, one must pass in a special
|
||||
// flag.
|
||||
let mut diag = infcx
|
||||
.tcx
|
||||
.sess
|
||||
.struct_span_err(span, "higher-ranked subtype error");
|
||||
let mut diag = infcx.tcx.sess.struct_span_err(span, "higher-ranked subtype error");
|
||||
diag.emit();
|
||||
}
|
||||
|
||||
fn check_pick_constraints(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
mir_def_id: DefId,
|
||||
errors_buffer: &mut Vec<Diagnostic>, // TODO
|
||||
) {
|
||||
let pick_constraints = self.pick_constraints.clone();
|
||||
for p_c_i in pick_constraints.all_indices() {
|
||||
debug!("check_pick_constraint(p_c_i={:?})", p_c_i);
|
||||
let p_c = &pick_constraints[p_c_i];
|
||||
let pick_region_vid = p_c.pick_region_vid;
|
||||
debug!("check_pick_constraint: pick_region_vid={:?} with value {}", pick_region_vid, self.region_value_str(pick_region_vid));
|
||||
let option_regions = pick_constraints.option_regions(p_c_i);
|
||||
debug!("check_pick_constraint: option_regions={:?}", option_regions);
|
||||
|
||||
// did the pick-region wind up equal to any of the option regions?
|
||||
if let Some(o) = option_regions.iter().find(|&&o_r| self.eval_equal(o_r, p_c.pick_region_vid)) {
|
||||
debug!("check_pick_constraint: evaluated as equal to {:?}", o);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if not, report an error
|
||||
let region_scope_tree = &infcx.tcx.region_scope_tree(mir_def_id);
|
||||
let pick_region = infcx.tcx.mk_region(ty::ReVar(pick_region_vid)); // XXX
|
||||
opaque_types::unexpected_hidden_region_diagnostic(
|
||||
infcx.tcx,
|
||||
Some(region_scope_tree),
|
||||
p_c.opaque_type_def_id,
|
||||
p_c.hidden_ty,
|
||||
pick_region,
|
||||
)
|
||||
.buffer(errors_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RegionDefinition<'tcx> {
|
||||
@ -1364,11 +1464,7 @@ impl<'tcx> RegionDefinition<'tcx> {
|
||||
_ => NLLRegionVariableOrigin::Existential,
|
||||
};
|
||||
|
||||
Self {
|
||||
origin,
|
||||
universe,
|
||||
external_name: None,
|
||||
}
|
||||
Self { origin, universe, external_name: None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1471,10 +1567,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
|
||||
if let ty::ReClosureBound(vid) = r {
|
||||
closure_mapping[*vid]
|
||||
} else {
|
||||
bug!(
|
||||
"subst_closure_mapping: encountered non-closure bound free region {:?}",
|
||||
r
|
||||
)
|
||||
bug!("subst_closure_mapping: encountered non-closure bound free region {:?}", r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
}
|
||||
|
||||
pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
|
||||
debug!("convert_all(query_constraints={:#?})", query_constraints);
|
||||
|
||||
let QueryRegionConstraints { outlives, pick_constraints } = query_constraints;
|
||||
|
||||
// Annoying: to invoke `self.to_region_vid`, we need access to
|
||||
|
Loading…
x
Reference in New Issue
Block a user