Skip to content

Cannot upcast dyn Trait in a way that reduces the number of associated types #114035

Closed
@compiler-errors

Description

@compiler-errors

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)));
}

Metadata

Metadata

Labels

C-bugCategory: This is a bug.F-trait_upcasting`#![feature(trait_upcasting)]`T-typesRelevant to the types team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions