From 78245286dcde9f2cf99a370ec0cd4383fa684404 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 31 Dec 2022 11:00:54 +0100 Subject: [PATCH 1/8] std: use id-based thread parking on SOLID --- library/std/src/sys/itron/thread_parking.rs | 37 +++++++ library/std/src/sys/itron/wait_flag.rs | 72 ------------- library/std/src/sys/solid/mod.rs | 4 +- .../std/src/sys_common/thread_parking/mod.rs | 4 +- .../sys_common/thread_parking/wait_flag.rs | 102 ------------------ 5 files changed, 40 insertions(+), 179 deletions(-) create mode 100644 library/std/src/sys/itron/thread_parking.rs delete mode 100644 library/std/src/sys/itron/wait_flag.rs delete mode 100644 library/std/src/sys_common/thread_parking/wait_flag.rs diff --git a/library/std/src/sys/itron/thread_parking.rs b/library/std/src/sys/itron/thread_parking.rs new file mode 100644 index 0000000000000..fe9934439d152 --- /dev/null +++ b/library/std/src/sys/itron/thread_parking.rs @@ -0,0 +1,37 @@ +use super::abi; +use super::error::expect_success_aborting; +use super::time::with_tmos; +use crate::time::Duration; + +pub type ThreadId = abi::ID; + +pub use super::task::current_task_id_aborting as current; + +pub fn park(_hint: usize) { + match unsafe { abi::slp_tsk() } { + abi::E_OK | abi::E_RLWAI => {} + err => { + expect_success_aborting(err, &"slp_tsk"); + } + } +} + +pub fn park_timeout(dur: Duration, _hint: usize) { + match with_tmos(dur, |tmo| unsafe { abi::tslp_tsk(tmo) }) { + abi::E_OK | abi::E_RLWAI | abi::E_TMOUT => {} + err => { + expect_success_aborting(err, &"tslp_tsk"); + } + } +} + +pub fn unpark(id: ThreadId, _hint: usize) { + match unsafe { abi::wup_tsk(id) } { + // It is allowed to try to wake up a destroyed or unrelated task, so we ignore all + // errors that could result from that situation. + abi::E_OK | abi::E_NOEXS | abi::E_OBJ | abi::E_QOVR => {} + err => { + expect_success_aborting(err, &"wup_tsk"); + } + } +} diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs deleted file mode 100644 index e432edd207754..0000000000000 --- a/library/std/src/sys/itron/wait_flag.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::mem::MaybeUninit; -use crate::time::Duration; - -use super::{ - abi, - error::{expect_success, fail}, - time::with_tmos, -}; - -const CLEAR: abi::FLGPTN = 0; -const RAISED: abi::FLGPTN = 1; - -/// A thread parking primitive that is not susceptible to race conditions, -/// but provides no atomic ordering guarantees and allows only one `raise` per wait. -pub struct WaitFlag { - flag: abi::ID, -} - -impl WaitFlag { - /// Creates a new wait flag. - pub fn new() -> WaitFlag { - let flag = expect_success( - unsafe { - abi::acre_flg(&abi::T_CFLG { - flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR, - iflgptn: CLEAR, - }) - }, - &"acre_flg", - ); - - WaitFlag { flag } - } - - /// Wait for the wait flag to be raised. - pub fn wait(&self) { - let mut token = MaybeUninit::uninit(); - expect_success( - unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) }, - &"wai_flg", - ); - } - - /// Wait for the wait flag to be raised or the timeout to occur. - /// - /// Returns whether the flag was raised (`true`) or the operation timed out (`false`). - pub fn wait_timeout(&self, dur: Duration) -> bool { - let mut token = MaybeUninit::uninit(); - let res = with_tmos(dur, |tmout| unsafe { - abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout) - }); - - match res { - abi::E_OK => true, - abi::E_TMOUT => false, - error => fail(error, &"twai_flg"), - } - } - - /// Raise the wait flag. - /// - /// Calls to this function should be balanced with the number of successful waits. - pub fn raise(&self) { - expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg"); - } -} - -impl Drop for WaitFlag { - fn drop(&mut self) { - expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg"); - } -} diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs index 5867979a2a729..923d27fd9369d 100644 --- a/library/std/src/sys/solid/mod.rs +++ b/library/std/src/sys/solid/mod.rs @@ -13,9 +13,9 @@ mod itron { pub(super) mod spin; pub(super) mod task; pub mod thread; + pub mod thread_parking; pub(super) mod time; use super::unsupported; - pub mod wait_flag; } pub mod alloc; @@ -43,8 +43,8 @@ pub use self::itron::thread; pub mod memchr; pub mod thread_local_dtor; pub mod thread_local_key; +pub use self::itron::thread_parking; pub mod time; -pub use self::itron::wait_flag; mod rwlock; diff --git a/library/std/src/sys_common/thread_parking/mod.rs b/library/std/src/sys_common/thread_parking/mod.rs index 0ead6633c3501..e8e028bb3308f 100644 --- a/library/std/src/sys_common/thread_parking/mod.rs +++ b/library/std/src/sys_common/thread_parking/mod.rs @@ -14,12 +14,10 @@ cfg_if::cfg_if! { } else if #[cfg(any( target_os = "netbsd", all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", ))] { mod id; pub use id::Parker; - } else if #[cfg(target_os = "solid_asp3")] { - mod wait_flag; - pub use wait_flag::Parker; } else if #[cfg(any(windows, target_family = "unix"))] { pub use crate::sys::thread_parking::Parker; } else { diff --git a/library/std/src/sys_common/thread_parking/wait_flag.rs b/library/std/src/sys_common/thread_parking/wait_flag.rs deleted file mode 100644 index d0f8899a94eb8..0000000000000 --- a/library/std/src/sys_common/thread_parking/wait_flag.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! A wait-flag-based thread parker. -//! -//! Some operating systems provide low-level parking primitives like wait counts, -//! event flags or semaphores which are not susceptible to race conditions (meaning -//! the wakeup can occur before the wait operation). To implement the `std` thread -//! parker on top of these primitives, we only have to ensure that parking is fast -//! when the thread token is available, the atomic ordering guarantees are maintained -//! and spurious wakeups are minimized. -//! -//! To achieve this, this parker uses an atomic variable with three states: `EMPTY`, -//! `PARKED` and `NOTIFIED`: -//! * `EMPTY` means the token has not been made available, but the thread is not -//! currently waiting on it. -//! * `PARKED` means the token is not available and the thread is parked. -//! * `NOTIFIED` means the token is available. -//! -//! `park` and `park_timeout` change the state from `EMPTY` to `PARKED` and from -//! `NOTIFIED` to `EMPTY`. If the state was `NOTIFIED`, the thread was unparked and -//! execution can continue without calling into the OS. If the state was `EMPTY`, -//! the token is not available and the thread waits on the primitive (here called -//! "wait flag"). -//! -//! `unpark` changes the state to `NOTIFIED`. If the state was `PARKED`, the thread -//! is or will be sleeping on the wait flag, so we raise it. - -use crate::pin::Pin; -use crate::sync::atomic::AtomicI8; -use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; -use crate::sys::wait_flag::WaitFlag; -use crate::time::Duration; - -const EMPTY: i8 = 0; -const PARKED: i8 = -1; -const NOTIFIED: i8 = 1; - -pub struct Parker { - state: AtomicI8, - wait_flag: WaitFlag, -} - -impl Parker { - /// Construct a parker for the current thread. The UNIX parker - /// implementation requires this to happen in-place. - pub unsafe fn new_in_place(parker: *mut Parker) { - parker.write(Parker { state: AtomicI8::new(EMPTY), wait_flag: WaitFlag::new() }) - } - - // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. - pub unsafe fn park(self: Pin<&Self>) { - match self.state.fetch_sub(1, Acquire) { - // NOTIFIED => EMPTY - NOTIFIED => return, - // EMPTY => PARKED - EMPTY => (), - _ => panic!("inconsistent park state"), - } - - // Avoid waking up from spurious wakeups (these are quite likely, see below). - loop { - self.wait_flag.wait(); - - match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) { - Ok(_) => return, - Err(PARKED) => (), - Err(_) => panic!("inconsistent park state"), - } - } - } - - // This implementation doesn't require `unsafe` and `Pin`, but other implementations do. - pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { - match self.state.fetch_sub(1, Acquire) { - NOTIFIED => return, - EMPTY => (), - _ => panic!("inconsistent park state"), - } - - self.wait_flag.wait_timeout(dur); - - // Either a wakeup or a timeout occurred. Wakeups may be spurious, as there can be - // a race condition when `unpark` is performed between receiving the timeout and - // resetting the state, resulting in the eventflag being set unnecessarily. `park` - // is protected against this by looping until the token is actually given, but - // here we cannot easily tell. - - // Use `swap` to provide acquire ordering. - match self.state.swap(EMPTY, Acquire) { - NOTIFIED => (), - PARKED => (), - _ => panic!("inconsistent park state"), - } - } - - // This implementation doesn't require `Pin`, but other implementations do. - pub fn unpark(self: Pin<&Self>) { - let state = self.state.swap(NOTIFIED, Release); - - if state == PARKED { - self.wait_flag.raise(); - } - } -} From 22f853c620d970c6f80c8c206614a3bf766d028f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Tue, 14 Feb 2023 16:11:15 +0100 Subject: [PATCH 2/8] Avoid looping past bounds of args There might be more type params than args to a method call, which leads to an index out of bounds panic. --- compiler/rustc_hir_typeck/src/demand.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index ae00042eae73d..16d3115c233b0 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -323,13 +323,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut param_found = FxHashMap::default(); if self.can_eq(self.param_env, ty, found).is_ok() { // We only point at the first place where the found type was inferred. - for (i, param_ty) in sig.inputs().skip_binder().iter().skip(1).enumerate() { + for (param_ty, arg) in sig.inputs().skip_binder().iter().skip(1).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 = &args[i]; let arg_ty = self.node_ty(arg.hir_id); if !arg.span.overlaps(mismatch_span) { err.span_label( From a14a4fc3d03482a2a42768bdee35201e37bab16c Mon Sep 17 00:00:00 2001 From: onestacked Date: Wed, 15 Feb 2023 15:49:17 +0100 Subject: [PATCH 3/8] Constify `RangeBounds`, `RangeX::contains` and `RangeX::is_empty`. --- library/core/src/cmp.rs | 5 +- library/core/src/ops/range.rs | 98 +++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f290e5baf9dd3..b4d58376aea5d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1491,9 +1491,10 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd<&B> for &A + #[rustc_const_unstable(feature = "const_cmp", issue = "92391")] + impl const PartialOrd<&B> for &A where - A: PartialOrd, + A: ~const PartialOrd, { #[inline] fn partial_cmp(&self, other: &&B) -> Option { diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index d29ae35614c1c..b8ab2656473df 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -96,7 +96,7 @@ impl fmt::Debug for Range { } } -impl> Range { +impl> Range { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -116,10 +116,11 @@ impl> Range { /// assert!(!(f32::NAN..1.0).contains(&0.5)); /// ``` #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: ~const PartialOrd, + U: ?Sized + ~const PartialOrd, { >::contains(self, item) } @@ -142,7 +143,8 @@ impl> Range { /// assert!( (f32::NAN..5.0).is_empty()); /// ``` #[stable(feature = "range_is_empty", since = "1.47.0")] - pub fn is_empty(&self) -> bool { + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] + pub const fn is_empty(&self) -> bool { !(self.start < self.end) } } @@ -199,7 +201,7 @@ impl fmt::Debug for RangeFrom { } } -impl> RangeFrom { +impl> RangeFrom { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -214,10 +216,11 @@ impl> RangeFrom { /// assert!(!(f32::NAN..).contains(&0.5)); /// ``` #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: ~const PartialOrd, + U: ?Sized + ~const PartialOrd, { >::contains(self, item) } @@ -280,7 +283,7 @@ impl fmt::Debug for RangeTo { } } -impl> RangeTo { +impl> RangeTo { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -295,10 +298,11 @@ impl> RangeTo { /// assert!(!(..f32::NAN).contains(&0.5)); /// ``` #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: ~const PartialOrd, + U: ?Sized + ~const PartialOrd, { >::contains(self, item) } @@ -437,7 +441,8 @@ impl RangeInclusive { /// ``` #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] - pub fn into_inner(self) -> (Idx, Idx) { + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] + pub const fn into_inner(self) -> (Idx, Idx) { (self.start, self.end) } } @@ -469,7 +474,7 @@ impl fmt::Debug for RangeInclusive { } } -impl> RangeInclusive { +impl> RangeInclusive { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -500,10 +505,11 @@ impl> RangeInclusive { /// assert!(!r.contains(&3) && !r.contains(&5)); /// ``` #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: ~const PartialOrd, + U: ?Sized + ~const PartialOrd, { >::contains(self, item) } @@ -535,8 +541,9 @@ impl> RangeInclusive { /// assert!(r.is_empty()); /// ``` #[stable(feature = "range_is_empty", since = "1.47.0")] + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] #[inline] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.exhausted || !(self.start <= self.end) } } @@ -598,7 +605,7 @@ impl fmt::Debug for RangeToInclusive { } } -impl> RangeToInclusive { +impl> RangeToInclusive { /// Returns `true` if `item` is contained in the range. /// /// # Examples @@ -613,10 +620,11 @@ impl> RangeToInclusive { /// assert!(!(..=f32::NAN).contains(&0.5)); /// ``` #[stable(feature = "range_contains", since = "1.35.0")] - pub fn contains(&self, item: &U) -> bool + #[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] + pub const fn contains(&self, item: &U) -> bool where - Idx: PartialOrd, - U: ?Sized + PartialOrd, + Idx: ~const PartialOrd, + U: ?Sized + ~const PartialOrd, { >::contains(self, item) } @@ -757,6 +765,7 @@ impl Bound<&T> { /// `RangeBounds` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`. #[stable(feature = "collections_range", since = "1.28.0")] +#[const_trait] pub trait RangeBounds { /// Start index bound. /// @@ -809,8 +818,8 @@ pub trait RangeBounds { #[stable(feature = "range_contains", since = "1.35.0")] fn contains(&self, item: &U) -> bool where - T: PartialOrd, - U: ?Sized + PartialOrd, + T: ~const PartialOrd, + U: ?Sized + ~const PartialOrd, { (match self.start_bound() { Included(start) => start <= item, @@ -827,7 +836,8 @@ pub trait RangeBounds { use self::Bound::{Excluded, Included, Unbounded}; #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeFull { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeFull { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -837,7 +847,8 @@ impl RangeBounds for RangeFull { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeFrom { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeFrom { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -847,7 +858,8 @@ impl RangeBounds for RangeFrom { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeTo { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeTo { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -857,7 +869,8 @@ impl RangeBounds for RangeTo { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for Range { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for Range { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -867,7 +880,8 @@ impl RangeBounds for Range { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeInclusive { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeInclusive { fn start_bound(&self) -> Bound<&T> { Included(&self.start) } @@ -883,7 +897,8 @@ impl RangeBounds for RangeInclusive { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeToInclusive { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeToInclusive { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -893,7 +908,8 @@ impl RangeBounds for RangeToInclusive { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for (Bound, Bound) { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for (Bound, Bound) { fn start_bound(&self) -> Bound<&T> { match *self { (Included(ref start), _) => Included(start), @@ -912,7 +928,8 @@ impl RangeBounds for (Bound, Bound) { } #[stable(feature = "collections_range", since = "1.28.0")] -impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl<'a, T: ?Sized + 'a> const RangeBounds for (Bound<&'a T>, Bound<&'a T>) { fn start_bound(&self) -> Bound<&T> { self.0 } @@ -923,7 +940,8 @@ impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeFrom<&T> { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeFrom<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -933,7 +951,8 @@ impl RangeBounds for RangeFrom<&T> { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeTo<&T> { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeTo<&T> { fn start_bound(&self) -> Bound<&T> { Unbounded } @@ -943,7 +962,8 @@ impl RangeBounds for RangeTo<&T> { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for Range<&T> { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for Range<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -953,7 +973,8 @@ impl RangeBounds for Range<&T> { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeInclusive<&T> { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeInclusive<&T> { fn start_bound(&self) -> Bound<&T> { Included(self.start) } @@ -963,7 +984,8 @@ impl RangeBounds for RangeInclusive<&T> { } #[stable(feature = "collections_range", since = "1.28.0")] -impl RangeBounds for RangeToInclusive<&T> { +#[rustc_const_unstable(feature = "const_range_bounds", issue = "108082")] +impl const RangeBounds for RangeToInclusive<&T> { fn start_bound(&self) -> Bound<&T> { Unbounded } From 08cc628e7334b7f200b09f5f2c77700231103fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Wed, 15 Feb 2023 15:51:48 +0100 Subject: [PATCH 4/8] Add point-at-inference ui test for wrong arity case --- .../type/type-check/point-at-inference-4.rs | 23 +++++++++++ .../type-check/point-at-inference-4.stderr | 38 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tests/ui/type/type-check/point-at-inference-4.rs create mode 100644 tests/ui/type/type-check/point-at-inference-4.stderr diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs new file mode 100644 index 0000000000000..647c7d622fa56 --- /dev/null +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -0,0 +1,23 @@ +struct S(Option<(A, B)>); + +impl S { + fn infer(&self, a: A, b: B) {} + //~^ NOTE associated function defined here + //~| NOTE + //~| NOTE +} + +fn main() { + let s = S(None); + s.infer(0i32); + //~^ ERROR this method takes 2 arguments but 1 argument was supplied + //~| NOTE an argument is missing + //~| HELP provide the argument + //~| NOTE this is of type `i32`, which causes `s` to be inferred as `S` + //~| HELP change the type of the numeric literal from `i32` to `u32` + let t: S = s; + //~^ ERROR mismatched types + //~| NOTE expected `S`, found `S` + //~| NOTE expected due to this + //~| NOTE expected struct `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 new file mode 100644 index 0000000000000..62e798e56f7cd --- /dev/null +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -0,0 +1,38 @@ +error[E0061]: this method takes 2 arguments but 1 argument was supplied + --> $DIR/point-at-inference-4.rs:12:7 + | +LL | s.infer(0i32); + | ^^^^^------ an argument is missing + | +note: associated function defined here + --> $DIR/point-at-inference-4.rs:4:8 + | +LL | fn infer(&self, a: A, b: B) {} + | ^^^^^ ---- ---- +help: provide the argument + | +LL | s.infer(0i32, /* b */); + | ~~~~~~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/point-at-inference-4.rs:18:24 + | +LL | s.infer(0i32); + | ---- this is of type `i32`, which causes `s` to be inferred as `S` +... +LL | let t: S = s; + | --------- ^ expected `S`, found `S` + | | + | expected due to this + | + = 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 + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`. From e159c1e0ec3c70c1876790984e769f1e20b19a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gammels=C3=A6ter?= Date: Wed, 15 Feb 2023 18:45:20 +0100 Subject: [PATCH 5/8] Skip method calls with arity mismatch --- compiler/rustc_hir_typeck/src/demand.rs | 8 +++++++- tests/ui/type/type-check/point-at-inference-4.rs | 2 -- tests/ui/type/type-check/point-at-inference-4.stderr | 9 +-------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 16d3115c233b0..79b3c0590b6bf 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -298,6 +298,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 @@ -323,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut param_found = FxHashMap::default(); if self.can_eq(self.param_env, ty, found).is_ok() { // We only point at the first place where the found type was inferred. - for (param_ty, arg) in sig.inputs().skip_binder().iter().skip(1).zip(args) { + 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 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 647c7d622fa56..7903e9e83cfb3 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -13,8 +13,6 @@ fn main() { //~^ ERROR this method takes 2 arguments but 1 argument was supplied //~| NOTE an argument is missing //~| HELP provide the argument - //~| NOTE this is of type `i32`, which causes `s` to be inferred as `S` - //~| 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 62e798e56f7cd..fac9701e4a11e 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -15,11 +15,8 @@ LL | s.infer(0i32, /* b */); | ~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/point-at-inference-4.rs:18:24 + --> $DIR/point-at-inference-4.rs:16:24 | -LL | s.infer(0i32); - | ---- this is of type `i32`, which causes `s` to be inferred as `S` -... LL | let t: S = s; | --------- ^ expected `S`, found `S` | | @@ -27,10 +24,6 @@ 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 e087f61075814ae2612193f98a84c7f77101f90f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 15 Feb 2023 23:18:40 +0100 Subject: [PATCH 6/8] don't clone types that are copy --- compiler/rustc_hir_typeck/src/method/probe.rs | 3 +-- compiler/rustc_query_system/src/query/caches.rs | 6 +++--- compiler/rustc_trait_selection/src/solve/mod.rs | 2 +- compiler/rustc_trait_selection/src/traits/object_safety.rs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b5e6727bfbadf..6dd3726a2be38 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -517,8 +517,7 @@ fn method_autoderef_steps<'tcx>( .by_ref() .map(|(ty, d)| { let step = CandidateStep { - self_ty: infcx - .make_query_response_ignoring_pending_obligations(inference_vars.clone(), ty), + self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty), autoderefs: d, from_unsafe_deref: reached_raw_pointer, unsize: false, diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index c9dd75e4d554b..81c7e4673d41b 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -92,7 +92,7 @@ where let mut lock = self.cache.lock(); // We may be overwriting another value. This is all right, since the dep-graph // will check that the fingerprint matches. - lock.insert(key, (value.clone(), index)); + lock.insert(key, (value, index)); value } @@ -153,7 +153,7 @@ where #[inline] fn complete(&self, _key: (), value: V, index: DepNodeIndex) -> Self::Stored { - *self.cache.lock() = Some((value.clone(), index)); + *self.cache.lock() = Some((value, index)); value } @@ -283,7 +283,7 @@ where let mut lock = self.cache.get_shard_by_hash(key.index() as u64).lock(); #[cfg(not(parallel_compiler))] let mut lock = self.cache.lock(); - lock.insert(key, (value.clone(), index)); + lock.insert(key, (value, index)); value } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 301eb4d95f892..28aa3d5270590 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -547,7 +547,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { response.value.certainty == Certainty::Yes && response.has_no_inference_or_external_constraints() }) { - return Ok(response.clone()); + return Ok(*response); } let certainty = candidates.iter().fold(Certainty::AMBIGUOUS, |certainty, response| { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c12ba103c340c..7ef39b2010743 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -599,7 +599,7 @@ fn virtual_call_violation_for_method<'tcx>( return false; } - contains_illegal_self_type_reference(tcx, trait_def_id, pred.clone()) + contains_illegal_self_type_reference(tcx, trait_def_id, pred) }) { return Some(MethodViolationCode::WhereClauseReferencesSelf); } From 46f895caddacf82ae6bf706272d73960a864b6fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Wed, 15 Feb 2023 23:41:23 +0100 Subject: [PATCH 7/8] simplify some refs --- compiler/rustc_middle/src/ty/flags.rs | 2 +- compiler/rustc_type_ir/src/sty.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 258bc9c3e4188..c9aa0ec66d561 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -125,7 +125,7 @@ impl FlagComputation { self.bound_computation(ts, |flags, ts| flags.add_tys(ts)); } - &ty::GeneratorWitnessMIR(_, ref substs) => { + ty::GeneratorWitnessMIR(_, substs) => { let should_remove_further_specializable = !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE); self.add_substs(substs); diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 61557fdc0eda4..e080726d91d58 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -336,7 +336,7 @@ impl PartialEq for TyKind { a_d == b_d && a_s == b_s && a_m == b_m } (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g, - (&GeneratorWitnessMIR(ref a_d, ref a_s), &GeneratorWitnessMIR(ref b_d, ref b_s)) => { + (GeneratorWitnessMIR(a_d, a_s), GeneratorWitnessMIR(b_d, b_s)) => { a_d == b_d && a_s == b_s } (Tuple(a_t), Tuple(b_t)) => a_t == b_t, @@ -397,8 +397,8 @@ impl Ord for TyKind { } (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g.cmp(b_g), ( - &GeneratorWitnessMIR(ref a_d, ref a_s), - &GeneratorWitnessMIR(ref b_d, ref b_s), + GeneratorWitnessMIR(a_d, a_s), + GeneratorWitnessMIR(b_d, b_s), ) => match Ord::cmp(a_d, b_d) { Ordering::Equal => Ord::cmp(a_s, b_s), cmp => cmp, From e17cd0c01961e58e551958f5878b88141dc5aefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 16 Feb 2023 00:06:51 +0100 Subject: [PATCH 8/8] be nice and don't slice These are already slices, no need to slice them again --- compiler/rustc_hir_analysis/src/astconv/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 8c753a99a09f0..9f560ebaf3318 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1970,7 +1970,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) = &qself.kind { // If the path segment already has type params, we want to overwrite // them. - match &path.segments[..] { + match &path.segments { // `segment` is the previous to last element on the path, // which would normally be the `enum` itself, while the last // `_` `PathSegment` corresponds to the variant. @@ -2671,7 +2671,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // `Self` in trait or type alias. assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments.iter(), |err| { - if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments[..] { + if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments { err.span_suggestion_verbose( ident.span.shrink_to_hi().to(args.span_ext), "the `Self` type doesn't accept type parameters",