Can't use type-based constant in generic

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4e1dc1beb0c02f4e0f21ebd5989ba95a

error[E0401]: can't use generic parameters from outer function
  --> src/main.rs:17:19
   |
16 | fn read<T>(cursor: &mut dyn Read) -> Result<T, Error> {
   |         - type parameter from outer function
17 |     const BYTES = T::BITS/8;
   |                   ^^^^^^^ use of generic parameter from outer function

Shouldn't that be allowed, now that we can have numeric parameters to generics? Is there a workaround? Is there a way to get the size of a type as a const?

It's been discussed at Can't assign results of generic functions to `const` variables · Issue #57775 · rust-lang/rust · GitHub

The way to think about items such as const, trait, type, or fn is that while they are allowed to appear inside of a function body, they still have to be defined in such a way that they could equally well be pulled outside of that function body. That’s why T isn’t allowed in the const. Similarly:


fn foo<T>() {
    type Ty = T;
}
fn bar<T>() {
    fn f(_: T) {}
}
fn baz<T>() {
    trait Tr {
        fn f(_: T);
    }
}
fn qux<T>() {
    trait Tr {
        type Ty: AsRef<T>;
    }
}
// etc

doesn’t work. The way to do compile-time but type-dependent stuff is by const fn, or with traits with associated items. By the way, I don’t know where the associated item BITS is supposed to come from, maybe you’re missing a trait or something in your code example?


Edit:

The way to do compile-time but type-dependent stuff is by const fn, or with traits with associated items.

actually, that might be wrong; maybe what you want isn’t possible on stable yet. I tried some stuff with a trait with an associated const BITS and I keep getting error: generic parameters may not be used in const operations.

Ref: Rust Playground

Not sure that's it. It's const-ness that's the problem, not definedness.

const BYTES = T::BITS/8; // NO
let bytes = T::BITS/8; // OK

Added the necessary trait constraints.

The specific issue on generic type sizes was merged into the const generics effort, but didn't get fixed when that went in.

Maybe some pointers to the reference might help. The word “item” is a technical term.

Items - The Rust Reference

and it’s different from statements

Statements - The Rust Reference

An item is a thing that can be put at top-level in Rust, a let … = …; statement is not an item. On the other hand, while items can technically count as statements, they’re really in essence not really part of the function or block they live in except for visibility concerns; so it’s best to think of items and statements of really different things. This means that a const …: … = …; is something entirely different from a let-statement in lots of ways, it isn’t just “a let-statement with some ‘const-ness’ constraints” or anything like that.

More on items as statements can be read in the reference here which is a section of the “Statements” page linked above. In particular, try to understand this part and relate it to the examples I gave above:

[…] It is otherwise identical in meaning to declaring the item inside a module.

There is no implicit capture of the containing function's generic parameters, parameters, and local variables. For example, inner may not access outer_var .

fn outer() {
 let outer_var = true;

 fn inner() { /* outer_var is not in scope here */ }

 inner();
}

That applies to a local variable, reasonably enough, because otherwise you could create a closure that way. It doesn't apply to an "item".

//  Nesting test
pub fn outer() {
    struct St {
        pub x: f32
        }
        
    const X: f32 = 1.0;
        
    fn fn1()-> St {
        let st = St{x: X};
        st
    }
    
    let stout = fn1();
    println!("{}", stout.x)
}

X and St, being compile-type objects, are visible within fn1.

So this isn't a general scope issue, it's a special problem with generics. One that really should have been fixed when const parameters came in, since the whole point of that was to improve behavior around items whose size is determined at compile time.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.