Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2c82fdc

Browse files
committedSep 27, 2023
Consider alias outlives bounds on opaque hidden type inference
1 parent 0135ccd commit 2c82fdc

File tree

2 files changed

+86
-110
lines changed

2 files changed

+86
-110
lines changed
 

‎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::opaque_types::VisitFreeRegionsVisitor;
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 VisitFreeRegionsVisitor {
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(

‎compiler/rustc_infer/src/infer/opaque_types.rs

+75-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use super::outlives::test_type_match;
2+
use super::region_constraints::VerifyIfEq;
13
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
24
use super::{DefineOpaqueTypes, InferResult};
35
use crate::errors::OpaqueHiddenTypeDiag;
@@ -380,8 +382,9 @@ impl<'tcx> InferCtxt<'tcx> {
380382
.collect(),
381383
);
382384

383-
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
385+
concrete_ty.visit_with(&mut VisitFreeRegionsVisitor {
384386
tcx: self.tcx,
387+
param_env,
385388
op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
386389
});
387390
}
@@ -415,9 +418,11 @@ impl<'tcx> InferCtxt<'tcx> {
415418
}
416419
}
417420

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+
/// Visitor that requires that (almost) all regions in the type visited are
422+
/// passed to `OP`.
423+
///
424+
/// We cannot use `push_outlives_components` because regions in closure
425+
/// signatures are not included in their outlives components. We need to
421426
/// ensure all regions outlive the given bound so that we don't end up with,
422427
/// say, `ReVar` appearing in a return type and causing ICEs when other
423428
/// functions end up with region constraints involving regions from other
@@ -428,12 +433,13 @@ impl<'tcx> InferCtxt<'tcx> {
428433
///
429434
/// We ignore any type parameters because impl trait values are assumed to
430435
/// capture all the in-scope type parameters.
431-
pub struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
436+
pub struct VisitFreeRegionsVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
432437
pub tcx: TyCtxt<'tcx>,
438+
pub param_env: ty::ParamEnv<'tcx>,
433439
pub op: OP,
434440
}
435441

436-
impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
442+
impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for VisitFreeRegionsVisitor<'tcx, OP>
437443
where
438444
OP: FnMut(ty::Region<'tcx>),
439445
{
@@ -484,19 +490,74 @@ where
484490
args.as_generator().resume_ty().visit_with(self);
485491
}
486492

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);
493+
// We can prove that an alias is live two ways:
494+
// 1. All the components are live.
495+
// 2. There is a known outlives bound or where-clause, and that
496+
// region is live.
497+
// We search through the item bounds and where clauses for
498+
// either `'static` or a unique outlives region, and if one is
499+
// found, we just need to prove that that region is still live.
500+
// If one is not found, then we continue to walk through the alias.
501+
ty::Alias(kind, ty::AliasTy { def_id, args, .. }) => {
502+
let tcx = self.tcx;
503+
let param_env = self.param_env;
504+
let outlives_bounds: Vec<_> = tcx
505+
.item_bounds(def_id)
506+
.iter_instantiated(tcx, args)
507+
.filter_map(|clause| {
508+
if let Some(outlives) = clause.as_type_outlives_clause()
509+
&& outlives.skip_binder().0 == ty
510+
{
511+
Some(outlives.skip_binder().1)
512+
} else {
513+
None
514+
}
515+
})
516+
.chain(param_env.caller_bounds().iter().filter_map(|clause| {
517+
let outlives = clause.as_type_outlives_clause()?;
518+
if let Some(outlives) = outlives.no_bound_vars()
519+
&& outlives.0 == ty
520+
{
521+
Some(outlives.1)
522+
} else {
523+
test_type_match::extract_verify_if_eq(
524+
tcx,
525+
param_env,
526+
&outlives.map_bound(|ty::OutlivesPredicate(ty, bound)| {
527+
VerifyIfEq { ty, bound }
528+
}),
529+
ty,
530+
)
531+
}
532+
}))
533+
.collect();
534+
// If we find `'static`, then we know the alias doesn't capture *any* regions.
535+
// Otherwise, all of the outlives regions should be equal -- if they're not,
536+
// we don't really know how to proceed, so we continue recursing through the
537+
// alias.
538+
if outlives_bounds.contains(&tcx.lifetimes.re_static) {
539+
// no
540+
} else if let Some(r) = outlives_bounds.first()
541+
&& outlives_bounds[1..].iter().all(|other_r| other_r == r)
542+
{
543+
r.visit_with(self)?;
544+
} else {
545+
// Skip lifetime parameters that are not captures.
546+
let variances = match kind {
547+
ty::Opaque => Some(self.tcx.variances_of(*def_id)),
548+
_ => None,
549+
};
550+
551+
for (idx, s) in args.iter().enumerate() {
552+
if variances.map(|variances| variances[idx]) != Some(ty::Variance::Bivariant) {
553+
s.visit_with(self)?;
554+
}
494555
}
495556
}
496557
}
497558

498559
_ => {
499-
ty.super_visit_with(self);
560+
ty.super_visit_with(self)?;
500561
}
501562
}
502563

0 commit comments

Comments
 (0)
Please sign in to comment.