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:
bors 2024-01-30 19:22:04 +00:00
commit cb4d9a1902
25 changed files with 211 additions and 70 deletions

View File

@ -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);
}

View File

@ -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,

View File

@ -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,
&region_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.

View File

@ -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::{

View File

@ -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,
};

View File

@ -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!(

View File

@ -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");

View File

@ -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
}

View File

@ -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,
}
}
}

View File

@ -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();

View File

@ -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,
),
}
}

View File

@ -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)
})
}
}

View File

@ -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

View File

@ -39,6 +39,7 @@ extern crate smallvec;
pub mod errors;
pub mod infer;
pub mod regions;
pub mod solve;
pub mod traits;

View 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)
}
})
}
}

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View 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() {}

View File

@ -1,4 +1,5 @@
// compile-flags: -Znext-solver
//~^ ERROR cannot normalize `<T as Default>::Id`
#![feature(specialization)]
//~^ WARN the feature `specialization` is incomplete

View File

@ -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`.

View 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() {}

View File

@ -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`.