-
Notifications
You must be signed in to change notification settings - Fork 20
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
Support vec![const { ... }; n]
syntax for creating a Vec
of non-Clone
values
#484
Comments
Seems like a good idea to me. I expect the implementation you have in mind involves expanding to error[E0277]: the trait bound `State: Copy` is not satisfied
--> src/main.rs:9:14
|
9 | let _ = [State::NotVisited; N];
| ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `State`
|
= note: the `Copy` trait is required because this value will be copied for each element of the array
help: consider annotating `State` with `#[derive(Copy)]`
|
2 + #[derive(Copy)]
3 | enum State {
|
help: create an inline `const` block
|
9 | let _ = [const { State::NotVisited }; N];
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ vs: error[E0277]: the trait bound `State: Clone` is not satisfied
--> src/main.rs:9:18
|
9 | let _ = vec![State::NotVisited; N];
| -----^^^^^^^^^^^^^^^^^----
| | |
| | the trait `Clone` is not implemented for `State`
| required by a bound introduced by this call
|
note: required by a bound in `from_elem`
--> $RUSTUP_HOME/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:3172:21
|
3172 | pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
| ^^^^^ required by this bound in `from_elem`
help: consider annotating `State` with `#[derive(Clone)]`
|
2 + #[derive(Clone)]
3 | enum State {
| So while I don't think the implementation of this needs to be blocked on a better diagnostic, I would encourage you to think about what it would take to hint for the user to write |
I don’t think the array syntax can be used to implement the |
vec![const { expr }; N]
syntax for creating a Vec
of non-Clone
values.vec![const { expr }; N]
syntax for creating a Vec
of non-Clone
values
Should it maybe be It feels like the |
Other examples where
|
Good call; I didn't consider non-const |
@cuviper Good point! A particularly subtle one is |
We should also be careful about how this interacts with ... but maybe that just means we would have to manually match the |
So, regardless of whether |
We talked about this in today's @rust-lang/libs-api meeting. We were in favor of We also wondered whether this would Just Work when the standard library is converted to the 2024 edition and uses the 2024 |
I don't see how, because it's a dynamic length. The implementation is going to be So I think that
Except it can't, because |
@scottmcm: This is what I have in mind: macro_rules! vec {
(const $elem:block; $n:expr) => {{
let n: usize = $n;
let mut result = Vec::with_capacity(n);
for target in unsafe { result.spare_capacity_mut().get_unchecked_mut(..n) } {
target.write(const $elem);
}
unsafe { result.set_len(n) };
result
}};
} The value is guaranteed to be computed at compile time. Also, Currently, we can’t differentiate implicit const expression ( macro_rules! vec {
(const $elem:const_expr; $n:expr) => { ... };
} I suggest we only support the explicit const expression syntax ( For reference, here is a summary of the behaviors of different situations:
|
This means |
The array syntax has a similar problem, although not exactly the same:
Now Another solution would be adding a new syntax or even a new macro that is dedicated to handing the const value case. |
vec![const { expr }; N]
syntax for creating a Vec
of non-Clone
valuesvec![const { ... }; N]
syntax for creating a Vec
of non-Clone
values
vec![const { ... }; N]
syntax for creating a Vec
of non-Clone
valuesvec![const { ... }; n]
syntax for creating a Vec
of non-Clone
values
@EFanZh It is a known design that |
It is also the case that I'd in general expect |
I wouldn't compare this to the
I do understand the problem this ACP is trying to solve, don't get me wrong.
It's not (all) about the parentheses, it's about the fact that adding a Moreover, I think the goal "[…] For array repeat literals Lastly, this change would render It's not (all) about the parentheses. |
if we want could then be defined like: macro_rules! vec {
($($values:expr),* $(,)?) => {
...
};
($value:expr; $len:expr) => {
{
let value = $value;
let len = $len;
unsafe { CloneOrCopy::<{ is_expr_copyable!($value) }>::repeat_vec(value, len) }
}
};
}
#[doc(hidden)]
pub struct CloneOrCopy<const IS_COPYABLE: bool>;
impl CloneOrCopy<false> {
#[doc(hidden)]
pub fn repeat_vec<T: Clone>(value: T, len: usize) -> Vec<T> {
...
}
}
impl CloneOrCopy<true> {
#[doc(hidden)]
pub unsafe fn repeat_vec<T>(value: T, len: usize) -> Vec<T> {
// TODO: handle value being all zero bytes, for using `alloc_zeroed`
// TODO: handle stuff that turns into `memset`
let mut retval = Vec::with_capacity(len);
// drop value if len == 0 for things like:
// struct MyStruct;
// impl Drop for MyStruct {
// fn drop(&mut self) {
// println!("dropped");
// }
// }
// vec![MyStruct; 0] // should drop MyStruct once
if len > 0 {
let value = ManuallyDrop::new(value);
for i in 0..len {
unsafe { retval.push(ptr::read(&*value)) };
}
}
retval
}
} |
I think it would be better to have an explicit syntax for "repeat this expression" (regardless of |
Proposal
Problem statement
For array types, I can use
[const { ... }; N]
syntax to create an array ofconst { ... }
, even if it’s does not implementClone
. But I can’t do the same thing withVec
:vec![const { ... }; n]
currently does not compile.Motivating examples or use cases
Imagining implementing a DFS algorithm with an array to save the traversal states, I can write something like:
But it could be more simple if I could just write:
Deriving
Clone
might not always be possible because the value type could be from a third party crate.Solution sketch
Reimplement
vec!
macro so it supports theconst { ... }
syntax above.Alternatives
Links and related work
What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
Second, if there's a concrete solution:
The text was updated successfully, but these errors were encountered: