Create VarValue::Empty

This commit is contained in:
Jack Huey 2022-06-26 00:10:07 -04:00
parent cc87d53da9
commit f29c91bf12
6 changed files with 191 additions and 22 deletions

View File

@ -109,7 +109,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.iter()
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
.unwrap_or(infcx.tcx.lifetimes.re_root_empty),
.unwrap_or(infcx.tcx.lifetimes.re_erased),
_ => region,
});

View File

@ -51,6 +51,13 @@ pub struct LexicalRegionResolutions<'tcx> {
#[derive(Copy, Clone, Debug)]
pub(crate) enum VarValue<'tcx> {
/// Empty lifetime is for data that is never accessed. We tag the
/// empty lifetime with a universe -- the idea is that we don't
/// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
/// Therefore, the `'empty` in a universe `U` is less than all
/// regions visible from `U`, but not less than regions not visible
/// from `U`.
Empty(ty::UniverseIndex),
Value(Region<'tcx>),
ErrorValue,
}
@ -117,7 +124,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
&mut self,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) -> LexicalRegionResolutions<'tcx> {
let mut var_data = self.construct_var_data(self.tcx());
let mut var_data = self.construct_var_data();
if cfg!(debug_assertions) {
self.dump_constraints();
@ -137,13 +144,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
/// Initially, the value for all variables is set to `'empty`, the
/// empty region. The `expansion` phase will grow this larger.
fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> {
LexicalRegionResolutions {
values: IndexVec::from_fn_n(
|vid| {
let vid_universe = self.var_infos[vid].universe;
let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe));
VarValue::Value(re_empty)
VarValue::Empty(vid_universe)
},
self.num_vars(),
),
@ -190,19 +196,132 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
// In the first pass, we expand region vids according to constraints we
// have previously found. In the second pass, we loop through the region
// vids we expanded and expand *across* region vids (effectively
// "expanding" new `RegSubVar` constraints).
// Tracks the `VarSubVar` constraints generated for each region vid. We
// later use this to expand across vids.
let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
// Tracks the changed region vids.
let mut changes = Vec::new();
for constraint in self.data.constraints.keys() {
let (a_vid, a_region, b_vid, b_data) = match *constraint {
match *constraint {
Constraint::RegSubVar(a_region, b_vid) => {
let b_data = var_values.value_mut(b_vid);
(None, a_region, b_vid, b_data)
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
}
Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
VarValue::ErrorValue => continue,
VarValue::Empty(a_universe) => {
let b_data = var_values.value_mut(b_vid);
let changed = (|| match *b_data {
VarValue::Empty(b_universe) => {
// Empty regions are ordered according to the universe
// they are associated with.
let ui = a_universe.min(b_universe);
debug!(
"Expanding value of {:?} \
from empty lifetime with universe {:?} \
to empty lifetime with universe {:?}",
b_vid, b_universe, ui
);
*b_data = VarValue::Empty(ui);
true
}
VarValue::Value(cur_region) => {
let lub = match *cur_region {
ReLateBound(..) | ReErased => {
bug!("cannot relate region: {:?}", cur_region);
}
ReVar(v_id) => {
span_bug!(
self.var_infos[v_id].origin.span(),
"lub_concrete_regions invoked with non-concrete regions: {:?}",
cur_region,
);
}
ReStatic => {
// nothing lives longer than `'static`
self.tcx().lifetimes.re_static
}
ReEarlyBound(_) | ReFree(_) => {
// All empty regions are less than early-bound, free,
// and scope regions.
cur_region
}
ReEmpty(b_ui) => {
// Empty regions are ordered according to the universe
// they are associated with.
let ui = a_universe.min(b_ui);
self.tcx().mk_region(ReEmpty(ui))
}
RePlaceholder(placeholder) => {
// If the empty and placeholder regions are in the same universe,
// then the LUB is the Placeholder region (which is the cur_region).
// If they are not in the same universe, the LUB is the Static lifetime.
if a_universe == placeholder.universe {
cur_region
} else {
self.tcx().lifetimes.re_static
}
}
};
if lub == cur_region {
return false;
}
debug!(
"Expanding value of {:?} from {:?} to {:?}",
b_vid, cur_region, lub
);
*b_data = VarValue::Value(lub);
true
}
VarValue::ErrorValue => false,
})();
if changed {
changes.push(b_vid);
}
match b_data {
VarValue::Value(Region(Interned(ReStatic, _)))
| VarValue::ErrorValue => (),
_ => {
constraints[a_vid].push((a_vid, b_vid));
constraints[b_vid].push((a_vid, b_vid));
}
}
}
VarValue::Value(a_region) => {
let b_data = var_values.value_mut(b_vid);
(Some(a_vid), a_region, b_vid, b_data)
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
match b_data {
VarValue::Value(Region(Interned(ReStatic, _)))
| VarValue::ErrorValue => (),
_ => {
constraints[a_vid].push((a_vid, b_vid));
constraints[b_vid].push((a_vid, b_vid));
}
}
}
},
Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
@ -210,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// is done, in `collect_errors`.
continue;
}
};
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
if let Some(a_vid) = a_vid {
match b_data {
VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (),
_ => {
constraints[a_vid].push((a_vid, b_vid));
constraints[b_vid].push((a_vid, b_vid));
}
}
}
}
@ -242,6 +349,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
}
/// Expands the value of the region represented with `b_vid` with current
/// value `b_data` to the lub of `b_data` and `a_region`. The corresponds
/// with the constraint `'?b: 'a` (`'a <: '?b`), where `'a` is some known
/// region and `'?b` is some region variable.
fn expand_node(
&self,
a_region: Region<'tcx>,
@ -263,6 +374,55 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
}
match *b_data {
VarValue::Empty(empty_ui) => {
let lub = match *a_region {
ReLateBound(..) | ReErased => {
bug!("cannot relate region: {:?}", a_region);
}
ReVar(v_id) => {
span_bug!(
self.var_infos[v_id].origin.span(),
"expand_node invoked with non-concrete regions: {:?}",
a_region,
);
}
ReStatic => {
// nothing lives longer than `'static`
self.tcx().lifetimes.re_static
}
ReEarlyBound(_) | ReFree(_) => {
// All empty regions are less than early-bound, free,
// and scope regions.
a_region
}
ReEmpty(a_ui) => {
// Empty regions are ordered according to the universe
// they are associated with.
let ui = a_ui.min(empty_ui);
self.tcx().mk_region(ReEmpty(ui))
}
RePlaceholder(placeholder) => {
// If this empty region is from a universe that can
// name the placeholder, then the placeholder is
// larger; otherwise, the only ancestor is `'static`.
if empty_ui.can_name(placeholder.universe) {
self.tcx().mk_region(RePlaceholder(placeholder))
} else {
self.tcx().lifetimes.re_static
}
}
};
debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub);
*b_data = VarValue::Value(lub);
true
}
VarValue::Value(cur_region) => {
// This is a specialized version of the `lub_concrete_regions`
// check below for a common case, here purely as an
@ -508,7 +668,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
for (node_vid, value) in var_data.values.iter_enumerated() {
match *value {
VarValue::Value(_) => { /* Inference successful */ }
VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ }
VarValue::ErrorValue => {
// Inference impossible: this value contains
// inconsistent constraints.
@ -876,6 +1036,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
) -> ty::Region<'tcx> {
let result = match *r {
ty::ReVar(rid) => match self.values[rid] {
VarValue::Empty(vid_universe) => tcx.mk_region(ty::ReEmpty(vid_universe)),
VarValue::Value(r) => r,
VarValue::ErrorValue => tcx.lifetimes.re_static,
},

View File

@ -101,6 +101,7 @@ pub fn trait_obligations<'a, 'tcx>(
wf.normalize(infcx)
}
#[instrument(skip(infcx), ret)]
pub fn predicate_obligations<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -440,6 +441,7 @@ impl<'tcx> WfPredicates<'tcx> {
let param_env = self.param_env;
let depth = self.recursion_depth;
while let Some(arg) = walker.next() {
debug!(?arg, ?self.out);
let ty = match arg.unpack() {
GenericArgKind::Type(ty) => ty,
@ -689,6 +691,8 @@ impl<'tcx> WfPredicates<'tcx> {
));
}
}
debug!(?self.out);
}
}

View File

@ -144,6 +144,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
let assumptions_in_impl_context = assumptions_in_impl_context.predicates;
debug!(?assumptions_in_impl_context, ?dtor_predicates.predicates);
let self_param_env = tcx.param_env(self_type_did);
// An earlier version of this code attempted to do this checking

View File

@ -1816,6 +1816,7 @@ fn report_bivariance(
impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
/// aren't true.
#[instrument(level = "debug", skip(self))]
fn check_false_global_bounds(&mut self) {
let tcx = self.ocx.infcx.tcx;
let mut span = self.span;

View File

@ -1808,6 +1808,7 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir
None
}
#[instrument(level = "debug", skip(tcx))]
fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
use rustc_hir::Node::*;
use rustc_hir::*;
@ -2038,8 +2039,8 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
/// Returns a list of type predicates for the definition with ID `def_id`, including inferred
/// lifetime constraints. This includes all predicates returned by `explicit_predicates_of`, plus
/// inferred constraints concerning which regions outlive other regions.
#[instrument(level = "debug", skip(tcx))]
fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
debug!("predicates_defined_on({:?})", def_id);
let mut result = tcx.explicit_predicates_of(def_id);
debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result,);
let inferred_outlives = tcx.inferred_outlives_of(def_id);