Skip to content

No way to get compile-time info from the type of local. #88531

New issue

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

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

Already on GitHub? # to your account

Open
m-ou-se opened this issue Aug 31, 2021 · 6 comments
Open

No way to get compile-time info from the type of local. #88531

m-ou-se opened this issue Aug 31, 2021 · 6 comments
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@m-ou-se
Copy link
Member

m-ou-se commented Aug 31, 2021

const fn bla<T>(_: &T) -> usize { type_name::<T>().len() }

fn z(_: &'static [usize]) {}

fn f() {
    let x = read_integer_or_whatever();
    z(&[bla(&x)]); // This line is expanded from a macro, e.g. something like `format_args!()`
}

This doesn't work. There's no way to express here that the value of x is entirely irrelevant, and that bla only cares about the type of the argument.

If we had a magic PhantomData::of(x) that would work in const contexts regardless of whether x itself is const, we could do things like this:

impl<T> PhantomData<T> {
    #[lang = "magic"]
    const fn of(_: &T) -> Self { Self }
}

const fn bla<T>(_: PhantomData<T>) -> usize { type_name::<T>().len() }

fn z(_: &'static [usize]) {}

fn f() {
    let x = read_integer_or_whatever();
    z(&[bla(PhantomData::of(&x))]);
}
@m-ou-se m-ou-se added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-feature-request Category: A feature request, i.e: not implemented / a PR. labels Aug 31, 2021
@m-ou-se
Copy link
Member Author

m-ou-se commented Aug 31, 2021

cc @oli-obk @eddyb

@m-ou-se
Copy link
Member Author

m-ou-se commented Aug 31, 2021

The more 'obvious' alternative is typeof:

const fn bla<T>() -> usize { type_name::<T>().len() }

fn z(_: &'static [usize]) {}

fn f() {
    let x = read_integer_or_whatever();
    z(&[bla::<typeof(x)>()]);
}

But I've been told that typeof does not and will probably never work on locals like that.

@SkiFire13
Copy link
Contributor

SkiFire13 commented Aug 31, 2021

You can kind of emulate typeof with type_alias_impl_trait, in particular this compiles on nightly:

#![feature(const_type_name)]
#![feature(type_alias_impl_trait)]

use core::any::type_name;

fn read_integer_or_whatever() -> i32 { todo!() }

const fn bla<T>() -> usize { type_name::<T>().len() }

fn z(_: &'static [usize]) {}

fn f() {
    let x = read_integer_or_whatever();
    
    // Here's where the magic happens:
    type TypeOfX = impl Sized;
    if false {
        let _def_use = move || -> TypeOfX { x };
        loop {}
    }

    // Note that `z(&[bla::<i32>()])` also doesn't work because
    // calls to const fns are not static promoted
    const B: usize = bla::<TypeOfX>();
    z(&[B]);
}

@oli-obk
Copy link
Contributor

oli-obk commented Aug 31, 2021

unknown

@rodrimati1992
Copy link
Contributor

As far as I know, there's no equivalent of this with TAIT:

let foo = 0i32;
let bar: typeof foo = 100;
[foo, bar];

@kanashimia
Copy link

So apparently with trait solver next globally #107374 -Znext-solver=globally you can ACTUALLY implement typeof:

#![feature(type_alias_impl_trait)]
#![allow(unused)]
struct Foo {
    x: u32,
    y: u32,
}

fn main() {
    let x = Foo { x: 1, y: 2 };
    
    type TypeOfX = impl Sized;
    
    if false {
        let _def_use = move || -> TypeOfX { x }; 
        loop {}
    }
    
    let c = TypeOfX { x: 1, y: 2 };
}

Image

TypeOfX is not an opaque type anymore.

And I think this is a feature, not a bug.
So you can actually emulate inferred type names _ { x: 1, y: 2 } like that for example.

Found this based on this doc: https://hackmd.io/@impl-trait-everywhere/S1lO4jy86

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
C-feature-request Category: A feature request, i.e: not implemented / a PR. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants