Skip to content

Commit ef5e31a

Browse files
committed
Move outlives checking to separate functions
1 parent 18421b1 commit ef5e31a

File tree

1 file changed

+146
-125
lines changed

1 file changed

+146
-125
lines changed

compiler/rustc_typeck/src/check/wfcheck.rs

+146-125
Original file line numberDiff line numberDiff line change
@@ -339,76 +339,36 @@ fn check_gat_where_clauses(
339339
// reflected in a where clause on the GAT itself.
340340
for (region, region_idx) in &visitor.regions {
341341
for (ty, ty_idx) in &visitor.types {
342-
// Unfortunately, we have to use a new `InferCtxt` for each
343-
// pair, because region constraints get added and solved there,
344-
// and we need to test each pair individually.
345-
tcx.infer_ctxt().enter(|infcx| {
346-
let mut outlives_environment = OutlivesEnvironment::new(param_env);
347-
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
348-
outlives_environment.save_implied_bounds(id);
349-
let region_bound_pairs =
350-
outlives_environment.region_bound_pairs_map().get(&id).unwrap();
351-
352-
let cause =
353-
ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
354-
355-
let sup_type = *ty;
356-
let sub_region = region;
357-
358-
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
359-
infer::RelateParamBound(cause.span, sup_type, None)
360-
});
361-
362-
let outlives = &mut TypeOutlives::new(
363-
&infcx,
364-
tcx,
365-
&region_bound_pairs,
366-
Some(tcx.lifetimes.re_root_empty),
367-
param_env,
368-
);
369-
// In our example, requires that Self: 'a
370-
outlives.type_must_outlive(origin, sup_type, sub_region);
371-
372-
let errors = infcx.resolve_regions(
373-
trait_item.def_id.to_def_id(),
374-
&outlives_environment,
375-
RegionckMode::default(),
376-
);
377-
378-
debug!(?errors, "errors");
379-
380-
// If we were able to prove that Self: 'a without an error,
381-
// it must be because of the implied or explicit bounds...
382-
if errors.is_empty() {
383-
debug!(?ty_idx, ?region_idx);
384-
debug!("required clause: {} must outlive {}", ty, region);
385-
// Translate into the generic parameters of the GAT. In
386-
// our example, the type was Self, which will also be
387-
// Self in the GAT.
388-
let ty_param = generics.param_at(*ty_idx, tcx);
389-
let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
390-
index: ty_param.index,
391-
name: ty_param.name,
342+
// In our example, requires that Self: 'a
343+
if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
344+
debug!(?ty_idx, ?region_idx);
345+
debug!("required clause: {} must outlive {}", ty, region);
346+
// Translate into the generic parameters of the GAT. In
347+
// our example, the type was Self, which will also be
348+
// Self in the GAT.
349+
let ty_param = generics.param_at(*ty_idx, tcx);
350+
let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
351+
index: ty_param.index,
352+
name: ty_param.name,
353+
}));
354+
// Same for the region. In our example, 'a corresponds
355+
// to the 'me parameter.
356+
let region_param = generics.param_at(*region_idx, tcx);
357+
let region_param =
358+
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
359+
def_id: region_param.def_id,
360+
index: region_param.index,
361+
name: region_param.name,
392362
}));
393-
// Same for the region. In our example, 'a corresponds
394-
// to the 'me parameter.
395-
let region_param = generics.param_at(*region_idx, tcx);
396-
let region_param =
397-
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
398-
def_id: region_param.def_id,
399-
index: region_param.index,
400-
name: region_param.name,
401-
}));
402-
// The predicate we expect to see. (In our example,
403-
// `Self: 'me`.)
404-
let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
405-
ty_param,
406-
region_param,
407-
));
408-
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
409-
function_clauses.insert(clause);
410-
}
411-
});
363+
// The predicate we expect to see. (In our example,
364+
// `Self: 'me`.)
365+
let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
366+
ty_param,
367+
region_param,
368+
));
369+
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
370+
function_clauses.insert(clause);
371+
}
412372
}
413373
}
414374

@@ -422,62 +382,33 @@ fn check_gat_where_clauses(
422382
continue;
423383
}
424384

