Skip to content

Commit cd7c99b

Browse files
Do not mix normalized and unnormalized caller bounds when constructing param-env for receiver_is_dispatchable
1 parent 7d49ae9 commit cd7c99b

File tree

3 files changed

+54
-26
lines changed

3 files changed

+54
-26
lines changed

compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -583,27 +583,29 @@ fn receiver_is_dispatchable<'tcx>(
583583
// create a modified param env, with `Self: Unsize<U>` and `U: Trait` (and all of
584584
// its supertraits) added to caller bounds. `U: ?Sized` is already implied here.
585585
let param_env = {
586-
let param_env = tcx.param_env(method.def_id);
586+
// N.B. We generally want to emulate the construction of the `unnormalized_param_env`
587+
// in the param-env query here. The fact that we don't just start with the clauses
588+
// in the param-env of the method is because those are already normalized, and mixing
589+
// normalized and unnormalized copies of predicates in `normalize_param_env_or_error`
590+
// will cause ambiguity that the user can't really avoid.
591+
let mut predicates = tcx.predicates_of(method.def_id).instantiate_identity(tcx).predicates;
587592

588593
// Self: Unsize<U>
589594
let unsize_predicate =
590-
ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]).upcast(tcx);
595+
ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]);
596+
predicates.push(unsize_predicate.upcast(tcx));
591597

592598
// U: Trait<Arg1, ..., ArgN>
593-
let trait_predicate = {
594-
let trait_def_id = method.trait_container(tcx).unwrap();
595-
let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
596-
if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
597-
});
598-
599-
ty::TraitRef::new_from_args(tcx, trait_def_id, args).upcast(tcx)
600-
};
599+
let trait_def_id = method.trait_container(tcx).unwrap();
600+
let args = GenericArgs::for_item(tcx, trait_def_id, |param, _| {
601+
if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
602+
});
603+
let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args);
604+
predicates.push(trait_predicate.upcast(tcx));
601605

602606
normalize_param_env_or_error(
603607
tcx,
604-
ty::ParamEnv::new(tcx.mk_clauses_from_iter(
605-
param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]),
606-
)),
608+
ty::ParamEnv::new(tcx.mk_clauses(&predicates)),
607609
ObligationCause::dummy_with_span(tcx.def_span(method.def_id)),
608610
)
609611
};

tests/ui/associated-types/issue-59324.stderr

+13-13
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,18 @@ LL | |
3636
LL | | &self,
3737
LL | | ) -> Self::AssocType;
3838
| |_________________________^ the trait `Foo` is not implemented for `Bug`
39+
40+
error[E0277]: the trait bound `(): Foo` is not satisfied
41+
--> $DIR/issue-59324.rs:24:29
3942
|
40-
help: consider further restricting type parameter `Bug` with trait `Foo`
43+
LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
44+
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
4145
|
42-
LL | pub trait ThriftService<Bug: NotFoo + Foo>:
43-
| +++++
46+
help: this trait has no implementations, consider adding one
47+
--> $DIR/issue-59324.rs:3:1
48+
|
49+
LL | pub trait Foo: NotFoo {
50+
| ^^^^^^^^^^^^^^^^^^^^^
4451

4552
error[E0277]: the trait bound `Bug: Foo` is not satisfied
4653
--> $DIR/issue-59324.rs:16:5
@@ -51,18 +58,11 @@ LL | |
5158
LL | | &self,
5259
LL | | ) -> Self::AssocType;
5360
| |_________________________^ the trait `Foo` is not implemented for `Bug`
54-
55-
error[E0277]: the trait bound `(): Foo` is not satisfied
56-
--> $DIR/issue-59324.rs:24:29
5761
|
58-
LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
59-
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
60-
|
61-
help: this trait has no implementations, consider adding one
62-
--> $DIR/issue-59324.rs:3:1
62+
help: consider further restricting type parameter `Bug` with trait `Foo`
6363
|
64-
LL | pub trait Foo: NotFoo {
65-
| ^^^^^^^^^^^^^^^^^^^^^
64+
LL | pub trait ThriftService<Bug: NotFoo + Foo>:
65+
| +++++
6666

6767
error[E0277]: the trait bound `Bug: Foo` is not satisfied
6868
--> $DIR/issue-59324.rs:20:10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ check-pass
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/138937>.
4+
5+
// Previously, we'd take the normalized param env's clauses which included
6+
// `<PF as TraitC>::Value = i32`, which comes from the supertraits of `TraitD`
7+
// after normalizing `<PF as TraitC>::Value = <PF as TraitD>::Scalar`. Since
8+
// `normalize_param_env_or_error` ends up re-elaborating `PF: TraitD`, we'd
9+
// end up with both versions of this predicate (normalized and unnormalized).
10+
// Since these projections preds are not equal, we'd fail with ambiguity.
11+
12+
trait TraitB<T> {}
13+
14+
trait TraitC: TraitB<Self::Value> {
15+
type Value;
16+
}
17+
18+
trait TraitD: TraitC<Value = Self::Scalar> {
19+
type Scalar;
20+
}
21+
22+
trait TraitE {
23+
fn apply<PF: TraitD<Scalar = i32>>(&self);
24+
}
25+
26+
fn main() {}

0 commit comments

Comments
 (0)