mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #119101 - compiler-errors:outlives, r=lcnr
Normalize region obligation in lexical region resolution with next-gen solver This normalizes region obligations when we `resolve_regions`, since they may be unnormalized with deferred projection equality. It's pretty hard to add tests that exercise this without also triggering MIR borrowck errors (because we don't normalize there yet). I've added one test with two revisions that should test that we both 1. normalize region obligations in the param env, and 2. normalize registered region obligations during lexical region resolution.
This commit is contained in:
commit
cb4d9a1902
@ -33,7 +33,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
/// our special inference variable there, we would mess that up.
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
@ -47,7 +47,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
@ -59,7 +59,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
span,
|
||||
category,
|
||||
@ -136,7 +136,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
|
||||
// Extract out various useful fields we'll need below.
|
||||
let ConstraintConversion {
|
||||
tcx, region_bound_pairs, implicit_region_bound, param_env, ..
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
known_type_outlives_obligations,
|
||||
..
|
||||
} = *self;
|
||||
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate;
|
||||
@ -157,7 +161,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
)
|
||||
.type_must_outlive(origin, t1, r2, constraint_category);
|
||||
}
|
||||
|
@ -45,12 +45,14 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
|
||||
pub(crate) struct CreateResult<'tcx> {
|
||||
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
pub(crate) known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
|
||||
}
|
||||
|
||||
pub(crate) fn create<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
@ -58,6 +60,7 @@ pub(crate) fn create<'tcx>(
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions: universal_regions.clone(),
|
||||
@ -175,6 +178,7 @@ impl UniversalRegionRelations<'_> {
|
||||
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
|
||||
infcx: &'this InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
||||
@ -200,7 +204,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
let defining_ty_def_id = self.universal_regions.defining_ty.def_id().expect_local();
|
||||
let span = tcx.def_span(defining_ty_def_id);
|
||||
|
||||
// Insert the facts we know from the predicates. Why? Why not.
|
||||
// Insert the `'a: 'b` we know from the predicates.
|
||||
// This does not consider the type-outlives.
|
||||
let param_env = self.param_env;
|
||||
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
|
||||
|
||||
@ -308,6 +313,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
outlives: self.outlives.freeze(),
|
||||
inverse_outlives: self.inverse_outlives.freeze(),
|
||||
}),
|
||||
known_type_outlives_obligations: self.known_type_outlives_obligations,
|
||||
region_bound_pairs: self.region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
}
|
||||
@ -322,7 +328,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
span,
|
||||
ConstraintCategory::Internal,
|
||||
|
@ -152,9 +152,14 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
universal_region_relations,
|
||||
region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
known_type_outlives_obligations,
|
||||
} = free_region_relations::create(
|
||||
infcx,
|
||||
param_env,
|
||||
// FIXME(-Znext-solver): These are unnormalized. Normalize them.
|
||||
infcx.tcx.arena.alloc_from_iter(
|
||||
param_env.caller_bounds().iter().filter_map(|clause| clause.as_type_outlives_clause()),
|
||||
),
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
@ -176,6 +181,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
body,
|
||||
param_env,
|
||||
®ion_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
&mut borrowck_context,
|
||||
);
|
||||
@ -850,6 +856,7 @@ struct TypeChecker<'a, 'tcx> {
|
||||
/// all of the promoted items.
|
||||
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
@ -1000,6 +1007,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
|
||||
) -> Self {
|
||||
@ -1010,6 +1018,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
user_type_annotations: &body.user_type_annotations,
|
||||
param_env,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
reported_errors: Default::default(),
|
||||
@ -1127,7 +1136,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.borrowck_context.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
locations.span(self.body),
|
||||
category,
|
||||
@ -2731,7 +2740,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.borrowck_context.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
DUMMY_SP, // irrelevant; will be overridden.
|
||||
ConstraintCategory::Boring, // same as above.
|
||||
|
@ -20,6 +20,7 @@ use rustc_middle::ty::{
|
||||
};
|
||||
use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
|
@ -8,6 +8,7 @@ use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
use rustc_trait_selection::traits::{
|
||||
elaborate, normalize_param_env_or_error, outlives_bounds::InferCtxtExt, ObligationCtxt,
|
||||
};
|
||||
|
@ -8,6 +8,7 @@ use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
|
||||
use rustc_middle::ty::util::CheckRegions;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
|
||||
use crate::errors;
|
||||
@ -188,6 +189,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
|
||||
format!("{b}: {a}", a = ty::Region::new_var(tcx, a))
|
||||
}
|
||||
RegionResolutionError::CannotNormalize(..) => unreachable!(),
|
||||
};
|
||||
guar = Some(
|
||||
struct_span_code_err!(
|
||||
|
@ -10,10 +10,8 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::ItemKind;
|
||||
use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs};
|
||||
use rustc_infer::infer::outlives::obligations::TypeOutlives;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||
@ -26,6 +24,7 @@ use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::regions::InferCtxtRegionExt;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::misc::{
|
||||
type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError,
|
||||
@ -731,10 +730,12 @@ fn ty_known_to_outlive<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
resolve_regions_with_wf_tys(tcx, id, param_env, wf_tys, |infcx, region_bound_pairs| {
|
||||
let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
|
||||
let outlives = &mut TypeOutlives::new(infcx, tcx, region_bound_pairs, None, param_env);
|
||||
outlives.type_must_outlive(origin, ty, region, ConstraintCategory::BoringNoLocation);
|
||||
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
|
||||
infcx.register_region_obligation(infer::RegionObligation {
|
||||
sub_region: region,
|
||||
sup_type: ty,
|
||||
origin: infer::RelateParamBound(DUMMY_SP, ty, None),
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@ -748,40 +749,32 @@ fn region_known_to_outlive<'tcx>(
|
||||
region_a: ty::Region<'tcx>,
|
||||
region_b: ty::Region<'tcx>,
|
||||
) -> bool {
|
||||
resolve_regions_with_wf_tys(tcx, id, param_env, wf_tys, |mut infcx, _| {
|
||||
use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
|
||||
let origin = infer::RelateRegionParamBound(DUMMY_SP);
|
||||
// `region_a: region_b` -> `region_b <= region_a`
|
||||
infcx.push_sub_region_constraint(
|
||||
origin,
|
||||
region_b,
|
||||
region_a,
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
);
|
||||
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
|
||||
infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP), region_b, region_a);
|
||||
})
|
||||
}
|
||||
|
||||
/// Given a known `param_env` and a set of well formed types, set up an
|
||||
/// `InferCtxt`, call the passed function (to e.g. set up region constraints
|
||||
/// to be tested), then resolve region and return errors
|
||||
fn resolve_regions_with_wf_tys<'tcx>(
|
||||
fn test_region_obligations<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
id: LocalDefId,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
wf_tys: &FxIndexSet<Ty<'tcx>>,
|
||||
add_constraints: impl for<'a> FnOnce(&'a InferCtxt<'tcx>, &'a RegionBoundPairs<'tcx>),
|
||||
add_constraints: impl FnOnce(&InferCtxt<'tcx>),
|
||||
) -> bool {
|
||||
// Unfortunately, we have to use a new `InferCtxt` each call, because
|
||||
// region constraints get added and solved there and we need to test each
|
||||
// call individually.
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
|
||||
add_constraints(&infcx);
|
||||
|
||||
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||
param_env,
|
||||
infcx.implied_bounds_tys(param_env, id, wf_tys),
|
||||
);
|
||||
let region_bound_pairs = outlives_environment.region_bound_pairs();
|
||||
|
||||
add_constraints(&infcx, region_bound_pairs);
|
||||
|
||||
let errors = infcx.resolve_regions(&outlives_environment);
|
||||
debug!(?errors, "errors");
|
||||
|
@ -518,6 +518,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit();
|
||||
}
|
||||
|
||||
RegionResolutionError::CannotNormalize(ty, origin) => {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.struct_span_err(origin.span(), format!("cannot normalize `{ty}`"))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -559,7 +566,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
RegionResolutionError::GenericBoundFailure(..) => true,
|
||||
RegionResolutionError::ConcreteFailure(..)
|
||||
| RegionResolutionError::SubSupConflict(..)
|
||||
| RegionResolutionError::UpperBoundUniverseConflict(..) => false,
|
||||
| RegionResolutionError::UpperBoundUniverseConflict(..)
|
||||
| RegionResolutionError::CannotNormalize(..) => false,
|
||||
};
|
||||
|
||||
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
|
||||
@ -574,6 +582,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
|
||||
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
|
||||
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
|
||||
RegionResolutionError::CannotNormalize(_, ref sro) => sro.span(),
|
||||
});
|
||||
errors
|
||||
}
|
||||
|
@ -98,6 +98,8 @@ pub enum RegionResolutionError<'tcx> {
|
||||
SubregionOrigin<'tcx>, // cause of the constraint
|
||||
Region<'tcx>, // the placeholder `'b`
|
||||
),
|
||||
|
||||
CannotNormalize(Ty<'tcx>, SubregionOrigin<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> RegionResolutionError<'tcx> {
|
||||
@ -106,7 +108,8 @@ impl<'tcx> RegionResolutionError<'tcx> {
|
||||
RegionResolutionError::ConcreteFailure(origin, _, _)
|
||||
| RegionResolutionError::GenericBoundFailure(origin, _, _)
|
||||
| RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _)
|
||||
| RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin,
|
||||
| RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _)
|
||||
| RegionResolutionError::CannotNormalize(_, origin) => origin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! Various code related to computing outlives relations.
|
||||
use self::env::OutlivesEnvironment;
|
||||
use super::region_constraints::RegionConstraintData;
|
||||
use super::{InferCtxt, RegionResolutionError};
|
||||
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
|
||||
use crate::infer::free_regions::RegionRelations;
|
||||
use crate::infer::lexical_region_resolve;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
||||
pub mod components;
|
||||
pub mod env;
|
||||
@ -41,12 +41,22 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
/// result. After this, no more unification operations should be
|
||||
/// 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.
|
||||
#[must_use]
|
||||
pub fn resolve_regions(
|
||||
pub fn resolve_regions_with_normalize(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
deeply_normalize_ty: impl Fn(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, Ty<'tcx>>,
|
||||
) -> Vec<RegionResolutionError<'tcx>> {
|
||||
self.process_registered_region_obligations(outlives_env);
|
||||
match self.process_registered_region_obligations(outlives_env, deeply_normalize_ty) {
|
||||
Ok(()) => {}
|
||||
Err((ty, origin)) => {
|
||||
return vec![RegionResolutionError::CannotNormalize(ty, origin)];
|
||||
}
|
||||
};
|
||||
|
||||
let (var_infos, data) = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
|
@ -70,6 +70,7 @@ use rustc_data_structures::undo_log::UndoLogs;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::GenericArgKind;
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use smallvec::smallvec;
|
||||
|
||||
use super::env::OutlivesEnvironment;
|
||||
@ -123,26 +124,54 @@ 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))]
|
||||
pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
|
||||
#[instrument(level = "debug", skip(self, outlives_env, deeply_normalize_ty))]
|
||||
pub fn process_registered_region_obligations<E>(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
mut deeply_normalize_ty: impl FnMut(Ty<'tcx>, SubregionOrigin<'tcx>) -> Result<Ty<'tcx>, E>,
|
||||
) -> Result<(), (E, SubregionOrigin<'tcx>)> {
|
||||
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
|
||||
|
||||
let normalized_caller_bounds: Vec<_> = outlives_env
|
||||
.param_env
|
||||
.caller_bounds()
|
||||
.iter()
|
||||
.filter_map(|clause| {
|
||||
let bound_clause = clause.kind();
|
||||
let ty::ClauseKind::TypeOutlives(outlives) = bound_clause.skip_binder() else {
|
||||
return None;
|
||||
};
|
||||
Some(
|
||||
deeply_normalize_ty(
|
||||
outlives.0,
|
||||
SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP),
|
||||
)
|
||||
.map(|ty| bound_clause.rebind(ty::OutlivesPredicate(ty, outlives.1))),
|
||||
)
|
||||
})
|
||||
// FIXME(-Znext-solver): How do we accurately report an error here :(
|
||||
.try_collect()
|
||||
.map_err(|e| (e, SubregionOrigin::AscribeUserTypeProvePredicate(DUMMY_SP)))?;
|
||||
|
||||
let my_region_obligations = self.take_registered_region_obligations();
|
||||
|
||||
for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
|
||||
let sup_type =
|
||||
deeply_normalize_ty(sup_type, origin.clone()).map_err(|e| (e, origin.clone()))?;
|
||||
debug!(?sup_type, ?sub_region, ?origin);
|
||||
let sup_type = self.resolve_vars_if_possible(sup_type);
|
||||
|
||||
let outlives = &mut TypeOutlives::new(
|
||||
self,
|
||||
self.tcx,
|
||||
outlives_env.region_bound_pairs(),
|
||||
None,
|
||||
outlives_env.param_env,
|
||||
&normalized_caller_bounds,
|
||||
);
|
||||
let category = origin.to_constraint_category();
|
||||
outlives.type_must_outlive(origin, sup_type, sub_region, category);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +219,7 @@ where
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
) -> Self {
|
||||
Self {
|
||||
delegate,
|
||||
@ -199,7 +228,7 @@ where
|
||||
tcx,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
caller_bounds,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ pub struct VerifyBoundCx<'cx, 'tcx> {
|
||||
/// Outside of borrowck the only way to prove `T: '?0` is by
|
||||
/// setting `'?0` to `'empty`.
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
@ -31,9 +31,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
caller_bounds: &'cx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
) -> Self {
|
||||
Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
|
||||
Self { tcx, region_bound_pairs, implicit_region_bound, caller_bounds }
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
@ -219,8 +219,9 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
// To start, collect bounds from user environment. Note that
|
||||
// parameter environments are already elaborated, so we don't
|
||||
// have to worry about that.
|
||||
let c_b = self.param_env.caller_bounds();
|
||||
let param_bounds = self.collect_outlives_from_clause_list(erased_ty, c_b.into_iter());
|
||||
let param_bounds = self.caller_bounds.iter().copied().filter(move |outlives_predicate| {
|
||||
super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty)
|
||||
});
|
||||
|
||||
// Next, collect regions we scraped from the well-formedness
|
||||
// constraints in the fn signature. To do that, we walk the list
|
||||
@ -307,22 +308,4 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
|
||||
.filter_map(|p| p.no_bound_vars())
|
||||
.map(|OutlivesPredicate(_, r)| r)
|
||||
}
|
||||
|
||||
/// Searches through a predicate list for a predicate `T: 'a`.
|
||||
///
|
||||
/// Careful: does not elaborate predicates, and just uses `==`
|
||||
/// when comparing `ty` for equality, so `ty` must be something
|
||||
/// that does not involve inference variables and where you
|
||||
/// otherwise want a precise match.
|
||||
fn collect_outlives_from_clause_list(
|
||||
&self,
|
||||
erased_ty: Ty<'tcx>,
|
||||
clauses: impl Iterator<Item = ty::Clause<'tcx>>,
|
||||
) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>>
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| {
|
||||
super::test_type_match::can_match_erased_ty(tcx, *outlives_predicate, erased_ty)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#![feature(extend_one)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iterator_try_collect)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "512"] // For rustdoc
|
||||
|
@ -39,6 +39,7 @@ extern crate smallvec;
|
||||
|
||||
pub mod errors;
|
||||
pub mod infer;
|
||||
pub mod regions;
|
||||
pub mod solve;
|
||||
pub mod traits;
|
||||
|
||||
|
40
compiler/rustc_trait_selection/src/regions.rs
Normal file
40
compiler/rustc_trait_selection/src/regions.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{InferCtxt, RegionResolutionError};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
|
||||
pub trait InferCtxtRegionExt<'tcx> {
|
||||
/// Resolve regions, using the deep normalizer to normalize any type-outlives
|
||||
/// obligations in the process. This is in `rustc_trait_selection` because
|
||||
/// we need to normalize.
|
||||
///
|
||||
/// Prefer this method over `resolve_regions_with_normalize`, unless you are
|
||||
/// doing something specific for normalization.
|
||||
fn resolve_regions(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Vec<RegionResolutionError<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
|
||||
fn resolve_regions(
|
||||
&self,
|
||||
outlives_env: &OutlivesEnvironment<'tcx>,
|
||||
) -> Vec<RegionResolutionError<'tcx>> {
|
||||
self.resolve_regions_with_normalize(outlives_env, |ty, origin| {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
|
||||
if self.next_trait_solver() {
|
||||
crate::solve::deeply_normalize(
|
||||
self.at(
|
||||
&ObligationCause::dummy_with_span(origin.span()),
|
||||
outlives_env.param_env,
|
||||
),
|
||||
ty,
|
||||
)
|
||||
.map_err(|_| ty)
|
||||
} else {
|
||||
Ok(ty)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -179,7 +179,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
||||
}
|
||||
|
||||
let outlives_env = OutlivesEnvironment::new(full_env);
|
||||
infcx.process_registered_region_obligations(&outlives_env);
|
||||
let _ = infcx.process_registered_region_obligations::<!>(&outlives_env, |ty, _| Ok(ty));
|
||||
|
||||
let region_data =
|
||||
infcx.inner.borrow_mut().unwrap_region_constraints().region_constraint_data().clone();
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::InferOk;
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
|
||||
use crate::traits::engine::TraitEngineExt;
|
||||
|
@ -3,6 +3,7 @@ use std::fmt::Debug;
|
||||
|
||||
use super::FulfillmentContext;
|
||||
use super::TraitEngine;
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::NormalizeExt;
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
|
||||
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::traits::{self, ObligationCause, ObligationCtxt};
|
||||
|
||||
use hir::LangItem;
|
||||
|
@ -25,6 +25,7 @@ pub mod wf;
|
||||
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use crate::regions::InferCtxtRegionExt;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
22
tests/ui/traits/next-solver/normalize-region-obligations.rs
Normal file
22
tests/ui/traits/next-solver/normalize-region-obligations.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// revisions: normalize_param_env normalize_obligation
|
||||
// check-pass
|
||||
// compile-flags: -Znext-solver
|
||||
|
||||
trait Foo {
|
||||
#[cfg(normalize_param_env)]
|
||||
type Gat<'a> where <Self as Mirror>::Assoc: 'a;
|
||||
#[cfg(normalize_obligation)]
|
||||
type Gat<'a> where Self: 'a;
|
||||
}
|
||||
|
||||
trait Mirror { type Assoc: ?Sized; }
|
||||
impl<T: ?Sized> Mirror for T { type Assoc = T; }
|
||||
|
||||
impl<T> Foo for T {
|
||||
#[cfg(normalize_param_env)]
|
||||
type Gat<'a> = i32 where T: 'a;
|
||||
#[cfg(normalize_obligation)]
|
||||
type Gat<'a> = i32 where <T as Mirror>::Assoc: 'a;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,4 +1,5 @@
|
||||
// compile-flags: -Znext-solver
|
||||
//~^ ERROR cannot normalize `<T as Default>::Id`
|
||||
|
||||
#![feature(specialization)]
|
||||
//~^ WARN the feature `specialization` is incomplete
|
||||
|
@ -1,5 +1,5 @@
|
||||
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/specialization-transmute.rs:3:12
|
||||
--> $DIR/specialization-transmute.rs:4:12
|
||||
|
|
||||
LL | #![feature(specialization)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
@ -8,12 +8,14 @@ LL | #![feature(specialization)]
|
||||
= help: consider using `min_specialization` instead, which is more stable and complete
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: cannot normalize `<T as Default>::Id`
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/specialization-transmute.rs:13:23
|
||||
--> $DIR/specialization-transmute.rs:14:23
|
||||
|
|
||||
LL | default type Id = T;
|
||||
| ^ cannot infer type for associated type `<T as Default>::Id`
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
||||
|
13
tests/ui/traits/next-solver/unsound-region-obligation.rs
Normal file
13
tests/ui/traits/next-solver/unsound-region-obligation.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//~ ERROR the type `<() as StaticTy>::Item<'a>` does not fulfill the required lifetime
|
||||
// compile-flags: -Znext-solver
|
||||
// Regression test for rust-lang/trait-system-refactor-initiative#59
|
||||
|
||||
trait StaticTy {
|
||||
type Item<'a>: 'static;
|
||||
}
|
||||
|
||||
impl StaticTy for () {
|
||||
type Item<'a> = &'a ();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,7 @@
|
||||
error[E0477]: the type `<() as StaticTy>::Item<'a>` does not fulfill the required lifetime
|
||||
|
|
||||
= note: type must satisfy the static lifetime
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0477`.
|
Loading…
Reference in New Issue
Block a user