From 261914a68b008bdb9ddad89e8d28701c2e681e5d Mon Sep 17 00:00:00 2001 From: yvt Date: Tue, 21 Mar 2023 01:57:40 +0900 Subject: [PATCH] refactor(core): use `Range: const Iterator` and `const_for` [rust-lang/rust#104100][1] has implemented `std::ops::Range: const Iterator`, resolving `[tag:range_const_iterator]`. [1]: https://github.com/rust-lang/rust/pull/104100 --- doc/toolchain_limitations.md | 38 +++++---- src/r3_core/src/bind.rs | 25 ++---- src/r3_core/src/bind/sorter.rs | 115 +++++++++++++--------------- src/r3_core/src/kernel/interrupt.rs | 34 +++----- src/r3_core/src/kernel/raw.rs | 12 +-- src/r3_core/src/lib.rs | 3 + src/r3_core/src/utils/init.rs | 6 +- src/r3_core/src/utils/sort.rs | 2 +- 8 files changed, 100 insertions(+), 135 deletions(-) diff --git a/doc/toolchain_limitations.md b/doc/toolchain_limitations.md index b8c100cd07..56fcaa0fc2 100644 --- a/doc/toolchain_limitations.md +++ b/doc/toolchain_limitations.md @@ -106,7 +106,7 @@ type Alias = Struct<{::N}>; ### `[tag:const_for]` `for` loops are unusable in `const fn` -Technically it's available under the compiler feature `const_for`, but the lack of essential trait implementations (e.g., `[ref:range_const_iterator]`, `[ref:const_slice_iter]`) makes it unusable in many cases. +Technically it's available under the compiler feature `const_for`, but the lack of essential trait implementations (e.g., `[ref:const_slice_iter]`, `[ref:const_rev_iter]`) makes it unusable in many cases. ### `[tag:const_static_item_ref]` `const`s and `const fn`s can't refer to `static`s @@ -296,6 +296,23 @@ const _: () = { b"".iter(); }; ``` +### `[tag:const_rev_iter]` `Rev` is not `const Iterator` + +```rust +for _ in (0..4).rev() {} +``` + +```rust,compile_fail,E0277 +#![feature(const_intoiterator_identity)] +#![feature(const_trait_impl)] +#![feature(const_mut_refs)] +#![feature(const_for)] +// error[E0277]: the trait bound `Rev>: ~const Iterator` +// is not satisfied +const _: () = for _ in (0..4).rev() {}; +``` + + ### `[tag:const_uninit_array]` `MaybeUninit::uninit_array` is unstable ```rust,compile_fail,E0658 @@ -430,25 +447,6 @@ const _: () = assert!(PartialEq::eq(&(A..A), &(A..A))); ``` -### `[tag:range_const_iterator]` `Range: !~const Iterator` - -The standard library doesn't provide a `const` trait implementation of `Range: Iterator`. - -```rust -assert!(matches!((2..4).next(), Some(2))); -``` - -```rust,compile_fail,E0277 -#![feature(const_trait_impl)] -#![feature(const_mut_refs)] -// `assert!` is used here due to [ref:const_assert_eq] -// `matches!` is used here due to [ref:option_const_partial_eq] -// error[E0277]: the trait bound `std::ops::Range: ~const Iterator` is not -// satisfied -const _: () = assert!(matches!((2..4).next(), Some(2))); -``` - - ### `[tag:const_assert_eq]` `assert_eq!` and similar macros are unusable in `const fn` ```rust,compile_fail,E0015 diff --git a/src/r3_core/src/bind.rs b/src/r3_core/src/bind.rs index 7226895da4..8707f78375 100644 --- a/src/r3_core/src/bind.rs +++ b/src/r3_core/src/bind.rs @@ -790,11 +790,8 @@ impl<'pool, const LEN: usize, System, T> const UnzipBind for Bind<'pool, System, let mut out = ComptimeVec::new_in(self.bind_registry.borrow().binds.allocator().clone()); - // `for` loops are unusable in `const fn` [ref:const_for] - let mut i = 0; - while i < LEN { + for i in 0..LEN { out.push(divide.slice(hunk.transmute::>().wrapping_offset(i as isize))); - i += 1; } out.to_array() @@ -988,10 +985,8 @@ impl CfgBindRegistry { // Because of [ref:bind_finalization_immediate_panic], reaching here // means the operation was successful - // `for` loops are barely useful in `const fn` at the moment - // [ref:const_for] - let mut i = 0; - while i < callback.bind_init_order.len() { + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..callback.bind_init_order.len() { let bind_i = callback.bind_init_order[i]; if let Some(initializer) = self.binds[bind_i].initializer { @@ -1000,8 +995,6 @@ impl CfgBindRegistry { .priority(INIT_HOOK_PRIORITY) .finish(cfg); } - - i += 1; } } } @@ -1784,11 +1777,9 @@ where type Runtime = [Binder::Runtime; LEN]; fn register_dependency(&self, ctx: &mut CfgBindCtx<'_>) { - // `for` loops are unusable in `const fn` [ref:const_for] - let mut i = 0; - while i < LEN { + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..LEN { self[i].register_dependency(ctx); - i += 1; } } @@ -1797,9 +1788,8 @@ where // `[T; N]::map` is unusable in `const fn` [ref:const_array_map] let mut out = MaybeUninit::uninit_array(); let this = MaybeUninit::new(self); - // `for` loops are unusable in `const fn` [ref:const_for] - let mut i = 0; - while i < LEN { + // `[T]::iter_mut` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..LEN { out[i] = MaybeUninit::new( this.as_ptr() .cast::() @@ -1807,7 +1797,6 @@ where .read() .into_runtime_binder(), ); - i += 1; } // Safety: All elements of `out` are initialized MaybeUninit::array_assume_init(out) diff --git a/src/r3_core/src/bind/sorter.rs b/src/r3_core/src/bind/sorter.rs index c48ab6a093..5079f2a20d 100644 --- a/src/r3_core/src/bind/sorter.rs +++ b/src/r3_core/src/bind/sorter.rs @@ -160,75 +160,66 @@ pub(super) const fn sort_bindings( assert!(temp_uses.is_empty()); assert!(temp_vertices.is_empty()); - { - // `for` loops are unusable in `const fn` [ref:const_for] - let mut bind_i = 0; - while bind_i < num_binds { - let bind_users = cb.bind_users(bind_i); - - let mut num_indefinite_shared = 0; - let mut num_indefinite_exclusive = 0; - - // `for` loops are unusable in `const fn` [ref:const_for] - let mut i = 0; - while i < bind_users.len() { - // Reject impossible combinations that should be caught earlier - match bind_users[i] { - (BindUsage::Bind(_), BindBorrowType::Borrow) - | (BindUsage::Bind(_), BindBorrowType::BorrowMut) - | (BindUsage::Bind(_), BindBorrowType::Take) - | (BindUsage::Bind(_), BindBorrowType::TakeRef) - | (BindUsage::Bind(_), BindBorrowType::TakeMut) - | (BindUsage::Executable, BindBorrowType::Take) - | (BindUsage::Executable, BindBorrowType::TakeRef) - | (BindUsage::Executable, BindBorrowType::TakeMut) => {} - // [ref:borrow_is_indefinite_for_executable] - (BindUsage::Executable, BindBorrowType::Borrow) - | (BindUsage::Executable, BindBorrowType::BorrowMut) => { - unreachable!() - } + for bind_i in 0..num_binds { + let bind_users = cb.bind_users(bind_i); + + let mut num_indefinite_shared = 0; + let mut num_indefinite_exclusive = 0; + + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..bind_users.len() { + // Reject impossible combinations that should be caught earlier + match bind_users[i] { + (BindUsage::Bind(_), BindBorrowType::Borrow) + | (BindUsage::Bind(_), BindBorrowType::BorrowMut) + | (BindUsage::Bind(_), BindBorrowType::Take) + | (BindUsage::Bind(_), BindBorrowType::TakeRef) + | (BindUsage::Bind(_), BindBorrowType::TakeMut) + | (BindUsage::Executable, BindBorrowType::Take) + | (BindUsage::Executable, BindBorrowType::TakeRef) + | (BindUsage::Executable, BindBorrowType::TakeMut) => {} + // [ref:borrow_is_indefinite_for_executable] + (BindUsage::Executable, BindBorrowType::Borrow) + | (BindUsage::Executable, BindBorrowType::BorrowMut) => { + unreachable!() } + } - // Count indefinite borrows - match bind_users[i].1 { - BindBorrowType::Borrow | BindBorrowType::BorrowMut => {} - BindBorrowType::TakeRef => { - num_indefinite_shared += 1; - } - BindBorrowType::Take | BindBorrowType::TakeMut => { - num_indefinite_exclusive += 1; - } + // Count indefinite borrows + match bind_users[i].1 { + BindBorrowType::Borrow | BindBorrowType::BorrowMut => {} + BindBorrowType::TakeRef => { + num_indefinite_shared += 1; } - - // Collect dependencies in the reverse direction - if let (BindUsage::Bind(user_bind_i), borrow_type) = bind_users[i] { - let use_i = temp_uses.len(); - let other_bind_first_use_i = &mut temp_binds1[user_bind_i].first_use_i; - temp_uses.push(SorterUseInfo { - bind_i, - borrow_type, - next_use_i: *other_bind_first_use_i, - }); - *other_bind_first_use_i = Some(use_i); + BindBorrowType::Take | BindBorrowType::TakeMut => { + num_indefinite_exclusive += 1; } - - i += 1; } - temp_binds1[bind_i].borrowed_indefinitely = - match (num_indefinite_shared, num_indefinite_exclusive) { - (0, 0) => None, - (_, 0) => Some(false), - (0, 1) => Some(true), - _ => { - // [ref:bind_conflicting_take] - cb.report_error(SorterError::ConflictingIndefiniteBorrow { bind_i }); - Some(false) - } - }; - - bind_i += 1; + // Collect dependencies in the reverse direction + if let (BindUsage::Bind(user_bind_i), borrow_type) = bind_users[i] { + let use_i = temp_uses.len(); + let other_bind_first_use_i = &mut temp_binds1[user_bind_i].first_use_i; + temp_uses.push(SorterUseInfo { + bind_i, + borrow_type, + next_use_i: *other_bind_first_use_i, + }); + *other_bind_first_use_i = Some(use_i); + } } + + temp_binds1[bind_i].borrowed_indefinitely = + match (num_indefinite_shared, num_indefinite_exclusive) { + (0, 0) => None, + (_, 0) => Some(false), + (0, 1) => Some(true), + _ => { + // [ref:bind_conflicting_take] + cb.report_error(SorterError::ConflictingIndefiniteBorrow { bind_i }); + Some(false) + } + }; } // Helper types needed for topological sorting. `Vertex` is defined outside diff --git a/src/r3_core/src/kernel/interrupt.rs b/src/r3_core/src/kernel/interrupt.rs index 442349939b..f972a595eb 100644 --- a/src/r3_core/src/kernel/interrupt.rs +++ b/src/r3_core/src/kernel/interrupt.rs @@ -433,28 +433,22 @@ pub(super) const fn panic_if_unmanaged_safety_is_violated, interrupt_handlers: &ComptimeVec, ) { - // `for` is unusable in `const fn` [ref:const_for] - let mut i = 0; - while i < interrupt_handlers.len() { + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..interrupt_handlers.len() { let handler = &interrupt_handlers[i]; - i += 1; if handler.unmanaged { continue; } - let is_line_assumed_managed = { + let is_line_assumed_managed = 'a: { let lines = System::RAW_MANAGED_INTERRUPT_LINES; - let mut i = 0; - loop { - if i < lines.len() { - if lines[i] == handler.line { - break true; - } - i += 1; - } else { - break false; + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..lines.len() { + if lines[i] == handler.line { + break 'a true; } } + false }; let managed_line_i = vec_position!(interrupt_lines, |line| line.num == handler.line @@ -663,12 +657,10 @@ pub const unsafe fn new_interrupt_handler_table< assert!(NumLines::N == NUM_LINES); assert!(Handlers::NumHandlers::N == NUM_HANDLERS); - // `for` is unusable in `const fn` [ref:const_for] - let mut i = 0; - while i < NUM_HANDLERS { + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..NUM_HANDLERS { let handler = Handlers::HANDLERS[i]; assert!(handler.line < NUM_LINES); - i += 1; } const_array_from_fn! { @@ -702,14 +694,12 @@ pub const unsafe fn new_interrupt_handler_table< #[doc(hidden)] pub const fn num_required_interrupt_line_slots(handlers: &[CfgInterruptHandler]) -> usize { - // `for` is unusable in `const fn` [ref:const_for] - let mut i = 0; + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] let mut out = 0; - while i < handlers.len() { + for i in 0..handlers.len() { if handlers[i].line + 1 > out { out = handlers[i].line + 1; } - i += 1; } out } diff --git a/src/r3_core/src/kernel/raw.rs b/src/r3_core/src/kernel/raw.rs index 98ed406e11..195ec88bbd 100644 --- a/src/r3_core/src/kernel/raw.rs +++ b/src/r3_core/src/kernel/raw.rs @@ -268,10 +268,9 @@ impl QueueOrder { QueueOrder::TaskPriority => QueueOrderKind::TaskPriority, }; - // `for` is unusable in `const fn` [ref:const_for] - let mut i = 0; + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] let values = System::RAW_SUPPORTED_QUEUE_ORDERS; - while i < values.len() { + for i in 0..values.len() { // `#[derive(PartialEq)]` doesn't derive `const PartialEq` // [ref:derive_const_partial_eq] if let Some(value) = values[i] { @@ -279,7 +278,6 @@ impl QueueOrder { return true; } } - i += 1; } false } @@ -537,10 +535,9 @@ impl MutexProtocol { MutexProtocol::Ceiling(_) => MutexProtocolKind::Ceiling, }; - // `for` is unusable in `const fn` [ref:const_for] - let mut i = 0; + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] let values = System::RAW_SUPPORTED_MUTEX_PROTOCOLS; - while i < values.len() { + for i in 0..values.len() { // `#[derive(PartialEq)]` doesn't derive `const PartialEq` // [ref:derive_const_partial_eq] if let Some(value) = values[i] { @@ -548,7 +545,6 @@ impl MutexProtocol { return true; } } - i += 1; } false } diff --git a/src/r3_core/src/lib.rs b/src/r3_core/src/lib.rs index 4446d08c72..b73791d9a5 100644 --- a/src/r3_core/src/lib.rs +++ b/src/r3_core/src/lib.rs @@ -7,6 +7,7 @@ #![feature(maybe_uninit_array_assume_init)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(nonnull_slice_from_raw_parts)] +#![feature(const_intoiterator_identity)] #![feature(type_changing_struct_update)] #![feature(maybe_uninit_uninit_array)] #![feature(const_precise_live_drops)] @@ -41,9 +42,11 @@ #![feature(cell_update)] #![feature(const_deref)] #![feature(const_heap)] +#![feature(const_iter)] #![feature(const_swap)] #![feature(decl_macro)] #![feature(never_type)] // `!` +#![feature(const_for)] #![feature(const_try)] #![feature(fn_traits)] // `impl FnOnce` #![feature(doc_cfg)] // `#[doc(cfg(...))]` diff --git a/src/r3_core/src/utils/init.rs b/src/r3_core/src/utils/init.rs index a1cca9af75..abb2d6b0b3 100644 --- a/src/r3_core/src/utils/init.rs +++ b/src/r3_core/src/utils/init.rs @@ -38,11 +38,9 @@ impl Init for [T; LEN] { // `<[T; LEN]>::from_fn` is not `const fn` [ref:const_array_from_fn] let mut array = mem::MaybeUninit::uninit_array(); - // `for` is unusable in `const fn` [ref:const_for] - let mut i = 0; - while i < LEN { + // `[T]::iter` is unusable in `const fn` [ref:const_slice_iter] + for i in 0..LEN { array[i] = mem::MaybeUninit::new(T::INIT); - i += 1; } // Safety: `array`'s elements are fully initialized diff --git a/src/r3_core/src/utils/sort.rs b/src/r3_core/src/utils/sort.rs index c6f66ca82f..0cdabc79ec 100644 --- a/src/r3_core/src/utils/sort.rs +++ b/src/r3_core/src/utils/sort.rs @@ -42,7 +42,7 @@ where } // Build the heap in linear time. - // `for` is unusable in `const fn` [ref:const_for] + // `Iterator::rev` is unusable in `const fn` [ref:const_rev_iter] let mut i = v.len() / 2; while i > 0 { i -= 1;