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

Add Box<[T; N]>: IntoIterator without any method dispatch hacks #124108

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Apr 18, 2024

Unlike Box<[T]> (#116607 (comment)), there's a much higher chance that this will not conflict with existing usages since it produces an iterator with the same type before/after this change, but let's test that theory with crater. Any breakage would need to be relying specifically on the expr Box::([...]).into_iter() yielding an iterator specifically of type array::IntoIter<T; N> as it currently does.

Ideally we have fewer migrations that are tangled up in hacks like rustc_skip_during_method_dispatch, so if this crater comes back clean, I'd strongly suggest landing this as-is.

As for the rationale for having this impl at all, I agree (as @clarfonthey pointed out in #124097 (comment)) that it is generally better for any user to not require moving the array out of the box just to turn it into an iterator.

@rustbot
Copy link
Collaborator

rustbot commented Apr 18, 2024

r? @Nilstrieb

rustbot has assigned @Nilstrieb.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Apr 18, 2024
@compiler-errors
Copy link
Member Author

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Apr 18, 2024
@compiler-errors
Copy link
Member Author

why did i rust-timer this -- i plan to use crater lol

bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 18, 2024
…=<try>

[crate] Add `Box<[T; N]>: IntoIterator` without any method dispatch hacks

**Unlike** `Box<[T]>` (rust-lang#116607 (comment)), there's a much higher chance that this will not conflict with existing usages since it produces an iterator with the same type before/after this change, but let's test that theory with crater.

Ideally we have fewer migrations that are tangled up in hacks like `rustc_skip_during_method_dispatch`, so if this crater comes back clean, I'd strongly suggest landing this as-is.

As for the rationale for having this impl at all, I agree (as `@clarfonthey` pointed out in rust-lang#124097 (comment)) that it is generally better for any user to not require moving the array *out* of the box just to turn it into an iterator.
@bors
Copy link
Contributor

bors commented Apr 18, 2024

⌛ Trying commit 78d9b1e with merge 2e5b773...

@compiler-errors
Copy link
Member Author

Well -- I guess Box<[T; N]> technically dispatches to the &[T] impl on edition < 2021 because we skip the [T; N] impl. Anyways, let's see what crater says.

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-17 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
#17 exporting to docker image format
#17 sending tarball 29.3s done
#17 DONE 34.3s
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-17]
---
sccache: Starting the server...
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-17', '--enable-llvm-link-shared', '--set', 'rust.thin-lto-import-instr-limit=10', '--set', 'change-id=99999999', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--enable-new-symbol-mangling']
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-17/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.thin-lto-import-instr-limit := 10
configure: change-id            := 99999999
---
---- [ui] tests/ui/iterators/into-iter-on-arrays-2021.rs stdout ----

error: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/iterators/into-iter-on-arrays-2021.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-2021" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-2021/auxiliary" "--edition=2021"
--- stderr -------------------------------
error[E0308]: mismatched types
##[error]  --> /checkout/tests/ui/iterators/into-iter-on-arrays-2021.rs:13:32
   |
   |
LL |     let _: IntoIter<i32, 10> = Box::new(array).into_iter();
   |            -----------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `IntoIter<i32, 10>`, found `IntoIter<i32>`
   |            expected due to this
   |
   |
   = note: `std::vec::IntoIter<i32>` and `std::array::IntoIter<i32, 10>` have similar names, but are actually distinct types
note: `std::vec::IntoIter<i32>` is defined in crate `alloc`
note: `std::array::IntoIter<i32, 10>` is defined in crate `core`
  --> /rustc/FAKE_PREFIX/library/core/src/array/iter.rs:17:1

error: aborting due to 1 previous error
---
---- [ui] tests/ui/iterators/into-iter-on-arrays-2018.rs stdout ----

error: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/iterators/into-iter-on-arrays-2018.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-2018" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-2018/auxiliary" "--edition=2018"
--- stderr -------------------------------
error[E0308]: mismatched types
##[error]  --> /checkout/tests/ui/iterators/into-iter-on-arrays-2018.rs:18:28
   |
   |
LL |     let _: Iter<'_, i32> = Box::new(array).into_iter();
   |            -------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Iter<'_, i32>`, found `IntoIter<i32>`
   |            expected due to this
   |
   = note: expected struct `std::slice::Iter<'_, i32>`
              found struct `std::vec::IntoIter<i32>`
---

67 LL |     IntoIterator::into_iter([0u8; 33]);
68    |     ++++++++++++++++++++++++         ~
69 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new(small).into_iter();
-    |                     ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new([1, 2]).into_iter();
-    |                      ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new(big).into_iter();
-    |                   ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new([0u8; 33]).into_iter();
-    |                         ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new(Box::new(small)).into_iter();
-    |                               ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new(Box::new([1, 2])).into_iter();
-    |                                ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new(Box::new(big)).into_iter();
-    |                             ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- 
- warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
-    |
-    |
- LL |     Box::new(Box::new([0u8; 33])).into_iter();
-    |                                   ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
-    = warning: this changes meaning in Rust 2021
-    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
- 
- warning: 12 warnings emitted
---
The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-lint/into-iter-on-arrays-lint.stderr
diff of fixed:

21     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
22     //~| WARNING this changes meaning
23 
-     Box::new(small).iter();
+     Box::new(small).into_iter();
25     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
26     //~| WARNING this changes meaning
-     Box::new([1, 2]).iter();
+     Box::new([1, 2]).into_iter();
28     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
29     //~| WARNING this changes meaning
-     Box::new(big).iter();
+     Box::new(big).into_iter();
31     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
32     //~| WARNING this changes meaning
-     Box::new([0u8; 33]).iter();
+     Box::new([0u8; 33]).into_iter();
34     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
35     //~| WARNING this changes meaning


-     Box::new(Box::new(small)).iter();
+     Box::new(Box::new(small)).into_iter();
38     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
39     //~| WARNING this changes meaning
-     Box::new(Box::new([1, 2])).iter();
+     Box::new(Box::new([1, 2])).into_iter();
41     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
42     //~| WARNING this changes meaning
-     Box::new(Box::new(big)).iter();
+     Box::new(Box::new(big)).into_iter();
44     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
45     //~| WARNING this changes meaning
-     Box::new(Box::new([0u8; 33])).iter();
+     Box::new(Box::new([0u8; 33])).into_iter();
47     //~^ WARNING this method call resolves to `<&[T; N] as IntoIterator>::into_iter`
48     //~| WARNING this changes meaning


The actual fixed differed from the expected fixed.
Actual fixed saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-lint/into-iter-on-arrays-lint.fixed
Actual fixed saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-lint/into-iter-on-arrays-lint.fixed
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args iterators/into-iter-on-arrays-lint.rs`

error: 2 errors occurred comparing output.
status: exit status: 0
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/iterators/into-iter-on-arrays-lint.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "-O" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-lint/a" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/iterators/into-iter-on-arrays-lint/auxiliary"
--- stderr -------------------------------
--- stderr -------------------------------
warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
   |
LL |     small.into_iter();
   |           ^^^^^^^^^
   |
   |
   = warning: this changes meaning in Rust 2021
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
   = note: `#[warn(array_into_iter)]` on by default
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
LL |     small.iter();
   |           ~~~~
   |           ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
LL |     IntoIterator::into_iter(small);
   |     ++++++++++++++++++++++++     ~


warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
   |
   |
LL |     [1, 2].into_iter();
   |
   = warning: this changes meaning in Rust 2021
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
   |
LL |     [1, 2].iter();
   |            ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
LL |     IntoIterator::into_iter([1, 2]);
   |     ++++++++++++++++++++++++      ~


warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
   |
LL |     big.into_iter();
   |         ^^^^^^^^^
   |
   |
   = warning: this changes meaning in Rust 2021
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
LL |     big.iter();
   |         ~~~~
   |         ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
LL |     IntoIterator::into_iter(big);
   |     ++++++++++++++++++++++++   ~


warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
   |
LL |     [0u8; 33].into_iter();
   |               ^^^^^^^^^
   |
   |
   = warning: this changes meaning in Rust 2021
   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
   |
LL |     [0u8; 33].iter();
   |               ~~~~
help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
LL |     IntoIterator::into_iter([0u8; 33]);
   |     ++++++++++++++++++++++++         ~

warning: 4 warnings emitted
---
diff of stderr:

76            which is required by `&mut dyn T: Iterator`
77    = help: items from traits can only be used if the trait is implemented and in scope
78    = note: the following traits define an item `cmp`, perhaps you need to implement one of them:
-            candidate #1: `Iterator`
-            candidate #2: `Ord`
+            candidate #1: `Ord`
+    = note: the trait `Iterator` defines an item `cmp`, but is explicitly unimplemented
82 error: aborting due to 4 previous errors
83 



The actual stderr differed from the expected stderr.
Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/traits/method-on-unbounded-type-param/method-on-unbounded-type-param.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args traits/method-on-unbounded-type-param.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/traits/method-on-unbounded-type-param.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/traits/method-on-unbounded-type-param" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/traits/method-on-unbounded-type-param/auxiliary"
--- stderr -------------------------------
--- stderr -------------------------------
error[E0599]: no method named `cmp` found for type parameter `T` in the current scope
   |
   |
LL | fn f<T>(a: T, b: T) -> std::cmp::Ordering {
   |      - method `cmp` not found for this type parameter
LL |     a.cmp(&b) //~ ERROR E0599
   |       ^^^ method cannot be called on `T` due to unsatisfied trait bounds
   = help: items from traits can only be used if the type parameter is bounded by the trait
   = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
   |
LL | fn f<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
   |       ++++++++++
LL | fn f<T: Ord>(a: T, b: T) -> std::cmp::Ordering {


error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
   |
   |
LL |     (&a).cmp(&b) //~ ERROR E0599
   |          ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `T: Ord`
           which is required by `&T: Ord`
           `&T: Iterator`
           which is required by `&mut &T: Iterator`
           `T: Iterator`
           which is required by `&mut T: Iterator`
   = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
   |
LL | fn g<T: Iterator>(a: T, b: T) -> std::cmp::Ordering {
   |       ++++++++++
LL | fn g<T: Ord>(a: T, b: T) -> std::cmp::Ordering {


error[E0599]: the method `cmp` exists for reference `&T`, but its trait bounds were not satisfied
   |
   |
LL |     a.cmp(&b) //~ ERROR E0599
   |       ^^^ method cannot be called on `&T` due to unsatisfied trait bounds
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `T: Ord`
           which is required by `&T: Ord`
           `&T: Iterator`
           which is required by `&mut &T: Iterator`
           `T: Iterator`
           which is required by `&mut T: Iterator`
   = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `cmp`, perhaps you need to restrict type parameter `T` with one of them:
   |
LL | fn h<T: Iterator>(a: &T, b: T) -> std::cmp::Ordering {
   |       ++++++++++
LL | fn h<T: Ord>(a: &T, b: T) -> std::cmp::Ordering {


error[E0599]: the method `cmp` exists for struct `Box<dyn T>`, but its trait bounds were not satisfied
   |
LL | trait T {}
LL | trait T {}
   | ------- doesn't satisfy `dyn T: Iterator` or `dyn T: Ord`
...
LL |     x.cmp(&x); //~ ERROR E0599
   |       ^^^ method cannot be called on `Box<dyn T>` due to unsatisfied trait bounds
   = note: the following trait bounds were not satisfied:
   = note: the following trait bounds were not satisfied:
           `dyn T: Iterator`
           which is required by `Box<dyn T>: Iterator`
           `dyn T: Ord`
           which is required by `Box<dyn T>: Ord`
           `Box<dyn T>: Iterator`
           which is required by `&mut Box<dyn T>: Iterator`
           `dyn T: Iterator`
           which is required by `&mut dyn T: Iterator`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following traits define an item `cmp`, perhaps you need to implement one of them:
           candidate #1: `Ord`
   = note: the trait `Iterator` defines an item `cmp`, but is explicitly unimplemented
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0599`.
------------------------------------------

@bors
Copy link
Contributor

bors commented Apr 18, 2024

☀️ Try build successful - checks-actions
Build commit: 2e5b773 (2e5b7739e5167b731ad5eb628f04a54f932f1fe2)

@rust-timer

This comment has been minimized.

@compiler-errors
Copy link
Member Author

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-124108 created and queued.
🤖 Automatically detected try build 2e5b773
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Apr 18, 2024
@rust-timer

This comment was marked as off-topic.

@craterbot
Copy link
Collaborator

🚧 Experiment pr-124108 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-124108 is completed!
📊 4 regressed and 2 fixed (439535 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the blacklist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Apr 22, 2024
@compiler-errors
Copy link
Member Author

compiler-errors commented Apr 22, 2024

The only regression is derive-visitor 0.3.0:

[INFO] [stdout]  --> tests/test_containers.rs:8:19
[INFO] [stdout]   |
[INFO] [stdout] 8 | #[derive(Default, Drive, DriveMut)]
[INFO] [stdout]   |                   ^^^^^
[INFO] [stdout]   |
[INFO] [stdout]   = note: multiple `impl`s satisfying `Box<[CountMe1; 5]>: Drive` found in the `derive_visitor` crate:
[INFO] [stdout]           - impl<T> Drive for Box<T>
[INFO] [stdout]             where T: Drive;
[INFO] [stdout]           - impl<T> Drive for T
[INFO] [stdout]             where T: 'static, for<'a> &'a T: IntoIterator, for<'a> <&'a T as IntoIterator>::Item: derive_visitor::DerefAndDrive;
[INFO] [stdout]   = note: this error originates in the derive macro `Drive` (in Nightly builds, run with -Z macro-backtrace for more info)

This will not be fixed by adding any method dispatch hacks, so I think we should just land this as-is. I don't think we should block landing this impl on the one breakage.1

Nominating this for T-libs-api for confirmation.

Footnotes

  1. Also, I'm not confident that the set of impls that are present in derive-visitor are actually even coherent/sound. We've been aware of its breakage in the new trait solver for a while: https://github.com/rust-lang/trait-system-refactor-initiative/issues/52

@compiler-errors compiler-errors added the I-libs-api-nominated The issue / PR has been nominated for discussion during a libs-api team meeting. label Apr 22, 2024
@compiler-errors compiler-errors changed the title [crate] Add Box<[T; N]>: IntoIterator without any method dispatch hacks Add Box<[T; N]>: IntoIterator without any method dispatch hacks Apr 22, 2024
@Amanieu Amanieu removed the I-libs-api-nominated The issue / PR has been nominated for discussion during a libs-api team meeting. label Apr 23, 2024
@Amanieu
Copy link
Member

Amanieu commented Apr 23, 2024

Discussed this in the libs-api meeting. The breakage looks acceptable, especially since it only occurs in a test.

@compiler-errors compiler-errors added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Apr 23, 2024
@compiler-errors
Copy link
Member Author

@Amanieu: Would you or someone else from @rust-lang/libs-api like to start an FCP then?

#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
impl<'a, const N: usize, I, A: Allocator> !Iterator for &'a Box<[I; N], A> {}

/// `Box` is fundamental, so coherence needs help understanding these impls are okay.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and the comment above it) are going to show up in public docs right? If so, could these be elaborated on a bit more? Maybe just a short description of what would happen if these impls didn't exist would be sufficient.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah I will make these less esoteric.

@BurntSushi
Copy link
Member

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Apr 23, 2024

Team member @BurntSushi has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Apr 23, 2024
@BurntSushi
Copy link
Member

Unlike Box<[T]> (#116607 (comment)), there's a much higher chance that this will not conflict with existing usages since it produces an iterator with the same type before/after this change, but let's test that theory with crater. Any breakage would need to be relying specifically on the expr Box::([...]).into_iter() yielding an iterator specifically of type array::IntoIter<T; N> as it currently does.

I'm having trouble parsing this. It starts by saying that the type remains the same before/after this change, but the change is actually changing the type from array::IntoIter<T, N> to vec::IntoIter<T>. Can you expand this a bit? I'm sure I'm just misunderstanding something here.

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Apr 23, 2024
@rfcbot
Copy link

rfcbot commented Apr 23, 2024

🔔 This is now entering its final comment period, as per the review above. 🔔

@compiler-errors
Copy link
Member Author

I'm having trouble parsing this. It starts by saying that the type remains the same before/after this change, but the change is actually changing the type from array::IntoIter<T, N> to vec::IntoIter<T>. Can you expand this a bit? I'm sure I'm just misunderstanding something here.

Sorry, I mean the Iterator::Item type doesn't change -- both are Iterator<Item = T>, it's just that the specific iterator type changes; however, I don't believe most people are relying on this specifically.

@BurntSushi
Copy link
Member

Ah I see now. Makes sense!

@scottmcm
Copy link
Member

100% agreed that array::IntoIter is a poor outcome here. See for example in #107634 how adding https://stdrs.dev/nightly/x86_64-unknown-linux-gnu/core/array/drain/struct.Drain.html to deal in pointers -- instead of moving the array into the iterator -- was a big part of making things optimize better. So moving this to give a different iterator is a great improvement.

Unlike #124097 (comment), I'm torn on re-using vec::IntoIter here. Maybe it's fine because compared to the allocation the extra usize is just not a big deal? People might plausibly be using Box<[T; 1 << 16]> for a thin pointer and no-checking-needed indexing (by u16) in a data structure but then not be worried about the extra usize in an iterator that they wouldn't be keeping around. The part of my brain that read Alexandrescu is shouting "capacity strategy template argument that can be zst or usize", but that complexity on the existing type seems questionable.

If we did the simpler vec::IntoIter for it now, would it be possible in future for someone to use a different Allocator parameter to remove the overhead? If that means there'd eventually be "there's a way if you really need it" it might justify sortof-closing the door here...

@scottmcm
Copy link
Member

Undigested thought: is there a way that Box<[T]>s iterator could be the Unsize (sortof) of Box<[T; N]>'s iterator? That might be a more rusty way of doing things than the parameter.

Then we could have mod vec { type IntoIter<T, A> = Box<[T], A>::IntoIter; } to share the implementation from the other direction...

@WaffleLapkin
Copy link
Member

If we had TAIT I could imagine Box::<[T; N]>::IntoIter being opaque (at least if we are not sure if we care about the capacity usize or not), but I don't think TAIT is ready for such usage yet?

@scottmcm
Copy link
Member

Hmm, I didn't actually mean a TAIT. Let's see if I can digest it further.

Suppose we had struct alloc::box::IntoIter<…> such that on a Box<[T], A> you get box::IntoIter<[T], A> and on Box<[T; N], A> you get box::IntoIter<[T; N], A>. Then we make vec::IntoIter<T, A> a type alias for box::IntoIter<[T], A>.

The idea would be to think of that [T] vs [T; N] as a tail of the struct, but of course it's not literally a tail of it, so I don't know if it would actually work out. But if you could "unsize" a box::IntoIter<[T; N], A> into a box::IntoIter<[T], A>, that might help people avoid the monomorphization costs of the array if they want, while also letting people avoid the extra usize in the iterator if they want.

(I don't know if that would actually work, though.)

@WaffleLapkin
Copy link
Member

WaffleLapkin commented Apr 26, 2024

@scottmcm what you are describing is actually quite possible: [playground] (finally, my love for unsizing paid off,,,). Basically what you need is just a CoerceUnsized implementation for box::IntoIter which coerces buf: *mut ArrayOrSliceGeneric (so that we can conditionally store length as metadata of the pointer, while allowing unsize coercion) (IIRC there is some work to make this nicer, but you can do that today too) (it currenlty requires a type like IntoIter<[T], T, A>, but I believe this is fixable with a smarter check).

I really dig your idea, this sounds nice :)

(P.S. to be clear I did not mean you meant TAIT, I just meant that it'd be possible to use TAIT)

@compiler-errors
Copy link
Member Author

While that's a clever idea, it also seems like a lot of work to avoid a single usize from the vec::IntoIter impl. Unless someone on T-libs wants this to be implemented, I'd rather we don't, tbh.

@WaffleLapkin
Copy link
Member

I don't think it's that much work, given that this would replace the existing vec::IntoIter with something only a bit more complex (most of the things don't need to change, only signatures and drop is different).

@scottmcm
Copy link
Member

it also seems like a lot of work

I'm hoping it wouldn't be that bad, actually. Looking at vec::IntoIter,

pub struct IntoIter<
T,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
pub(super) buf: NonNull<T>,
pub(super) phantom: PhantomData<T>,
pub(super) cap: usize,
// the drop impl reconstructs a RawVec from buf, cap and alloc
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
pub(super) alloc: ManuallyDrop<A>,
pub(super) ptr: NonNull<T>,
/// If T is a ZST, this is actually ptr+len. This encoding is picked so that
/// ptr == end is a quick test for the Iterator being empty, that works
/// for both ZST and non-ZST.
/// For non-ZSTs the pointer is treated as `NonNull<T>`
pub(super) end: *const T,
}

if we can "just" change that NonNull<T>+usize to be either NonNull<[T]> or NonNull<[T; N]> accordingly, surprisingly little else would have to change, and it'd save the extra usize. All the iterator stuff working on the ptr+end fields wouldn't have to change at all, for example.

libs-api folks, if the code needed to make it happens turned out to not be too bad, might you be interested? Or is it not worth bothering making a sample PR because you'd not want it anyway?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet