Skip to content
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

Specialization hack might stop working in future rust versions. #2945

Closed
theemathas opened this issue Feb 6, 2025 · 1 comment · Fixed by #2946
Closed

Specialization hack might stop working in future rust versions. #2945

theemathas opened this issue Feb 6, 2025 · 1 comment · Fixed by #2946

Comments

@theemathas
Copy link

Currently, this code relies on the fact that std uses specialization for cloning arrays. This is an implementation detail, and is not supported.

/// Returns if the type `T` is equal to `U`, ignoring lifetimes.
#[inline] // this entire call gets optimized away :)
#[must_use]
pub fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
// decider struct: hold a cell (which we will update if the types are unequal) and some
// phantom data using a function pointer to allow for Copy to be implemented
struct W<'a, T: ?Sized, U: ?Sized>(&'a Cell<bool>, PhantomData<fn() -> (&'a T, &'a U)>);
// default implementation: if the types are unequal, we will use the clone implementation
impl<T: ?Sized, U: ?Sized> Clone for W<'_, T, U> {
#[inline]
fn clone(&self) -> Self {
// indicate that the types are unequal
// unfortunately, use of interior mutability (Cell) makes this not const-compatible
// not really possible to get around at this time
self.0.set(false);
W(self.0, self.1)
}
}
// specialized implementation: Copy is only implemented if the types are the same
#[expect(clippy::mismatching_type_param_order)]
impl<T: ?Sized> Copy for W<'_, T, T> {}
let detected = Cell::new(true);
// [].clone() is *specialized* in core.
// Types which implement copy will have their copy implementations used, falling back to clone.
// If the types are the same, then our clone implementation (which sets our Cell to false)
// will never be called, meaning that our Cell's content remains true.
let res = [W::<T, U>(&detected, PhantomData)].clone();
res[0].0.get()
}

In a future version of rust, this specialization might be removed, breaking this code. See rust-lang/rust#135634 and rust-lang/rust#132442

Maybe consider using the typeid crate instead.

@addisoncrump
Copy link
Collaborator

Hey, thanks for pointing to typeid. We've needed a proper replacement for this hack for some time, I'll see if I can't migrate to this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants