From 75657d5289b9ac3ca4b72279fb700a037975eb57 Mon Sep 17 00:00:00 2001 From: schneems Date: Fri, 17 Mar 2023 12:42:40 -0500 Subject: [PATCH 01/12] Add Command environment variable inheritance docs The interaction between the environment variable methods can be confusing. Specifically `env_clear` and `remove_env` have a side effects not mentioned: they disable inheriting environment variables from the parent process. I wanted to fully document this behavior as well as explain relevant edge cases in each of the `Command` env methods. This is further confused by the return of `get_envs` which will return key/None if `remove_env` has been used, but an empty iterator if `env_clear` has been called. Or a non-empty iterator if `env_clear` was called and later explicit mappings are added. Currently there is no way (that I'm able to find) of observing whether or not the internal `env_clear=true` been toggled on the `Command` struct via its public API. Ultimately environment variable mappings can be in one of several states: - Explicitly set value (via `envs` / `env`) will take precedence over parent mapping - Not explicitly set, will inherit mapping from parent - Explicitly removed via `remove_env`, this single mapping will not inherit from parent - Implicitly removed via `env_clear`, no mappings will inherit from parent I tried to represent this in the relevant sections of the docs. This is my second ever doc PR (whoop!). I'm happy to take specific or general doc feedback. Also happy to explain the logic behind any changes or additions I made. --- library/std/src/process.rs | 76 ++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 1952e19e60720..086eae3344046 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -644,10 +644,19 @@ impl Command { self } - /// Inserts or updates an environment variable mapping. + /// Inserts or updates an explicit environment variable mapping. /// - /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, - /// and case-sensitive on all other platforms. + /// This method allows you to add an environment variable mapping to the spawned process or + /// overwrite a previously set value. You can use [`Command::envs`] to set multiple environment + /// variables simultaneously. + /// + /// Child processes will inherit environment variables from their parent process by default. + /// Environment variables explicitly set using [`Command::env`] take precedence over inherited + /// variables. You can disable environment variable inheritance entirely using + /// [`Command::env_clear`] or for a single key using [`Command::env_remove`]. + /// + /// Note that environment variable names are case-insensitive (but + /// case-preserving) on Windows and case-sensitive on all other platforms. /// /// # Examples /// @@ -671,7 +680,19 @@ impl Command { self } - /// Adds or updates multiple environment variable mappings. + /// Inserts or updates multiple explicit environment variable mappings. + /// + /// This method allows you to add multiple environment variable mappings to the spawned process + /// or overwrite previously set values. You can use [`Command::env`] to set a single environment + /// variable. + /// + /// Child processes will inherit environment variables from their parent process by default. + /// Environment variables explicitly set using [`Command::envs`] take precedence over inherited + /// variables. You can disable environment variable inheritance entirely using + /// [`Command::env_clear`] or for a single key using [`Command::env_remove`]. + /// + /// Note that environment variable names are case-insensitive (but case-preserving) on Windows + /// and case-sensitive on all other platforms. /// /// # Examples /// @@ -708,7 +729,18 @@ impl Command { self } - /// Removes an environment variable mapping. + /// Removes an explicitly set environment variable and prevents inheriting it from a parent + /// process. + /// + /// This method will remove the explicit value of an environment variable set via + /// [`Command::env`] or [`Command::envs`]. In addition, it will prevent the spawned child + /// process from inheriting that environment variable from its parent process. + /// + /// After calling [`Command::env_remove`], the value associated with its key from + /// [`Command::get_envs`] will be [`None`]. + /// + /// To clear all explicitly set environment variables and disable all environment variable + /// inheritance, you can use [`Command::env_clear`]. /// /// # Examples /// @@ -728,7 +760,17 @@ impl Command { self } - /// Clears the entire environment map for the child process. + /// Clears all explicitly set environment variables and prevents inheriting any parent process + /// environment variables. + /// + /// This method will remove all explicitly added environment variables set via [`Command::env`] + /// or [`Command::envs`]. In addition, it will prevent the spawned child process from inheriting + /// any environment variable from its parent process. + /// + /// After calling [`Command::env_remove`], the iterator from [`Command::get_envs`] will be + /// empty. + /// + /// You can use [`Command::env_remove`] to clear a single mapping. /// /// # Examples /// @@ -980,17 +1022,21 @@ impl Command { CommandArgs { inner: self.inner.get_args() } } - /// Returns an iterator of the environment variables that will be set when - /// the process is spawned. + /// Returns an iterator of the environment variables explicitly set for the child process. + /// + /// Environment variables explicitly set using [`Command::env`], [`Command::envs`], and + /// [`Command::env_remove`] can be retrieved with this method. + /// + /// Note that this output does not include environment variables inherited from the parent + /// process. /// - /// Each element is a tuple `(&OsStr, Option<&OsStr>)`, where the first - /// value is the key, and the second is the value, which is [`None`] if - /// the environment variable is to be explicitly removed. + /// Each element is a tuple key/value pair `(&OsStr, Option<&OsStr>)`. A [`None`] value + /// indicates its key was explicitly removed via [`Command::env_clear`]. The associated key for + /// the [`None`] value will no longer inherit from its parent process. /// - /// This only includes environment variables explicitly set with - /// [`Command::env`], [`Command::envs`], and [`Command::env_remove`]. It - /// does not include environment variables that will be inherited by the - /// child process. + /// An empty iterator can indicate that no explicit mappings were added or that + /// [`Command::env_clear`] was called. After calling [`Command::env_clear`], the child process + /// will not inherit any environment variables from its parent process. /// /// # Examples /// From 8d4cccd168772849895492fad9486c6f6c7a74f4 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 4 Apr 2023 21:59:06 +0100 Subject: [PATCH 02/12] Add links from `core::cmp` derives to their traits --- library/core/src/cmp.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 5b5f55d0e65b0..55331475aff2a 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -231,7 +231,8 @@ pub trait PartialEq { } } -/// Derive macro generating an impl of the trait `PartialEq`. +/// Derive macro generating an impl of the trait [`PartialEq`]. +/// The behavior of this macro is described in detail [here](PartialEq#derivable). #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics, structural_match)] @@ -297,7 +298,7 @@ pub trait Eq: PartialEq { fn assert_receiver_is_total_eq(&self) {} } -/// Derive macro generating an impl of the trait `Eq`. +/// Derive macro generating an impl of the trait [`Eq`]. #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics, derive_eq, structural_match, no_coverage)] @@ -859,7 +860,8 @@ pub trait Ord: Eq + PartialOrd { } } -/// Derive macro generating an impl of the trait `Ord`. +/// Derive macro generating an impl of the trait [`Ord`]. +/// The behavior of this macro is described in detail [here](Ord#derivable). #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics)] @@ -1138,7 +1140,8 @@ pub trait PartialOrd: PartialEq { } } -/// Derive macro generating an impl of the trait `PartialOrd`. +/// Derive macro generating an impl of the trait [`PartialOrd`]. +/// The behavior of this macro is described in detail [here](PartialOrd#derivable). #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics)] From d9f99c36fe5122618a44caf393f9743e84a38c19 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 9 Apr 2023 14:29:16 +0200 Subject: [PATCH 03/12] Use `Display` in top-level example for `PanicInfo` --- library/core/src/panic/panic_info.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index 0d385c9d18744..06fbe083ca13d 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -15,14 +15,10 @@ use crate::panic::Location; /// use std::panic; /// /// panic::set_hook(Box::new(|panic_info| { -/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() { -/// println!("panic occurred: {s:?}"); -/// } else { -/// println!("panic occurred"); -/// } +/// println!("panic occurred: {panic_info}"); /// })); /// -/// panic!("Normal panic"); +/// panic!("critical system failure"); /// ``` #[lang = "panic_info"] #[stable(feature = "panic_hooks", since = "1.10.0")] From e612d785d75b84832725f3c265592c0e512f2ed3 Mon Sep 17 00:00:00 2001 From: Richard Schneeman Date: Sun, 9 Apr 2023 09:21:19 -0500 Subject: [PATCH 04/12] Apply suggestions from code review Fixes documentation. I wrote `env_clear` when I meant `env_remove`. Good catch. Co-authored-by: Josh Stone --- library/std/src/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 086eae3344046..aeb9897e5e61f 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1031,7 +1031,7 @@ impl Command { /// process. /// /// Each element is a tuple key/value pair `(&OsStr, Option<&OsStr>)`. A [`None`] value - /// indicates its key was explicitly removed via [`Command::env_clear`]. The associated key for + /// indicates its key was explicitly removed via [`Command::env_remove`]. The associated key for /// the [`None`] value will no longer inherit from its parent process. /// /// An empty iterator can indicate that no explicit mappings were added or that From a0daf22b95ff1cd3f7ac55ea9370987535f3134d Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:07:29 +0200 Subject: [PATCH 05/12] Fix typos in library --- library/core/src/intrinsics/mir.rs | 2 +- library/core/src/slice/sort.rs | 2 +- library/core/src/str/pattern.rs | 2 +- library/std/src/sys/unix/fs.rs | 2 +- library/std/src/sys/windows/c/errors.rs | 2 +- library/std/src/sys_common/thread_parking/id.rs | 2 +- library/test/src/lib.rs | 10 +++++----- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 6690c1a76d5f0..3f6c445af7b66 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -246,7 +246,7 @@ //! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the //! otherwise branch. //! - [`Call`] has an associated function as well. The third argument of this function is a normal -//! function call expresion, for example `my_other_function(a, 5)`. +//! function call expression, for example `my_other_function(a, 5)`. //! #![unstable( diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 2333f60a8889b..07fd96f929586 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -1486,7 +1486,7 @@ where } /// Finds a streak of presorted elements starting at the beginning of the slice. Returns the first -/// value that is not part of said streak, and a bool denoting wether the streak was reversed. +/// value that is not part of said streak, and a bool denoting whether the streak was reversed. /// Streaks can be increasing or decreasing. fn find_streak(v: &[T], is_less: &mut F) -> (usize, bool) where diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 19da6d2fbecbc..e3a464a1c51a9 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -1891,7 +1891,7 @@ unsafe fn small_slice_eq(x: &[u8], y: &[u8]) -> bool { // SAFETY: Via the conditional above, we know that both `px` and `py` // have the same length, so `px < pxend` implies that `py < pyend`. - // Thus, derefencing both `px` and `py` in the loop below is safe. + // Thus, dereferencing both `px` and `py` in the loop below is safe. // // Moreover, we set `pxend` and `pyend` to be 4 bytes before the actual // end of `px` and `py`. Thus, the final dereference outside of the diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 7566fafda24a9..b29a51f219291 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1892,7 +1892,7 @@ mod remove_dir_impl { // file descriptor is automatically closed by libc::closedir() now, so give up ownership let new_parent_fd = dir_fd.into_raw_fd(); // a valid root is not needed because we do not call any functions involving the full path - // of the DirEntrys. + // of the `DirEntry`s. let dummy_root = PathBuf::new(); let inner = InnerReadDir { dirp, root: dummy_root }; Ok((ReadDir::new(inner), new_parent_fd)) diff --git a/library/std/src/sys/windows/c/errors.rs b/library/std/src/sys/windows/c/errors.rs index 23dcc119db9f6..ad8da19b6daa8 100644 --- a/library/std/src/sys/windows/c/errors.rs +++ b/library/std/src/sys/windows/c/errors.rs @@ -12,7 +12,7 @@ pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910; pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014; pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705; -// The followiung list was obtained from +// The following list was obtained from // `/usr/x86_64-w64-mingw32/include/winerror.h` // in the Debian package // mingw-w64_6.0.0-3_all.deb diff --git a/library/std/src/sys_common/thread_parking/id.rs b/library/std/src/sys_common/thread_parking/id.rs index 575988ec760c7..15042fc3beecb 100644 --- a/library/std/src/sys_common/thread_parking/id.rs +++ b/library/std/src/sys_common/thread_parking/id.rs @@ -79,7 +79,7 @@ impl Parker { park_timeout(dur, self.state.as_ptr().addr()); // Swap to ensure that we observe all state changes with acquire // ordering, even if the state has been changed after the timeout - // occured. + // occurred. self.state.swap(EMPTY, Acquire); } } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 88d8e5fe97ad7..ae3a65d5ea6e8 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -220,14 +220,14 @@ pub fn assert_test_result(result: T) -> Result<(), String> { struct FilteredTests { tests: Vec<(TestId, TestDescAndFn)>, - benchs: Vec<(TestId, TestDescAndFn)>, + benches: Vec<(TestId, TestDescAndFn)>, next_id: usize, } impl FilteredTests { fn add_bench(&mut self, desc: TestDesc, testfn: TestFn) { let test = TestDescAndFn { desc, testfn }; - self.benchs.push((TestId(self.next_id), test)); + self.benches.push((TestId(self.next_id), test)); self.next_id += 1; } fn add_test(&mut self, desc: TestDesc, testfn: TestFn) { @@ -246,7 +246,7 @@ impl FilteredTests { self.add_test(desc, testfn); } fn total_len(&self) -> usize { - self.tests.len() + self.benchs.len() + self.tests.len() + self.benches.len() } } @@ -291,7 +291,7 @@ where let tests_len = tests.len(); - let mut filtered = FilteredTests { tests: Vec::new(), benchs: Vec::new(), next_id: 0 }; + let mut filtered = FilteredTests { tests: Vec::new(), benches: Vec::new(), next_id: 0 }; for test in filter_tests(opts, tests) { let mut desc = test.desc; @@ -458,7 +458,7 @@ where if opts.bench_benchmarks { // All benchmarks run at the end, in serial. - for (id, b) in filtered.benchs { + for (id, b) in filtered.benches { let event = TestEvent::TeWait(b.desc.clone()); notify_about_test_event(event)?; let join_handle = run_test(opts, false, id, b, run_strategy, tx.clone()); From ad2b34d0e37e2f968f226e2401bcb894207ca1c5 Mon Sep 17 00:00:00 2001 From: KaDiWa Date: Tue, 9 Aug 2022 02:14:43 +0200 Subject: [PATCH 06/12] remove some unneeded imports --- library/alloc/benches/btree/map.rs | 1 - library/alloc/benches/vec.rs | 2 +- library/alloc/src/boxed.rs | 7 +--- .../alloc/src/collections/binary_heap/mod.rs | 4 +- library/alloc/src/collections/btree/map.rs | 5 +-- .../alloc/src/collections/btree/map/tests.rs | 3 +- library/alloc/src/collections/btree/set.rs | 4 +- .../alloc/src/collections/btree/set/tests.rs | 1 - library/alloc/src/collections/linked_list.rs | 3 +- .../src/collections/vec_deque/into_iter.rs | 1 - .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/raw_vec.rs | 1 - library/alloc/src/rc.rs | 22 +++++----- library/alloc/src/string.rs | 4 +- library/alloc/src/sync.rs | 13 +++--- library/alloc/src/vec/cow.rs | 1 - library/alloc/src/vec/into_iter.rs | 2 +- library/alloc/src/vec/mod.rs | 7 +--- library/core/src/iter/sources/repeat_with.rs | 1 - library/core/src/iter/traits/iterator.rs | 1 - library/core/src/net/parser.rs | 2 +- library/core/src/primitive_docs.rs | 6 --- library/core/src/sync/exclusive.rs | 3 -- .../crates/core_simd/src/masks/full_masks.rs | 2 +- library/proc_macro/src/bridge/fxhash.rs | 2 - library/proc_macro/src/lib.rs | 6 +-- library/std/src/collections/hash/map.rs | 1 - library/std/src/collections/hash/set.rs | 1 - library/std/src/collections/mod.rs | 2 - library/std/src/ffi/os_str.rs | 1 - library/std/src/io/error.rs | 1 - library/std/src/keyword_docs.rs | 2 +- library/std/src/path.rs | 42 +++++++++---------- library/std/src/prelude/mod.rs | 6 +-- library/std/src/primitive_docs.rs | 6 --- .../std/src/sys/sgx/abi/usercalls/alloc.rs | 1 - library/std/src/sys/unix/futex.rs | 2 - library/std/src/sys/unix/os.rs | 1 - .../src/sys/unix/process/process_fuchsia.rs | 2 - library/std/src/sys_common/net.rs | 1 - src/bootstrap/cache.rs | 3 +- src/librustdoc/clean/mod.rs | 1 - src/librustdoc/clean/types.rs | 3 +- src/librustdoc/config.rs | 1 - src/librustdoc/html/markdown.rs | 1 - src/librustdoc/html/render/mod.rs | 1 - src/librustdoc/html/render/search_index.rs | 2 +- src/librustdoc/json/conversions.rs | 1 - src/librustdoc/lib.rs | 1 - src/tools/bump-stage0/src/main.rs | 1 - src/tools/tidy/src/bins.rs | 4 +- src/tools/tidy/src/pal.rs | 1 - .../src/raw_emitter.rs | 1 - .../unicode-table-generator/src/skiplist.rs | 1 - tests/ui/hygiene/panic-location.run.stderr | 2 +- 55 files changed, 64 insertions(+), 135 deletions(-) diff --git a/library/alloc/benches/btree/map.rs b/library/alloc/benches/btree/map.rs index 1f6b87fb0e40f..ec1b0a8eba039 100644 --- a/library/alloc/benches/btree/map.rs +++ b/library/alloc/benches/btree/map.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::iter::Iterator; use std::ops::RangeBounds; use std::vec::Vec; diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 663f6b9dd1c9c..c1d3e1bdfe79d 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -1,5 +1,5 @@ use rand::RngCore; -use std::iter::{repeat, FromIterator}; +use std::iter::repeat; use test::{black_box, Bencher}; #[bench] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 09041bb119bb7..7f88327bf190a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -150,16 +150,13 @@ use core::any::Any; use core::async_iter::AsyncIterator; use core::borrow; use core::cmp::Ordering; -use core::convert::{From, TryFrom}; use core::error::Error; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; -#[cfg(not(no_global_oom_handling))] -use core::iter::FromIterator; -use core::iter::{FusedIterator, Iterator}; +use core::iter::FusedIterator; use core::marker::Tuple; -use core::marker::{Unpin, Unsize}; +use core::marker::Unsize; use core::mem; use core::ops::{ CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver, diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index bc86125c7c33c..8aa4d342e6e37 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -144,7 +144,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::fmt; -use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; +use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; use core::mem::{self, swap, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{Deref, DerefMut}; @@ -263,7 +263,6 @@ mod tests; /// more detailed analysis. /// /// [`core::cmp::Reverse`]: core::cmp::Reverse -/// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell /// [push]: BinaryHeap::push @@ -1418,7 +1417,6 @@ impl FusedIterator for Iter<'_, T> {} /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BinaryHeap::into_iter -/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 61db46314b780..7b378ccc01adb 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -3,7 +3,7 @@ use core::borrow::Borrow; use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; -use core::iter::{FromIterator, FusedIterator}; +use core::iter::FusedIterator; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; use core::ops::{Bound, Index, RangeBounds}; @@ -420,7 +420,6 @@ impl<'a, K: 'a, V: 'a> Default for IterMut<'a, K, V> { /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter -/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct IntoIter< @@ -650,7 +649,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { // avoid moving the allocator - mem::drop(BTreeMap { + drop(BTreeMap { root: mem::replace(&mut self.root, None), length: mem::replace(&mut self.length, 0), alloc: self.alloc.clone(), diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 76c2f27b46634..1c6ed0b4f8bc4 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -9,8 +9,7 @@ use crate::testing::ord_chaos::{Cyclic3, Governed, Governor}; use crate::testing::rng::DeterministicRng; use crate::vec::Vec; use std::cmp::Ordering; -use std::convert::TryFrom; -use std::iter::{self, FromIterator}; +use std::iter; use std::mem; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::ops::RangeBounds; diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index a7cb3948aa112..232a017314e5e 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -4,7 +4,7 @@ use core::cmp::Ordering::{self, Equal, Greater, Less}; use core::cmp::{max, min}; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; -use core::iter::{FromIterator, FusedIterator, Peekable}; +use core::iter::{FusedIterator, Peekable}; use core::mem::ManuallyDrop; use core::ops::{BitAnd, BitOr, BitXor, RangeBounds, Sub}; @@ -30,7 +30,6 @@ use crate::alloc::{Allocator, Global}; /// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case /// logarithmic and amortized constant time per item returned. /// -/// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell /// @@ -147,7 +146,6 @@ impl fmt::Debug for Iter<'_, T> { /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BTreeSet#method.into_iter -/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IntoIter< diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 7b8d41a603176..a7c839d77ed4c 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -4,7 +4,6 @@ use crate::testing::rng::DeterministicRng; use crate::vec::Vec; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; -use std::iter::FromIterator; use std::ops::Bound::{Excluded, Included}; use std::panic::{catch_unwind, AssertUnwindSafe}; diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 080a4a14eda6e..1743a155c5abf 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -15,7 +15,7 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; -use core::iter::{FromIterator, FusedIterator}; +use core::iter::FusedIterator; use core::marker::PhantomData; use core::mem; use core::ptr::NonNull; @@ -130,7 +130,6 @@ impl fmt::Debug for IterMut<'_, T> { /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: LinkedList::into_iter -/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index e2b40f7912e0f..d9e274df0f5f2 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -12,7 +12,6 @@ use super::VecDeque; /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: VecDeque::into_iter -/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter< diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 05dbcdc904e05..8916b42eda05e 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -10,7 +10,7 @@ use core::cmp::{self, Ordering}; use core::fmt; use core::hash::{Hash, Hasher}; -use core::iter::{repeat_n, repeat_with, ByRefSized, FromIterator}; +use core::iter::{repeat_n, repeat_with, ByRefSized}; use core::mem::{ManuallyDrop, SizedTypeProperties}; use core::ops::{Index, IndexMut, Range, RangeBounds}; use core::ptr; diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 3751f2a245456..dfd30d99cf041 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -4,7 +4,6 @@ use core::alloc::LayoutError; use core::cmp; use core::intrinsics; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; -use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 1e9cf404f77ea..cf93a40496fdf 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -15,7 +15,7 @@ //! //! [`Rc`] uses non-atomic reference counting. This means that overhead is very //! low, but an [`Rc`] cannot be sent between threads, and consequently [`Rc`] -//! does not implement [`Send`][send]. As a result, the Rust compiler +//! does not implement [`Send`]. As a result, the Rust compiler //! will check *at compile time* that you are not sending [`Rc`]s between //! threads. If you need multi-threaded, atomic reference counting, use //! [`sync::Arc`][arc]. @@ -232,7 +232,6 @@ //! [clone]: Clone::clone //! [`Cell`]: core::cell::Cell //! [`RefCell`]: core::cell::RefCell -//! [send]: core::marker::Send //! [arc]: crate::sync::Arc //! [`Deref`]: core::ops::Deref //! [downgrade]: Rc::downgrade @@ -251,13 +250,12 @@ use core::any::Any; use core::borrow; use core::cell::Cell; use core::cmp::Ordering; -use core::convert::{From, TryFrom}; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; -use core::marker::{self, PhantomData, Unpin, Unsize}; +use core::marker::{PhantomData, Unsize}; #[cfg(not(no_global_oom_handling))] use core::mem::size_of_val; use core::mem::{self, align_of_val_raw, forget}; @@ -321,7 +319,7 @@ pub struct Rc { } #[stable(feature = "rust1", since = "1.0.0")] -impl !marker::Send for Rc {} +impl !Send for Rc {} // Note that this negative impl isn't strictly necessary for correctness, // as `Rc` transitively contains a `Cell`, which is itself `!Sync`. @@ -329,7 +327,7 @@ impl !marker::Send for Rc {} // having an explicit negative impl is nice for documentation purposes // and results in nicer error messages. #[stable(feature = "rust1", since = "1.0.0")] -impl !marker::Sync for Rc {} +impl !Sync for Rc {} #[stable(feature = "catch_unwind", since = "1.9.0")] impl UnwindSafe for Rc {} @@ -1060,7 +1058,7 @@ impl Rc { #[inline] #[stable(feature = "rc_mutate_strong_count", since = "1.53.0")] pub unsafe fn decrement_strong_count(ptr: *const T) { - unsafe { mem::drop(Rc::from_raw(ptr)) }; + unsafe { drop(Rc::from_raw(ptr)) }; } /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to @@ -1496,7 +1494,7 @@ impl Rc<[T]> { /// /// Behavior is undefined should the size be wrong. #[cfg(not(no_global_oom_handling))] - unsafe fn from_iter_exact(iter: impl iter::Iterator, len: usize) -> Rc<[T]> { + unsafe fn from_iter_exact(iter: impl Iterator, len: usize) -> Rc<[T]> { // Panic guard while cloning T elements. // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. @@ -2088,7 +2086,7 @@ impl TryFrom> for Rc<[T; N]> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_iter", since = "1.37.0")] -impl iter::FromIterator for Rc<[T]> { +impl FromIterator for Rc<[T]> { /// Takes each element in the `Iterator` and collects it into an `Rc<[T]>`. /// /// # Performance characteristics @@ -2127,7 +2125,7 @@ impl iter::FromIterator for Rc<[T]> { /// let evens: Rc<[u8]> = (0..10).collect(); // Just a single allocation happens here. /// # assert_eq!(&*evens, &*(0..10).collect::>()); /// ``` - fn from_iter>(iter: I) -> Self { + fn from_iter>(iter: I) -> Self { ToRcSlice::to_rc_slice(iter.into_iter()) } } @@ -2204,9 +2202,9 @@ pub struct Weak { } #[stable(feature = "rc_weak", since = "1.4.0")] -impl !marker::Send for Weak {} +impl !Send for Weak {} #[stable(feature = "rc_weak", since = "1.4.0")] -impl !marker::Sync for Weak {} +impl !Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "18598")] impl, U: ?Sized> CoerceUnsized> for Weak {} diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index c1cd3c74ab676..be41919b9dc23 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -45,9 +45,9 @@ use core::error::Error; use core::fmt; use core::hash; -use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] -use core::iter::{from_fn, FromIterator}; +use core::iter::from_fn; +use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] use core::ops::Add; #[cfg(not(no_global_oom_handling))] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 150924851d21d..5bfe537bc830f 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -11,14 +11,13 @@ use core::any::Any; use core::borrow; use core::cmp::Ordering; -use core::convert::{From, TryFrom}; use core::fmt; use core::hash::{Hash, Hasher}; use core::hint; use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; -use core::marker::{PhantomData, Unpin, Unsize}; +use core::marker::{PhantomData, Unsize}; #[cfg(not(no_global_oom_handling))] use core::mem::size_of_val; use core::mem::{self, align_of_val_raw}; @@ -188,8 +187,6 @@ macro_rules! acquire { /// [mutex]: ../../std/sync/struct.Mutex.html /// [rwlock]: ../../std/sync/struct.RwLock.html /// [atomic]: core::sync::atomic -/// [`Send`]: core::marker::Send -/// [`Sync`]: core::marker::Sync /// [deref]: core::ops::Deref /// [downgrade]: Arc::downgrade /// [upgrade]: Weak::upgrade @@ -1241,7 +1238,7 @@ impl Arc { #[inline] #[stable(feature = "arc_mutate_strong_count", since = "1.51.0")] pub unsafe fn decrement_strong_count(ptr: *const T) { - unsafe { mem::drop(Arc::from_raw(ptr)) }; + unsafe { drop(Arc::from_raw(ptr)) }; } #[inline] @@ -1404,7 +1401,7 @@ impl Arc<[T]> { /// /// Behavior is undefined should the size be wrong. #[cfg(not(no_global_oom_handling))] - unsafe fn from_iter_exact(iter: impl iter::Iterator, len: usize) -> Arc<[T]> { + unsafe fn from_iter_exact(iter: impl Iterator, len: usize) -> Arc<[T]> { // Panic guard while cloning T elements. // In the event of a panic, elements that have been written // into the new ArcInner will be dropped, then the memory freed. @@ -2818,7 +2815,7 @@ impl TryFrom> for Arc<[T; N]> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "shared_from_iter", since = "1.37.0")] -impl iter::FromIterator for Arc<[T]> { +impl FromIterator for Arc<[T]> { /// Takes each element in the `Iterator` and collects it into an `Arc<[T]>`. /// /// # Performance characteristics @@ -2857,7 +2854,7 @@ impl iter::FromIterator for Arc<[T]> { /// let evens: Arc<[u8]> = (0..10).collect(); // Just a single allocation happens here. /// # assert_eq!(&*evens, &*(0..10).collect::>()); /// ``` - fn from_iter>(iter: I) -> Self { + fn from_iter>(iter: I) -> Self { ToArcSlice::to_arc_slice(iter.into_iter()) } } diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 64943a273c9a5..2c799605b7b67 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -1,5 +1,4 @@ use crate::borrow::Cow; -use core::iter::FromIterator; use super::Vec; diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 6a05f70e43747..02faf8e638948 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -108,7 +108,7 @@ impl IntoIter { /// ``` /// # let mut into_iter = Vec::::with_capacity(10).into_iter(); /// let mut into_iter = std::mem::replace(&mut into_iter, Vec::new().into_iter()); - /// (&mut into_iter).for_each(core::mem::drop); + /// (&mut into_iter).for_each(drop); /// std::mem::forget(into_iter); /// ``` /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 9f0111db4524c..3736a6e0b0ecb 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -56,12 +56,9 @@ #[cfg(not(no_global_oom_handling))] use core::cmp; use core::cmp::Ordering; -use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::iter; -#[cfg(not(no_global_oom_handling))] -use core::iter::FromIterator; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::ops::{self, Index, IndexMut, Range, RangeBounds}; @@ -2990,7 +2987,7 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec { } } -/// Implements comparison of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). +/// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Vec { #[inline] @@ -3002,7 +2999,7 @@ impl PartialOrd for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for Vec {} -/// Implements ordering of vectors, [lexicographically](core::cmp::Ord#lexicographical-comparison). +/// Implements ordering of vectors, [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] impl Ord for Vec { #[inline] diff --git a/library/core/src/iter/sources/repeat_with.rs b/library/core/src/iter/sources/repeat_with.rs index 3f34105a3e071..d3cd74a448375 100644 --- a/library/core/src/iter/sources/repeat_with.rs +++ b/library/core/src/iter/sources/repeat_with.rs @@ -19,7 +19,6 @@ use crate::ops::Try; /// please open a GitHub issue explaining your use case. /// /// [`repeat()`]: crate::iter::repeat -/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator /// /// # Examples /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f3d1e45f4fb6a..02877604248df 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -764,7 +764,6 @@ pub trait Iterator { /// more idiomatic to use [`for`] than `map()`. /// /// [`for`]: ../../book/ch03-05-control-flow.html#looping-through-a-collection-with-for - /// [`FnMut`]: crate::ops::FnMut /// /// # Examples /// diff --git a/library/core/src/net/parser.rs b/library/core/src/net/parser.rs index a08d2792d0456..b9a1924d66898 100644 --- a/library/core/src/net/parser.rs +++ b/library/core/src/net/parser.rs @@ -9,7 +9,7 @@ use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::str::FromStr; -trait ReadNumberHelper: crate::marker::Sized { +trait ReadNumberHelper: Sized { const ZERO: Self; fn checked_mul(&self, other: u32) -> Option; fn checked_add(&self, other: u32) -> Option; diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 51e6947a9c25a..3df990e5dd9fe 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -577,7 +577,6 @@ impl Copy for () { /// [`is_null`]: pointer::is_null /// [`offset`]: pointer::offset #[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))] -/// [`drop`]: mem::drop /// [`write`]: ptr::write #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} @@ -1026,7 +1025,6 @@ mod prim_str {} /// * [`UnwindSafe`] /// * [`RefUnwindSafe`] /// -/// [`Unpin`]: marker::Unpin /// [`UnwindSafe`]: panic::UnwindSafe /// [`RefUnwindSafe`]: panic::RefUnwindSafe /// @@ -1405,10 +1403,6 @@ mod prim_ref {} /// /// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].* /// -/// [`Fn`]: ops::Fn -/// [`FnMut`]: ops::FnMut -/// [`FnOnce`]: ops::FnOnce -/// /// Function pointers are pointers that point to *code*, not data. They can be called /// just like functions. Like references, function pointers are, among other things, assumed to /// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index 301ad41c96634..3f3e19c55d4ba 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -69,9 +69,6 @@ use core::task::{Context, Poll}; /// for any value. This is a parallel with the fact that /// `&` and `&mut` references together can be thought of as a _compile-time_ /// version of a read-write lock. -/// -/// -/// [`Sync`]: core::marker::Sync #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[doc(alias = "SyncWrapper")] #[doc(alias = "SyncCell")] diff --git a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs index adf0fcbeae2bd..b5ba198e5041b 100644 --- a/library/portable-simd/crates/core_simd/src/masks/full_masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks/full_masks.rs @@ -257,7 +257,7 @@ where } } -impl core::convert::From> for Simd +impl From> for Simd where T: MaskElement, LaneCount: SupportedLaneCount, diff --git a/library/proc_macro/src/bridge/fxhash.rs b/library/proc_macro/src/bridge/fxhash.rs index 17bd0a1b33646..f4e9054419721 100644 --- a/library/proc_macro/src/bridge/fxhash.rs +++ b/library/proc_macro/src/bridge/fxhash.rs @@ -5,8 +5,6 @@ //! on the `rustc_hash` crate. use std::collections::HashMap; -use std::convert::TryInto; -use std::default::Default; use std::hash::BuildHasherDefault; use std::hash::Hasher; use std::mem::size_of; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 938935771d64e..9d081c8b842d5 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -47,7 +47,7 @@ use std::cmp::Ordering; use std::ops::RangeBounds; use std::path::PathBuf; use std::str::FromStr; -use std::{error, fmt, iter}; +use std::{error, fmt}; /// Determines whether proc_macro has been made accessible to the currently /// running program. @@ -310,7 +310,7 @@ impl ConcatStreamsHelper { /// Collects a number of token trees into a single stream. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { let iter = trees.into_iter(); let mut builder = ConcatTreesHelper::new(iter.size_hint().0); @@ -322,7 +322,7 @@ impl iter::FromIterator for TokenStream { /// A "flattening" operation on token streams, collects token trees /// from multiple token streams into a single stream. #[stable(feature = "proc_macro_lib", since = "1.15.0")] -impl iter::FromIterator for TokenStream { +impl FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { let iter = streams.into_iter(); let mut builder = ConcatStreamsHelper::new(iter.size_hint().0); diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 742c4cc7c5539..3afc8287ecc00 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1446,7 +1446,6 @@ impl<'a, K, V> IterMut<'a, K, V> { /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter -/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Example /// diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 837a18bff6087..ac906e682d5f0 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1272,7 +1272,6 @@ pub struct Iter<'a, K: 'a> { /// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter -/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Examples /// diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 575f56ff4df29..49d3b7a1f6143 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -395,8 +395,6 @@ //! // ...but the key hasn't changed. b is still "baz", not "xyz". //! assert_eq!(map.keys().next().unwrap().b, "baz"); //! ``` -//! -//! [IntoIterator]: crate::iter::IntoIterator "iter::IntoIterator" #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 80ed34157e6dc..5c0541d3caf33 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -6,7 +6,6 @@ use crate::cmp; use crate::collections::TryReserveError; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::iter::Extend; use crate::ops; use crate::rc::Rc; use crate::str::FromStr; diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 1cedd6eedfaf9..34c0ce9dcf848 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -11,7 +11,6 @@ mod repr_unpacked; #[cfg(not(target_pointer_width = "64"))] use repr_unpacked::Repr; -use crate::convert::From; use crate::error; use crate::fmt; use crate::result; diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 203c490fa29a6..43842bee992a7 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1678,7 +1678,7 @@ mod super_keyword {} /// below `Iterator` is a **supertrait** and `ThreeIterator` is a **subtrait**: /// /// ```rust -/// trait ThreeIterator: std::iter::Iterator { +/// trait ThreeIterator: Iterator { /// fn next_three(&mut self) -> Option<[Self::Item; 3]>; /// } /// ``` diff --git a/library/std/src/path.rs b/library/std/src/path.rs index dbc18f7827e60..8014ba992eaf8 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -78,7 +78,7 @@ use crate::fmt; use crate::fs; use crate::hash::{Hash, Hasher}; use crate::io; -use crate::iter::{self, FusedIterator}; +use crate::iter::FusedIterator; use crate::ops::{self, Deref}; use crate::rc::Rc; use crate::str::FromStr; @@ -450,26 +450,26 @@ impl<'a> PrefixComponent<'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialEq for PrefixComponent<'a> { +impl<'a> PartialEq for PrefixComponent<'a> { #[inline] fn eq(&self, other: &PrefixComponent<'a>) -> bool { - cmp::PartialEq::eq(&self.parsed, &other.parsed) + self.parsed == other.parsed } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialOrd for PrefixComponent<'a> { +impl<'a> PartialOrd for PrefixComponent<'a> { #[inline] fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option { - cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed) + PartialOrd::partial_cmp(&self.parsed, &other.parsed) } } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Ord for PrefixComponent<'_> { +impl Ord for PrefixComponent<'_> { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { - cmp::Ord::cmp(&self.parsed, &other.parsed) + Ord::cmp(&self.parsed, &other.parsed) } } @@ -988,7 +988,7 @@ impl<'a> DoubleEndedIterator for Components<'a> { impl FusedIterator for Components<'_> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialEq for Components<'a> { +impl<'a> PartialEq for Components<'a> { #[inline] fn eq(&self, other: &Components<'a>) -> bool { let Components { path: _, front: _, back: _, has_physical_root: _, prefix: _ } = self; @@ -1015,10 +1015,10 @@ impl<'a> cmp::PartialEq for Components<'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Eq for Components<'_> {} +impl Eq for Components<'_> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> cmp::PartialOrd for Components<'a> { +impl<'a> PartialOrd for Components<'a> { #[inline] fn partial_cmp(&self, other: &Components<'a>) -> Option { Some(compare_components(self.clone(), other.clone())) @@ -1026,7 +1026,7 @@ impl<'a> cmp::PartialOrd for Components<'a> { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Ord for Components<'_> { +impl Ord for Components<'_> { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { compare_components(self.clone(), other.clone()) @@ -1741,7 +1741,7 @@ impl FromStr for PathBuf { } #[stable(feature = "rust1", since = "1.0.0")] -impl> iter::FromIterator

for PathBuf { +impl> FromIterator

for PathBuf { fn from_iter>(iter: I) -> PathBuf { let mut buf = PathBuf::new(); buf.extend(iter); @@ -1750,7 +1750,7 @@ impl> iter::FromIterator

for PathBuf { } #[stable(feature = "rust1", since = "1.0.0")] -impl> iter::Extend

for PathBuf { +impl> Extend

for PathBuf { fn extend>(&mut self, iter: I) { iter.into_iter().for_each(move |p| self.push(p.as_ref())); } @@ -1904,7 +1904,7 @@ impl ToOwned for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialEq for PathBuf { +impl PartialEq for PathBuf { #[inline] fn eq(&self, other: &PathBuf) -> bool { self.components() == other.components() @@ -1919,10 +1919,10 @@ impl Hash for PathBuf { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Eq for PathBuf {} +impl Eq for PathBuf {} #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialOrd for PathBuf { +impl PartialOrd for PathBuf { #[inline] fn partial_cmp(&self, other: &PathBuf) -> Option { Some(compare_components(self.components(), other.components())) @@ -1930,7 +1930,7 @@ impl cmp::PartialOrd for PathBuf { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Ord for PathBuf { +impl Ord for PathBuf { #[inline] fn cmp(&self, other: &PathBuf) -> cmp::Ordering { compare_components(self.components(), other.components()) @@ -3025,7 +3025,7 @@ impl fmt::Display for Display<'_> { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialEq for Path { +impl PartialEq for Path { #[inline] fn eq(&self, other: &Path) -> bool { self.components() == other.components() @@ -3084,10 +3084,10 @@ impl Hash for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Eq for Path {} +impl Eq for Path {} #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::PartialOrd for Path { +impl PartialOrd for Path { #[inline] fn partial_cmp(&self, other: &Path) -> Option { Some(compare_components(self.components(), other.components())) @@ -3095,7 +3095,7 @@ impl cmp::PartialOrd for Path { } #[stable(feature = "rust1", since = "1.0.0")] -impl cmp::Ord for Path { +impl Ord for Path { #[inline] fn cmp(&self, other: &Path) -> cmp::Ordering { compare_components(self.components(), other.components()) diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index c314bbbb68e57..1b29c887d2100 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -34,7 +34,7 @@ //! marker traits that indicate fundamental properties of types. //! * [std::ops]::{[Drop], [Fn], [FnMut], [FnOnce]}, various //! operations for both destructors and overloading `()`. -//! * [std::mem]::[drop][mem::drop], a convenience function for explicitly +//! * [std::mem]::[drop], a convenience function for explicitly //! dropping a value. //! * [std::boxed]::[Box], a way to allocate values on the heap. //! * [std::borrow]::[ToOwned], the conversion trait that defines @@ -66,7 +66,6 @@ //! * [std::convert]::{[TryFrom], [TryInto]}, //! * [std::iter]::[FromIterator]. //! -//! [mem::drop]: crate::mem::drop //! [std::borrow]: crate::borrow //! [std::boxed]: crate::boxed //! [std::clone]: crate::clone @@ -86,9 +85,6 @@ //! [std::slice]: crate::slice //! [std::string]: crate::string //! [std::vec]: mod@crate::vec -//! [TryFrom]: crate::convert::TryFrom -//! [TryInto]: crate::convert::TryInto -//! [FromIterator]: crate::iter::FromIterator //! [`to_owned`]: crate::borrow::ToOwned::to_owned //! [book-closures]: ../../book/ch13-01-closures.html //! [book-dtor]: ../../book/ch15-03-drop.html diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 51e6947a9c25a..3df990e5dd9fe 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -577,7 +577,6 @@ impl Copy for () { /// [`is_null`]: pointer::is_null /// [`offset`]: pointer::offset #[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))] -/// [`drop`]: mem::drop /// [`write`]: ptr::write #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} @@ -1026,7 +1025,6 @@ mod prim_str {} /// * [`UnwindSafe`] /// * [`RefUnwindSafe`] /// -/// [`Unpin`]: marker::Unpin /// [`UnwindSafe`]: panic::UnwindSafe /// [`RefUnwindSafe`]: panic::RefUnwindSafe /// @@ -1405,10 +1403,6 @@ mod prim_ref {} /// /// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].* /// -/// [`Fn`]: ops::Fn -/// [`FnMut`]: ops::FnMut -/// [`FnOnce`]: ops::FnOnce -/// /// Function pointers are pointers that point to *code*, not data. They can be called /// just like functions. Like references, function pointers are, among other things, assumed to /// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 0d934318c22a4..01505e94487b2 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -3,7 +3,6 @@ use crate::arch::asm; use crate::cell::UnsafeCell; use crate::cmp; -use crate::convert::TryInto; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; use crate::ptr::{self, NonNull}; diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs index 8d5b540212a17..d310be6c7a1eb 100644 --- a/library/std/src/sys/unix/futex.rs +++ b/library/std/src/sys/unix/futex.rs @@ -273,8 +273,6 @@ pub mod zircon { #[cfg(target_os = "fuchsia")] pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) -> bool { - use crate::convert::TryFrom; - // Sleep forever if the timeout is longer than fits in a i64. let deadline = timeout .and_then(|d| { diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 1c44058aff79d..a345af76fa217 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -7,7 +7,6 @@ mod tests; use crate::os::unix::prelude::*; -use crate::convert::TryFrom; use crate::error::Error as StdError; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index d4c7e58b34d2e..e45c380a0bb84 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -166,7 +166,6 @@ impl Process { } pub fn wait(&mut self) -> io::Result { - use crate::default::Default; use crate::sys::process::zircon::*; let mut proc_info: zx_info_process_t = Default::default(); @@ -199,7 +198,6 @@ impl Process { } pub fn try_wait(&mut self) -> io::Result> { - use crate::default::Default; use crate::sys::process::zircon::*; let mut proc_info: zx_info_process_t = Default::default(); diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index eb427dbda2393..cb24caa1e8a60 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -2,7 +2,6 @@ mod tests; use crate::cmp; -use crate::convert::{TryFrom, TryInto}; use crate::fmt; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; use crate::mem; diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 05f25af68ea8f..5376c4ec9c325 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -1,9 +1,8 @@ use std::any::{Any, TypeId}; use std::borrow::Borrow; use std::cell::RefCell; -use std::cmp::{Ord, Ordering, PartialOrd}; +use std::cmp::Ordering; use std::collections::HashMap; -use std::convert::AsRef; use std::fmt; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b3df12a9df13b..02cec16b35c44 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -35,7 +35,6 @@ use rustc_span::{self, ExpnKind}; use std::borrow::Cow; use std::collections::hash_map::Entry; use std::collections::BTreeMap; -use std::default::Default; use std::hash::Hash; use std::mem; use thin_vec::ThinVec; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index e34ece9264cfb..6d2ce9e2833f4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::default::Default; use std::hash::Hash; use std::path::PathBuf; use std::rc::Rc; @@ -980,7 +979,7 @@ pub(crate) trait NestedAttributesExt { /// Returns `true` if the attribute list contains a specific `word` fn has_word(self, word: Symbol) -> bool where - Self: std::marker::Sized, + Self: Sized, { ::get_word_attr(self, word).is_some() } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index c848089dad6b9..b97bb190dd8cc 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::convert::TryFrom; use std::ffi::OsStr; use std::fmt; use std::path::PathBuf; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index fd81a21f5a994..00aadb8e82aeb 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -36,7 +36,6 @@ use rustc_span::{Span, Symbol}; use once_cell::sync::Lazy; use std::borrow::Cow; use std::collections::VecDeque; -use std::default::Default; use std::fmt::Write; use std::ops::{ControlFlow, Range}; use std::str; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1e3cd2668506f..463184acaa14f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -38,7 +38,6 @@ pub(crate) use self::context::*; pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc}; use std::collections::VecDeque; -use std::default::Default; use std::fmt::{self, Write}; use std::fs; use std::iter::Peekable; diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 08a0e1c377ef8..f5b4a3f5abd65 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -59,7 +59,7 @@ pub(crate) fn build_index<'tcx>( // `sort_unstable_by_key` produces lifetime errors let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent); let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent); - std::cmp::Ord::cmp(&k1, &k2) + Ord::cmp(&k1, &k2) }); // Set up alias indexes. diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index c39caf73a9367..cd6509607d561 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -4,7 +4,6 @@ #![allow(rustc::default_hash_types)] -use std::convert::From; use std::fmt; use rustc_ast::ast; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 79f53ee57cc9d..9fd130c4717b4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -69,7 +69,6 @@ extern crate test; #[cfg(feature = "jemalloc")] extern crate jemalloc_sys; -use std::default::Default; use std::env::{self, VarError}; use std::io::{self, IsTerminal}; use std::process; diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index f530a4d73d360..b007f9a22c36f 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -2,7 +2,6 @@ use anyhow::{Context, Error}; use curl::easy::Easy; use indexmap::IndexMap; use std::collections::HashMap; -use std::convert::TryInto; const PATH: &str = "src/stage0.json"; const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo"]; diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 7e5b4d810ba93..197e9a9965f7d 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -57,8 +57,8 @@ mod os_impl { match fs::File::create(&path) { Ok(file) => { let exec = is_executable(&path).unwrap_or(false); - std::mem::drop(file); - std::fs::remove_file(&path).expect("Deleted temp file"); + drop(file); + fs::remove_file(&path).expect("Deleted temp file"); // If the file is executable, then we assume that this // filesystem does not track executability, so skip this check. return if exec { Unsupported } else { Supported }; diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index d40c4ad0711cf..6fd41e833624f 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -31,7 +31,6 @@ //! this in the long term. use crate::walk::{filter_dirs, walk}; -use std::iter::Iterator; use std::path::Path; // Paths that may contain platform-specific code. diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index 890ff986c2be0..7547b49ab2a54 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -1,6 +1,5 @@ use crate::fmt_list; use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::convert::TryFrom; use std::fmt::{self, Write}; use std::ops::Range; diff --git a/src/tools/unicode-table-generator/src/skiplist.rs b/src/tools/unicode-table-generator/src/skiplist.rs index 6e439968c3bfd..9b613a94c5795 100644 --- a/src/tools/unicode-table-generator/src/skiplist.rs +++ b/src/tools/unicode-table-generator/src/skiplist.rs @@ -1,6 +1,5 @@ use crate::fmt_list; use crate::raw_emitter::RawEmitter; -use std::convert::TryInto; use std::fmt::Write as _; use std::ops::Range; diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index 1c6a7b02f8e77..a7252a4002770 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:525:5 +thread 'main' panicked at 'capacity overflow', library/alloc/src/raw_vec.rs:524:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 42c4373ad11a86d3028ddfe29d7f33edc9670ba8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Mar 2023 22:55:37 +0000 Subject: [PATCH 07/12] Make note_source_of_type_mismatch_constraint simpler --- compiler/rustc_hir_typeck/src/demand.rs | 276 +++++------------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 22 +- .../type/type-check/assignment-in-if.stderr | 9 - .../type-check/point-at-inference-3.fixed | 1 - .../type/type-check/point-at-inference-3.rs | 1 - .../type-check/point-at-inference-3.stderr | 5 +- .../type/type-check/point-at-inference-4.rs | 1 + .../type-check/point-at-inference-4.stderr | 5 +- .../type/type-check/point-at-inference.fixed | 2 +- .../type/type-check/point-at-inference.stderr | 6 +- .../ui/typeck/bad-type-in-vec-contains.stderr | 1 - tests/ui/typeck/bad-type-in-vec-push.stderr | 2 - tests/ui/typeck/issue-107775.stderr | 4 +- 13 files changed, 94 insertions(+), 241 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index a4c3be1d17745..0c4f73e0db0eb 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,6 +1,5 @@ use crate::FnCtxt; use rustc_ast::util::parser::PREC_POSTFIX; -use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; @@ -13,15 +12,13 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder}; -use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; -use rustc_middle::ty::relate::TypeRelation; -use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeVisitableExt}; +use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::traits::error_reporting::method_chain::CollectAllMismatches; use rustc_trait_selection::traits::ObligationCause; use super::method::probe; @@ -62,9 +59,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected) || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected) - || self.note_result_coercion(err, expr, expected, expr_ty); + || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty); + if !suggested { - self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span); + self.note_source_of_type_mismatch_constraint(err, expr, expected); } } @@ -218,37 +216,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (expected, Some(err)) } - pub fn point_at_expr_source_of_inferred_type( + /// Notes the point at which a variable is constrained to some type incompatible + /// with `expected_ty`. + pub fn note_source_of_type_mismatch_constraint( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, - found: Ty<'tcx>, - expected: Ty<'tcx>, - mismatch_span: Span, + expected_ty: Ty<'tcx>, ) -> bool { - let map = self.tcx.hir(); + let hir = self.tcx.hir(); let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind else { return false; }; let [hir::PathSegment { ident, args: None, .. }] = p.segments else { return false; }; - let hir::def::Res::Local(hir_id) = p.res else { return false; }; - let Some(hir::Node::Pat(pat)) = map.find(hir_id) else { return false; }; - let Some(hir::Node::Local(hir::Local { - ty: None, - init: Some(init), - .. - })) = map.find_parent(pat.hir_id) else { return false; }; - let Some(ty) = self.node_ty_opt(init.hir_id) else { return false; }; - if ty.is_closure() || init.span.overlaps(expr.span) || pat.span.from_expansion() { - return false; - } + let hir::def::Res::Local(local_hir_id) = p.res else { return false; }; + let hir::Node::Pat(pat) = hir.get(local_hir_id) else { return false; }; + let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) { + hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init), + hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)), + _ => return false, + }; + let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else { return false; }; // Locate all the usages of the relevant binding. - struct FindExprs<'hir> { + struct FindExprs<'tcx> { hir_id: hir::HirId, - uses: Vec<&'hir hir::Expr<'hir>>, + uses: Vec<&'tcx hir::Expr<'tcx>>, } - impl<'v> Visitor<'v> for FindExprs<'v> { - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + impl<'tcx> Visitor<'tcx> for FindExprs<'tcx> { + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = ex.kind && let hir::def::Res::Local(hir_id) = path.res && hir_id == self.hir_id @@ -259,180 +254,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let mut expr_finder = FindExprs { hir_id, uses: vec![] }; - let id = map.get_parent_item(hir_id); - let hir_id: hir::HirId = id.into(); - - let Some(node) = map.find(hir_id) else { return false; }; - let Some(body_id) = node.body_id() else { return false; }; - let body = map.body(body_id); + let mut expr_finder = FindExprs { hir_id: local_hir_id, uses: init.into_iter().collect() }; + let body = + hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body")); expr_finder.visit_expr(body.value); - // Hack to make equality checks on types with inference variables and regions useful. - let mut eraser = BottomUpFolder { - tcx: self.tcx, - lt_op: |_| self.tcx.lifetimes.re_erased, - ct_op: |c| c, - ty_op: |t| match *t.kind() { - ty::Infer(ty::TyVar(_)) => self.tcx.mk_ty_var(ty::TyVid::from_u32(0)), - ty::Infer(ty::IntVar(_)) => self.tcx.mk_int_var(ty::IntVid { index: 0 }), - ty::Infer(ty::FloatVar(_)) => self.tcx.mk_float_var(ty::FloatVid { index: 0 }), - _ => t, - }, - }; - let mut prev = eraser.fold_ty(ty); - let mut prev_span: Option = None; - - for binding in expr_finder.uses { - // In every expression where the binding is referenced, we will look at that - // expression's type and see if it is where the incorrect found type was fully - // "materialized" and point at it. We will also try to provide a suggestion there. - if let Some(hir::Node::Expr(expr) - | hir::Node::Stmt(hir::Stmt { - kind: hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr), - .. - })) = &map.find_parent(binding.hir_id) - && let hir::ExprKind::MethodCall(segment, rcvr, args, _span) = expr.kind - && rcvr.hir_id == binding.hir_id - && let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(expr.hir_id) - { - // We special case methods, because they can influence inference through the - // call's arguments and we can provide a more explicit span. - let sig = self.tcx.fn_sig(def_id).subst_identity(); - let def_self_ty = sig.input(0).skip_binder(); - let param_tys = sig.inputs().skip_binder().iter().skip(1); - // If there's an arity mismatch, pointing out the call as the source of an inference - // can be misleading, so we skip it. - if param_tys.len() != args.len() { - continue; - } - let rcvr_ty = self.node_ty(rcvr.hir_id); - // Get the evaluated type *after* calling the method call, so that the influence - // of the arguments can be reflected in the receiver type. The receiver - // expression has the type *before* this analysis is done. - let ty = match self.lookup_probe_for_diagnostic( - segment.ident, - rcvr_ty, - expr, - probe::ProbeScope::TraitsInScope, - None, - ) { - Ok(pick) => eraser.fold_ty(pick.self_ty), - Err(_) => rcvr_ty, - }; - // Remove one layer of references to account for `&mut self` and - // `&self`, so that we can compare it against the binding. - let (ty, def_self_ty) = match (ty.kind(), def_self_ty.kind()) { - (ty::Ref(_, ty, a), ty::Ref(_, self_ty, b)) if a == b => (*ty, *self_ty), - _ => (ty, def_self_ty), - }; - let mut param_args = FxHashMap::default(); - let mut param_expected = FxHashMap::default(); - let mut param_found = FxHashMap::default(); - if self.can_eq(self.param_env, ty, found) { - // We only point at the first place where the found type was inferred. - for (param_ty, arg) in param_tys.zip(args) { - if def_self_ty.contains(*param_ty) && let ty::Param(_) = param_ty.kind() { - // We found an argument that references a type parameter in `Self`, - // so we assume that this is the argument that caused the found - // type, which we know already because of `can_eq` above was first - // inferred in this method call. - let arg_ty = self.node_ty(arg.hir_id); - if !arg.span.overlaps(mismatch_span) { - err.span_label( - arg.span, - &format!( - "this is of type `{arg_ty}`, which causes `{ident}` to be \ - inferred as `{ty}`", - ), - ); - } - param_args.insert(param_ty, (arg, arg_ty)); - } - } - } - // Here we find, for a type param `T`, the type that `T` is in the current - // method call *and* in the original expected type. That way, we can see if we - // can give any structured suggestion for the function argument. - let mut c = CollectAllMismatches { - infcx: &self.infcx, - param_env: self.param_env, - errors: vec![], - }; - let _ = c.relate(def_self_ty, ty); - for error in c.errors { - if let TypeError::Sorts(error) = error { - param_found.insert(error.expected, error.found); + let fudge_equals_found_ty = |use_ty: Ty<'tcx>| { + use rustc_infer::infer::type_variable::*; + use rustc_middle::infer::unify_key::*; + let use_ty = use_ty.fold_with(&mut BottomUpFolder { + tcx: self.tcx, + ty_op: |ty| { + if let ty::Infer(infer) = ty.kind() { + match infer { + ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: DUMMY_SP, + }), + ty::InferTy::IntVar(_) => self.next_int_var(), + ty::InferTy::FloatVar(_) => self.next_float_var(), + _ => bug!(), + } + } else { + ty } - } - c.errors = vec![]; - let _ = c.relate(def_self_ty, expected); - for error in c.errors { - if let TypeError::Sorts(error) = error { - param_expected.insert(error.expected, error.found); + }, + lt_op: |_| self.tcx.lifetimes.re_erased, + ct_op: |ct| { + if let ty::ConstKind::Infer(_) = ct.kind() { + self.next_const_var( + ct.ty(), + ConstVariableOrigin { + kind: ConstVariableOriginKind::MiscVariable, + span: DUMMY_SP, + }, + ) + } else { + ct } - } - for (param, (arg, arg_ty)) in param_args.iter() { - let Some(expected) = param_expected.get(param) else { continue; }; - let Some(found) = param_found.get(param) else { continue; }; - if !self.can_eq(self.param_env, *arg_ty, *found) { continue; } - self.emit_coerce_suggestions(err, arg, *found, *expected, None, None); - } + }, + }); + self.can_eq(self.param_env, expected_ty, use_ty) + }; - let ty = eraser.fold_ty(ty); - if ty.references_error() { - break; - } - if ty != prev - && param_args.is_empty() - && self.can_eq(self.param_env, ty, found) - { - // We only point at the first place where the found type was inferred. - if !segment.ident.span.overlaps(mismatch_span) { - err.span_label( - segment.ident.span, - with_forced_trimmed_paths!(format!( - "here the type of `{ident}` is inferred to be `{ty}`", - )), - );} - break; - } else if !param_args.is_empty() { - break; - } - prev = ty; - } else { - let ty = eraser.fold_ty(self.node_ty(binding.hir_id)); - if ty.references_error() { - break; - } - if ty != prev - && let Some(span) = prev_span - && self.can_eq(self.param_env, ty, found) - { - // We only point at the first place where the found type was inferred. - // We use the *previous* span because if the type is known *here* it means - // it was *evaluated earlier*. We don't do this for method calls because we - // evaluate the method's self type eagerly, but not in any other case. - if !span.overlaps(mismatch_span) { - err.span_label( - span, - with_forced_trimmed_paths!(format!( - "here the type of `{ident}` is inferred to be `{ty}`", - )), - ); - } - break; - } - prev = ty; + if !fudge_equals_found_ty(init_ty) { + return false; + } + + for window in expr_finder.uses.windows(2) { + let [binding, next_usage] = *window else { continue; }; + let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; }; + if !fudge_equals_found_ty(next_use_ty) { + err.span_label( + binding.span, + format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"), + ); + return true; } - if binding.hir_id == expr.hir_id { - // Do not look at expressions that come after the expression we were originally - // evaluating and had a type error. + + if next_usage.hir_id == expr.hir_id { break; } - prev_span = Some(binding.span); } - true + + // We must've not found something that constrained the expr. + false } fn annotate_expected_due_to_let_ty( @@ -708,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - pub(crate) fn note_result_coercion( + pub(crate) fn suggest_coercing_result_via_try_operator( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a009ae5d44eb1..d98e0d9096f53 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -807,24 +807,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { full_call_span, format!("arguments to this {} are incorrect", call_name), ); - if let (Some(callee_ty), hir::ExprKind::MethodCall(_, rcvr, _, _)) = - (callee_ty, &call_expr.kind) - { - // Type that would have accepted this argument if it hadn't been inferred earlier. - // FIXME: We leave an inference variable for now, but it'd be nice to get a more - // specific type to increase the accuracy of the diagnostic. - let expected = self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: full_call_span, - }); - self.point_at_expr_source_of_inferred_type( - &mut err, - rcvr, - expected, - callee_ty, - provided_arg_span, - ); - } + + // TODO: We would like to point out when the rcvr was constrained + // such that the arg mismatch occurs. + // Call out where the function is defined self.label_fn_like( &mut err, diff --git a/tests/ui/type/type-check/assignment-in-if.stderr b/tests/ui/type/type-check/assignment-in-if.stderr index de133e5599cf9..9f4558adab150 100644 --- a/tests/ui/type/type-check/assignment-in-if.stderr +++ b/tests/ui/type/type-check/assignment-in-if.stderr @@ -67,9 +67,6 @@ LL | x == 5 error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:44:18 | -LL | if y = (Foo { foo: x }) { - | - here the type of `x` is inferred to be `usize` -... LL | if x == x && x = x && x == x { | ------ ^ expected `bool`, found `usize` | | @@ -78,9 +75,6 @@ LL | if x == x && x = x && x == x { error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:44:22 | -LL | if y = (Foo { foo: x }) { - | - here the type of `x` is inferred to be `usize` -... LL | if x == x && x = x && x == x { | ^ expected `bool`, found `usize` @@ -98,9 +92,6 @@ LL | if x == x && x == x && x == x { error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:51:28 | -LL | if y = (Foo { foo: x }) { - | - here the type of `x` is inferred to be `usize` -... LL | if x == x && x == x && x = x { | ---------------- ^ expected `bool`, found `usize` | | diff --git a/tests/ui/type/type-check/point-at-inference-3.fixed b/tests/ui/type/type-check/point-at-inference-3.fixed index edd4adf8bd256..9c93063e04ae2 100644 --- a/tests/ui/type/type-check/point-at-inference-3.fixed +++ b/tests/ui/type/type-check/point-at-inference-3.fixed @@ -2,7 +2,6 @@ fn main() { let mut v = Vec::new(); v.push(0i32); - //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec` v.push(0); v.push(1i32); //~ ERROR mismatched types //~^ NOTE expected `i32`, found `u32` diff --git a/tests/ui/type/type-check/point-at-inference-3.rs b/tests/ui/type/type-check/point-at-inference-3.rs index 49d7b50075bbc..8bb1487420baa 100644 --- a/tests/ui/type/type-check/point-at-inference-3.rs +++ b/tests/ui/type/type-check/point-at-inference-3.rs @@ -2,7 +2,6 @@ fn main() { let mut v = Vec::new(); v.push(0i32); - //~^ NOTE this is of type `i32`, which causes `v` to be inferred as `Vec` v.push(0); v.push(1u32); //~ ERROR mismatched types //~^ NOTE expected `i32`, found `u32` diff --git a/tests/ui/type/type-check/point-at-inference-3.stderr b/tests/ui/type/type-check/point-at-inference-3.stderr index 2c4907ed263ba..32663bd632e12 100644 --- a/tests/ui/type/type-check/point-at-inference-3.stderr +++ b/tests/ui/type/type-check/point-at-inference-3.stderr @@ -1,9 +1,6 @@ error[E0308]: mismatched types - --> $DIR/point-at-inference-3.rs:7:12 + --> $DIR/point-at-inference-3.rs:6:12 | -LL | v.push(0i32); - | ---- this is of type `i32`, which causes `v` to be inferred as `Vec` -... LL | v.push(1u32); | ---- ^^^^ expected `i32`, found `u32` | | diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs index aea9b2c6c14ee..7c25b91fd89e9 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -11,6 +11,7 @@ fn main() { let s = S(None); s.infer(0i32); //~^ ERROR this method takes 2 arguments but 1 argument was supplied + //~| NOTE here the type of `s` is inferred to be `S` //~| NOTE an argument is missing //~| HELP provide the argument let t: S = s; diff --git a/tests/ui/type/type-check/point-at-inference-4.stderr b/tests/ui/type/type-check/point-at-inference-4.stderr index 28833d2ed1c92..6181af70c8ed4 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -15,8 +15,11 @@ LL | s.infer(0i32, /* b */); | ~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/point-at-inference-4.rs:16:24 + --> $DIR/point-at-inference-4.rs:17:24 | +LL | s.infer(0i32); + | - here the type of `s` is inferred to be `S` +... LL | let t: S = s; | --------- ^ expected `S`, found `S` | | diff --git a/tests/ui/type/type-check/point-at-inference.fixed b/tests/ui/type/type-check/point-at-inference.fixed index f41fbe59fba6c..6419e42e70d12 100644 --- a/tests/ui/type/type-check/point-at-inference.fixed +++ b/tests/ui/type/type-check/point-at-inference.fixed @@ -6,7 +6,7 @@ fn main() { let mut foo = vec![]; baz(&foo); for i in &v { - foo.push(*i); + foo.push(i); } baz(&foo); bar(foo); //~ ERROR E0308 diff --git a/tests/ui/type/type-check/point-at-inference.stderr b/tests/ui/type/type-check/point-at-inference.stderr index a76b4f90c734b..89c4cd1c37632 100644 --- a/tests/ui/type/type-check/point-at-inference.stderr +++ b/tests/ui/type/type-check/point-at-inference.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/point-at-inference.rs:12:9 | LL | foo.push(i); - | - this is of type `&{integer}`, which causes `foo` to be inferred as `Vec<&{integer}>` + | --- here the type of `foo` is inferred to be `Vec<&{integer}>` ... LL | bar(foo); | --- ^^^ expected `Vec`, found `Vec<&{integer}>` @@ -16,10 +16,6 @@ note: function defined here | LL | fn bar(_: Vec) {} | ^^^ ----------- -help: consider dereferencing the borrow - | -LL | foo.push(*i); - | + error: aborting due to previous error diff --git a/tests/ui/typeck/bad-type-in-vec-contains.stderr b/tests/ui/typeck/bad-type-in-vec-contains.stderr index 0e03388d2d58c..72533ab1fa37f 100644 --- a/tests/ui/typeck/bad-type-in-vec-contains.stderr +++ b/tests/ui/typeck/bad-type-in-vec-contains.stderr @@ -7,7 +7,6 @@ LL | primes.contains(3); | | expected `&_`, found integer | | help: consider borrowing here: `&3` | arguments to this method are incorrect - | here the type of `primes` is inferred to be `[_]` | = note: expected reference `&_` found type `{integer}` diff --git a/tests/ui/typeck/bad-type-in-vec-push.stderr b/tests/ui/typeck/bad-type-in-vec-push.stderr index ae46050c91be2..1d5337260fa0a 100644 --- a/tests/ui/typeck/bad-type-in-vec-push.stderr +++ b/tests/ui/typeck/bad-type-in-vec-push.stderr @@ -1,8 +1,6 @@ error[E0308]: mismatched types --> $DIR/bad-type-in-vec-push.rs:11:17 | -LL | vector.sort(); - | ------ here the type of `vector` is inferred to be `Vec<_>` LL | result.push(vector); | ---- ^^^^^^ expected integer, found `Vec<_>` | | diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr index 9ee9c022c6e8c..39c727bd278bc 100644 --- a/tests/ui/typeck/issue-107775.stderr +++ b/tests/ui/typeck/issue-107775.stderr @@ -2,9 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-107775.rs:35:16 | LL | map.insert(1, Struct::do_something); - | - -------------------- this is of type `fn(u8) -> Pin + Send>> {::do_something::<'_>}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` - | | - | this is of type `{integer}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` + | --- here the type of `map` is inferred to be `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` LL | Self { map } | ^^^ expected `HashMap Pin<...>>`, found `HashMap<{integer}, ...>` | From e72c45ad987b296baee79865b7e2ca00c518fb8b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Mar 2023 23:23:07 +0000 Subject: [PATCH 08/12] Point at which arg causes a binding to be constrained --- compiler/rustc_hir_typeck/src/demand.rs | 61 +++++++++++++++---- .../type/type-check/point-at-inference.stderr | 4 +- tests/ui/typeck/issue-107775.stderr | 4 +- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 0c4f73e0db0eb..0d3e4bde497f8 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -259,10 +259,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body")); expr_finder.visit_expr(body.value); - let fudge_equals_found_ty = |use_ty: Ty<'tcx>| { + let fudge_ty = |ty: Ty<'tcx>| { use rustc_infer::infer::type_variable::*; use rustc_middle::infer::unify_key::*; - let use_ty = use_ty.fold_with(&mut BottomUpFolder { + ty.fold_with(&mut BottomUpFolder { tcx: self.tcx, ty_op: |ty| { if let ty::Infer(infer) = ty.kind() { @@ -293,7 +293,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ct } }, - }); + }) + }; + + let fudge_equals_found_ty = |use_ty: Ty<'tcx>| { + let use_ty = fudge_ty(use_ty); self.can_eq(self.param_env, expected_ty, use_ty) }; @@ -303,18 +307,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for window in expr_finder.uses.windows(2) { let [binding, next_usage] = *window else { continue; }; + + // Don't go past the binding (always gonna be a nonsense label if so) + if binding.hir_id == expr.hir_id { + break; + } + let Some(next_use_ty) = self.node_ty_opt(next_usage.hir_id) else { continue; }; - if !fudge_equals_found_ty(next_use_ty) { - err.span_label( - binding.span, - format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"), - ); - return true; + + // If the type is not constrained in a way making it not possible to + // equate with `expected_ty` by this point, skip. + if fudge_equals_found_ty(next_use_ty) { + continue; } - if next_usage.hir_id == expr.hir_id { - break; + if let hir::Node::Expr(parent_expr) = hir.get_parent(binding.hir_id) + && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind + && rcvr.hir_id == binding.hir_id + { + let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; + let rcvr_ty = fudge_ty(rcvr_ty); + if let Ok(method) = + self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + { + for (expected_arg_ty, arg_expr) in std::iter::zip(&method.sig.inputs()[1..], args) { + let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; + let arg_ty = fudge_ty(arg_ty); + let _ = self.try_coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None); + if !self.can_eq(self.param_env, rcvr_ty, expected_ty) { + err.span_label( + arg_expr.span, + format!("this argument has type `{arg_ty}`...") + ); + err.span_label( + binding.span, + format!("... which constrains `{ident}` to have type `{next_use_ty}`") + ); + return true; + } + } + } } + + err.span_label( + binding.span, + format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"), + ); + return true; } // We must've not found something that constrained the expr. diff --git a/tests/ui/type/type-check/point-at-inference.stderr b/tests/ui/type/type-check/point-at-inference.stderr index 89c4cd1c37632..5d46368b1fd38 100644 --- a/tests/ui/type/type-check/point-at-inference.stderr +++ b/tests/ui/type/type-check/point-at-inference.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/point-at-inference.rs:12:9 | LL | foo.push(i); - | --- here the type of `foo` is inferred to be `Vec<&{integer}>` + | --- - this argument has type `&{integer}`... + | | + | ... which causes `foo` to have type `Vec<&{integer}>` ... LL | bar(foo); | --- ^^^ expected `Vec`, found `Vec<&{integer}>` diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr index 39c727bd278bc..b97e74b7e53fa 100644 --- a/tests/ui/typeck/issue-107775.stderr +++ b/tests/ui/typeck/issue-107775.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/issue-107775.rs:35:16 | LL | map.insert(1, Struct::do_something); - | --- here the type of `map` is inferred to be `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` + | --- -------------------- this argument has type `fn(u8) -> Pin + Send>> {::do_something::<'_>}`... + | | + | ... which causes `map` to have type `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` LL | Self { map } | ^^^ expected `HashMap Pin<...>>`, found `HashMap<{integer}, ...>` | From 29aee6a125ac65a01932cb0ece5485e7cf8cfe87 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 2 Mar 2023 23:49:24 +0000 Subject: [PATCH 09/12] Restore suggestion based off of backwards inference from bad usage to method call --- compiler/rustc_hir_typeck/src/demand.rs | 141 +++++++++++------- .../type/type-check/point-at-inference.fixed | 2 +- .../type/type-check/point-at-inference.stderr | 4 + 3 files changed, 88 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 0d3e4bde497f8..f219068b4e87b 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -259,49 +259,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body")); expr_finder.visit_expr(body.value); - let fudge_ty = |ty: Ty<'tcx>| { - use rustc_infer::infer::type_variable::*; - use rustc_middle::infer::unify_key::*; - ty.fold_with(&mut BottomUpFolder { - tcx: self.tcx, - ty_op: |ty| { - if let ty::Infer(infer) = ty.kind() { - match infer { - ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: DUMMY_SP, - }), - ty::InferTy::IntVar(_) => self.next_int_var(), - ty::InferTy::FloatVar(_) => self.next_float_var(), - _ => bug!(), - } - } else { - ty - } - }, - lt_op: |_| self.tcx.lifetimes.re_erased, - ct_op: |ct| { - if let ty::ConstKind::Infer(_) = ct.kind() { - self.next_const_var( - ct.ty(), - ConstVariableOrigin { - kind: ConstVariableOriginKind::MiscVariable, - span: DUMMY_SP, - }, - ) - } else { - ct + use rustc_infer::infer::type_variable::*; + use rustc_middle::infer::unify_key::*; + + let mut fudger = BottomUpFolder { + tcx: self.tcx, + ty_op: |ty| { + if let ty::Infer(infer) = ty.kind() { + match infer { + ty::InferTy::TyVar(_) => self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: DUMMY_SP, + }), + ty::InferTy::IntVar(_) => self.next_int_var(), + ty::InferTy::FloatVar(_) => self.next_float_var(), + _ => bug!(), } - }, - }) - }; - - let fudge_equals_found_ty = |use_ty: Ty<'tcx>| { - let use_ty = fudge_ty(use_ty); - self.can_eq(self.param_env, expected_ty, use_ty) + } else { + ty + } + }, + lt_op: |_| self.tcx.lifetimes.re_erased, + ct_op: |ct| { + if let ty::ConstKind::Infer(_) = ct.kind() { + self.next_const_var( + ct.ty(), + ConstVariableOrigin { + kind: ConstVariableOriginKind::MiscVariable, + span: DUMMY_SP, + }, + ) + } else { + ct + } + }, }; - if !fudge_equals_found_ty(init_ty) { + if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) { return false; } @@ -317,7 +311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the type is not constrained in a way making it not possible to // equate with `expected_ty` by this point, skip. - if fudge_equals_found_ty(next_use_ty) { + if self.can_eq(self.param_env, expected_ty, next_use_ty.fold_with(&mut fudger)) { continue; } @@ -326,26 +320,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && rcvr.hir_id == binding.hir_id { let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; - let rcvr_ty = fudge_ty(rcvr_ty); - if let Ok(method) = + let rcvr_ty = rcvr_ty.fold_with(&mut fudger); + let Ok(method) = self.lookup_method(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + else { + continue; + }; + + // NOTE: For future removers of `fudge_inference_if_ok`, you + // can replace this with another call to `lookup_method` but + // using `expected_ty` as the rcvr. + let ideal_method_sig: Result<_, TypeError<'tcx>> = self.fudge_inference_if_ok(|| { + let _ = self.at(&ObligationCause::dummy(), self.param_env).eq(rcvr_ty, expected_ty)?; + Ok(method.sig) + }); + + for (idx, (expected_arg_ty, arg_expr)) in + std::iter::zip(&method.sig.inputs()[1..], args).enumerate() { - for (expected_arg_ty, arg_expr) in std::iter::zip(&method.sig.inputs()[1..], args) { - let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; - let arg_ty = fudge_ty(arg_ty); - let _ = self.try_coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None); - if !self.can_eq(self.param_env, rcvr_ty, expected_ty) { - err.span_label( - arg_expr.span, - format!("this argument has type `{arg_ty}`...") - ); - err.span_label( - binding.span, - format!("... which constrains `{ident}` to have type `{next_use_ty}`") - ); - return true; - } + let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; + let arg_ty = arg_ty.fold_with(&mut fudger); + let _ = self.try_coerce( + arg_expr, + arg_ty, + *expected_arg_ty, + AllowTwoPhase::No, + None, + ); + if self.can_eq(self.param_env, rcvr_ty, expected_ty) { + continue; + } + err.span_label( + arg_expr.span, + format!("this argument has type `{arg_ty}`..."), + ); + err.span_label( + binding.span, + format!( + "... which constrains `{ident}` to have type `{next_use_ty}`" + ), + ); + if let Ok(ideal_method_sig) = ideal_method_sig { + self.emit_type_mismatch_suggestions( + err, + arg_expr, + arg_ty, + ideal_method_sig.inputs()[idx + 1], + None, + None, + ); } + return true; } } diff --git a/tests/ui/type/type-check/point-at-inference.fixed b/tests/ui/type/type-check/point-at-inference.fixed index 6419e42e70d12..f41fbe59fba6c 100644 --- a/tests/ui/type/type-check/point-at-inference.fixed +++ b/tests/ui/type/type-check/point-at-inference.fixed @@ -6,7 +6,7 @@ fn main() { let mut foo = vec![]; baz(&foo); for i in &v { - foo.push(i); + foo.push(*i); } baz(&foo); bar(foo); //~ ERROR E0308 diff --git a/tests/ui/type/type-check/point-at-inference.stderr b/tests/ui/type/type-check/point-at-inference.stderr index 5d46368b1fd38..5fc94d4d1b6ba 100644 --- a/tests/ui/type/type-check/point-at-inference.stderr +++ b/tests/ui/type/type-check/point-at-inference.stderr @@ -18,6 +18,10 @@ note: function defined here | LL | fn bar(_: Vec) {} | ^^^ ----------- +help: consider dereferencing the borrow + | +LL | foo.push(*i); + | + error: aborting due to previous error From 5a71029dd3b54046fbd6144de20e320db539820f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 3 Mar 2023 00:44:22 +0000 Subject: [PATCH 10/12] Properly note source of arg mismatch --- compiler/rustc_hir_typeck/src/demand.rs | 57 ++++++++++++++++++- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 13 ++++- .../type-check/point-at-inference-3.fixed | 2 + .../type/type-check/point-at-inference-3.rs | 2 + .../type-check/point-at-inference-3.stderr | 7 ++- 5 files changed, 74 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index f219068b4e87b..9ffee56702329 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -62,7 +62,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty); if !suggested { - self.note_source_of_type_mismatch_constraint(err, expr, expected); + self.note_source_of_type_mismatch_constraint( + err, + expr, + TypeMismatchSource::Ty(expected), + ); } } @@ -222,7 +226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, - expected_ty: Ty<'tcx>, + source: TypeMismatchSource<'tcx>, ) -> bool { let hir = self.tcx.hir(); @@ -295,6 +299,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; + let expected_ty = match source { + TypeMismatchSource::Ty(expected_ty) => expected_ty, + TypeMismatchSource::Arg(call_expr, idx) => { + let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else { + return false; + }; + let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else { + return false; + }; + let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| { + let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?; + let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger); + let method = self + .lookup_method( + possible_rcvr_ty, + segment, + DUMMY_SP, + call_expr, + binding, + args, + ) + .ok()?; + let _ = self + .at(&ObligationCause::dummy(), self.param_env) + .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty) + .ok()?; + self.select_obligations_where_possible(|errs| { + // Yeet the errors, we're already reporting errors. + errs.clear(); + }); + Some(self.resolve_vars_if_possible(possible_rcvr_ty)) + }); + if let Some(rcvr_ty) = possible_rcvr_ty { + rcvr_ty + } else { + return false; + } + } + }; + if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) { return false; } @@ -360,7 +404,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "... which constrains `{ident}` to have type `{next_use_ty}`" ), ); - if let Ok(ideal_method_sig) = ideal_method_sig { + if matches!(source, TypeMismatchSource::Ty(_)) + && let Ok(ideal_method_sig) = ideal_method_sig + { self.emit_type_mismatch_suggestions( err, arg_expr, @@ -2044,3 +2090,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +pub enum TypeMismatchSource<'tcx> { + Ty(Ty<'tcx>), + Arg(&'tcx hir::Expr<'tcx>, usize), +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index d98e0d9096f53..9ecb78e2dda80 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -472,7 +472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err_code: &str, fn_def_id: Option, call_span: Span, - call_expr: &hir::Expr<'tcx>, + call_expr: &'tcx hir::Expr<'tcx>, ) { // Next, let's construct the error let (error_span, full_call_span, call_name, is_method) = match &call_expr.kind { @@ -808,8 +808,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {} are incorrect", call_name), ); - // TODO: We would like to point out when the rcvr was constrained - // such that the arg mismatch occurs. + if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind + && provided_idx.as_usize() == expected_idx.as_usize() + { + self.note_source_of_type_mismatch_constraint( + &mut err, + rcvr, + crate::demand::TypeMismatchSource::Arg(call_expr, provided_idx.as_usize()), + ); + } // Call out where the function is defined self.label_fn_like( diff --git a/tests/ui/type/type-check/point-at-inference-3.fixed b/tests/ui/type/type-check/point-at-inference-3.fixed index 9c93063e04ae2..15a3b580568d6 100644 --- a/tests/ui/type/type-check/point-at-inference-3.fixed +++ b/tests/ui/type/type-check/point-at-inference-3.fixed @@ -2,6 +2,8 @@ fn main() { let mut v = Vec::new(); v.push(0i32); + //~^ NOTE this argument has type `i32`... + //~| NOTE ... which causes `v` to have type `Vec` v.push(0); v.push(1i32); //~ ERROR mismatched types //~^ NOTE expected `i32`, found `u32` diff --git a/tests/ui/type/type-check/point-at-inference-3.rs b/tests/ui/type/type-check/point-at-inference-3.rs index 8bb1487420baa..a48c4f9862f75 100644 --- a/tests/ui/type/type-check/point-at-inference-3.rs +++ b/tests/ui/type/type-check/point-at-inference-3.rs @@ -2,6 +2,8 @@ fn main() { let mut v = Vec::new(); v.push(0i32); + //~^ NOTE this argument has type `i32`... + //~| NOTE ... which causes `v` to have type `Vec` v.push(0); v.push(1u32); //~ ERROR mismatched types //~^ NOTE expected `i32`, found `u32` diff --git a/tests/ui/type/type-check/point-at-inference-3.stderr b/tests/ui/type/type-check/point-at-inference-3.stderr index 32663bd632e12..238764812364c 100644 --- a/tests/ui/type/type-check/point-at-inference-3.stderr +++ b/tests/ui/type/type-check/point-at-inference-3.stderr @@ -1,6 +1,11 @@ error[E0308]: mismatched types - --> $DIR/point-at-inference-3.rs:6:12 + --> $DIR/point-at-inference-3.rs:8:12 | +LL | v.push(0i32); + | - ---- this argument has type `i32`... + | | + | ... which causes `v` to have type `Vec` +... LL | v.push(1u32); | ---- ^^^^ expected `i32`, found `u32` | | From 5cc475742151cd458091ca3c67598ddece3ee39b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 3 Mar 2023 01:35:51 +0000 Subject: [PATCH 11/12] More accurate argument blames, add some comments --- compiler/rustc_hir_typeck/src/demand.rs | 75 +++++++++++++------ .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 +- .../type/type-check/point-at-inference-4.rs | 4 +- .../type-check/point-at-inference-4.stderr | 10 ++- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 9ffee56702329..13442c3164928 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Notes the point at which a variable is constrained to some type incompatible - /// with `expected_ty`. + /// with some expectation given by `source`. pub fn note_source_of_type_mismatch_constraint( &self, err: &mut Diagnostic, @@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { use rustc_infer::infer::type_variable::*; use rustc_middle::infer::unify_key::*; - + // Replaces all of the variables in the given type with a fresh inference variable. let mut fudger = BottomUpFolder { tcx: self.tcx, ty_op: |ty| { @@ -301,7 +301,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected_ty = match source { TypeMismatchSource::Ty(expected_ty) => expected_ty, - TypeMismatchSource::Arg(call_expr, idx) => { + // Try to deduce what the possible value of `expr` would be if the + // incompatible arg were compatible. For example, given `Vec` + // and `vec.push(1u32)`, we ideally want to deduce that the type of + // `vec` *should* have been `Vec`. This will allow us to then + // run the subsequent code with this expectation, finding out exactly + // when this type diverged from our expectation. + TypeMismatchSource::Arg { call_expr, incompatible_arg: idx } => { let hir::ExprKind::MethodCall(segment, _, args, _) = call_expr.kind else { return false; }; @@ -310,6 +316,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| { let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?; + // Fudge the receiver, so we can do new inference on it. let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger); let method = self .lookup_method( @@ -321,6 +328,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args, ) .ok()?; + // Unify the method signature with our incompatible arg, to + // do inference in the *opposite* direction and to find out + // what our ideal rcvr ty would look like. let _ = self .at(&ObligationCause::dummy(), self.param_env) .eq(DefineOpaqueTypes::No, method.sig.inputs()[idx + 1], arg_ty) @@ -339,11 +349,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + // If our expected_ty does not equal init_ty, then it *began* as incompatible. + // No need to note in this case... if !self.can_eq(self.param_env, expected_ty, init_ty.fold_with(&mut fudger)) { return false; } for window in expr_finder.uses.windows(2) { + // Bindings always update their recorded type after the fact, so we + // need to look at the *following* usage's type to see when the + // binding became incompatible. let [binding, next_usage] = *window else { continue; }; // Don't go past the binding (always gonna be a nonsense label if so) @@ -363,6 +378,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind && rcvr.hir_id == binding.hir_id { + // If our binding became incompatible while it was a receiver + // to a method call, we may be able to make a better guess to + // the source of a type mismatch. let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; let rcvr_ty = rcvr_ty.fold_with(&mut fudger); let Ok(method) = @@ -371,14 +389,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; }; - // NOTE: For future removers of `fudge_inference_if_ok`, you - // can replace this with another call to `lookup_method` but - // using `expected_ty` as the rcvr. - let ideal_method_sig: Result<_, TypeError<'tcx>> = self.fudge_inference_if_ok(|| { - let _ = self.at(&ObligationCause::dummy(), self.param_env).eq(rcvr_ty, expected_ty)?; - Ok(method.sig) - }); + let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger); + let ideal_method = self + .lookup_method(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr, args) + .ok() + .and_then(|method| { + let _ = self.at(&ObligationCause::dummy(), self.param_env) + .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty) + .ok()?; + Some(method) + }); + // Find what argument caused our rcvr to become incompatible + // with the expected ty. for (idx, (expected_arg_ty, arg_expr)) in std::iter::zip(&method.sig.inputs()[1..], args).enumerate() { @@ -391,27 +414,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { AllowTwoPhase::No, None, ); + self.select_obligations_where_possible(|errs| { + // Yeet the errors, we're already reporting errors. + errs.clear(); + }); + // If our rcvr, after inference due to unifying the signature + // with the expected argument type, is still compatible with + // the rcvr, then it must've not been the source of blame. if self.can_eq(self.param_env, rcvr_ty, expected_ty) { continue; } - err.span_label( - arg_expr.span, - format!("this argument has type `{arg_ty}`..."), - ); + err.span_label(arg_expr.span, format!("this argument has type `{arg_ty}`...")); err.span_label( binding.span, - format!( - "... which constrains `{ident}` to have type `{next_use_ty}`" - ), + format!("... which causes `{ident}` to have type `{next_use_ty}`"), ); + // Using our "ideal" method signature, suggest a fix to this + // blame arg, if possible. Don't do this if we're coming from + // arg mismatch code, because we'll possibly suggest a mutually + // incompatible fix at the original mismatch site. if matches!(source, TypeMismatchSource::Ty(_)) - && let Ok(ideal_method_sig) = ideal_method_sig + && let Some(ideal_method) = ideal_method { self.emit_type_mismatch_suggestions( err, arg_expr, arg_ty, - ideal_method_sig.inputs()[idx + 1], + self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1]), None, None, ); @@ -419,7 +448,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } } - err.span_label( binding.span, format!("here the type of `{ident}` is inferred to be `{next_use_ty}`"), @@ -2092,6 +2120,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub enum TypeMismatchSource<'tcx> { + /// Expected the binding to have the given type, but it was found to have + /// a different type. Find out when that type first became incompatible. Ty(Ty<'tcx>), - Arg(&'tcx hir::Expr<'tcx>, usize), + /// When we fail during method argument checking, try to find out if a previous + /// expression has constrained the method's receiver in a way that makes the + /// argument's type incompatible. + Arg { call_expr: &'tcx hir::Expr<'tcx>, incompatible_arg: usize }, } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9ecb78e2dda80..ea1b52daaa5e5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -814,7 +814,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.note_source_of_type_mismatch_constraint( &mut err, rcvr, - crate::demand::TypeMismatchSource::Arg(call_expr, provided_idx.as_usize()), + crate::demand::TypeMismatchSource::Arg { + call_expr, + incompatible_arg: provided_idx.as_usize(), + }, ); } diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs index 7c25b91fd89e9..3deb234c2751e 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -11,9 +11,11 @@ fn main() { let s = S(None); s.infer(0i32); //~^ ERROR this method takes 2 arguments but 1 argument was supplied - //~| NOTE here the type of `s` is inferred to be `S` + //~| NOTE this argument has type `i32`... + //~| NOTE ... which causes `s` to have type `S` //~| NOTE an argument is missing //~| HELP provide the argument + //~| HELP change the type of the numeric literal from `i32` to `u32` let t: S = s; //~^ ERROR mismatched types //~| NOTE expected `S`, found `S` diff --git a/tests/ui/type/type-check/point-at-inference-4.stderr b/tests/ui/type/type-check/point-at-inference-4.stderr index 6181af70c8ed4..5f7bb8b9367ec 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -15,10 +15,12 @@ LL | s.infer(0i32, /* b */); | ~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/point-at-inference-4.rs:17:24 + --> $DIR/point-at-inference-4.rs:19:24 | LL | s.infer(0i32); - | - here the type of `s` is inferred to be `S` + | - ---- this argument has type `i32`... + | | + | ... which causes `s` to have type `S` ... LL | let t: S = s; | --------- ^ expected `S`, found `S` @@ -27,6 +29,10 @@ LL | let t: S = s; | = note: expected struct `S` found struct `S` +help: change the type of the numeric literal from `i32` to `u32` + | +LL | s.infer(0u32); + | ~~~ error: aborting due to 2 previous errors From d38fd29b5b2ed78ef801af19f8b6e6ae98f24210 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Apr 2023 20:21:07 +0200 Subject: [PATCH 12/12] Add explanations for auto-disambiguation when an intra doc link is resolved to a proc-macro and a trait at the same time --- .../src/write-documentation/linking-to-items-by-name.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md index 36bc312b9c99a..eb2285ef90646 100644 --- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md @@ -103,6 +103,13 @@ macro_rules! foo { } ``` +There is one case where the disambiguation will be performed automatically: if an intra doc +link is resolved at the same time as a trait and as a derive proc-macro. In this case, it'll +always generate a link to the trait and not emit a "missing disambiguation" warning. A good +example of this case is when you link to the `Clone` trait: there is also a `Clone` +proc-macro but it ignores it in this case. If you want to link to the proc-macro, you can +use the `macro@` disambiguator. + ## Warnings, re-exports, and scoping Links are resolved in the scope of the module where the item is defined, even