1
Fork 0

Rollup merge of #138941 - compiler-errors:receiver-is-dispatchable-bounds, r=BoxyUwU

Do not mix normalized and unnormalized caller bounds when constructing param-env for `receiver_is_dispatchable`

See comments in code and in test I added.

r? `@BoxyUwU` since you reviewed the last PR, or reassign

Fixes #138937
This commit is contained in:
Stuart Cook 2025-04-02 13:10:38 +11:00 committed by GitHub
commit 781240939f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 63 additions and 28 deletions

View file

@ -583,27 +583,36 @@ fn receiver_is_dispatchable<'tcx>(
// create a modified param env, with `Self: Unsize<U>` and `U: Trait` (and all of
// its supertraits) added to caller bounds. `U: ?Sized` is already implied here.
let param_env = {
let param_env = tcx.param_env(method.def_id);
// N.B. We generally want to emulate the construction of the `unnormalized_param_env`
// in the param-env query here. The fact that we don't just start with the clauses
// in the param-env of the method is because those are already normalized, and mixing
// normalized and unnormalized copies of predicates in `normalize_param_env_or_error`
// will cause ambiguity that the user can't really avoid.
//
// We leave out certain complexities of the param-env query here. Specifically, we:
// 1. Do not add `~const` bounds since there are no `dyn const Trait`s.
// 2. Do not add RPITIT self projection bounds for defaulted methods, since we
// are not constructing a param-env for "inside" of the body of the defaulted
// method, so we don't really care about projecting to a specific RPIT type,
// and because RPITITs are not dyn compatible (yet).
let mut predicates = tcx.predicates_of(method.def_id).instantiate_identity(tcx).predicates;
// Self: Unsize<U>
let unsize_predicate =
ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]).upcast(tcx);
ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]);
predicates.push(unsize_predicate.upcast(tcx));
// U: Trait<Arg1, ..., ArgN>
let trait_predicate = {
let trait_def_id = method.trait_container(tcx).unwrap();
let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
});
ty::TraitRef::new_from_args(tcx, trait_def_id, args).upcast(tcx)
};
let trait_def_id = method.trait_container(tcx).unwrap();
let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
});
let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args);
predicates.push(trait_predicate.upcast(tcx));
normalize_param_env_or_error(
tcx,
ty::ParamEnv::new(tcx.mk_clauses_from_iter(
param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]),
)),
ty::ParamEnv::new(tcx.mk_clauses(&predicates)),
ObligationCause::dummy_with_span(tcx.def_span(method.def_id)),
)
};