Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bootstrap.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@
# which is also used in places like debuginfo `DW_AT_producer`. This may be useful for
# supplementary build information, like distro-specific package versions.
#
# IMPORTANT: Changing this value changes crate IDs and symbol name mangling, making
# compiled artifacts incompatible. PGO profiles cannot be reused across different
# descriptions, and incremental compilation caches are invalidated. Keep this value
# consistent when reusing build artifacts.
#
# The Rust compiler will differentiate between versions of itself, including
# based on this string, which means that if you wish to be compatible with
# upstream Rust you need to set this to "". However, note that if you set this to "" but
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ impl MetadataLoader for DefaultMetadataLoader {
format!("failed to parse aix dylib '{}': {}", path.display(), e)
})?;

match archive.members().exactly_one() {
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
match Itertools::exactly_one(archive.members()) {
Ok(lib) => {
let lib = lib.map_err(|e| {
format!("failed to parse aix dylib '{}': {}", path.display(), e)
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ impl<'a> Formatter<'a> {
//
// 2) Placeholders representation (e.g. format_args!("hello {name}\n"))
// ┌────────────────────────────────┐
// template: │ *const u8 │ ─▷ b"\x06hello \x80\x01\n\x00"
// template: │ *const u8 │ ─▷ b"\x06hello \xC0\x01\n\x00"
// ├────────────────────────────────┤
// args: │ &'a [Argument<'a>; _] 0│ (lower bit is 0 due to alignment of Argument type)
// └────────────────────────────────┘
Expand Down
56 changes: 56 additions & 0 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4034,6 +4034,62 @@ pub trait Iterator {
{
unreachable!("Always specialized");
}

/// Checks if the iterator contains *exactly* one element.
/// If so, returns this one element.
///
/// See also [`collect_array`](Iterator::collect_array) for lengths other than `1`.
///
/// # Examples
///
/// ```
/// #![feature(exact_length_collection)]
///
/// assert_eq!([1].into_iter().exactly_one(), Some(1));
/// assert_eq!([].into_iter().exactly_one(), None::<()>);
///
/// // There is exactly one even integer in the array:
/// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 0).exactly_one(), Some(2));
/// // But there are two odds, which is too many:
/// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 1).exactly_one(), None);
/// ```
#[inline]
#[unstable(feature = "exact_length_collection", issue = "149266")]
fn exactly_one(self) -> Option<Self::Item>
where
Self: Sized,
{
self.collect_array::<1>().map(|[i]| i)
}

/// Checks if an iterator has *exactly* `N` elements.
/// If so, returns those `N` elements in an array.
///
/// See also [`exactly_one`](Iterator::exactly_one) when expecting a single element.
///
/// # Examples
///
/// ```
/// #![feature(exact_length_collection)]
///
/// assert_eq!([1, 2, 3, 4].into_iter().collect_array(), Some([1, 2, 3, 4]));
/// assert_eq!([1, 2].into_iter().chain([3, 4]).collect_array(), Some([1, 2, 3, 4]));
///
/// // Iterator contains too few elements:
/// assert_eq!([1, 2].into_iter().collect_array::<4>(), None);
/// // Iterator contains too many elements:
/// assert_eq!([1, 2, 3, 4, 5].into_iter().collect_array::<4>(), None);
/// // Taking 4 makes it work again:
/// assert_eq!([1, 2, 3, 4, 5].into_iter().take(4).collect_array(), Some([1, 2, 3, 4]));
/// ```
#[inline]
#[unstable(feature = "exact_length_collection", issue = "149266")]
fn collect_array<const N: usize>(mut self) -> Option<[Self::Item; N]>
where
Self: Sized,
{
self.next_chunk().ok().filter(|_| self.next().is_none())
}
}

trait SpecIterEq<B: Iterator>: Iterator {
Expand Down
24 changes: 20 additions & 4 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ macro_rules! int_impl {
///
/// On big endian this is a no-op. On little endian the bytes are swapped.
///
/// See also [from_be_bytes()](Self::from_be_bytes).
///
/// # Examples
///
/// ```
Expand Down Expand Up @@ -402,6 +404,8 @@ macro_rules! int_impl {
///
/// On little endian this is a no-op. On big endian the bytes are swapped.
///
/// See also [from_le_bytes()](Self::from_le_bytes).
///
/// # Examples
///
/// ```
Expand All @@ -428,9 +432,15 @@ macro_rules! int_impl {
}
}

/// Converts `self` to big endian from the target's endianness.
/// Swaps bytes of `self` on little endian targets.
///
/// On big endian this is a no-op. On little endian the bytes are swapped.
/// On big endian this is a no-op.
///
/// The returned value has the same type as `self`, and will be interpreted
/// as (a potentially different) value of a native-endian
#[doc = concat!("`", stringify!($SelfT), "`.")]
///
/// See [`to_be_bytes()`](Self::to_be_bytes) for a type-safe alternative.
///
/// # Examples
///
Expand Down Expand Up @@ -459,9 +469,15 @@ macro_rules! int_impl {
}
}

/// Converts `self` to little endian from the target's endianness.
/// Swaps bytes of `self` on big endian targets.
///
/// On little endian this is a no-op. On big endian the bytes are swapped.
/// On little endian this is a no-op.
///
/// The returned value has the same type as `self`, and will be interpreted
/// as (a potentially different) value of a native-endian
#[doc = concat!("`", stringify!($SelfT), "`.")]
///
/// See [`to_le_bytes()`](Self::to_le_bytes) for a type-safe alternative.
///
/// # Examples
///
Expand Down
4 changes: 3 additions & 1 deletion src/bootstrap/src/core/build_steps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ pub(crate) fn is_ci_llvm_available_for_target(
("aarch64-unknown-linux-gnu", false),
("aarch64-apple-darwin", false),
("aarch64-pc-windows-msvc", false),
("i686-pc-windows-gnu", false),
("i686-pc-windows-msvc", false),
("i686-unknown-linux-gnu", false),
("x86_64-unknown-linux-gnu", true),
Expand All @@ -215,9 +214,11 @@ pub(crate) fn is_ci_llvm_available_for_target(
("x86_64-pc-windows-msvc", true),
// tier 2 with host tools
("aarch64-unknown-linux-musl", false),
("aarch64-pc-windows-gnullvm", false),
("arm-unknown-linux-gnueabi", false),
("arm-unknown-linux-gnueabihf", false),
("armv7-unknown-linux-gnueabihf", false),
("i686-pc-windows-gnu", false),
("loongarch64-unknown-linux-gnu", false),
("loongarch64-unknown-linux-musl", false),
("powerpc-unknown-linux-gnu", false),
Expand All @@ -226,6 +227,7 @@ pub(crate) fn is_ci_llvm_available_for_target(
("powerpc64le-unknown-linux-musl", false),
("riscv64gc-unknown-linux-gnu", false),
("s390x-unknown-linux-gnu", false),
("x86_64-pc-windows-gnullvm", true),
("x86_64-unknown-freebsd", false),
("x86_64-unknown-illumos", false),
("x86_64-unknown-linux-musl", false),
Expand Down
2 changes: 2 additions & 0 deletions src/bootstrap/src/core/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo
// All tier 1 targets and tier 2 targets with host tools.
const SUPPORTED_PLATFORMS: &[&str] = &[
"aarch64-apple-darwin",
"aarch64-pc-windows-gnullvm",
"aarch64-pc-windows-msvc",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
Expand All @@ -465,6 +466,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo
"s390x-unknown-linux-gnu",
"x86_64-apple-darwin",
"x86_64-pc-windows-gnu",
"x86_64-pc-windows-gnullvm",
"x86_64-pc-windows-msvc",
"x86_64-unknown-freebsd",
"x86_64-unknown-illumos",
Expand Down
6 changes: 4 additions & 2 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,8 @@ pub(crate) fn print_impl(
}
if impl_.kind.is_fake_variadic()
&& let Some(generics) = ty.generics()
&& let Ok(inner_type) = generics.exactly_one()
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
&& let Ok(inner_type) = Itertools::exactly_one(generics)
{
let last = ty.last();
if f.alternate() {
Expand Down Expand Up @@ -1206,7 +1207,8 @@ impl clean::Impl {
}
} else if let clean::Type::Path { path } = type_
&& let Some(generics) = path.generics()
&& let Ok(ty) = generics.exactly_one()
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
&& let Ok(ty) = Itertools::exactly_one(generics)
&& self.kind.is_fake_variadic()
{
print_anchor(path.def_id(), path.last(), cx).fmt(f)?;
Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -5050,9 +5050,11 @@ ${obj.displayPath}<span class="${type}">${name}</span>\
if (query.proposeCorrectionFrom !== null && isTypeSearch) {
const orig = query.proposeCorrectionFrom;
const targ = query.proposeCorrectionTo;
correctionOutput = "<h3 class=\"search-corrections\">" +
`Type "${orig}" not found and used as generic parameter. ` +
`Consider searching for "${targ}" instead.</h3>`;
let message = `Type "${orig}" not found and used as generic parameter.`;
if (targ !== null) {
message += ` Consider searching for "${targ}" instead.`;
}
correctionOutput = `<h3 class="search-corrections">${message}</h3>`;
}
if (firstResult.value) {
if (correctionOutput !== "") {
Expand Down
6 changes: 4 additions & 2 deletions src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
(matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id)))
.then_some((v.def_id, v.span))
});
if let Ok((id, span)) = iter.exactly_one()
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
if let Ok((id, span)) = Itertools::exactly_one(iter)
&& !find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::NonExhaustive(..))
{
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
Expand All @@ -104,7 +105,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
.iter()
.filter(|field| !cx.effective_visibilities.is_exported(field.def_id));
if fields.len() > 1
&& let Ok(field) = private_fields.exactly_one()
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
&& let Ok(field) = Itertools::exactly_one(private_fields)
&& let TyKind::Tup([]) = field.ty.kind
{
span_lint_and_then(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,8 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> {
&& let DelimiterKind::Parenthesis | DelimiterKind::Invisible = sub.delimiter.kind
{
tt =
tt_iter.exactly_one().map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?;
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
Itertools::exactly_one(tt_iter).map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?;
}

match tt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
let name_ref = ctx.find_node_at_offset::<ast::NameRef>()?;
let mcall = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
let receiver = mcall.receiver()?;
let closure_body = mcall.arg_list()?.args().exactly_one().ok()?;
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
let closure_body = Itertools::exactly_one(mcall.arg_list()?.args()).ok()?;
let closure_body = match closure_body {
ast::Expr::ClosureExpr(expr) => expr.body()?,
_ => return None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn extract_range(iterable: &ast::Expr) -> Option<(ast::Expr, Option<ast::Expr>,
(range.start()?, range.end(), make::expr_literal("1").into(), inclusive)
}
ast::Expr::MethodCallExpr(call) if call.name_ref()?.text() == "step_by" => {
let [step] = call.arg_list()?.args().collect_array()?;
let [step] = Itertools::collect_array(call.arg_list()?.args())?;
let (start, end, _, inclusive) = extract_range(&call.receiver()?)?;
(start, end, step, inclusive)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
let completions = completion_list_with_config_raw(TEST_CONFIG, ra_fixture, true, None);
let (db, position) = position(ra_fixture);
let mut actual = db.file_text(position.file_id).text(&db).to_string();
completions
.into_iter()
.exactly_one()
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
Itertools::exactly_one(completions.into_iter())
.expect("more than one completion")
.text_edit
.apply(&mut actual);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ impl Project<'_> {
let mut buf = Vec::new();
flags::Lsif::run(
flags::Lsif {
path: tmp_dir_path.join(self.roots.iter().exactly_one().unwrap()).into(),
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
path: tmp_dir_path.join(Itertools::exactly_one(self.roots.iter()).unwrap()).into(),
exclude_vendored_libraries: false,
},
&mut buf,
Expand Down
21 changes: 21 additions & 0 deletions tests/rustdoc-js/generics-trait.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,24 @@ const EXPECTED = [
],
},
];

const PARSED = [
{
'query': 'Result<SomeTraiz>',
'userQuery': 'Result<SomeTraiz>',
'foundElems': 1,
'returned': [],
'error': null,
'proposeCorrectionFrom': 'SomeTraiz',
'proposeCorrectionTo': 'SomeTrait',
},
{
'query': 'Result<NoSuchTrait>',
'userQuery': 'Result<NoSuchTrait>',
'foundElems': 1,
'returned': [],
'error': null,
'proposeCorrectionFrom': 'NoSuchTrait',
'proposeCorrectionTo': null,
},
];
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! Regression test for issue <https://github.com/rust-lang/rust/issues/51515>
//! Test that assigning through an immutable reference (`&`) correctly yields
//! an assignment error (E0594) and suggests using a mutable reference.
fn main() {
let foo = &16;
//~^ HELP consider changing this to be a mutable reference
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
--> $DIR/issue-51515.rs:4:5
--> $DIR/assignment-to-immutable-ref.rs:8:5
|
LL | *foo = 32;
| ^^^^^^^^^ `foo` is a `&` reference, so it cannot be written to
Expand All @@ -10,7 +10,7 @@ LL | let foo = &mut 16;
| +++

error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
--> $DIR/issue-51515.rs:8:5
--> $DIR/assignment-to-immutable-ref.rs:12:5
|
LL | *bar = 64;
| ^^^^^^^^^ `bar` is a `&` reference, so it cannot be written to
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/closures/box-generic-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Regression test for issue <https://github.com/rust-lang/rust/issues/51154>
//! Test that anonymous closure types cannot be coerced to a generic type
//! parameter (F: FnMut()) when trying to box them.

fn foo<F: FnMut()>() {
let _: Box<F> = Box::new(|| ());
//~^ ERROR mismatched types
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/issue-51154.rs:2:30
--> $DIR/box-generic-closure.rs:6:30
|
LL | fn foo<F: FnMut()>() {
| - expected this type parameter
Expand All @@ -9,7 +9,7 @@ LL | let _: Box<F> = Box::new(|| ());
| arguments to this function are incorrect
|
= note: expected type parameter `F`
found closure `{closure@$DIR/issue-51154.rs:2:30: 2:32}`
found closure `{closure@$DIR/box-generic-closure.rs:6:30: 6:32}`
= help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`
note: associated function defined here
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/type-dependent/issue-71805.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::mem::MaybeUninit;
trait CollectSlice<'a>: Iterator {
fn inner_array<const N: usize>(&mut self) -> [Self::Item; N];

fn collect_array<const N: usize>(&mut self) -> [Self::Item; N] {
fn custom_collect_array<const N: usize>(&mut self) -> [Self::Item; N] {
let result = self.inner_array();
assert!(self.next().is_none());
result
Expand Down Expand Up @@ -34,5 +34,5 @@ where

fn main() {
let mut foos = [0u64; 9].iter().cloned();
let _bar: [u64; 9] = foos.collect_array::<9_usize>();
let _bar: [u64; 9] = foos.custom_collect_array::<9_usize>();
}
6 changes: 0 additions & 6 deletions tests/ui/issues/issue-51154.rs

This file was deleted.

Loading
Loading