Skip to content

Commit fe7cfaa

Browse files
Use liveness visitor when considering regions in opaque hidden types
1 parent 56ec828 commit fe7cfaa

File tree

6 files changed

+208
-189
lines changed

6 files changed

+208
-189
lines changed

Diff for: compiler/rustc_borrowck/src/type_check/liveness/trace.rs

+11-96
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
22
use rustc_index::bit_set::HybridBitSet;
33
use rustc_index::interval::IntervalSet;
44
use rustc_infer::infer::canonical::QueryRegionConstraints;
5-
use rustc_infer::infer::outlives::test_type_match;
6-
use rustc_infer::infer::region_constraints::VerifyIfEq;
5+
use rustc_infer::infer::outlives::for_liveness::FreeRegionsVisitor;
76
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
87
use rustc_middle::traits::query::DropckOutlivesResult;
9-
use rustc_middle::ty::{
10-
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
11-
};
8+
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
129
use rustc_span::DUMMY_SP;
1310
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
1411
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
15-
use std::ops::ControlFlow;
1612
use std::rc::Rc;
1713

1814
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
@@ -559,99 +555,18 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
559555
"make_all_regions_live: live_at={}",
560556
values::location_set_str(elements, live_at.iter()),
561557
);
562-
563-
struct MakeAllRegionsLive<'a, 'b, 'tcx> {
564-
typeck: &'b mut TypeChecker<'a, 'tcx>,
565-
live_at: &'b IntervalSet<PointIndex>,
566-
}
567-
impl<'tcx> MakeAllRegionsLive<'_, '_, 'tcx> {
568-
/// We can prove that an alias is live two ways:
569-
/// 1. All the components are live.
570-
/// 2. There is a known outlives bound or where-clause, and that
571-
/// region is live.
572-
/// We search through the item bounds and where clauses for
573-
/// either `'static` or a unique outlives region, and if one is
574-
/// found, we just need to prove that that region is still live.
575-
/// If one is not found, then we continue to walk through the alias.
576-
fn make_alias_live(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
577-
let ty::Alias(_kind, alias_ty) = t.kind() else {
578-
bug!("`make_alias_live` only takes alias types");
579-
};
580-
let tcx = self.typeck.infcx.tcx;
581-
let param_env = self.typeck.param_env;
582-
let outlives_bounds: Vec<_> = tcx
583-
.item_bounds(alias_ty.def_id)
584-
.iter_instantiated(tcx, alias_ty.args)
585-
.filter_map(|clause| {
586-
if let Some(outlives) = clause.as_type_outlives_clause()
587-
&& outlives.skip_binder().0 == t
588-
{
589-
Some(outlives.skip_binder().1)
590-
} else {
591-
None
592-
}
593-
})
594-
.chain(param_env.caller_bounds().iter().filter_map(|clause| {
595-
let outlives = clause.as_type_outlives_clause()?;
596-
if let Some(outlives) = outlives.no_bound_vars()
597-
&& outlives.0 == t
598-
{
599-
Some(outlives.1)
600-
} else {
601-
test_type_match::extract_verify_if_eq(
602-
tcx,
603-
param_env,
604-
&outlives.map_bound(|ty::OutlivesPredicate(ty, bound)| {
605-
VerifyIfEq { ty, bound }
606-
}),
607-
t,
608-
)
609-
}
610-
}))
611-
.collect();
612-
// If we find `'static`, then we know the alias doesn't capture *any* regions.
613-
// Otherwise, all of the outlives regions should be equal -- if they're not,
614-
// we don't really know how to proceed, so we continue recursing through the
615-
// alias.
616-
if outlives_bounds.contains(&tcx.lifetimes.re_static) {
617-
ControlFlow::Continue(())
618-
} else if let Some(r) = outlives_bounds.first()
619-
&& outlives_bounds[1..].iter().all(|other_r| other_r == r)
620-
{
621-
r.visit_with(self)
622-
} else {
623-
t.super_visit_with(self)
624-
}
625-
}
626-
}
627-
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MakeAllRegionsLive<'_, '_, 'tcx> {
628-
type BreakTy = !;
629-
630-
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
631-
if r.is_late_bound() {
632-
return ControlFlow::Continue(());
633-
}
634-
let live_region_vid =
635-
self.typeck.borrowck_context.universal_regions.to_region_vid(r);
636-
self.typeck
558+
value.visit_with(&mut FreeRegionsVisitor {
559+
tcx: typeck.tcx(),
560+
param_env: typeck.param_env,
561+
op: |r| {
562+
let live_region_vid = typeck.borrowck_context.universal_regions.to_region_vid(r);
563+
typeck
637564
.borrowck_context
638565
.constraints
639566
.liveness_constraints
640-
.add_elements(live_region_vid, self.live_at);
641-
ControlFlow::Continue(())
642-
}
643-
644-
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
645-
if !t.has_free_regions() {
646-
ControlFlow::Continue(())
647-
} else if let ty::Alias(..) = t.kind() {
648-
self.make_alias_live(t)
649-
} else {
650-
t.super_visit_with(self)
651-
}
652-
}
653-
}
654-
value.visit_with(&mut MakeAllRegionsLive { typeck, live_at });
567+
.add_elements(live_region_vid, live_at);
568+
},
569+
});
655570
}
656571

