1
Fork 0

Deeply normalize associated type bounds before proving them

This commit is contained in:
Michael Goulet 2025-02-14 01:28:15 +00:00
parent 2cdb7fac95
commit b002b5cc82
10 changed files with 87 additions and 67 deletions

View file

@ -2105,18 +2105,21 @@ pub(super) fn check_type_bounds<'tcx>(
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
};
let mut obligations: Vec<_> = tcx
.explicit_item_bounds(trait_ty.def_id)
.iter_instantiated_copied(tcx, rebased_args)
.map(|(concrete_ty_bound, span)| {
debug!(?concrete_ty_bound);
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
})
.collect();
let mut obligations: Vec<_> = util::elaborate(
tcx,
tcx.explicit_item_bounds(trait_ty.def_id).iter_instantiated_copied(tcx, rebased_args).map(
|(concrete_ty_bound, span)| {
debug!(?concrete_ty_bound);
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
},
),
)
.collect();
// Only in a const implementation do we need to check that the `~const` item bounds hold.
if tcx.is_conditionally_const(impl_ty_def_id) {
obligations.extend(
obligations.extend(util::elaborate(
tcx,
tcx.explicit_implied_const_bounds(trait_ty.def_id)
.iter_instantiated_copied(tcx, rebased_args)
.map(|(c, span)| {
@ -2127,7 +2130,7 @@ pub(super) fn check_type_bounds<'tcx>(
c.to_host_effect_clause(tcx, ty::BoundConstness::Maybe),
)
}),
);
));
}
debug!(item_bounds=?obligations);
@ -2135,26 +2138,19 @@ pub(super) fn check_type_bounds<'tcx>(
// to its definition type. This should be the param-env we use to *prove* the
// predicate too, but we don't do that because of performance issues.
// See <https://github.com/rust-lang/rust/pull/117542#issue-1976337685>.
let trait_projection_ty = Ty::new_projection_from_args(tcx, trait_ty.def_id, rebased_args);
let impl_identity_ty = tcx.type_of(impl_ty.def_id).instantiate_identity();
let normalize_param_env = param_env_with_gat_bounds(tcx, impl_ty, impl_trait_ref);
for mut obligation in util::elaborate(tcx, obligations) {
let normalized_predicate = if infcx.next_trait_solver() {
obligation.predicate.fold_with(&mut ReplaceTy {
tcx,
from: trait_projection_ty,
to: impl_identity_ty,
})
} else {
ocx.normalize(&normalize_cause, normalize_param_env, obligation.predicate)
};
debug!(?normalized_predicate);
obligation.predicate = normalized_predicate;
ocx.register_obligation(obligation);
for obligation in &mut obligations {
match ocx.deeply_normalize(&normalize_cause, normalize_param_env, obligation.predicate) {
Ok(pred) => obligation.predicate = pred,
Err(e) => {
return Err(infcx.err_ctxt().report_fulfillment_errors(e));
}
}
}
// Check that all obligations are satisfied by the implementation's
// version.
ocx.register_obligations(obligations);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
@ -2166,22 +2162,6 @@ pub(super) fn check_type_bounds<'tcx>(
ocx.resolve_regions_and_report_errors(impl_ty_def_id, param_env, assumed_wf_types)
}
struct ReplaceTy<'tcx> {
tcx: TyCtxt<'tcx>,
from: Ty<'tcx>,
to: Ty<'tcx>,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceTy<'tcx> {
fn cx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if self.from == ty { self.to } else { ty.super_fold_with(self) }
}
}
/// Install projection predicates that allow GATs to project to their own
/// definition types. This is not allowed in general in cases of default
/// associated types in trait definitions, or when specialization is involved,