IAT: Proper WF computation
This commit is contained in:
parent
61e1eda6db
commit
cd6dec33c2
@ -1274,29 +1274,14 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let impl_def_id = tcx.parent(alias_ty.def_id);
|
let substs = compute_inherent_assoc_ty_substs(
|
||||||
let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
|
selcx,
|
||||||
|
param_env,
|
||||||
let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
|
alias_ty,
|
||||||
let impl_ty =
|
cause.clone(),
|
||||||
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
|
depth,
|
||||||
|
obligations,
|
||||||
// Infer the generic parameters of the impl by unifying the
|
);
|
||||||
// impl type with the self type of the projection.
|
|
||||||
let self_ty = alias_ty.self_ty();
|
|
||||||
match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
|
|
||||||
Ok(mut ok) => obligations.append(&mut ok.obligations),
|
|
||||||
Err(_) => {
|
|
||||||
tcx.sess.delay_span_bug(
|
|
||||||
cause.span,
|
|
||||||
format!(
|
|
||||||
"{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let substs = alias_ty.rebase_substs_onto_impl(impl_substs, tcx);
|
|
||||||
|
|
||||||
// Register the obligations arising from the impl and from the associated type itself.
|
// Register the obligations arising from the impl and from the associated type itself.
|
||||||
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
|
let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
|
||||||
@ -1343,6 +1328,41 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
|
|||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>(
|
||||||
|
selcx: &'a mut SelectionContext<'b, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
alias_ty: ty::AliasTy<'tcx>,
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
depth: usize,
|
||||||
|
obligations: &mut Vec<PredicateObligation<'tcx>>,
|
||||||
|
) -> ty::SubstsRef<'tcx> {
|
||||||
|
let tcx = selcx.tcx();
|
||||||
|
|
||||||
|
let impl_def_id = tcx.parent(alias_ty.def_id);
|
||||||
|
let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
|
||||||
|
|
||||||
|
let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
|
||||||
|
let impl_ty =
|
||||||
|
normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
|
||||||
|
|
||||||
|
// Infer the generic parameters of the impl by unifying the
|
||||||
|
// impl type with the self type of the projection.
|
||||||
|
let self_ty = alias_ty.self_ty();
|
||||||
|
match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
|
||||||
|
Ok(mut ok) => obligations.append(&mut ok.obligations),
|
||||||
|
Err(_) => {
|
||||||
|
tcx.sess.delay_span_bug(
|
||||||
|
cause.span,
|
||||||
|
format!(
|
||||||
|
"{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alias_ty.rebase_substs_onto_impl(impl_substs, tcx)
|
||||||
|
}
|
||||||
|
|
||||||
enum Projected<'tcx> {
|
enum Projected<'tcx> {
|
||||||
Progress(Progress<'tcx>),
|
Progress(Progress<'tcx>),
|
||||||
NoProgress(ty::Term<'tcx>),
|
NoProgress(ty::Term<'tcx>),
|
||||||
|
@ -58,15 +58,8 @@ pub fn obligations<'tcx>(
|
|||||||
GenericArgKind::Lifetime(..) => return Some(Vec::new()),
|
GenericArgKind::Lifetime(..) => return Some(Vec::new()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut wf = WfPredicates {
|
let mut wf =
|
||||||
tcx: infcx.tcx,
|
WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
|
||||||
param_env,
|
|
||||||
body_id,
|
|
||||||
span,
|
|
||||||
out: vec![],
|
|
||||||
recursion_depth,
|
|
||||||
item: None,
|
|
||||||
};
|
|
||||||
wf.compute(arg);
|
wf.compute(arg);
|
||||||
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
|
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
|
||||||
|
|
||||||
@ -91,7 +84,7 @@ pub fn unnormalized_obligations<'tcx>(
|
|||||||
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
|
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
|
||||||
|
|
||||||
let mut wf = WfPredicates {
|
let mut wf = WfPredicates {
|
||||||
tcx: infcx.tcx,
|
infcx,
|
||||||
param_env,
|
param_env,
|
||||||
body_id: CRATE_DEF_ID,
|
body_id: CRATE_DEF_ID,
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
@ -116,7 +109,7 @@ pub fn trait_obligations<'tcx>(
|
|||||||
item: &'tcx hir::Item<'tcx>,
|
item: &'tcx hir::Item<'tcx>,
|
||||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||||
let mut wf = WfPredicates {
|
let mut wf = WfPredicates {
|
||||||
tcx: infcx.tcx,
|
infcx,
|
||||||
param_env,
|
param_env,
|
||||||
body_id,
|
body_id,
|
||||||
span,
|
span,
|
||||||
@ -138,7 +131,7 @@ pub fn predicate_obligations<'tcx>(
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||||
let mut wf = WfPredicates {
|
let mut wf = WfPredicates {
|
||||||
tcx: infcx.tcx,
|
infcx,
|
||||||
param_env,
|
param_env,
|
||||||
body_id,
|
body_id,
|
||||||
span,
|
span,
|
||||||
@ -190,8 +183,8 @@ pub fn predicate_obligations<'tcx>(
|
|||||||
wf.normalize(infcx)
|
wf.normalize(infcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WfPredicates<'tcx> {
|
struct WfPredicates<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
infcx: &'a InferCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
body_id: LocalDefId,
|
body_id: LocalDefId,
|
||||||
span: Span,
|
span: Span,
|
||||||
@ -290,9 +283,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> WfPredicates<'tcx> {
|
impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
self.tcx
|
self.infcx.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
|
fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
|
||||||
@ -325,7 +318,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
|
|
||||||
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
|
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
|
||||||
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
|
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx();
|
||||||
let trait_ref = &trait_pred.trait_ref;
|
let trait_ref = &trait_pred.trait_ref;
|
||||||
|
|
||||||
// Negative trait predicates don't require supertraits to hold, just
|
// Negative trait predicates don't require supertraits to hold, just
|
||||||
@ -369,7 +362,6 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
self.out.extend(obligations);
|
self.out.extend(obligations);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = self.tcx();
|
|
||||||
self.out.extend(
|
self.out.extend(
|
||||||
trait_ref
|
trait_ref
|
||||||
.substs
|
.substs
|
||||||
@ -436,13 +428,45 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
|
let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
|
||||||
self.out.extend(obligations);
|
self.out.extend(obligations);
|
||||||
|
|
||||||
|
self.compute_projection_substs(data.substs);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
|
||||||
|
// An inherent projection is well-formed if
|
||||||
|
//
|
||||||
|
// (a) its predicates hold (*)
|
||||||
|
// (b) its substs are wf
|
||||||
|
//
|
||||||
|
// (*) The predicates of an inherent associated type include the
|
||||||
|
// predicates of the impl that it's contained in.
|
||||||
|
|
||||||
|
if !data.self_ty().has_escaping_bound_vars() {
|
||||||
|
// FIXME(inherent_associated_types): Should this happen inside of a snapshot?
|
||||||
|
// FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm!
|
||||||
|
let substs = traits::project::compute_inherent_assoc_ty_substs(
|
||||||
|
&mut traits::SelectionContext::new(self.infcx),
|
||||||
|
self.param_env,
|
||||||
|
data,
|
||||||
|
self.cause(traits::WellFormed(None)),
|
||||||
|
self.recursion_depth,
|
||||||
|
&mut self.out,
|
||||||
|
);
|
||||||
|
// Inherent projection types do not require const predicates.
|
||||||
|
let obligations = self.nominal_obligations_without_const(data.def_id, substs);
|
||||||
|
self.out.extend(obligations);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.compute_projection_substs(data.substs);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_projection_substs(&mut self, substs: SubstsRef<'tcx>) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let cause = self.cause(traits::WellFormed(None));
|
let cause = self.cause(traits::WellFormed(None));
|
||||||
let param_env = self.param_env;
|
let param_env = self.param_env;
|
||||||
let depth = self.recursion_depth;
|
let depth = self.recursion_depth;
|
||||||
|
|
||||||
self.out.extend(
|
self.out.extend(
|
||||||
data.substs
|
substs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|arg| {
|
.filter(|arg| {
|
||||||
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
|
||||||
@ -464,9 +488,9 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
if !subty.has_escaping_bound_vars() {
|
if !subty.has_escaping_bound_vars() {
|
||||||
let cause = self.cause(cause);
|
let cause = self.cause(cause);
|
||||||
let trait_ref =
|
let trait_ref =
|
||||||
ty::TraitRef::from_lang_item(self.tcx, LangItem::Sized, cause.span, [subty]);
|
ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]);
|
||||||
self.out.push(traits::Obligation::with_depth(
|
self.out.push(traits::Obligation::with_depth(
|
||||||
self.tcx,
|
self.tcx(),
|
||||||
cause,
|
cause,
|
||||||
self.recursion_depth,
|
self.recursion_depth,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
@ -605,8 +629,9 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
walker.skip_current_subtree(); // Subtree handled by compute_projection.
|
walker.skip_current_subtree(); // Subtree handled by compute_projection.
|
||||||
self.compute_projection(data);
|
self.compute_projection(data);
|
||||||
}
|
}
|
||||||
ty::Alias(ty::Inherent, _) => {
|
ty::Alias(ty::Inherent, data) => {
|
||||||
// WF if their substs are WF.
|
walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection.
|
||||||
|
self.compute_inherent_projection(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Adt(def, substs) => {
|
ty::Adt(def, substs) => {
|
||||||
@ -700,7 +725,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
// All of the requirements on type parameters
|
// All of the requirements on type parameters
|
||||||
// have already been checked for `impl Trait` in
|
// have already been checked for `impl Trait` in
|
||||||
// return position. We do need to check type-alias-impl-trait though.
|
// return position. We do need to check type-alias-impl-trait though.
|
||||||
if self.tcx.is_type_alias_impl_trait(def_id) {
|
if self.tcx().is_type_alias_impl_trait(def_id) {
|
||||||
let obligations = self.nominal_obligations(def_id, substs);
|
let obligations = self.nominal_obligations(def_id, substs);
|
||||||
self.out.extend(obligations);
|
self.out.extend(obligations);
|
||||||
}
|
}
|
||||||
@ -770,15 +795,15 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
substs: SubstsRef<'tcx>,
|
substs: SubstsRef<'tcx>,
|
||||||
remap_constness: bool,
|
remap_constness: bool,
|
||||||
) -> Vec<traits::PredicateObligation<'tcx>> {
|
) -> Vec<traits::PredicateObligation<'tcx>> {
|
||||||
let predicates = self.tcx.predicates_of(def_id);
|
let predicates = self.tcx().predicates_of(def_id);
|
||||||
let mut origins = vec![def_id; predicates.predicates.len()];
|
let mut origins = vec![def_id; predicates.predicates.len()];
|
||||||
let mut head = predicates;
|
let mut head = predicates;
|
||||||
while let Some(parent) = head.parent {
|
while let Some(parent) = head.parent {
|
||||||
head = self.tcx.predicates_of(parent);
|
head = self.tcx().predicates_of(parent);
|
||||||
origins.extend(iter::repeat(parent).take(head.predicates.len()));
|
origins.extend(iter::repeat(parent).take(head.predicates.len()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let predicates = predicates.instantiate(self.tcx, substs);
|
let predicates = predicates.instantiate(self.tcx(), substs);
|
||||||
trace!("{:#?}", predicates);
|
trace!("{:#?}", predicates);
|
||||||
debug_assert_eq!(predicates.predicates.len(), origins.len());
|
debug_assert_eq!(predicates.predicates.len(), origins.len());
|
||||||
|
|
||||||
@ -791,10 +816,10 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
};
|
};
|
||||||
let cause = self.cause(code);
|
let cause = self.cause(code);
|
||||||
if remap_constness {
|
if remap_constness {
|
||||||
pred = pred.without_const(self.tcx);
|
pred = pred.without_const(self.tcx());
|
||||||
}
|
}
|
||||||
traits::Obligation::with_depth(
|
traits::Obligation::with_depth(
|
||||||
self.tcx,
|
self.tcx(),
|
||||||
cause,
|
cause,
|
||||||
self.recursion_depth,
|
self.recursion_depth,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
@ -859,7 +884,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
|
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
|
||||||
// am looking forward to the future here.
|
// am looking forward to the future here.
|
||||||
if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
|
if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
|
||||||
let implicit_bounds = object_region_bounds(self.tcx, data);
|
let implicit_bounds = object_region_bounds(self.tcx(), data);
|
||||||
|
|
||||||
let explicit_bound = region;
|
let explicit_bound = region;
|
||||||
|
|
||||||
@ -869,7 +894,7 @@ impl<'tcx> WfPredicates<'tcx> {
|
|||||||
let outlives =
|
let outlives =
|
||||||
ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
|
ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
|
||||||
self.out.push(traits::Obligation::with_depth(
|
self.out.push(traits::Obligation::with_depth(
|
||||||
self.tcx,
|
self.tcx(),
|
||||||
cause,
|
cause,
|
||||||
self.recursion_depth,
|
self.recursion_depth,
|
||||||
self.param_env,
|
self.param_env,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user