diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 278ffed07477b..9675e105abde1 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,6 +2,7 @@ #![allow(rustc::potential_query_instability)] #![feature(box_patterns)] +#![feature(control_flow_enum)] #![feature(let_chains)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 42b577175e437..7adcdb5cab0af 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -3,10 +3,11 @@ use rustc_index::bit_set::HybridBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; -use rustc_middle::ty::{Ty, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; +use std::ops::ControlFlow; use std::rc::Rc; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; @@ -551,16 +552,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { values::location_set_str(elements, live_at.iter()), ); - let tcx = typeck.tcx(); - tcx.for_each_free_region(&value, |live_region| { - let live_region_vid = - typeck.borrowck_context.universal_regions.to_region_vid(live_region); - typeck - .borrowck_context - .constraints - .liveness_constraints - .add_elements(live_region_vid, live_at); - }); + value.visit_with(&mut LivenessMarker { live_at, typeck, outer_index: ty::INNERMOST }); } fn compute_drop_data( @@ -576,3 +568,58 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { DropData { dropck_result: output, region_constraint_data: constraints } } } + +struct LivenessMarker<'tcx, 'a, 'b, 'c> { + live_at: &'a IntervalSet, + typeck: &'b mut TypeChecker<'c, 'tcx>, + outer_index: ty::DebruijnIndex, +} + +impl<'tcx> TypeVisitor<'tcx> for LivenessMarker<'tcx, '_, '_, '_> { + type BreakTy = !; + + fn visit_binder>( + &mut self, + t: &ty::Binder<'tcx, T>, + ) -> ControlFlow { + self.outer_index.shift_in(1); + let result = t.super_visit_with(self); + self.outer_index.shift_out(1); + result + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + match *r { + ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => ControlFlow::CONTINUE, + _ => { + let live_region_vid = + self.typeck.borrowck_context.universal_regions.to_region_vid(r); + self.typeck + .borrowck_context + .constraints + .liveness_constraints + .add_elements(live_region_vid, self.live_at); + ControlFlow::CONTINUE + } + } + } + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + // We're only interested in types involving regions + if ty.has_free_regions() { + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) = ty.kind() { + let variances = self.typeck.tcx().variances_of(def_id); + for (&v, s) in std::iter::zip(variances, *substs) { + if v != ty::Bivariant { + s.visit_with(self); + } + } + ControlFlow::CONTINUE + } else { + ty.super_visit_with(self) + } + } else { + ControlFlow::CONTINUE + } + } +} diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index f71c39dc0d26a..e39f2b5613bbc 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -446,7 +446,8 @@ where if approx_env_bounds.is_empty() && trait_bounds.is_empty() && (needs_infer || is_opaque) { debug!("no declared bounds"); - self.substs_must_outlive(substs, origin, region); + let opt_variances = is_opaque.then(|| self.tcx.variances_of(def_id)); + self.substs_must_outlive(substs, origin, region, opt_variances); return; } @@ -498,22 +499,31 @@ where self.delegate.push_verify(origin, generic, region, verify_bound); } + #[instrument(level = "debug", skip(self))] fn substs_must_outlive( &mut self, substs: SubstsRef<'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, + opt_variances: Option<&[ty::Variance]>, ) { let constraint = origin.to_constraint_category(); - for k in substs { + for (index, k) in substs.iter().enumerate() { match k.unpack() { GenericArgKind::Lifetime(lt) => { - self.delegate.push_sub_region_constraint( - origin.clone(), - region, - lt, - constraint, - ); + let variance = if let Some(variances) = opt_variances { + variances[index] + } else { + ty::Invariant + }; + if variance == ty::Invariant { + self.delegate.push_sub_region_constraint( + origin.clone(), + region, + lt, + constraint, + ); + } } GenericArgKind::Type(ty) => { self.type_must_outlive(origin.clone(), ty, region, constraint);