Move outlives checking to separate functions
This commit is contained in:
parent
18421b1f08
commit
ef5e31ac06
@ -339,76 +339,36 @@ fn check_gat_where_clauses(
|
||||
// reflected in a where clause on the GAT itself.
|
||||
for (region, region_idx) in &visitor.regions {
|
||||
for (ty, ty_idx) in &visitor.types {
|
||||
// Unfortunately, we have to use a new `InferCtxt` for each
|
||||
// pair, because region constraints get added and solved there,
|
||||
// and we need to test each pair individually.
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
|
||||
outlives_environment.save_implied_bounds(id);
|
||||
let region_bound_pairs =
|
||||
outlives_environment.region_bound_pairs_map().get(&id).unwrap();
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
|
||||
|
||||
let sup_type = *ty;
|
||||
let sub_region = region;
|
||||
|
||||
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
|
||||
infer::RelateParamBound(cause.span, sup_type, None)
|
||||
});
|
||||
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
&infcx,
|
||||
tcx,
|
||||
®ion_bound_pairs,
|
||||
Some(tcx.lifetimes.re_root_empty),
|
||||
param_env,
|
||||
);
|
||||
// In our example, requires that Self: 'a
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region);
|
||||
|
||||
let errors = infcx.resolve_regions(
|
||||
trait_item.def_id.to_def_id(),
|
||||
&outlives_environment,
|
||||
RegionckMode::default(),
|
||||
);
|
||||
|
||||
debug!(?errors, "errors");
|
||||
|
||||
// If we were able to prove that Self: 'a without an error,
|
||||
// it must be because of the implied or explicit bounds...
|
||||
if errors.is_empty() {
|
||||
debug!(?ty_idx, ?region_idx);
|
||||
debug!("required clause: {} must outlive {}", ty, region);
|
||||
// Translate into the generic parameters of the GAT. In
|
||||
// our example, the type was Self, which will also be
|
||||
// Self in the GAT.
|
||||
let ty_param = generics.param_at(*ty_idx, tcx);
|
||||
let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
|
||||
index: ty_param.index,
|
||||
name: ty_param.name,
|
||||
// In our example, requires that Self: 'a
|
||||
if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
|
||||
debug!(?ty_idx, ?region_idx);
|
||||
debug!("required clause: {} must outlive {}", ty, region);
|
||||
// Translate into the generic parameters of the GAT. In
|
||||
// our example, the type was Self, which will also be
|
||||
// Self in the GAT.
|
||||
let ty_param = generics.param_at(*ty_idx, tcx);
|
||||
let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
|
||||
index: ty_param.index,
|
||||
name: ty_param.name,
|
||||
}));
|
||||
// Same for the region. In our example, 'a corresponds
|
||||
// to the 'me parameter.
|
||||
let region_param = generics.param_at(*region_idx, tcx);
|
||||
let region_param =
|
||||
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: region_param.def_id,
|
||||
index: region_param.index,
|
||||
name: region_param.name,
|
||||
}));
|
||||
// Same for the region. In our example, 'a corresponds
|
||||
// to the 'me parameter.
|
||||
let region_param = generics.param_at(*region_idx, tcx);
|
||||
let region_param =
|
||||
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: region_param.def_id,
|
||||
index: region_param.index,
|
||||
name: region_param.name,
|
||||
}));
|
||||
// The predicate we expect to see. (In our example,
|
||||
// `Self: 'me`.)
|
||||
let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty_param,
|
||||
region_param,
|
||||
));
|
||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||
function_clauses.insert(clause);
|
||||
}
|
||||
});
|
||||
// The predicate we expect to see. (In our example,
|
||||
// `Self: 'me`.)
|
||||
let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
|
||||
ty_param,
|
||||
region_param,
|
||||
));
|
||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||
function_clauses.insert(clause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,62 +382,33 @@ fn check_gat_where_clauses(
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unfortunately, we have to use a new `InferCtxt` for each
|
||||
// pair, because region constraints get added and solved there,
|
||||
// and we need to test each pair individually.
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
|
||||
outlives_environment.save_implied_bounds(id);
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
|
||||
|
||||
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
|
||||
infer::RelateRegionParamBound(cause.span)
|
||||
});
|
||||
|
||||
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
|
||||
(&infcx).push_sub_region_constraint(origin, region_a, region_b);
|
||||
|
||||
let errors = infcx.resolve_regions(
|
||||
trait_item.def_id.to_def_id(),
|
||||
&outlives_environment,
|
||||
RegionckMode::default(),
|
||||
);
|
||||
|
||||
debug!(?errors, "errors");
|
||||
|
||||
// If we were able to prove that Self: 'a without an error,
|
||||
// it must be because of the implied or explicit bounds...
|
||||
if errors.is_empty() {
|
||||
debug!(?region_a_idx, ?region_b_idx);
|
||||
debug!("required clause: {} must outlive {}", region_a, region_b);
|
||||
// Translate into the generic parameters of the GAT.
|
||||
let region_a_param = generics.param_at(*region_a_idx, tcx);
|
||||
let region_a_param =
|
||||
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: region_a_param.def_id,
|
||||
index: region_a_param.index,
|
||||
name: region_a_param.name,
|
||||
}));
|
||||
// Same for the region.
|
||||
let region_b_param = generics.param_at(*region_b_idx, tcx);
|
||||
let region_b_param =
|
||||
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: region_b_param.def_id,
|
||||
index: region_b_param.index,
|
||||
name: region_b_param.name,
|
||||
}));
|
||||
// The predicate we expect to see.
|
||||
let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
|
||||
region_a_param,
|
||||
region_b_param,
|
||||
));
|
||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||
function_clauses.insert(clause);
|
||||
}
|
||||
});
|
||||
if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
|
||||
debug!(?region_a_idx, ?region_b_idx);
|
||||
debug!("required clause: {} must outlive {}", region_a, region_b);
|
||||
// Translate into the generic parameters of the GAT.
|
||||
let region_a_param = generics.param_at(*region_a_idx, tcx);
|
||||
let region_a_param =
|
||||
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: region_a_param.def_id,
|
||||
index: region_a_param.index,
|
||||
name: region_a_param.name,
|
||||
}));
|
||||
// Same for the region.
|
||||
let region_b_param = generics.param_at(*region_b_idx, tcx);
|
||||
let region_b_param =
|
||||
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
|
||||
def_id: region_b_param.def_id,
|
||||
index: region_b_param.index,
|
||||
name: region_b_param.name,
|
||||
}));
|
||||
// The predicate we expect to see.
|
||||
let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
|
||||
region_a_param,
|
||||
region_b_param,
|
||||
));
|
||||
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
|
||||
function_clauses.insert(clause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,6 +461,96 @@ fn check_gat_where_clauses(
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a known `param_env` and a set of well formed types, can we prove that
|
||||
/// `ty` outlives `region`.
|
||||
fn ty_known_to_outlive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: hir::HirId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
wf_tys: &FxHashSet<Ty<'tcx>>,
|
||||
ty: Ty<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
// Unfortunately, we have to use a new `InferCtxt` each call, because
|
||||
// region constraints get added and solved there and we need to test each
|
||||
// call individually.
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
|
||||
outlives_environment.save_implied_bounds(id);
|
||||
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
|
||||
|
||||
let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
|
||||
|
||||
let sup_type = ty;
|
||||
let sub_region = region;
|
||||
|
||||
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
|
||||
infer::RelateParamBound(cause.span, sup_type, None)
|
||||
});
|
||||
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
&infcx,
|
||||
tcx,
|
||||
®ion_bound_pairs,
|
||||
Some(infcx.tcx.lifetimes.re_root_empty),
|
||||
param_env,
|
||||
);
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region);
|
||||
|
||||
let errors = infcx.resolve_regions(
|
||||
id.expect_owner().to_def_id(),
|
||||
&outlives_environment,
|
||||
RegionckMode::default(),
|
||||
);
|
||||
|
||||
debug!(?errors, "errors");
|
||||
|
||||
// If we were able to prove that the type outlives the region without
|
||||
// an error, it must be because of the implied or explicit bounds...
|
||||
errors.is_empty()
|
||||
})
|
||||
}
|
||||
|
||||
fn region_known_to_outlive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: hir::HirId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
wf_tys: &FxHashSet<Ty<'tcx>>,
|
||||
region_a: ty::Region<'tcx>,
|
||||
region_b: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
// Unfortunately, we have to use a new `InferCtxt` each call, because
|
||||
// region constraints get added and solved there and we need to test each
|
||||
// call individually.
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut outlives_environment = OutlivesEnvironment::new(param_env);
|
||||
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
|
||||
outlives_environment.save_implied_bounds(id);
|
||||
|
||||
let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
|
||||
|
||||
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
|
||||
infer::RelateRegionParamBound(cause.span)
|
||||
});
|
||||
|
||||
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
|
||||
(&infcx).push_sub_region_constraint(origin, region_a, region_b);
|
||||
|
||||
let errors = infcx.resolve_regions(
|
||||
id.expect_owner().to_def_id(),
|
||||
&outlives_environment,
|
||||
RegionckMode::default(),
|
||||
);
|
||||
|
||||
debug!(?errors, "errors");
|
||||
|
||||
// If we were able to prove that the type outlives the region without
|
||||
// an error, it must be because of the implied or explicit bounds...
|
||||
errors.is_empty()
|
||||
})
|
||||
}
|
||||
|
||||
/// TypeVisitor that looks for uses of GATs like
|
||||
/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
|
||||
/// the two vectors, `regions` and `types` (depending on their kind). For each
|
||||
|
Loading…
x
Reference in New Issue
Block a user