657572
fn compute_drop_data(

Diff for: compiler/rustc_infer/src/infer/opaque_types.rs

+5-93
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
22
use super::{DefineOpaqueTypes, InferResult};
33
use crate::errors::OpaqueHiddenTypeDiag;
4+
use crate::infer::outlives::for_liveness::FreeRegionsVisitor;
45
use crate::infer::{InferCtxt, InferOk};
56
use crate::traits::{self, PredicateObligation};
67
use hir::def_id::{DefId, LocalDefId};
@@ -13,11 +14,10 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
1314
use rustc_middle::ty::fold::BottomUpFolder;
1415
use rustc_middle::ty::GenericArgKind;
1516
use rustc_middle::ty::{
16-
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
17-
TypeVisitable, TypeVisitableExt, TypeVisitor,
17+
self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitable,
18+
TypeVisitableExt,
1819
};
1920
use rustc_span::Span;
20-
use std::ops::ControlFlow;
2121

2222
mod table;
2323

@@ -380,8 +380,9 @@ impl<'tcx> InferCtxt<'tcx> {
380380
.collect(),
381381
);
382382

383-
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
383+
concrete_ty.visit_with(&mut FreeRegionsVisitor {
384384
tcx: self.tcx,
385+
param_env,
385386
op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
386387
});
387388
}
@@ -415,95 +416,6 @@ impl<'tcx> InferCtxt<'tcx> {
415416
}
416417
}
417418

418-
/// Visitor that requires that (almost) all regions in the type visited outlive
419-
/// `least_region`. We cannot use `push_outlives_components` because regions in
420-
/// closure signatures are not included in their outlives components. We need to
421-
/// ensure all regions outlive the given bound so that we don't end up with,
422-
/// say, `ReVar` appearing in a return type and causing ICEs when other
423-
/// functions end up with region constraints involving regions from other
424-
/// functions.
425-
///
426-
/// We also cannot use `for_each_free_region` because for closures it includes
427-
/// the regions parameters from the enclosing item.
428-
///
429-
/// We ignore any type parameters because impl trait values are assumed to
430-
/// capture all the in-scope type parameters.
431-
pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
432-
pub tcx: TyCtxt<'tcx>,
433-
pub op: OP,
434-
}
435-
436-
impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
437-
where
438-
OP: FnMut(ty::Region<'tcx>),
439-
{
440-
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
441-
&mut self,
442-
t: &ty::Binder<'tcx, T>,
443-
) -> ControlFlow<Self::BreakTy> {
444-
t.super_visit_with(self);
445-
ControlFlow::Continue(())
446-
}
447-
448-
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
449-
match *r {
450-
// ignore bound regions, keep visiting
451-
ty::ReLateBound(_, _) => ControlFlow::Continue(()),
452-
_ => {
453-
(self.op)(r);
454-
ControlFlow::Continue(())
455-
}
456-
}
457-
}
458-
459-
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
460-
// We're only interested in types involving regions
461-
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
462-
return ControlFlow::Continue(());
463-
}
464-
465-
match ty.kind() {
466-
ty::Closure(_, ref args) => {
467-
// Skip lifetime parameters of the enclosing item(s)
468-
469-
for upvar in args.as_closure().upvar_tys() {
470-
upvar.visit_with(self);
471-
}
472-
args.as_closure().sig_as_fn_ptr_ty().visit_with(self);
473-
}
474-
475-
ty::Generator(_, ref args, _) => {
476-
// Skip lifetime parameters of the enclosing item(s)
477-
// Also skip the witness type, because that has no free regions.
478-
479-
for upvar in args.as_generator().upvar_tys() {
480-
upvar.visit_with(self);
481-
}
482-
args.as_generator().return_ty().visit_with(self);
483-
args.as_generator().yield_ty().visit_with(self);
484-
args.as_generator().resume_ty().visit_with(self);
485-
}
486-
487-
ty::Alias(ty::Opaque, ty::AliasTy { def_id, ref args, .. }) => {
488-
// Skip lifetime parameters that are not captures.
489-
let variances = self.tcx.variances_of(*def_id);
490-
491-
for (v, s) in std::iter::zip(variances, args.iter()) {
492-
if *v != ty::Variance::Bivariant {
493-
s.visit_with(self);
494-
}
495-
}
496-
}
497-
498-
_ => {
499-
ty.super_visit_with(self);
500-
}
501-
}
502-
503-
ControlFlow::Continue(())
504-
}
505-
}
506-
507419
pub enum UseKind {
508420
DefiningUse,
509421
OpaqueUse,

0 commit comments

Comments
 (0)