I tried this code:
#![feature(trait_upcasting)]
trait A: B {
type Assoc;
}
trait B {}
fn upcast(a: &dyn A<Assoc = i32>) -> &dyn B { a }
fn main() {}
I expected to see it compile.
Instead, this happened:
error[E0308]: mismatched types
--> src/main.rs:9:47
|
9 | fn upcast(a: &dyn A<Assoc = i32>) -> &dyn B { a }
| ------ ^ expected trait `B`, found trait `A<Assoc = i32>`
| |
| expected `&dyn B` because of return type
|
= note: expected reference `&dyn B`
found reference `&dyn A<Assoc = i32>`
The algorithm we use to do trait upcasting is incorrect, since it simply copies the existential associated types over:
|
.chain( |
|
data_a |
|
.projection_bounds() |
|
.map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), |
|
) |
So if we upcast to a trait with fewer associated types (like B), then the subtyping we do here is wrong:
|
let InferOk { obligations, .. } = self |
|
.infcx |
|
.at(&obligation.cause, obligation.param_env) |
|
.sup(DefineOpaqueTypes::No, target, source_trait) |
|
.map_err(|_| Unimplemented)?; |
Since we require the list of existential trait bounds to be structurally compatible:
|
let mut a_v: Vec<_> = a.into_iter().collect(); |
|
let mut b_v: Vec<_> = b.into_iter().collect(); |
|
// `skip_binder` here is okay because `stable_cmp` doesn't look at binders |
|
a_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); |
|
a_v.dedup(); |
|
b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); |
|
b_v.dedup(); |
|
if a_v.len() != b_v.len() { |
|
return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); |
|
} |
I tried this code:
I expected to see it compile.
Instead, this happened:
The algorithm we use to do trait upcasting is incorrect, since it simply copies the existential associated types over:
rust/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Lines 933 to 937 in fd56162
So if we upcast to a trait with fewer associated types (like
B), then the subtyping we do here is wrong:rust/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Lines 949 to 953 in fd56162
Since we require the list of existential trait bounds to be structurally compatible:
rust/compiler/rustc_middle/src/ty/relate.rs
Lines 689 to 698 in fd56162