Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 33 additions & 96 deletions compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ use rustc_infer::infer::canonical::{QueryRegionConstraint, QueryRegionConstraint
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::traits::query::type_op::Normalize;
use rustc_middle::bug;
use rustc_middle::ty::{
self, GenericArgKind, RegionExt, RegionUtilitiesExt, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, elaborate, fold_regions,
self, GenericArgKind, RegionExt, RegionUtilitiesExt, TyCtxt, TypeFoldable, TypeVisitableExt,
elaborate, fold_regions,
};
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::TypeOpOutput;
use tracing::{debug, instrument};

use crate::constraints::OutlivesConstraint;
Expand Down Expand Up @@ -137,83 +134,49 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {

// Extract out various useful fields we'll need below.
let ConstraintConversion {
infcx,
infcx: _,
universal_regions,
region_bound_pairs,
known_type_outlives_obligations,
..
} = *self;

let mut outlives_predicates = vec![(predicate, constraint_category)];
for iteration in 0.. {
if outlives_predicates.is_empty() {
break;
}
let pred = predicate;
// Constraint is implied by a coroutine's well-formedness.
if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
&& higher_ranked_assumptions.contains(&pred)
{
return;
}

if !tcx.recursion_limit().value_within_limit(iteration) {
// This may actually be reachable. If so, we should convert
// this to a proper error/consider whether we should detect
// this somewhere else.
bug!(
"unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
);
let ty::OutlivesPredicate(k1, r2) = pred;
match k1.kind() {
GenericArgKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
let r2_vid = self.to_region_vid(r2);
self.add_outlives(r1_vid, r2_vid, constraint_category);
}

let mut next_outlives_predicates = vec![];
for (pred, constraint_category) in outlives_predicates {
// Constraint is implied by a coroutine's well-formedness.
if self.infcx.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
&& higher_ranked_assumptions.contains(&pred)
{
continue;
}

let ty::OutlivesPredicate(k1, r2) = pred;
match k1.kind() {
GenericArgKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
let r2_vid = self.to_region_vid(r2);
self.add_outlives(r1_vid, r2_vid, constraint_category);
}

GenericArgKind::Type(mut t1) => {
// Scraped constraints may have had inference vars.
t1 = self.infcx.resolve_vars_if_possible(t1);

// Normalize the type we receive from a `TypeOutlives` obligation
// in the new trait solver.
if infcx.next_trait_solver() {
t1 = self.normalize_and_add_type_outlives_constraints(
ty::Unnormalized::new_wip(t1),
&mut next_outlives_predicates,
);
}
GenericArgKind::Type(mut t1) => {
// Scraped constraints may have had inference vars.
t1 = self.infcx.resolve_vars_if_possible(t1);

let implicit_region_bound =
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = SubregionOrigin::RelateParamBound(self.span, t1, None);
TypeOutlives::new(
&mut *self,
tcx,
region_bound_pairs,
Some(implicit_region_bound),
known_type_outlives_obligations,
)
.type_must_outlive(
origin,
t1,
r2,
constraint_category,
);
}

GenericArgKind::Const(_) => unreachable!(),
}
let implicit_region_bound =
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = SubregionOrigin::RelateParamBound(self.span, t1, None);
TypeOutlives::new(
&mut *self,
tcx,
region_bound_pairs,
Some(implicit_region_bound),
known_type_outlives_obligations,
)
.type_must_outlive(origin, t1, r2, constraint_category);
}

outlives_predicates = next_outlives_predicates;
GenericArgKind::Const(_) => unreachable!(),
}
}

Expand Down Expand Up @@ -279,32 +242,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
debug!("add_type_test(type_test={:?})", type_test);
self.constraints.type_tests.push(type_test);
}

// FIXME(trait-refactor-initiative#260): This function should be
// removed.
fn normalize_and_add_type_outlives_constraints(
&self,
ty: ty::Unnormalized<'tcx, Ty<'tcx>>,
next_outlives_predicates: &mut Vec<(
ty::ArgOutlivesPredicate<'tcx>,
ConstraintCategory<'tcx>,
)>,
) -> Ty<'tcx> {
match self.infcx.fully_perform(Normalize { value: ty }, self.span) {
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
next_outlives_predicates.extend(constraints.iter().flat_map(
|QueryRegionConstraint { constraint, category, .. }| {
constraint.iter_outlives().map(|outlives| (outlives, *category))
},
));
}
ty
}
Err(_) => ty.skip_norm_wip(),
}
}
}

impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'b, 'tcx> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/always_applicable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
// reference the params from the ADT instead of from the impl which is bad UX. To resolve
// this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
let adt_env = ty::EarlyBinder::bind(tcx, tcx.param_env(adt_def_id))
let adt_env = ty::EarlyBinder::bind_unchecked(tcx.param_env(adt_def_id))
.instantiate(tcx, adt_to_impl_args)
.skip_norm_wip();

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use rustc_session::diagnostics::feature_err;
use rustc_span::{DUMMY_SP, Span, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::regions::{
InferCtxtRegionExt, OutlivesEnvironmentBuildExt, region_known_to_outlive, ty_known_to_outlive,
OutlivesEnvironmentBuildExt, region_known_to_outlive, ty_known_to_outlive,
};
use rustc_trait_selection::traits::misc::{
ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/outlives/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
span_bug!(span, "Should not deduce placeholder outlives component");
}

Component::Alias(alias_ty) => {
Component::Alias(is_rigid, alias_ty) => {
// This would either arise from something like:
//
// ```
Expand All @@ -102,7 +102,7 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
//
// Here we want to add an explicit `where <T as Iterator>::Item: 'a`
// or `Opaque<T>: 'a` depending on the alias kind.
let ty = alias_ty.to_ty(tcx, ty::IsRigid::No);
let ty = alias_ty.to_ty(tcx, is_rigid);
required_predicates
.entry(ty::OutlivesPredicate(ty.into(), outlived_region))
.or_insert(span);
Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_infer/src/infer/outlives/for_liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ where
// either `'static` or a unique outlives region, and if one is
// found, we just need to prove that that region is still live.
// If one is not found, then we continue to walk through the alias.
ty::Alias(_, alias_ty @ ty::AliasTy { kind, args, .. }) => {
ty::Alias(is_rigid, alias_ty @ ty::AliasTy { kind, args, .. }) => {
let tcx = self.tcx;
let param_env = self.param_env;
let def_id = match kind {
Expand All @@ -82,11 +82,7 @@ where
&outlives.map_bound(|ty::OutlivesPredicate(ty, bound)| {
VerifyIfEq { ty, bound }
}),
// FIXME(#155345): Region handling should generally only
// deal with rigid aliases, making sure we do so correctly
// everywhere is effort, so we're just using `No` everywhere
// for now. This should change soon.
alias_ty.to_ty(tcx, ty::IsRigid::No),
alias_ty.to_ty(tcx, is_rigid),
)
}
})
Expand Down
22 changes: 6 additions & 16 deletions compiler/rustc_infer/src/infer/outlives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
use std::iter;

use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::traits::query::{NoSolution, OutlivesBound};
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty;
use rustc_span::Span;
use tracing::instrument;

use self::env::OutlivesEnvironment;
use super::region_constraints::{RegionConstraintData, UndoLog};
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
use super::{InferCtxt, RegionResolutionError};
use crate::infer::free_regions::RegionRelations;
use crate::infer::lexical_region_resolve;
use crate::infer::region_constraints::ConstraintKind;
Expand Down Expand Up @@ -38,25 +38,15 @@ impl<'tcx> InferCtxt<'tcx> {
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
///
/// If you are in a crate that has access to `rustc_trait_selection`,
/// then it's probably better to use `resolve_regions`,
/// which knows how to normalize registered region obligations.
/// Don't call this directly unless you know what you're doing.
/// You probably want to use `resolve_regions` instead.
#[must_use]
pub fn resolve_regions_with_normalize(
pub fn resolve_regions_with_outlives_env(
&self,
outlives_env: &OutlivesEnvironment<'tcx>,
deeply_normalize_ty: impl Fn(
ty::PolyTypeOutlivesPredicate<'tcx>,
SubregionOrigin<'tcx>,
) -> Result<ty::PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
span: Span,
) -> Vec<RegionResolutionError<'tcx>> {
match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty, span) {
Ok(()) => {}
Err((clause, origin)) => {
return vec![RegionResolutionError::CannotNormalize(clause, origin)];
}
};
self.process_registered_region_obligations(outlives_env, span);

let mut storage = {
let mut inner = self.inner.borrow_mut();
Expand Down
34 changes: 13 additions & 21 deletions compiler/rustc_infer/src/infer/outlives/obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,10 @@ use rustc_data_structures::transitive_relation::TransitiveRelation;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::bug;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::outlives::{Component, push_outlives_components};
use rustc_middle::ty::{
self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, RegionExt, RegionVid,
Ty, TyCtxt, TypeFoldable as _, TypeVisitableExt,
Ty, TyCtxt, TypeVisitableExt, eager_resolve_vars,
};
use rustc_span::Span;
use smallvec::smallvec;
Expand All @@ -76,7 +75,6 @@ use tracing::{debug, instrument};
use super::env::OutlivesEnvironment;
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::outlives::verify::VerifyBoundCx;
use crate::infer::resolve::OpportunisticRegionResolver;
use crate::infer::snapshot::undo_log::UndoLog;
use crate::infer::{
self, GenericKind, InferCtxt, SubregionOrigin, TypeOutlivesConstraint, VerifyBound,
Expand Down Expand Up @@ -288,17 +286,12 @@ impl<'tcx> InferCtxt<'tcx> {
/// flow of the inferencer. The key point is that it is
/// invoked after all type-inference variables have been bound --
/// right before lexical region resolution.
#[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
#[instrument(level = "debug", skip(self, outlives_env))]
pub fn process_registered_region_obligations(
&self,
outlives_env: &OutlivesEnvironment<'tcx>,
mut deeply_normalize_ty: impl FnMut(
PolyTypeOutlivesPredicate<'tcx>,
SubregionOrigin<'tcx>,
)
-> Result<PolyTypeOutlivesPredicate<'tcx>, NoSolution>,
span: Span,
) -> Result<(), (PolyTypeOutlivesPredicate<'tcx>, SubregionOrigin<'tcx>)> {
) {
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");

if self.tcx.assumptions_on_binders() {
Expand All @@ -322,17 +315,10 @@ impl<'tcx> InferCtxt<'tcx> {
}

for TypeOutlivesConstraint { sup_type, sub_region, origin } in my_region_obligations {
let outlives = ty::Binder::dummy(ty::OutlivesPredicate(sup_type, sub_region));
let ty::OutlivesPredicate(sup_type, sub_region) =
deeply_normalize_ty(outlives, origin.clone())
.map_err(|NoSolution| (outlives, origin.clone()))?
.no_bound_vars()
.expect("started with no bound vars, should end with no bound vars");
// `TypeOutlives` is structural, so we should try to opportunistically resolve all
// region vids before processing regions, so we have a better chance to match clauses
// in our param-env.
let (sup_type, sub_region) =
(sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self));
let (sup_type, sub_region) = eager_resolve_vars(self, (sup_type, sub_region));

if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions
&& outlives_env
Expand All @@ -355,8 +341,6 @@ impl<'tcx> InferCtxt<'tcx> {
outlives.type_must_outlive(origin, sup_type, sub_region, category);
}
}

Ok(())
}
}

Expand Down Expand Up @@ -435,6 +419,11 @@ where
category: ConstraintCategory<'tcx>,
) {
assert!(!ty.has_escaping_bound_vars());
debug_assert!(!ty.has_non_region_infer());
debug_assert!(
!self.tcx.next_trait_solver_globally() || !ty.has_non_rigid_aliases(),
"{ty:?} has non-rigid aliases"
);

let mut components = smallvec![];
push_outlives_components(self.tcx, ty, &mut components);
Expand All @@ -460,7 +449,10 @@ where
Component::Placeholder(placeholder_ty) => {
self.placeholder_ty_must_outlive(origin, region, *placeholder_ty);
}
Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
Component::Alias(is_rigid, alias_ty) => {
debug_assert_eq!(*is_rigid, ty::IsRigid::yes_if_next_solver(self.tcx));
self.alias_ty_must_outlive(origin, region, *alias_ty);
}
Component::EscapingAlias(subcomponents) => {
self.components_must_outlive(origin, subcomponents, region, category);
}
Expand Down
17 changes: 4 additions & 13 deletions compiler/rustc_infer/src/infer/outlives/test_type_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,10 @@ pub fn extract_verify_if_eq<'tcx>(
assert!(!verify_if_eq_b.has_escaping_bound_vars());
let mut m = MatchAgainstHigherRankedOutlives::new(tcx);
let verify_if_eq = verify_if_eq_b.skip_binder();
// FIXME(#155345): Region handling should generally only
// deal with rigid aliases, making sure we do so correctly
// everywhere is effort, so we're just using `No` everywhere
// for now. This should change soon.
let (verify_ty, test_ty) =
ty::set_aliases_to_non_rigid(tcx, (verify_if_eq.ty, test_ty)).skip_norm_wip();
m.relate(verify_ty, test_ty).ok()?;
debug_assert!(
!tcx.next_trait_solver_globally() || !(verify_if_eq.ty, test_ty).has_non_rigid_aliases()
);
m.relate(verify_if_eq.ty, test_ty).ok()?;

if let ty::RegionKind::ReBound(index_kind, br) = verify_if_eq.bound.kind() {
assert!(matches!(index_kind, ty::BoundVarIndexKind::Bound(ty::INNERMOST)));
Expand Down Expand Up @@ -86,12 +83,6 @@ pub(super) fn can_match_erased_ty<'tcx>(
assert!(!outlives_predicate.has_escaping_bound_vars());
let erased_outlives_predicate = tcx.erase_and_anonymize_regions(outlives_predicate);
let outlives_ty = erased_outlives_predicate.skip_binder().0;
// FIXME(#155345): Region handling should generally only
// deal with rigid aliases, making sure we do so correctly
// everywhere is effort, so we're just using `No` everywhere
// for now. This should change soon.
let (outlives_ty, erased_ty) =
ty::set_aliases_to_non_rigid(tcx, (outlives_ty, erased_ty)).skip_normalization();
if outlives_ty == erased_ty {
// pointless micro-optimization
true
Expand Down
Loading
Loading