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

Constructing Option<&'static dyn T>::None in a const fn requires const_fn_trait_bounds #87240

Open
cceckman opened this issue Jul 18, 2021 · 5 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@cceckman
Copy link

Thank you for filing a bug report! 🐛

Thank you for continuing to improve Rust!


Given the following code: playground

trait Irrelevant {}

struct Buffer {
    ptr: Option<&'static dyn Irrelevant>,
}

impl Buffer {
    pub const fn new() -> Self {
        Buffer {
            ptr: None,
        }
    }
}

The current output is:

error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
  --> src/lib.rs:10:18
   |
10 |             ptr: None,
   |                  ^^^^
   |
   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

After reading this message and reading #57563, I'm not sure what trait bound is a problem. The code that is literally written here does not have any trait bounds - no syntax R: T; nor does it have any (explicit) generic const fn.

I assume there is a good reason why this doesn't immediately work - I know the Rust team has put tons of work into making all this analysis correct, so this is not a complaint about the analysis. :-) I'm just not sure how to go from the compiler's message to an action other than "switch to nightly".

(I can confirm that switching to nightly and enabling #![feature(const_fn_trait_bounds)] does quiet the warning. It's not clear to me what more-specific issue than #57563 is tracking it?)


Experiments / speculation:

I'm assuming there's some sort of desugaring here that's causing a trait bound to appear - e.g. the None constructor becoming a const fn (per #61456) , and something in the Option's generic argument turning into a trait bound. However, Option<T> itself doesn't have any trait bounds on T (...other than the default Sized, which the error message says is OK), so I'm not sure what to change.

Some experimenting shows that Option<&static T> its OK for a built-in T:

trait Irrelevant {}

struct Buffer {
    ptr: Option<&'static usize>,
}

impl Buffer {
    pub const fn new() -> Self {
        Buffer {
            ptr: None,
        }
    }
}

compiles on stable (1.53.0).

And even using a different ?Sized type - [u8] - works out alright:

trait Irrelevant {}

struct Buffer {
    ptr: Option<&'static [u8]>,
}

impl Buffer {
    pub const fn new() -> Self {
        Buffer {
            ptr: None,
        }
    }
}

compiles as well.

That's based on a not-great understanding of Sized - if I understand correctly both dyn T and [u8] are ?Sized.

@cceckman cceckman added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jul 18, 2021
@cceckman
Copy link
Author

It looks like #64992 has more context:

While we can't allow unsizing to dyn Trait until we've figured out trait bounds in const fns, we can easily allow unsizing casts for slices,

matches my experimentation above.

I see #85078 is marked as 1.54.0; however, this example still fails to compile on beta.

I see const_eval says:

Notable features that const contexts have, but const fn haven't are:
...

  • dyn Trait types

Perhaps that is a better warning / error to provide? "Cannot construct Option<...> in const fn: dyn Trait cannot appear in const fn contexts" or something similar, if that is the constraint?

@RalfJung
Copy link
Member

Indeed the current check basically ensures that dyn Trait does not appear anywhere in any type in a const fn. This is because we might want to change the very meaning of that type in the future. (Basically, it is not clear if this should refer to a trait object that has a const impl, or just any trait object.)

So the error is expected, and we can't allow such code until we commit to what dyn Trait (and fn()) will mean in const fn. But the message could probably be improved.

Cc @rust-lang/wg-const-eval

@oli-obk
Copy link
Contributor

oli-obk commented Oct 6, 2021

I have come around to just allowing everything related to function pointers, trait bounds and dyn trait that works in const initializers in const fn. The current design will require extra annotations when you want to actually use them beyond copying their value around or accessing associated types or constants.

Maybe we could write up sth along those lines and ask T-lang to consider it?

@RalfJung
Copy link
Member

RalfJung commented Oct 8, 2021

So basically, you have given up on trying to do anything with the existing syntax, and think we need new syntax for everything anyway?

That is my preferred solution I think, but I am nevertheless a bit hesitant to close down the design space. But maybe we have kept it open long enough.

@oli-obk
Copy link
Contributor

oli-obk commented Oct 8, 2021

Well, we can let the experimental new syntax bake a little on master, and if it pans out, we can stabilize non-const behaviour of the regular syntax that already works in const items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints 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

3 participants