425-
// Unfortunately, we have to use a new `InferCtxt` for each
426-
// pair, because region constraints get added and solved there,
427-
// and we need to test each pair individually.
428-
tcx.infer_ctxt().enter(|infcx| {
429-
let mut outlives_environment = OutlivesEnvironment::new(param_env);
430-
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
431-
outlives_environment.save_implied_bounds(id);
432-
433-
let cause =
434-
ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
435-
436-
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
437-
infer::RelateRegionParamBound(cause.span)
438-
});
439-
440-
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
441-
(&infcx).push_sub_region_constraint(origin, region_a, region_b);
442-
443-
let errors = infcx.resolve_regions(
444-
trait_item.def_id.to_def_id(),
445-
&outlives_environment,
446-
RegionckMode::default(),
447-
);
448-
449-
debug!(?errors, "errors");
450-
451-
// If we were able to prove that Self: 'a without an error,
452-
// it must be because of the implied or explicit bounds...
453-
if errors.is_empty() {
454-
debug!(?region_a_idx, ?region_b_idx);
455-
debug!("required clause: {} must outlive {}", region_a, region_b);
456-
// Translate into the generic parameters of the GAT.
457-
let region_a_param = generics.param_at(*region_a_idx, tcx);
458-
let region_a_param =
459-
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
460-
def_id: region_a_param.def_id,
461-
index: region_a_param.index,
462-
name: region_a_param.name,
463-
}));
464-
// Same for the region.
465-
let region_b_param = generics.param_at(*region_b_idx, tcx);
466-
let region_b_param =
467-
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
468-
def_id: region_b_param.def_id,
469-
index: region_b_param.index,
470-
name: region_b_param.name,
471-
}));
472-
// The predicate we expect to see.
473-
let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
474-
region_a_param,
475-
region_b_param,
476-
));
477-
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
478-
function_clauses.insert(clause);
479-
}
480-
});
385+
if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
386+
debug!(?region_a_idx, ?region_b_idx);
387+
debug!("required clause: {} must outlive {}", region_a, region_b);
388+
// Translate into the generic parameters of the GAT.
389+
let region_a_param = generics.param_at(*region_a_idx, tcx);
390+
let region_a_param =
391+
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
392+
def_id: region_a_param.def_id,
393+
index: region_a_param.index,
394+
name: region_a_param.name,
395+
}));
396+
// Same for the region.
397+
let region_b_param = generics.param_at(*region_b_idx, tcx);
398+
let region_b_param =
399+
tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
400+
def_id: region_b_param.def_id,
401+
index: region_b_param.index,
402+
name: region_b_param.name,
403+
}));
404+
// The predicate we expect to see.
405+
let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
406+
region_a_param,
407+
region_b_param,
408+
));
409+
let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
410+
function_clauses.insert(clause);
411+
}
481412
}
482413
}
483414

@@ -530,6 +461,96 @@ fn check_gat_where_clauses(
530461
}
531462
}
532463

464+
/// Given a known `param_env` and a set of well formed types, can we prove that
465+
/// `ty` outlives `region`.
466+
fn ty_known_to_outlive<'tcx>(
467+
tcx: TyCtxt<'tcx>,
468+
id: hir::HirId,
469+
param_env: ty::ParamEnv<'tcx>,
470+
wf_tys: &FxHashSet<Ty<'tcx>>,
471+
ty: Ty<'tcx>,
472+
region: ty::Region<'tcx>,
473+
) -> bool {
474+
// Unfortunately, we have to use a new `InferCtxt` each call, because
475+
// region constraints get added and solved there and we need to test each
476+
// call individually.
477+
tcx.infer_ctxt().enter(|infcx| {
478+
let mut outlives_environment = OutlivesEnvironment::new(param_env);
479+
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
480+
outlives_environment.save_implied_bounds(id);
481+
let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
482+
483+
let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
484+
485+
let sup_type = ty;
486+
let sub_region = region;
487+
488+
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
489+
infer::RelateParamBound(cause.span, sup_type, None)
490+
});
491+
492+
let outlives = &mut TypeOutlives::new(
493+
&infcx,
494+
tcx,
495+
&region_bound_pairs,
496+
Some(infcx.tcx.lifetimes.re_root_empty),
497+
param_env,
498+
);
499+
outlives.type_must_outlive(origin, sup_type, sub_region);
500+
501+
let errors = infcx.resolve_regions(
502+
id.expect_owner().to_def_id(),
503+
&outlives_environment,
504+
RegionckMode::default(),
505+
);
506+
507+
debug!(?errors, "errors");
508+
509+
// If we were able to prove that the type outlives the region without
510+
// an error, it must be because of the implied or explicit bounds...
511+
errors.is_empty()
512+
})
513+
}
514+
515+
fn region_known_to_outlive<'tcx>(
516+
tcx: TyCtxt<'tcx>,
517+
id: hir::HirId,
518+
param_env: ty::ParamEnv<'tcx>,
519+
wf_tys: &FxHashSet<Ty<'tcx>>,
520+
region_a: ty::Region<'tcx>,
521+
region_b: ty::Region<'tcx>,
522+
) -> bool {
523+
// Unfortunately, we have to use a new `InferCtxt` each call, because
524+
// region constraints get added and solved there and we need to test each
525+
// call individually.
526+
tcx.infer_ctxt().enter(|infcx| {
527+
let mut outlives_environment = OutlivesEnvironment::new(param_env);
528+
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
529+
outlives_environment.save_implied_bounds(id);
530+
531+
let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
532+
533+
let origin = SubregionOrigin::from_obligation_cause(&cause, || {
534+
infer::RelateRegionParamBound(cause.span)
535+
});
536+
537+
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
538+
(&infcx).push_sub_region_constraint(origin, region_a, region_b);
539+
540+
let errors = infcx.resolve_regions(
541+
id.expect_owner().to_def_id(),
542+
&outlives_environment,
543+
RegionckMode::default(),
544+
);
545+
546+
debug!(?errors, "errors");
547+
548+
// If we were able to prove that the type outlives the region without
549+
// an error, it must be because of the implied or explicit bounds...
550+
errors.is_empty()
551+
})
552+
}
553+
533554
/// TypeVisitor that looks for uses of GATs like
534555
/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
535556
/// the two vectors, `regions` and `types` (depending on their kind). For each

0 commit comments

Comments
 (0)