Skip to content

Unsizing coercion does not normalize associated types in structs. #75899

Closed
@eddyb

Description

Example code I'd expect to work (playground):

// NOTE: this is only needed for coerce_tuple, you can remove both for a stable version.
#![feature(unsized_tuple_coercion)]

trait Trait {}
impl<T> Trait for T {}

trait Noop {
    type Assoc: ?Sized;
}
impl<T: ?Sized> Noop for T {
    type Assoc = T;
}

// Both of these work:
fn coerce<T: Trait>(x: &<T as Noop>::Assoc) -> &<dyn Trait as Noop>::Assoc { x }
fn coerce_tuple<T: Trait>(x: &(String, <T as Noop>::Assoc)) -> &(String, <dyn Trait as Noop>::Assoc) { x }

// But this doesn't:
struct NoopNewtype<T: ?Sized + Noop>(T::Assoc);
fn coerce_newtype<T: Trait>(x: &NoopNewtype<T>) -> &NoopNewtype<dyn Trait> { x }

(in case the example above seems artificial, the realistic one I've reduced this from involves using an associated trait to add Option around sized types, but not dyn Trait, since Option<dyn Trait> wouldn't itself work)


I'd expect coerce_newtype to work because <T as Noop>::Assoc: Unsize<<dyn Trait as Noop>::Assoc> should hold, after normalization to T: Unsize<dyn Trait> (which holds here because T: Trait), but nothing performs that normalization before coercion gives up entirely.

Unlike CoerceUnsized (where I've been wary of associated types in the past), there should be no weird interactions here, we should be able to largely treat the struct as a tuple (and we already ensure the type parameter being changed doesn't show up anywhere else in the struct, anyway).


The coerce and coerce_tuple examples get to normalize before asking the trait system about any CoerceUnsized or Unsized obligations - I wonder if we could just normalize trait_pred here?

match selcx.select(&obligation.with(trait_pred)) {

But we would have to be careful, because we are in a speculative operation, so we would have to use normalize_associated_types_in_as_infer_ok, like this other piece of coercion logic:

let InferOk { value: a_sig, mut obligations } =
self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);

cc @mystor (author of the object-provider crate where this could be useful) @nikomatsakis

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

A-DSTsArea: Dynamically-sized types (DSTs)A-associated-itemsArea: Associated items (types, constants & functions)A-coercionsArea: implicit and explicit `expr as Type` coercionsE-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.T-compilerRelevant to the compiler 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