Why are type aliases of type parameters disallowed?


#1

In the following example, why can’t I alias the type parameter?

use std::marker::PhantomData;

trait Foo {
    fn foo();
}

struct Bar<T>(PhantomData<T>);
impl<T: Foo> Bar<T> {
    fn bar() {
        T::foo(); // OK
        { type U = T; U::foo(); } // FAILS
    }
}

I get the failure “error[E0401]: can’t use type parameters from outer function; try using a local type parameter instead”. I think of type as creating a very “thin” alias, so in this case its little more than a textual substitution of T -> U - why is it disallowed here?

(The real reason this came up was from macro manipulations, which I managed to solve.)


#2

I guess T is seen as outside fn bar(). So maybe fn bar<T>() { ... } will work? Or maybe the subscope { ... } is seen as a different function that you must pass T down into? Which in that case, no idea how you’d do that…


#3

I think the official answer is: because type is an item (like mod, struct, etc.), and nesting items inside functions only affects naming and privacy, nothing deeper than that. So U can only be a single thing, rather than being instantiated separately for each instantiation of Bar.

Which is just a fancy way of saying “because that’s how it is”. I’ve wanted to see this feature for years, but I don’t think anyone’s written an RFC for it (including me). There is an RFC issue for it though:

https://github.com/rust-lang/rfcs/issues/1697

Feel free to write a proper RFC once the impl period ends! For the reasons you note, I don’t think it would be hard to implement for type. Allowing outer type parameters to be used in nested structs or entire modules would probably be much harder – though, IMO, still desirable.


#4

See also: an old rust-internals thread about the same thing, which I had forgotten about, and which (maybe not coincidentally) was just bumped :slight_smile: