Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Constancy broken by tuple indexing (newtypes may unwrap in the runtime) #19244

Closed
mnemnion opened this issue Nov 23, 2014 · 4 comments · Fixed by #19266
Closed

Constancy broken by tuple indexing (newtypes may unwrap in the runtime) #19244

mnemnion opened this issue Nov 23, 2014 · 4 comments · Fixed by #19266

Comments

@mnemnion
Copy link

I'm translating a VM, and make heavy use of struct NewType(u32) as an idiom to separate the logical uses of numbers. I was advised to use new_type.0 to unwrap/dereference the value of such a type.

Since the type is known at compile time, it is at least possible to infer the type of a new_type.0 statically. It seems this may not be happening, or at least not consistently.

Here is the breaking code:

#![feature(tuple_indexing)]

use std::default::Default;

const WORKS_CONST: uint = 23 ;
const ALSO_WORKS_CONST: uint = WORKS_CONST + 5 ;

struct Wrapper(uint);
const WRAPPED_CONST: Wrapper = Wrapper(42) ;
const BAD_CONST: uint = WRAPPED_CONST.0 ;

struct ConstCheck {
    broken_array: [int, ..BAD_CONST],
    works_array: [int, ..ALSO_WORKS_CONST],
}

fn main() {
    println!("Wrapped Constant is: {}", BAD_CONST);
}

The definition of broken_array breaks the compiler, with the following message:

/../src/main.rs:13:19: 13:37 error: expected constant expr for array length: unsupported constant expr
/../src/main.rs:13     broken_array: [int, ..BAD_CONST],
                                                                            ^~~~~~~~~~~~~~~~~~
Could not compile `rusty_sandbox`.

If that line is commented out, the code compiles, creating BAD_CONST and printing the correct value.

I infer from this that new_type.0 unwrapping is happening in the runtime. This is going to be terrible for my VMs performance. It would seem that a major use case for newtypes would be wrapping raw numbers for math-heavy applications, so your Kilos don't mix with your Meters.

I'm brand new here, so take this for the naive perspective that it is, but it seems to me the fix would involve reifying newtypes, at least somewhat. A type that's a simple synonym should disappear completely at compile time, with the syntax enforcing correct use. It's my old Perl side talking, I expect, but syntax such as newtype.$ for self could force the compiler to try and unwrap a single value from the tuple and fail if the struct isn't a single-field tuple.

I do feel that the code provided should compile. Thank you.

@mnemnion
Copy link
Author

IRC at large tells me the problem is almost certainly in the compiler, and that newtypes that compile work as a VM writer would expect/hope. I'll proceed on that basis. Thanks to the people who took time to explain this.

@aochagavia
Copy link
Contributor

This is also an issue for fields of constant structs.

Example:

struct MyStruct {
    field1: uint
}

const S: MyStruct = MyStruct { field1: 10 };
const SField : uint = S.field1;

struct ConstCheck {
    broken_array: [int, ..SField],
}

@huonw
Copy link
Member

huonw commented Nov 24, 2014

I infer from this that new_type.0 unwrapping is happening in the runtime. This is going to be terrible for my VMs performance. It would seem that a major use case for newtypes would be wrapping raw numbers for math-heavy applications, so your Kilos don't mix with your Meters.

This isn't something to worry about at all: in Rust, there's no implicit layers of pointers/indirection insert, meaning struct Foo(int) and int have the same representation at runtime. Secondly, a field access is one of the cheapest things you can do with a struct, it's just a pointer offset (and for the first field of a struct, like .0, it's a no-op). Furthermore, this sort of simplistic data access is very easy for the compiler to optimise and the constant value will be inlined directly.

@mnemnion
Copy link
Author

Thank you Huon, these were my initial assumptions (prior to hitting this snag) and it's good to have it confirmed. Interesting that it is also a problem for structs; the tuple.0 language is experimental, but struct.field most certainly is not.

alexcrichton added a commit to alexcrichton/rust that referenced this issue Nov 27, 2014
With this PR, the following code works:

```
#![feature(tuple_indexing)]
struct MyStruct { field1: uint }

const S: MyStruct = MyStruct { field1: 42u };
const T: (uint,) = (42u,);

struct ConstCheck {
    array1: [int, ..S.field1],
    array2: [int, ..T.0],
}
```

Closes rust-lang#19244
Related rust-lang#19265
lnicola pushed a commit to lnicola/rust that referenced this issue Mar 10, 2025
Warn when the used toolchain looks too old for rust-analyzer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants