From c18646067734f03354daa0d1c568e97433e4ad49 Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Sat, 19 Feb 2022 17:29:51 +0100 Subject: [PATCH 1/6] Fix some confusing wording and improve slice-search-related docs --- library/alloc/src/collections/linked_list.rs | 10 +++++----- library/alloc/src/collections/vec_deque/mod.rs | 18 +++++++++++++++--- library/core/src/slice/mod.rs | 18 +++++++++++++++--- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index d81f24e72024d..736b38370ab87 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -645,7 +645,7 @@ impl LinkedList { /// Returns `true` if the `LinkedList` contains an element equal to the /// given value. /// - /// This operation should compute in *O*(*n*) time. + /// This operation should compute linearly in *O*(*n*) time. /// /// # Examples /// @@ -1569,7 +1569,7 @@ impl<'a, T> CursorMut<'a, T> { /// Appends an element to the front of the cursor's parent list. The node /// that the cursor points to is unchanged, even if it is the "ghost" node. /// - /// This operation should compute in O(1) time. + /// This operation should compute in *O*(1) time. // `push_front` continues to point to "ghost" when it addes a node to mimic // the behavior of `insert_before` on an empty list. #[unstable(feature = "linked_list_cursors", issue = "58533")] @@ -1584,7 +1584,7 @@ impl<'a, T> CursorMut<'a, T> { /// Appends an element to the back of the cursor's parent list. The node /// that the cursor points to is unchanged, even if it is the "ghost" node. /// - /// This operation should compute in O(1) time. + /// This operation should compute in *O*(1) time. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn push_back(&mut self, elt: T) { // Safety: We know that `push_back` does not change the position in @@ -1603,7 +1603,7 @@ impl<'a, T> CursorMut<'a, T> { /// unchanged, unless it was pointing to the front element. In that case, it /// points to the new front element. /// - /// This operation should compute in O(1) time. + /// This operation should compute in *O*(1) time. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn pop_front(&mut self) -> Option { // We can't check if current is empty, we must check the list directly. @@ -1630,7 +1630,7 @@ impl<'a, T> CursorMut<'a, T> { /// unchanged, unless it was pointing to the back element. In that case, it /// points to the "ghost" element. /// - /// This operation should compute in O(1) time. + /// This operation should compute in *O*(1) time. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn pop_back(&mut self) -> Option { if self.list.is_empty() { diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 7139a0fb94d76..33b9838970265 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1322,6 +1322,12 @@ impl VecDeque { /// Returns `true` if the deque contains an element equal to the /// given value. /// + /// This operation is *O*(*n*). + /// + /// Note that if you have a sorted `VecDeque`, [`binary_search`] may be faster. + /// + /// [`binary_search`]: VecDeque::binary_search + /// /// # Examples /// /// ``` @@ -2528,7 +2534,8 @@ impl VecDeque { } } - /// Binary searches the sorted deque for a given element. + /// Binary searches this `VecDeque` for a given element. + /// This behaves similarly to [`contains`] if this `VecDeque` is sorted. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2538,6 +2545,7 @@ impl VecDeque { /// /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. /// + /// [`contains`]: VecDeque::contains /// [`binary_search_by`]: VecDeque::binary_search_by /// [`binary_search_by_key`]: VecDeque::binary_search_by_key /// [`partition_point`]: VecDeque::partition_point @@ -2581,7 +2589,8 @@ impl VecDeque { self.binary_search_by(|e| e.cmp(x)) } - /// Binary searches the sorted deque with a comparator function. + /// Binary searches this `VecDeque` with a comparator function. + /// This behaves similarly to [`contains`] if this `VecDeque` is sorted. /// /// The comparator function should implement an order consistent /// with the sort order of the deque, returning an order code that @@ -2596,6 +2605,7 @@ impl VecDeque { /// /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. /// + /// [`contains`]: VecDeque::contains /// [`binary_search`]: VecDeque::binary_search /// [`binary_search_by_key`]: VecDeque::binary_search_by_key /// [`partition_point`]: VecDeque::partition_point @@ -2634,7 +2644,8 @@ impl VecDeque { } } - /// Binary searches the sorted deque with a key extraction function. + /// Binary searches this `VecDeque` with a key extraction function. + /// This behaves similarly to [`contains`] if this `VecDeque` is sorted. /// /// Assumes that the deque is sorted by the key, for instance with /// [`make_contiguous().sort_by_key()`] using the same key extraction function. @@ -2647,6 +2658,7 @@ impl VecDeque { /// /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. /// + /// [`contains`]: VecDeque::contains /// [`make_contiguous().sort_by_key()`]: VecDeque::make_contiguous /// [`binary_search`]: VecDeque::binary_search /// [`binary_search_by`]: VecDeque::binary_search_by diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index cd38c3a75473d..d68982d18e031 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2095,6 +2095,12 @@ impl [T] { /// Returns `true` if the slice contains an element with the given value. /// + /// This operation is *O*(*n*). + /// + /// Note that if you have a sorted slice, [`binary_search`] may be faster. + /// + /// [`binary_search`]: slice::binary_search + /// /// # Examples /// /// ``` @@ -2251,7 +2257,8 @@ impl [T] { None } - /// Binary searches this sorted slice for a given element. + /// Binary searches this slice for a given element. + /// This behaves similary to [`contains`] if this slice is sorted. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -2263,6 +2270,7 @@ impl [T] { /// /// See also [`binary_search_by`], [`binary_search_by_key`], and [`partition_point`]. /// + /// [`contains`]: slice::contains /// [`binary_search_by`]: slice::binary_search_by /// [`binary_search_by_key`]: slice::binary_search_by_key /// [`partition_point`]: slice::partition_point @@ -2301,7 +2309,8 @@ impl [T] { self.binary_search_by(|p| p.cmp(x)) } - /// Binary searches this sorted slice with a comparator function. + /// Binary searches this slice with a comparator function. + /// This behaves similarly to [`contains`] if this slice is sorted. /// /// The comparator function should implement an order consistent /// with the sort order of the underlying slice, returning an @@ -2318,6 +2327,7 @@ impl [T] { /// /// See also [`binary_search`], [`binary_search_by_key`], and [`partition_point`]. /// + /// [`contains`]: slice::contains /// [`binary_search`]: slice::binary_search /// [`binary_search_by_key`]: slice::binary_search_by_key /// [`partition_point`]: slice::partition_point @@ -2376,7 +2386,8 @@ impl [T] { Err(left) } - /// Binary searches this sorted slice with a key extraction function. + /// Binary searches this slice with a key extraction function. + /// This behaves similarly to [`contains`] if this slice is sorted. /// /// Assumes that the slice is sorted by the key, for instance with /// [`sort_by_key`] using the same key extraction function. @@ -2391,6 +2402,7 @@ impl [T] { /// /// See also [`binary_search`], [`binary_search_by`], and [`partition_point`]. /// + /// [`contains`]: slice::contains /// [`sort_by_key`]: slice::sort_by_key /// [`binary_search`]: slice::binary_search /// [`binary_search_by`]: slice::binary_search_by From 3c1e1661e7dbb5b0eb98f4f389878b3ed16f5171 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 17 Apr 2022 14:18:08 +0200 Subject: [PATCH 2/6] Remove unused macro rules --- .../rustc_errors/src/diagnostic_builder.rs | 13 ---------- compiler/rustc_middle/src/ty/codec.rs | 3 --- compiler/rustc_serialize/src/serialize.rs | 1 - compiler/rustc_target/src/spec/mod.rs | 4 ---- library/core/src/internal_macros.rs | 24 ------------------- library/core/tests/num/ops.rs | 12 ---------- library/proc_macro/src/quote.rs | 1 - 7 files changed, 58 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 74e0f74294613..d218040847704 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -255,19 +255,6 @@ impl EmissionGuarantee for ! { /// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes /// it easy to declare such methods on the builder. macro_rules! forward { - // Forward pattern for &self -> &Self - ( - $(#[$attrs:meta])* - pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self - ) => { - $(#[$attrs])* - #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] - pub fn $n(&self, $($name: $ty),*) -> &Self { - self.diagnostic.$n($($name),*); - self - } - }; - // Forward pattern for &mut self -> &mut Self ( $(#[$attrs:meta])* diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 7fcc46cc7c206..23c377651cc6c 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -453,9 +453,6 @@ macro_rules! impl_arena_allocatable_decoder { } } }; - ([$ignore:ident $(, $attrs:ident)*]$args:tt) => { - impl_arena_allocatable_decoder!([$($attrs),*]$args); - }; } macro_rules! impl_arena_allocatable_decoders { diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs index d5053034ed882..7d6b8c760ff6a 100644 --- a/compiler/rustc_serialize/src/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -498,7 +498,6 @@ macro_rules! peel { /// Therefore, the recursion depth is the binary logarithm of the number of /// tokens to count, and the expanded tree is likewise very small. macro_rules! count { - () => (0usize); ($one:tt) => (1usize); ($($pairs:tt $_p:tt)*) => (count!($($pairs)*) << 1usize); ($odd:tt $($rest:tt)*) => (count!($($rest)*) | 1usize); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index bd5b712c143c5..965a3c109832b 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2249,10 +2249,6 @@ impl ToJson for Target { let name = (stringify!($attr)).replace("_", "-"); d.insert(name, self.$attr.to_json()); }}; - ($attr:ident, $key_name:expr) => {{ - let name = $key_name; - d.insert(name.into(), self.$attr.to_json()); - }}; } macro_rules! target_option_val { diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index 417ed51c6b6a2..7ef78e0b48af1 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -1,10 +1,6 @@ // implements the unary operator "op &T" // based on "op T" where T is expected to be `Copy`able macro_rules! forward_ref_unop { - (impl $imp:ident, $method:ident for $t:ty) => { - forward_ref_unop!(impl $imp, $method for $t, - #[stable(feature = "rust1", since = "1.0.0")]); - }; (impl const $imp:ident, $method:ident for $t:ty) => { forward_ref_unop!(impl const $imp, $method for $t, #[stable(feature = "rust1", since = "1.0.0")]); @@ -38,10 +34,6 @@ macro_rules! forward_ref_unop { // implements binary operators "&T op U", "T op &U", "&T op &U" // based on "T op U" where T and U are expected to be `Copy`able macro_rules! forward_ref_binop { - (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { - forward_ref_binop!(impl $imp, $method for $t, $u, - #[stable(feature = "rust1", since = "1.0.0")]); - }; (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => { forward_ref_binop!(impl const $imp, $method for $t, $u, #[stable(feature = "rust1", since = "1.0.0")]); @@ -230,22 +222,6 @@ macro_rules! cfg_if { } }; - // match if/else chains lacking a final `else` - ( - if #[cfg( $i_meta:meta )] { $( $i_tokens:tt )* } - $( - else if #[cfg( $e_meta:meta )] { $( $e_tokens:tt )* } - )* - ) => { - cfg_if! { - @__items () ; - (( $i_meta ) ( $( $i_tokens )* )) , - $( - (( $e_meta ) ( $( $e_tokens )* )) , - )* - } - }; - // Internal and recursive macro to emit all the items // // Collects all the previous cfgs in a list at the beginning, so they can be diff --git a/library/core/tests/num/ops.rs b/library/core/tests/num/ops.rs index 9979cc8fde434..ae8b938250ec9 100644 --- a/library/core/tests/num/ops.rs +++ b/library/core/tests/num/ops.rs @@ -43,18 +43,6 @@ macro_rules! impls_defined { } macro_rules! test_op { - ($fn_name:ident, $op:ident::$method:ident($lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => { - #[test] - fn $fn_name() { - impls_defined!($op, $method($lhs, $rhs), $result, $($t),+); - } - }; - ($fn_name:ident, $op:ident::$method:ident(&mut $lhs:literal, $rhs:literal), $result:literal, $($t:ty),+) => { - #[test] - fn $fn_name() { - impls_defined!($op, $method(&mut $lhs, $rhs), $result, $($t),+); - } - }; ($fn_name:ident, $op:ident::$method:ident($lhs:literal), $result:literal, $($t:ty),+) => { #[test] fn $fn_name() { diff --git a/library/proc_macro/src/quote.rs b/library/proc_macro/src/quote.rs index 1fd59889709b2..04fa696d5e6be 100644 --- a/library/proc_macro/src/quote.rs +++ b/library/proc_macro/src/quote.rs @@ -12,7 +12,6 @@ macro_rules! quote_tt { ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; (,) => { Punct::new(',', Spacing::Alone) }; (.) => { Punct::new('.', Spacing::Alone) }; - (:) => { Punct::new(':', Spacing::Alone) }; (;) => { Punct::new(';', Spacing::Alone) }; (!) => { Punct::new('!', Spacing::Alone) }; (<) => { Punct::new('<', Spacing::Alone) }; From 35874069679cf394e8a93bd5764ce13f9696096b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 23 Apr 2022 19:44:25 -0700 Subject: [PATCH 3/6] Better handle too many `#` recovery in raw str Point at all the unnecessary trailing `#`. Better handle interaction with outer attributes when `;` is missing. Fix #95030. --- .../rustc_parse/src/parser/diagnostics.rs | 43 +++++++++++++++---- src/test/ui/parser/raw/raw-str-unbalanced.rs | 20 ++++++++- .../ui/parser/raw/raw-str-unbalanced.stderr | 36 +++++++++++++--- 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ed2640451705b..acc0d7a6ee05e 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -431,10 +431,11 @@ impl<'a> Parser<'a> { return Ok(true); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(token::Brace) - || ( - t.can_begin_expr() && t != &token::Semi && t != &token::Pound - // Avoid triggering with too many trailing `#` in raw string. - ) + || (t.can_begin_expr() && t != &token::Semi && t != &token::Pound) + // Avoid triggering with too many trailing `#` in raw string. + || (sm.is_multiline( + self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()) + ) && t == &token::Pound) }) { // Missing semicolon typo. This is triggered if the next token could either start a // new statement or is a block close. For example: @@ -508,7 +509,12 @@ impl<'a> Parser<'a> { } if self.check_too_many_raw_str_terminators(&mut err) { - return Err(err); + if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) { + err.emit(); + return Ok(true); + } else { + return Err(err); + } } if self.prev_token.span == DUMMY_SP { @@ -538,6 +544,7 @@ impl<'a> Parser<'a> { } fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool { + let sm = self.sess.source_map(); match (&self.prev_token.kind, &self.token.kind) { ( TokenKind::Literal(Lit { @@ -545,15 +552,33 @@ impl<'a> Parser<'a> { .. }), TokenKind::Pound, - ) => { + ) if !sm.is_multiline( + self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo()), + ) => + { + let n_hashes: u8 = *n_hashes; err.set_primary_message("too many `#` when terminating raw string"); + let str_span = self.prev_token.span; + let mut span = self.token.span; + let mut count = 0; + while self.token.kind == TokenKind::Pound + && !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo())) + { + span = span.with_hi(self.token.span.hi()); + self.bump(); + count += 1; + } + err.set_span(span); err.span_suggestion( - self.token.span, - "remove the extra `#`", + span, + &format!("remove the extra `#`{}", pluralize!(count)), String::new(), Applicability::MachineApplicable, ); - err.note(&format!("the raw string started with {n_hashes} `#`s")); + err.span_label( + str_span, + &format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)), + ); true } _ => false, diff --git a/src/test/ui/parser/raw/raw-str-unbalanced.rs b/src/test/ui/parser/raw/raw-str-unbalanced.rs index 35f118f5ce6ee..38537f8b31e64 100644 --- a/src/test/ui/parser/raw/raw-str-unbalanced.rs +++ b/src/test/ui/parser/raw/raw-str-unbalanced.rs @@ -1,4 +1,22 @@ static s: &'static str = + r#""## //~ ERROR too many `#` when terminating raw string +; + +static s2: &'static str = r#" - "## //~ too many `#` when terminating raw string + "#### //~ ERROR too many `#` when terminating raw string ; + +const A: &'static str = r"" //~ ERROR expected `;`, found `#` + +// Test +#[test] +fn test() {} + +const B: &'static str = r""## //~ ERROR too many `#` when terminating raw string + +// Test +#[test] +fn test2() {} + +fn main() {} diff --git a/src/test/ui/parser/raw/raw-str-unbalanced.stderr b/src/test/ui/parser/raw/raw-str-unbalanced.stderr index bf8f3a7a5a4bd..eac8c06c1df5c 100644 --- a/src/test/ui/parser/raw/raw-str-unbalanced.stderr +++ b/src/test/ui/parser/raw/raw-str-unbalanced.stderr @@ -1,10 +1,36 @@ error: too many `#` when terminating raw string - --> $DIR/raw-str-unbalanced.rs:3:9 + --> $DIR/raw-str-unbalanced.rs:2:10 | -LL | "## - | ^ help: remove the extra `#` +LL | r#""## + | -----^ help: remove the extra `#` + | | + | this raw string started with 1 `#` + +error: too many `#` when terminating raw string + --> $DIR/raw-str-unbalanced.rs:7:9 + | +LL | / r#" +LL | | "#### + | | -^^^ help: remove the extra `#`s + | |________| + | this raw string started with 1 `#` + +error: expected `;`, found `#` + --> $DIR/raw-str-unbalanced.rs:10:28 + | +LL | const A: &'static str = r"" + | ^ help: add `;` here +... +LL | #[test] + | - unexpected token + +error: too many `#` when terminating raw string + --> $DIR/raw-str-unbalanced.rs:16:28 | - = note: the raw string started with 1 `#`s +LL | const B: &'static str = r""## + | ---^^ help: remove the extra `#`s + | | + | this raw string started with 0 `#`s -error: aborting due to previous error +error: aborting due to 4 previous errors From dff7f25981e219f70dc55a2056da8d5b6d715ebf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 24 Apr 2022 16:45:39 -0700 Subject: [PATCH 4/6] suggestion if struct field has method --- compiler/rustc_typeck/src/check/expr.rs | 36 +++++++--------- .../rustc_typeck/src/check/method/suggest.rs | 42 ++++++++++++++++++- src/test/ui/hrtb/issue-30786.migrate.stderr | 8 ++++ src/test/ui/hrtb/issue-30786.nll.stderr | 8 ++++ src/test/ui/suggestions/field-has-method.rs | 23 ++++++++++ .../ui/suggestions/field-has-method.stderr | 17 ++++++++ 6 files changed, 113 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/suggestions/field-has-method.rs create mode 100644 src/test/ui/suggestions/field-has-method.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e88082dbb9744..ffc4e5f970573 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2277,14 +2277,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // try to add a suggestion in case the field is a nested field of a field of the Adt if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) { for candidate_field in fields.iter() { - if let Some(field_path) = self.check_for_nested_field( + if let Some(mut field_path) = self.check_for_nested_field_satisfying( span, - field, + &|candidate_field, _| candidate_field.ident(self.tcx()) == field, candidate_field, substs, vec![], self.tcx.parent_module(id).to_def_id(), ) { + // field_path includes `field` that we're looking for, so pop it. + field_path.pop(); + let field_path_str = field_path .iter() .map(|id| id.name.to_ident_string()) @@ -2304,7 +2307,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err } - fn get_field_candidates( + crate fn get_field_candidates( &self, span: Span, base_t: Ty<'tcx>, @@ -2329,49 +2332,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This method is called after we have encountered a missing field error to recursively /// search for the field - fn check_for_nested_field( + crate fn check_for_nested_field_satisfying( &self, span: Span, - target_field: Ident, + matches: &impl Fn(&ty::FieldDef, Ty<'tcx>) -> bool, candidate_field: &ty::FieldDef, subst: SubstsRef<'tcx>, mut field_path: Vec, id: DefId, ) -> Option> { debug!( - "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}", + "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", span, candidate_field, field_path ); - if candidate_field.ident(self.tcx) == target_field { - Some(field_path) - } else if field_path.len() > 3 { + if field_path.len() > 3 { // For compile-time reasons and to avoid infinite recursion we only check for fields // up to a depth of three None } else { // recursively search fields of `candidate_field` if it's a ty::Adt - field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); let field_ty = candidate_field.ty(self.tcx, subst); if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) { for field in nested_fields.iter() { - let accessible = field.vis.is_accessible_from(id, self.tcx); - if accessible { - let ident = field.ident(self.tcx).normalize_to_macros_2_0(); - if ident == target_field { + if field.vis.is_accessible_from(id, self.tcx) { + if matches(candidate_field, field_ty) { return Some(field_path); - } - let field_path = field_path.clone(); - if let Some(path) = self.check_for_nested_field( + } else if let Some(field_path) = self.check_for_nested_field_satisfying( span, - target_field, + matches, field, subst, - field_path, + field_path.clone(), id, ) { - return Some(path); + return Some(field_path); } } } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 2921176ca4b38..88e0a4bada845 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -28,7 +28,7 @@ use rustc_trait_selection::traits::{ use std::cmp::Ordering; use std::iter; -use super::probe::Mode; +use super::probe::{Mode, ProbeScope}; use super::{CandidateSource, MethodError, NoMatchData}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1129,6 +1129,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { label_span_not_found(); } + if let SelfSource::MethodCall(expr) = source + && let Some((fields, substs)) = self.get_field_candidates(span, actual) + { + let call_expr = + self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); + for candidate_field in fields.iter() { + if let Some(field_path) = self.check_for_nested_field_satisfying( + span, + &|_, field_ty| { + self.lookup_probe( + span, + item_name, + field_ty, + call_expr, + ProbeScope::AllTraits, + ) + .is_ok() + }, + candidate_field, + substs, + vec![], + self.tcx.parent_module(expr.hir_id).to_def_id(), + ) { + let field_path_str = field_path + .iter() + .map(|id| id.name.to_ident_string()) + .collect::>() + .join("."); + debug!("field_path_str: {:?}", field_path_str); + + err.span_suggestion_verbose( + item_name.span.shrink_to_lo(), + "one of the expressions' fields has a method of the same name", + format!("{field_path_str}."), + Applicability::MaybeIncorrect, + ); + } + } + } + bound_spans.sort(); bound_spans.dedup(); for (span, msg) in bound_spans.into_iter() { diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr index 7ffe2f4cd7e1c..7157b186fc8ad 100644 --- a/src/test/ui/hrtb/issue-30786.migrate.stderr +++ b/src/test/ui/hrtb/issue-30786.migrate.stderr @@ -18,6 +18,10 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here +help: one of the expressions' fields has a method of the same name + | +LL | let filter = map.stream.filterx(|x: &_| true); + | +++++++ error[E0599]: the method `countx` exists for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:140:24 @@ -39,6 +43,10 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here +help: one of the expressions' fields has a method of the same name + | +LL | let count = filter.stream.countx(); + | +++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr index 7ffe2f4cd7e1c..7157b186fc8ad 100644 --- a/src/test/ui/hrtb/issue-30786.nll.stderr +++ b/src/test/ui/hrtb/issue-30786.nll.stderr @@ -18,6 +18,10 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here +help: one of the expressions' fields has a method of the same name + | +LL | let filter = map.stream.filterx(|x: &_| true); + | +++++++ error[E0599]: the method `countx` exists for struct `Filter fn(&'r u64) -> &'r u64 {identity::}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:140:24 @@ -39,6 +43,10 @@ note: the following trait bounds were not satisfied: | LL | impl StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here +help: one of the expressions' fields has a method of the same name + | +LL | let count = filter.stream.countx(); + | +++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/field-has-method.rs b/src/test/ui/suggestions/field-has-method.rs new file mode 100644 index 0000000000000..980000151e2f7 --- /dev/null +++ b/src/test/ui/suggestions/field-has-method.rs @@ -0,0 +1,23 @@ +struct Kind; + +struct Ty { + kind: Kind, +} + +impl Ty { + fn kind(&self) -> Kind { + todo!() + } +} + +struct InferOk { + value: T, + predicates: Vec<()>, +} + +fn foo(i: InferOk) { + let k = i.kind(); + //~^ no method named `kind` found for struct `InferOk` in the current scope +} + +fn main() {} diff --git a/src/test/ui/suggestions/field-has-method.stderr b/src/test/ui/suggestions/field-has-method.stderr new file mode 100644 index 0000000000000..3a57436f200ba --- /dev/null +++ b/src/test/ui/suggestions/field-has-method.stderr @@ -0,0 +1,17 @@ +error[E0599]: no method named `kind` found for struct `InferOk` in the current scope + --> $DIR/field-has-method.rs:19:15 + | +LL | struct InferOk { + | ----------------- method `kind` not found for this +... +LL | let k = i.kind(); + | ^^^^ method not found in `InferOk` + | +help: one of the expressions' fields has a method of the same name + | +LL | let k = i.value.kind(); + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. From 5165295452276e6c45ba48b1a53224a41a69ecdb Mon Sep 17 00:00:00 2001 From: Preston From Date: Sun, 24 Apr 2022 02:00:12 -0600 Subject: [PATCH 5/6] Delay bug when adjusting NeverToAny twice during diagnostic --- compiler/rustc_typeck/src/check/expr.rs | 16 ++++++++--- src/test/ui/never_type/issue-96335.rs | 5 ++++ src/test/ui/never_type/issue-96335.stderr | 35 +++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/never_type/issue-96335.rs create mode 100644 src/test/ui/never_type/issue-96335.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e88082dbb9744..76ac356efd6d5 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -78,10 +78,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. if ty.is_never() { - assert!( - !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id), - "expression with never type wound up being adjusted" - ); + if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { + self.tcx().sess.delay_span_bug( + expr.span, + "expression with never type wound up being adjusted", + ); + return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] { + target.to_owned() + } else { + self.tcx().ty_error() + }; + } + let adj_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::AdjustmentType, span: expr.span, diff --git a/src/test/ui/never_type/issue-96335.rs b/src/test/ui/never_type/issue-96335.rs new file mode 100644 index 0000000000000..411a7c9df657b --- /dev/null +++ b/src/test/ui/never_type/issue-96335.rs @@ -0,0 +1,5 @@ +fn main() { + 0.....{loop{}1}; + //~^ ERROR unexpected token + //~| ERROR mismatched types +} diff --git a/src/test/ui/never_type/issue-96335.stderr b/src/test/ui/never_type/issue-96335.stderr new file mode 100644 index 0000000000000..168cf2f83535d --- /dev/null +++ b/src/test/ui/never_type/issue-96335.stderr @@ -0,0 +1,35 @@ +error: unexpected token: `...` + --> $DIR/issue-96335.rs:2:6 + | +LL | 0.....{loop{}1}; + | ^^^ + | +help: use `..` for an exclusive range + | +LL | 0....{loop{}1}; + | ~~ +help: or `..=` for an inclusive range + | +LL | 0..=..{loop{}1}; + | ~~~ + +error[E0308]: mismatched types + --> $DIR/issue-96335.rs:2:9 + | +LL | 0.....{loop{}1}; + | ----^^^^^^^^^^^ + | | | + | | expected integer, found struct `RangeTo` + | arguments to this function are incorrect + | + = note: expected type `{integer}` + found struct `RangeTo<{integer}>` +note: associated function defined here + --> $SRC_DIR/core/src/ops/range.rs:LL:COL + | +LL | pub const fn new(start: Idx, end: Idx) -> Self { + | ^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 5594db097540d831cb7d98a662c7f3df7011411b Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 25 Apr 2022 08:51:26 +0200 Subject: [PATCH 6/6] do not consider two extern types to be similar --- .../src/traits/error_reporting/mod.rs | 1 + .../ui/extern/extern-type-diag-not-similar.rs | 22 +++++++++++++++++++ .../extern-type-diag-not-similar.stderr | 16 ++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/test/ui/extern/extern-type-diag-not-similar.rs create mode 100644 src/test/ui/extern/extern-type-diag-not-similar.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 50e4fafdd6c82..082402a38e3f5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1727,6 +1727,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { } else if cat_a == cat_b { match (a.kind(), b.kind()) { (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b, + (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b, // Matching on references results in a lot of unhelpful // suggestions, so let's just not do that for now. // diff --git a/src/test/ui/extern/extern-type-diag-not-similar.rs b/src/test/ui/extern/extern-type-diag-not-similar.rs new file mode 100644 index 0000000000000..39d00a6c1bc31 --- /dev/null +++ b/src/test/ui/extern/extern-type-diag-not-similar.rs @@ -0,0 +1,22 @@ +// We previously mentioned other extern types in the error message here. +// +// Two extern types shouldn't really be considered similar just +// because they are both extern types. + +#![feature(extern_types)] +extern { + type ShouldNotBeMentioned; +} + +extern { + type Foo; +} + +unsafe impl Send for ShouldNotBeMentioned {} + +fn assert_send() {} + +fn main() { + assert_send::() + //~^ ERROR `Foo` cannot be sent between threads safely +} diff --git a/src/test/ui/extern/extern-type-diag-not-similar.stderr b/src/test/ui/extern/extern-type-diag-not-similar.stderr new file mode 100644 index 0000000000000..75836f7eca19c --- /dev/null +++ b/src/test/ui/extern/extern-type-diag-not-similar.stderr @@ -0,0 +1,16 @@ +error[E0277]: `Foo` cannot be sent between threads safely + --> $DIR/extern-type-diag-not-similar.rs:20:19 + | +LL | assert_send::() + | ^^^ `Foo` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `Foo` +note: required by a bound in `assert_send` + --> $DIR/extern-type-diag-not-similar.rs:17:19 + | +LL | fn assert_send() {} + | ^^^^ required by this bound in `assert_send` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.