Normalize type outlives obligations in NLL
This commit is contained in:
parent
7576b77e50
commit
7d1fda7b40
5 changed files with 158 additions and 52 deletions
|
@ -5,10 +5,15 @@ use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelega
|
||||||
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
||||||
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
|
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
|
||||||
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||||
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::ty::GenericArgKind;
|
use rustc_middle::ty::GenericArgKind;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
|
use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
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::{
|
use crate::{
|
||||||
constraints::OutlivesConstraint,
|
constraints::OutlivesConstraint,
|
||||||
|
@ -33,6 +38,7 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||||
/// our special inference variable there, we would mess that up.
|
/// our special inference variable there, we would mess that up.
|
||||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -47,6 +53,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
universal_regions: &'a UniversalRegions<'tcx>,
|
universal_regions: &'a UniversalRegions<'tcx>,
|
||||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||||
locations: Locations,
|
locations: Locations,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -59,6 +66,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
universal_regions,
|
universal_regions,
|
||||||
region_bound_pairs,
|
region_bound_pairs,
|
||||||
implicit_region_bound,
|
implicit_region_bound,
|
||||||
|
param_env,
|
||||||
known_type_outlives_obligations,
|
known_type_outlives_obligations,
|
||||||
locations,
|
locations,
|
||||||
span,
|
span,
|
||||||
|
@ -137,36 +145,83 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||||
// Extract out various useful fields we'll need below.
|
// Extract out various useful fields we'll need below.
|
||||||
let ConstraintConversion {
|
let ConstraintConversion {
|
||||||
tcx,
|
tcx,
|
||||||
|
infcx,
|
||||||
|
param_env,
|
||||||
region_bound_pairs,
|
region_bound_pairs,
|
||||||
implicit_region_bound,
|
implicit_region_bound,
|
||||||
known_type_outlives_obligations,
|
known_type_outlives_obligations,
|
||||||
..
|
..
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
let ty::OutlivesPredicate(k1, r2) = predicate;
|
let mut outlives_predicates = vec![(predicate, constraint_category)];
|
||||||
match k1.unpack() {
|
while let Some((ty::OutlivesPredicate(k1, r2), constraint_category)) =
|
||||||
GenericArgKind::Lifetime(r1) => {
|
outlives_predicates.pop()
|
||||||
let r1_vid = self.to_region_vid(r1);
|
{
|
||||||
let r2_vid = self.to_region_vid(r2);
|
match k1.unpack() {
|
||||||
self.add_outlives(r1_vid, r2_vid, constraint_category);
|
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) => {
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericArgKind::Type(t1) => {
|
|
||||||
// we don't actually use this for anything, but
|
|
||||||
// the `TypeOutlives` code needs an origin.
|
|
||||||
let origin = infer::RelateParamBound(DUMMY_SP, 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!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,11 @@ use rustc_infer::infer::region_constraints::GenericKind;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_infer::infer::InferCtxt;
|
||||||
use rustc_middle::mir::ConstraintCategory;
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
use rustc_middle::traits::query::OutlivesBound;
|
use rustc_middle::traits::query::OutlivesBound;
|
||||||
|
use rustc_middle::traits::ObligationCause;
|
||||||
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
|
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 rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use type_op::TypeOpOutput;
|
use type_op::TypeOpOutput;
|
||||||
|
@ -52,7 +55,6 @@ pub(crate) struct CreateResult<'tcx> {
|
||||||
pub(crate) fn create<'tcx>(
|
pub(crate) fn create<'tcx>(
|
||||||
infcx: &InferCtxt<'tcx>,
|
infcx: &InferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
universal_regions: &Rc<UniversalRegions<'tcx>>,
|
||||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||||
|
@ -60,7 +62,6 @@ pub(crate) fn create<'tcx>(
|
||||||
UniversalRegionRelationsBuilder {
|
UniversalRegionRelationsBuilder {
|
||||||
infcx,
|
infcx,
|
||||||
param_env,
|
param_env,
|
||||||
known_type_outlives_obligations,
|
|
||||||
implicit_region_bound,
|
implicit_region_bound,
|
||||||
constraints,
|
constraints,
|
||||||
universal_regions: universal_regions.clone(),
|
universal_regions: universal_regions.clone(),
|
||||||
|
@ -178,7 +179,6 @@ impl UniversalRegionRelations<'_> {
|
||||||
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
|
struct UniversalRegionRelationsBuilder<'this, 'tcx> {
|
||||||
infcx: &'this InferCtxt<'tcx>,
|
infcx: &'this InferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
known_type_outlives_obligations: &'tcx [ty::PolyTypeOutlivesPredicate<'tcx>],
|
|
||||||
universal_regions: Rc<UniversalRegions<'tcx>>,
|
universal_regions: Rc<UniversalRegions<'tcx>>,
|
||||||
implicit_region_bound: ty::Region<'tcx>,
|
implicit_region_bound: ty::Region<'tcx>,
|
||||||
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
constraints: &'this mut MirTypeckRegionConstraints<'tcx>,
|
||||||
|
@ -222,6 +222,35 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
self.relate_universal_regions(fr, fr_fn_body);
|
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
|
let unnormalized_input_output_tys = self
|
||||||
.universal_regions
|
.universal_regions
|
||||||
.unnormalized_input_tys
|
.unnormalized_input_tys
|
||||||
|
@ -239,7 +268,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
// the `relations` is built.
|
// the `relations` is built.
|
||||||
let mut normalized_inputs_and_output =
|
let mut normalized_inputs_and_output =
|
||||||
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
|
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
|
||||||
let mut constraints = vec![];
|
|
||||||
for ty in unnormalized_input_output_tys {
|
for ty in unnormalized_input_output_tys {
|
||||||
debug!("build: input_or_output={:?}", ty);
|
debug!("build: input_or_output={:?}", ty);
|
||||||
// We add implied bounds from both the unnormalized and normalized ty.
|
// We add implied bounds from both the unnormalized and normalized ty.
|
||||||
|
@ -304,7 +332,19 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in constraints {
|
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 {
|
CreateResult {
|
||||||
|
@ -313,30 +353,12 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||||
outlives: self.outlives.freeze(),
|
outlives: self.outlives.freeze(),
|
||||||
inverse_outlives: self.inverse_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,
|
region_bound_pairs: self.region_bound_pairs,
|
||||||
normalized_inputs_and_output,
|
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
|
/// Update the type of a single local, which should represent
|
||||||
/// either the return type of the MIR or one of its arguments. At
|
/// either the return type of the MIR or one of its arguments. At
|
||||||
/// the same time, compute and add any implied bounds that come
|
/// 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(
|
} = free_region_relations::create(
|
||||||
infcx,
|
infcx,
|
||||||
param_env,
|
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,
|
implicit_region_bound,
|
||||||
universal_regions,
|
universal_regions,
|
||||||
&mut constraints,
|
&mut constraints,
|
||||||
|
@ -1136,6 +1132,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
self.borrowck_context.universal_regions,
|
self.borrowck_context.universal_regions,
|
||||||
self.region_bound_pairs,
|
self.region_bound_pairs,
|
||||||
self.implicit_region_bound,
|
self.implicit_region_bound,
|
||||||
|
self.param_env,
|
||||||
self.known_type_outlives_obligations,
|
self.known_type_outlives_obligations,
|
||||||
locations,
|
locations,
|
||||||
locations.span(self.body),
|
locations.span(self.body),
|
||||||
|
@ -2740,6 +2737,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
self.borrowck_context.universal_regions,
|
self.borrowck_context.universal_regions,
|
||||||
self.region_bound_pairs,
|
self.region_bound_pairs,
|
||||||
self.implicit_region_bound,
|
self.implicit_region_bound,
|
||||||
|
self.param_env,
|
||||||
self.known_type_outlives_obligations,
|
self.known_type_outlives_obligations,
|
||||||
locations,
|
locations,
|
||||||
DUMMY_SP, // irrelevant; will be overridden.
|
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…
Add table
Add a link
Reference in a new issue