rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.38k stars 12.72k forks source link

Get rid of the "rust-call" hack #41058

Open aochagavia opened 7 years ago

aochagavia commented 7 years ago

Based on https://github.com/rust-lang/rfcs/pull/1921#issuecomment-282164515

Currently, we fake variadics by defining functions with the rust-call ABI. These functions receive a tuple as parameter (of arbitrary arity and types), but in their ABI the tuple is expanded. It would be great to get rid of this hack and in the process pave the way for the eventual feature of variadic generics.

aochagavia commented 7 years ago

@eddyb would you be willing to mentor me on this issue?

eddyb commented 7 years ago

@aochagavia Sure thing, poke me on IRC.

eddyb commented 7 years ago

One way to start would be to modify https://github.com/rust-lang/rust/blob/44855a4cef3e83c76c386fdcf034447a8ee128e4/src/librustc/ty/context.rs#L1407 to replace RustCall with Rust by expanding the last argument in-place, if it's a concrete tuple (not a parameter). However, that might not be the only place that you'd need to modify to get that working. But if you get it to consistently do that, then trans should be able to expect RustCall to never exist.

aochagavia commented 7 years ago

I think I am missing some context. Just to make things clear for myself, this issue is about implementing variadic generics in rustc without changing the syntax, right? In my understanding, variadic generics provide the ability to create traits where functions accept arbitrary arguments, specified by the implementor. Something like the code below:

trait VariadicTrait<Args> {
    fn variadic_fn(&self, args: Args);
}

impl VariadicTrait<(&'static str,)> for () {
    fn variadic_fn(&self, (s,): (&'static str,)) {
        println!("{}", s)
    }
}

fn main() {
    ().variadic_fn(("hi",))
}

Previous code compiles perfectly in stable Rust, though it looks ugly. From my perspective, this looks like we already have variadic generics. However, this can't be true, so what am I missing?

Also, one of the problems with the code above is that the tuple is not expanded in the ABI, which is bad for performance (IIRC). Is this the problem we are trying to solve here? Would it be enough to infer whether a tuple parameter needs to be expanded? That way we wouldn't need "rust-call" anymore.

eddyb commented 7 years ago

@aochagavia The problem is that you can't write this:

trait VariadicTrait<Args> {
    fn variadic_fn(&self, ...Args);
}

That is, true variadic functions, that for Args being a given tuple they become regular functions (e.g. fn(&self, A, B) for Args = (A, B)).

Removing "rust-call" from the source would more or less require VG to be implemented, at that's ways off - what we can do now, however, is desugar "rust-call" into an internal VG-like form, or at least expand it into regular functions as early as possible - so that it doesn't have to be manually handled by backends.

steveklabnik commented 6 years ago

Triage: no changes I'm aware of.

eddyb commented 6 years ago

I started a branch of this but had to lower priority on it.