Normalize type outlives obligations in NLL
This commit is contained in:
parent
7576b77e50
commit
7d1fda7b40
@ -5,10 +5,15 @@
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
||||
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
|
||||
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::GenericArgKind;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_trait_selection::solve::deeply_normalize;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
|
||||
use crate::{
|
||||
constraints::OutlivesConstraint,
|
||||
@ -33,6 +38,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,
|
||||
@ -47,6 +53,7 @@ pub(crate) fn new(
|
||||
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,
|
||||
@ -59,6 +66,7 @@ pub(crate) fn new(
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
span,
|
||||
@ -137,13 +145,18 @@ fn convert(
|
||||
// Extract out various useful fields we'll need below.
|
||||
let ConstraintConversion {
|
||||
tcx,
|
||||
infcx,
|
||||
param_env,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
known_type_outlives_obligations,
|
||||
..
|
||||
} = *self;
|
||||
|
||||
let ty::OutlivesPredicate(k1, r2) = predicate;
|
||||
let mut outlives_predicates = vec![(predicate, constraint_category)];
|
||||
while let Some((ty::OutlivesPredicate(k1, r2), constraint_category)) =
|
||||
outlives_predicates.pop()
|
||||
{
|
||||
match k1.unpack() {
|
||||
GenericArgKind::Lifetime(r1) => {
|
||||
let r1_vid = self.to_region_vid(r1);
|
||||
@ -151,7 +164,48 @@ fn convert(
|
||||
self.add_outlives(r1_vid, r2_vid, constraint_category);
|
||||
}
|
||||
|
||||
GenericArgKind::Type(t1) => {
|
||||
GenericArgKind::Type(mut t1) => {
|
||||
// Normalize the type we receive from a `TypeOutlives` obligation
|
||||
// in the new trait solver.
|
||||
if infcx.next_trait_solver() {
|
||||
let result = CustomTypeOp::new(
|
||||
|ocx| {
|
||||
match deeply_normalize(
|
||||
ocx.infcx.at(
|
||||
&ObligationCause::dummy_with_span(self.span),
|
||||
param_env,
|
||||
),
|
||||
t1,
|
||||
) {
|
||||
Ok(normalized_ty) => {
|
||||
t1 = normalized_ty;
|
||||
}
|
||||
Err(e) => {
|
||||
infcx.err_ctxt().report_fulfillment_errors(e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
"normalize type outlives obligation",
|
||||
)
|
||||
.fully_perform(infcx, self.span);
|
||||
|
||||
match result {
|
||||
Ok(TypeOpOutput { output: (), constraints, .. }) => {
|
||||
if let Some(constraints) = constraints {
|
||||
assert!(
|
||||
constraints.member_constraints.is_empty(),
|
||||
"FIXME(-Znext-solver): How do I handle these?"
|
||||
);
|
||||
outlives_predicates
|
||||
.extend(constraints.outlives.iter().copied());
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// we don't actually use this for anything, but
|
||||
// the `TypeOutlives` code needs an origin.
|
||||
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
|
||||
@ -169,6 +223,7 @@ fn convert(
|
||||
GenericArgKind::Const(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Placeholder regions need to be converted eagerly because it may
|
||||
/// create new region variables, which we must not do when verifying
|
||||
|
@ -8,8 +8,11 @@
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
||||
use rustc_trait_selection::solve::deeply_normalize_with_skipped_universes;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use std::rc::Rc;
|
||||
use type_op::TypeOpOutput;
|
||||
@ -52,7 +55,6 @@ pub(crate) struct CreateResult<'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>,
|
||||
@ -60,7 +62,6 @@ pub(crate) fn create<'tcx>(
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions: universal_regions.clone(),
|
||||
@ -178,7 +179,6 @@ pub(crate) fn known_outlives(&self) -> impl Iterator<Item = (RegionVid, RegionVi
|
||||
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>,
|
||||
@ -222,6 +222,35 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
|
||||
self.relate_universal_regions(fr, fr_fn_body);
|
||||
}
|
||||
|
||||
// Normalize the assumptions we use to borrowck the program.
|
||||
let mut constraints = vec![];
|
||||
let mut known_type_outlives_obligations = vec![];
|
||||
for bound in param_env.caller_bounds() {
|
||||
let Some(outlives) = bound.as_type_outlives_clause() else { continue };
|
||||
let ty::OutlivesPredicate(mut ty, region) = outlives.skip_binder();
|
||||
|
||||
// In the new solver, normalize the type-outlives obligation assumptions.
|
||||
if self.infcx.next_trait_solver() {
|
||||
match deeply_normalize_with_skipped_universes(
|
||||
self.infcx.at(&ObligationCause::misc(span, defining_ty_def_id), self.param_env),
|
||||
ty,
|
||||
vec![None; ty.outer_exclusive_binder().as_usize()],
|
||||
) {
|
||||
Ok(normalized_ty) => {
|
||||
ty = normalized_ty;
|
||||
}
|
||||
Err(e) => {
|
||||
self.infcx.err_ctxt().report_fulfillment_errors(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
known_type_outlives_obligations
|
||||
.push(outlives.rebind(ty::OutlivesPredicate(ty, region)));
|
||||
}
|
||||
let known_type_outlives_obligations =
|
||||
self.infcx.tcx.arena.alloc_slice(&known_type_outlives_obligations);
|
||||
|
||||
let unnormalized_input_output_tys = self
|
||||
.universal_regions
|
||||
.unnormalized_input_tys
|
||||
@ -239,7 +268,6 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
|
||||
// the `relations` is built.
|
||||
let mut normalized_inputs_and_output =
|
||||
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
|
||||
let mut constraints = vec![];
|
||||
for ty in unnormalized_input_output_tys {
|
||||
debug!("build: input_or_output={:?}", ty);
|
||||
// We add implied bounds from both the unnormalized and normalized ty.
|
||||
@ -304,7 +332,19 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
|
||||
}
|
||||
|
||||
for c in constraints {
|
||||
self.push_region_constraints(c, span);
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
span,
|
||||
ConstraintCategory::Internal,
|
||||
self.constraints,
|
||||
)
|
||||
.convert_all(c);
|
||||
}
|
||||
|
||||
CreateResult {
|
||||
@ -313,30 +353,12 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
|
||||
outlives: self.outlives.freeze(),
|
||||
inverse_outlives: self.inverse_outlives.freeze(),
|
||||
}),
|
||||
known_type_outlives_obligations: self.known_type_outlives_obligations,
|
||||
known_type_outlives_obligations,
|
||||
region_bound_pairs: self.region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, data), level = "debug")]
|
||||
fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
|
||||
debug!("constraints generated: {:#?}", data);
|
||||
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
span,
|
||||
ConstraintCategory::Internal,
|
||||
self.constraints,
|
||||
)
|
||||
.convert_all(data);
|
||||
}
|
||||
|
||||
/// Update the type of a single local, which should represent
|
||||
/// either the return type of the MIR or one of its arguments. At
|
||||
/// the same time, compute and add any implied bounds that come
|
||||
|
@ -156,10 +156,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
||||
} = 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,
|
||||
@ -1136,6 +1132,7 @@ fn push_region_constraints(
|
||||
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),
|
||||
@ -2740,6 +2737,7 @@ fn prove_closure_bounds(
|
||||
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.
|
||||
|
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
// compile-flags: -Znext-solver
|
||||
|
||||
trait Mirror {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Mirror for T {
|
||||
type Assoc = T;
|
||||
}
|
||||
|
||||
fn is_static<T: 'static>() {}
|
||||
|
||||
fn test<T>() where <T as Mirror>::Assoc: 'static {
|
||||
is_static::<T>();
|
||||
}
|
||||
|
||||
fn main() {}
|
13
tests/ui/traits/next-solver/normalize-type-outlives.rs
Normal file
13
tests/ui/traits/next-solver/normalize-type-outlives.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// check-pass
|
||||
|
||||
trait Tr<'a> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
fn outlives<'o, T: 'o>() {}
|
||||
|
||||
fn foo<'a, 'b, T: Tr<'a, Assoc = ()>>() {
|
||||
outlives::<'b, T::Assoc>();
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user