Skip to content

WIP: Normalize associated types in structs when performing unsizing coercion #87548

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion compiler/rustc_typeck/src/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b));
match unsize {
Ok(_) => {
debug!("coerce: unsize successful");
debug!("coerce: unsize successful: {:?}", unsize);
return unsize;
}
Err(TypeError::ObjectUnsafeCoercion(did)) => {
Expand Down Expand Up @@ -603,6 +603,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
continue;
}
};


let InferOk { value: trait_pred2, obligations: obls } =
self.normalize_associated_types_in_as_infer_ok(self.cause.span, trait_pred);

debug!("coerce_unsized: normalized {:?} to {:?}; obls: {:?}", trait_pred, trait_pred2, obls);
let trait_pred = trait_pred2;
// coercion.obligations.extend(obls);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this commented out? We definitely shouldn't drop these obligations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very WIP and actually even abandoned 😅

At the time, I was experimenting with this and was hitting problems I couldn't understand, so I was commenting out different parts in an attempt to understand what and how (doesn't) work.

We've discussed this with Niko in a zulip thread and he said that it would probably be better to remove the "special trait solver" altogether:

nikomatsakis: as it happens, I would love to remove this part of the coercion code that you are fixing
nikomatsakis: I'm not sure if we can get away with it, but it's going to be really painful to make a part of chalk
nikomatsakis: the reason I dislike this code is that it is basically reproducing part of the normal "evaluate whether a trait matches" logic
nikomatsakis: but doing it in a custom and different way
nikomatsakis: anyway, I imagine that this is part of why you are seeing different behavior
nikomatsakis: I'm debating whether I can convince you into trying to remove this logic, instead of fixing it

I wanted to work on this (the issue I'm trying to fix really bothers me), but this never ended up happening.

I can try to revive this PR or try to make the refactor Niko proposed. But I'd need some guidance since I haven't worked on the compiler much before, so I'm not sure if I'll help or just spend someones time 😅

I'm assuming since you've assigned yourself, you know this part of the compiler well?


match selcx.select(&obligation.with(trait_pred)) {
// Uncertain or unimplemented.
Ok(None) => {
Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/coercion/coerce-normalization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// check-pass

trait Trait {}

impl<T0> Trait for T0 {}

impl<T1: ?Sized> Id for T1 {
type Assoc = T1;
}

trait Id {
type Assoc: ?Sized;
}

struct NewType<T2: ?Sized + Id>(T2::Assoc);

fn coerce_newtype_slice<'a, T3, const N: usize>(array: &'a NewType<[T3; N]>) -> &'a NewType<[T3]> {
array
}

fn coerce_newtype_trait<T4: Trait + 'static>(tr: &NewType<T4>) -> &NewType<dyn Trait> {
tr
}

fn main() {
let nt = NewType::<[i32; 1]>([0]);
coerce_newtype_slice(&nt);
coerce_newtype_trait(&nt);
}