rust-lang / rust-lang/rust

TypeId exposes placeholders type generics with `-Znext-solver`

Open
#130,785 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug F-generic_const_exprs P-low T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

So, this isn't necessarily a bug, it's just interesting behavior and I'm not sure if it's intended:

#![feature(const_type_id, generic_const_exprs)]
const fn type_id<T: 'static>() -> u128 {
    unsafe { std::mem::transmute::<_, u128>(std::any::TypeId::of::<T>()) }
}

const fn c<X: 'static>() -> usize {
    // A: the evaluated program panicked at '63102938254854923095314763309601158984'
    const_panic::concat_panic!(type_id::<X>());
}

pub fn u<X: 'static>() {
    let _: [(); c::<X>()];
    println!("{}", type_id::<X>()); // B
}

This happens without even calling u. The values printed at A and B (by commenting out the call to c and adding a call to u with any arbitrary type) are different. I'm posting this issue because I'm not sure if there's ICE potential here, for values being different in a const vs runtime context.

I stumbled across this while looking for a way to make a "commutative type" i.e. where Com<A, B> and Com<B, A> are the same type. It only works in -Znext-solver and I believe that's due to -Znext-solver eagerly evaluating stuff using these placeholder types?

#![feature(const_type_id, core_intrinsics, generic_const_exprs)]
#![allow(warnings)]
struct Foo; struct Bar;

struct Bool<const B: bool>;

trait TrueOrFalse {
    type Ite<Then, Else>;
}

impl TrueOrFalse for Bool<true> {
    type Ite<Then, Else> = Then;
}

impl TrueOrFalse for Bool<false> {
    type Ite<Then, Else> = Else;
}

type Ite<const B: bool, T, E> = <Bool<B> as TrueOrFalse>::Ite<T, E>;

trait Map<T: 'static, U: 'static> where {
    type Output;
}

impl<T: 'static, U: 'static> Map<T, U> for (T, U) {
    type Output = Ite<{
        std::intrinsics::type_id::<T>() > std::intrinsics::type_id::<U>()
    }, (U, T), (T, U)>;
}

pub fn u<X: 'static, Y: 'static>() {
    let _x: <(X, Y) as Map<X, Y>>::Output = loop {};
    let mut _y: <(Y, X) as Map<Y, X>>::Output = loop {};
    _y = _x;
}

pub fn f() {
    u::<Foo, Bar>();
}

If this does happen to be fixed in a way which breaks the code above it would be nice to have a (perma-unstable) way to order types.

Meta

rustc 1.79.0-nightly (aed2187d5 2024-04-27)
binary: rustc
commit-hash: aed2187d53b8789e3a37f50ae36f894a2a679077
commit-date: 2024-04-27
host: x86_64-pc-windows-msvc
release: 1.79.0-nightly
LLVM version: 18.1.4

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the two provided reproductions with the noted nightly compiler and -Znext-solver, comparing the TypeId values produced during const evaluation and at runtime. Investigate whether placeholder types are being eagerly evaluated and whether the discrepancy can cause an ICE. Done means the behavior is resolved or its intended semantics are clearly established, with the commutative-type example addressed.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.