From 321247deb31545b41e29f703bf2f2770b6809f38 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Fri, 18 Feb 2022 15:21:56 +0100 Subject: [PATCH 01/13] Share testing utilities with non-btree test cases --- library/alloc/src/collections/btree/map/tests.rs | 6 +++--- library/alloc/src/collections/btree/mod.rs | 3 --- library/alloc/src/collections/btree/set/tests.rs | 4 ++-- library/alloc/src/lib.rs | 2 ++ .../alloc/src/{collections/btree => }/testing/crash_test.rs | 0 library/alloc/src/{collections/btree => }/testing/mod.rs | 0 .../alloc/src/{collections/btree => }/testing/ord_chaos.rs | 0 library/alloc/src/{collections/btree => }/testing/rng.rs | 0 8 files changed, 7 insertions(+), 8 deletions(-) rename library/alloc/src/{collections/btree => }/testing/crash_test.rs (100%) rename library/alloc/src/{collections/btree => }/testing/mod.rs (100%) rename library/alloc/src/{collections/btree => }/testing/ord_chaos.rs (100%) rename library/alloc/src/{collections/btree => }/testing/rng.rs (100%) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 47ba1777ae903..ee588282291eb 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1,12 +1,12 @@ -use super::super::testing::crash_test::{CrashTestDummy, Panic}; -use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor}; -use super::super::testing::rng::DeterministicRng; use super::Entry::{Occupied, Vacant}; use super::*; use crate::boxed::Box; use crate::fmt::Debug; use crate::rc::Rc; use crate::string::{String, ToString}; +use crate::testing::crash_test::{CrashTestDummy, Panic}; +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; diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 9571b3d594df8..9728c284315dc 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -20,6 +20,3 @@ trait Recover { fn take(&mut self, key: &Q) -> Option; fn replace(&mut self, key: Self::Key) -> Option; } - -#[cfg(test)] -mod testing; diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index 429b1644976c7..4d49d9e83de7e 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -1,6 +1,6 @@ -use super::super::testing::crash_test::{CrashTestDummy, Panic}; -use super::super::testing::rng::DeterministicRng; use super::*; +use crate::testing::crash_test::{CrashTestDummy, Panic}; +use crate::testing::rng::DeterministicRng; use crate::vec::Vec; use std::cmp::Ordering; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4d2dc4ecee0b8..658f7b3bae797 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -188,6 +188,8 @@ extern crate std; #[cfg(test)] extern crate test; +#[cfg(test)] +mod testing; // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] diff --git a/library/alloc/src/collections/btree/testing/crash_test.rs b/library/alloc/src/testing/crash_test.rs similarity index 100% rename from library/alloc/src/collections/btree/testing/crash_test.rs rename to library/alloc/src/testing/crash_test.rs diff --git a/library/alloc/src/collections/btree/testing/mod.rs b/library/alloc/src/testing/mod.rs similarity index 100% rename from library/alloc/src/collections/btree/testing/mod.rs rename to library/alloc/src/testing/mod.rs diff --git a/library/alloc/src/collections/btree/testing/ord_chaos.rs b/library/alloc/src/testing/ord_chaos.rs similarity index 100% rename from library/alloc/src/collections/btree/testing/ord_chaos.rs rename to library/alloc/src/testing/ord_chaos.rs diff --git a/library/alloc/src/collections/btree/testing/rng.rs b/library/alloc/src/testing/rng.rs similarity index 100% rename from library/alloc/src/collections/btree/testing/rng.rs rename to library/alloc/src/testing/rng.rs From 204f854586cebc5b2e46b1c83fb6d83fe01acf6a Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Fri, 18 Feb 2022 15:21:56 +0100 Subject: [PATCH 02/13] Slightly tighten leak-on-panic test cases --- .../src/collections/binary_heap/tests.rs | 45 +++++++-------- .../src/collections/linked_list/tests.rs | 56 +++++++++---------- 2 files changed, 49 insertions(+), 52 deletions(-) diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs index 7c758dbb3ab8a..4e54d7d5ab621 100644 --- a/library/alloc/src/collections/binary_heap/tests.rs +++ b/library/alloc/src/collections/binary_heap/tests.rs @@ -1,8 +1,8 @@ use super::*; use crate::boxed::Box; +use crate::testing::crash_test::{CrashTestDummy, Panic}; use std::iter::TrustedLen; use std::panic::{catch_unwind, AssertUnwindSafe}; -use std::sync::atomic::{AtomicU32, Ordering}; #[test] fn test_iterator() { @@ -291,33 +291,30 @@ fn test_drain_sorted() { #[test] fn test_drain_sorted_leak() { - static DROPS: AtomicU32 = AtomicU32::new(0); - - #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] - struct D(u32, bool); - - impl Drop for D { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - - if self.1 { - panic!("panic in `drop`"); - } - } - } - + let d0 = CrashTestDummy::new(0); + let d1 = CrashTestDummy::new(1); + let d2 = CrashTestDummy::new(2); + let d3 = CrashTestDummy::new(3); + let d4 = CrashTestDummy::new(4); + let d5 = CrashTestDummy::new(5); let mut q = BinaryHeap::from(vec![ - D(0, false), - D(1, false), - D(2, false), - D(3, true), - D(4, false), - D(5, false), + d0.spawn(Panic::Never), + d1.spawn(Panic::Never), + d2.spawn(Panic::Never), + d3.spawn(Panic::InDrop), + d4.spawn(Panic::Never), + d5.spawn(Panic::Never), ]); - catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok(); + catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).unwrap_err(); - assert_eq!(DROPS.load(Ordering::SeqCst), 6); + assert_eq!(d0.dropped(), 1); + assert_eq!(d1.dropped(), 1); + assert_eq!(d2.dropped(), 1); + assert_eq!(d3.dropped(), 1); + assert_eq!(d4.dropped(), 1); + assert_eq!(d5.dropped(), 1); + assert!(q.is_empty()); } #[test] diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index 38c702aa387bd..bb98262684f4f 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -1,4 +1,5 @@ use super::*; +use crate::testing::crash_test::{CrashTestDummy, Panic}; use crate::vec::Vec; use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -984,35 +985,34 @@ fn drain_filter_complex() { #[test] fn drain_filter_drop_panic_leak() { - static mut DROPS: i32 = 0; - - struct D(bool); - - impl Drop for D { - fn drop(&mut self) { - unsafe { - DROPS += 1; - } - - if self.0 { - panic!("panic in `drop`"); - } - } - } - + let d0 = CrashTestDummy::new(0); + let d1 = CrashTestDummy::new(1); + let d2 = CrashTestDummy::new(2); + let d3 = CrashTestDummy::new(3); + let d4 = CrashTestDummy::new(4); + let d5 = CrashTestDummy::new(5); + let d6 = CrashTestDummy::new(6); + let d7 = CrashTestDummy::new(7); let mut q = LinkedList::new(); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_back(D(false)); - q.push_front(D(false)); - q.push_front(D(true)); - q.push_front(D(false)); - - catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok(); - - assert_eq!(unsafe { DROPS }, 8); + q.push_back(d3.spawn(Panic::Never)); + q.push_back(d4.spawn(Panic::Never)); + q.push_back(d5.spawn(Panic::Never)); + q.push_back(d6.spawn(Panic::Never)); + q.push_back(d7.spawn(Panic::Never)); + q.push_front(d2.spawn(Panic::Never)); + q.push_front(d1.spawn(Panic::InDrop)); + q.push_front(d0.spawn(Panic::Never)); + + catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err(); + + assert_eq!(d0.dropped(), 1); + assert_eq!(d1.dropped(), 1); + assert_eq!(d2.dropped(), 1); + assert_eq!(d3.dropped(), 1); + assert_eq!(d4.dropped(), 1); + assert_eq!(d5.dropped(), 1); + assert_eq!(d6.dropped(), 1); + assert_eq!(d7.dropped(), 1); assert!(q.is_empty()); } From a80e685e11a6876d3ec1e54f4e5fafd92c6c4eb2 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Fri, 18 Feb 2022 16:01:39 +0100 Subject: [PATCH 03/13] Test leaking of BinaryHeap Drain iterators --- .../src/collections/binary_heap/tests.rs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/library/alloc/src/collections/binary_heap/tests.rs b/library/alloc/src/collections/binary_heap/tests.rs index 4e54d7d5ab621..4a4c6fbdcfe00 100644 --- a/library/alloc/src/collections/binary_heap/tests.rs +++ b/library/alloc/src/collections/binary_heap/tests.rs @@ -317,6 +317,59 @@ fn test_drain_sorted_leak() { assert!(q.is_empty()); } +#[test] +fn test_drain_forget() { + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut q = + BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]); + + catch_unwind(AssertUnwindSafe(|| { + let mut it = q.drain(); + it.next(); + mem::forget(it); + })) + .unwrap(); + // Behaviour after leaking is explicitly unspecified and order is arbitrary, + // so it's fine if these start failing, but probably worth knowing. + assert!(q.is_empty()); + assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1); + assert_eq!(a.dropped(), 0); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 1); + drop(q); + assert_eq!(a.dropped(), 0); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 1); +} + +#[test] +fn test_drain_sorted_forget() { + let a = CrashTestDummy::new(0); + let b = CrashTestDummy::new(1); + let c = CrashTestDummy::new(2); + let mut q = + BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]); + + catch_unwind(AssertUnwindSafe(|| { + let mut it = q.drain_sorted(); + it.next(); + mem::forget(it); + })) + .unwrap(); + // Behaviour after leaking is explicitly unspecified, + // so it's fine if these start failing, but probably worth knowing. + assert_eq!(q.len(), 2); + assert_eq!(a.dropped(), 0); + assert_eq!(b.dropped(), 0); + assert_eq!(c.dropped(), 1); + drop(q); + assert_eq!(a.dropped(), 1); + assert_eq!(b.dropped(), 1); + assert_eq!(c.dropped(), 1); +} + #[test] fn test_extend_ref() { let mut a = BinaryHeap::new(); From d2eb2bb8548e97e29abfeab1825c006c5ba02efc Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 2 Nov 2022 15:38:15 +0200 Subject: [PATCH 04/13] Clarify docs of `RefCell` Comparison operators only panic if the `RefCell` is mutably borrowed, and `RefCell::swap()` can also panic if swapping a `RefCell` with itself. --- library/core/src/cell.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 7bf32cb0d98f2..0a48603257b41 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -807,7 +807,8 @@ impl RefCell { /// /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently borrowed, or + /// if `self` and `other` point to the same `RefCell`. /// /// # Examples /// @@ -1193,7 +1194,7 @@ impl Default for RefCell { impl PartialEq for RefCell { /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently mutably borrowed. #[inline] fn eq(&self, other: &RefCell) -> bool { *self.borrow() == *other.borrow() @@ -1207,7 +1208,7 @@ impl Eq for RefCell {} impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently mutably borrowed. #[inline] fn partial_cmp(&self, other: &RefCell) -> Option { self.borrow().partial_cmp(&*other.borrow()) @@ -1215,7 +1216,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently mutably borrowed. #[inline] fn lt(&self, other: &RefCell) -> bool { *self.borrow() < *other.borrow() @@ -1223,7 +1224,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently mutably borrowed. #[inline] fn le(&self, other: &RefCell) -> bool { *self.borrow() <= *other.borrow() @@ -1231,7 +1232,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently mutably borrowed. #[inline] fn gt(&self, other: &RefCell) -> bool { *self.borrow() > *other.borrow() @@ -1239,7 +1240,7 @@ impl PartialOrd for RefCell { /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently mutably borrowed. #[inline] fn ge(&self, other: &RefCell) -> bool { *self.borrow() >= *other.borrow() @@ -1250,7 +1251,7 @@ impl PartialOrd for RefCell { impl Ord for RefCell { /// # Panics /// - /// Panics if the value in either `RefCell` is currently borrowed. + /// Panics if the value in either `RefCell` is currently mutably borrowed. #[inline] fn cmp(&self, other: &RefCell) -> Ordering { self.borrow().cmp(&*other.borrow()) From 3b8b0ac62ad2a8f828763350a37dfd5e14db171e Mon Sep 17 00:00:00 2001 From: Anett Seeker Date: Sat, 5 Nov 2022 21:52:18 +0100 Subject: [PATCH 05/13] Fix unused_must_use warning for Box::from_raw --- library/alloc/src/boxed.rs | 2 +- src/test/ui/lint/unused/must-use-box-from-raw.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index b7e7d5a38a5b1..f73df698f166c 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -952,7 +952,7 @@ impl Box { /// [`Layout`]: crate::Layout #[stable(feature = "box_raw", since = "1.4.0")] #[inline] - #[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `Box`"] + #[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"] pub unsafe fn from_raw(raw: *mut T) -> Self { unsafe { Self::from_raw_in(raw, Global) } } diff --git a/src/test/ui/lint/unused/must-use-box-from-raw.stderr b/src/test/ui/lint/unused/must-use-box-from-raw.stderr index 011acc3bf5d6e..fcf32b75d8d92 100644 --- a/src/test/ui/lint/unused/must-use-box-from-raw.stderr +++ b/src/test/ui/lint/unused/must-use-box-from-raw.stderr @@ -4,7 +4,7 @@ warning: unused return value of `Box::::from_raw` that must be used LL | Box::from_raw(ptr); | ^^^^^^^^^^^^^^^^^^^ | - = note: call `drop(from_raw(ptr))` if you intend to drop the `Box` + = note: call `drop(Box::from_raw(ptr))` if you intend to drop the `Box` note: the lint level is defined here --> $DIR/must-use-box-from-raw.rs:5:9 | From 70bba3b62aa604063fb884602bf3a45dad990fe2 Mon Sep 17 00:00:00 2001 From: Jonas Spinner Date: Tue, 22 Nov 2022 11:06:57 +0100 Subject: [PATCH 06/13] rustdoc: Fix backoff doc to match implementation --- library/std/src/sync/mpmc/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sync/mpmc/utils.rs b/library/std/src/sync/mpmc/utils.rs index d0904b4b94cbc..e030c55ce8f61 100644 --- a/library/std/src/sync/mpmc/utils.rs +++ b/library/std/src/sync/mpmc/utils.rs @@ -136,7 +136,7 @@ impl Backoff { } } - /// Returns `true` if exponential backoff has completed and blocking the thread is advised. + /// Returns `true` if quadratic backoff has completed and blocking the thread is advised. #[inline] pub fn is_completed(&self) -> bool { self.step.get() > YIELD_LIMIT From 1b341fe8a1ce3c4922b5e39aee6c4375e05b6750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 26 Dec 2022 17:44:16 -0800 Subject: [PATCH 07/13] Suggest `impl Iterator` when possible for `_` return type Address #106096. --- compiler/rustc_hir_analysis/src/collect.rs | 66 ++++++++++++++++++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/iter/traits/iterator.rs | 1 + .../ui/typeck/typeck_type_placeholder_item.rs | 8 +++ .../typeck_type_placeholder_item.stderr | 23 ++++++- 5 files changed, 96 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b7d599f57fd44..0a7a3038d00d6 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -24,14 +24,20 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericParamKind, Node}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::hir::nested_filter; use rustc_middle::ty::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeVisitable, +}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::spec::abi; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; +use rustc_trait_selection::traits::ObligationCtxt; use std::iter; mod generics_of; @@ -1224,7 +1230,17 @@ fn infer_return_ty_for_fn_sig<'tcx>( // to prevent the user from getting a papercut while trying to use the unique closure // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`). diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound"); - diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html"); + diag.note( + "for more information on `Fn` traits and closure types, see \ + https://doc.rust-lang.org/book/ch13-01-closures.html", + ); + } else if let Some(i_ty) = suggest_impl_iterator(tcx, ret_ty, ty.span, hir_id, def_id) { + diag.span_suggestion( + ty.span, + "replace with an appropriate return type", + format!("impl Iterator", i_ty), + Applicability::MachineApplicable, + ); } diag.emit(); @@ -1242,6 +1258,52 @@ fn infer_return_ty_for_fn_sig<'tcx>( } } +fn suggest_impl_iterator<'tcx>( + tcx: TyCtxt<'tcx>, + ret_ty: Ty<'tcx>, + span: Span, + hir_id: hir::HirId, + def_id: LocalDefId, +) -> Option> { + let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) else { return None; }; + let Some(iterator_item) = tcx.get_diagnostic_item(sym::IteratorItem) else { return None; }; + if !tcx + .infer_ctxt() + .build() + .type_implements_trait(iter_trait, [ret_ty], tcx.param_env(iter_trait)) + .must_apply_modulo_regions() + { + return None; + } + let infcx = tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new_in_snapshot(&infcx); + // Find the type of `Iterator::Item`. + let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }; + let ty_var = infcx.next_ty_var(origin); + let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection( + ty::ProjectionPredicate { + projection_ty: tcx.mk_alias_ty(iterator_item, tcx.mk_substs([ret_ty.into()].iter())), + term: ty_var.into(), + }, + ))); + // Add `::Item = _` obligation. + ocx.register_obligation(crate::traits::Obligation::misc( + tcx, + span, + hir_id, + tcx.param_env(def_id), + projection, + )); + if ocx.select_where_possible().is_empty() + && let item_ty = infcx.resolve_vars_if_possible(ty_var) + && !item_ty.references_error() + && !item_ty.has_placeholders() + { + return Some(item_ty); + } + None +} + fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { let icx = ItemCtxt::new(tcx, def_id); let item = tcx.hir().expect_item(def_id.expect_local()); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 90f654c68ecbf..85510fa2c660c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -213,6 +213,7 @@ symbols! { Is, ItemContext, Iterator, + IteratorItem, Layout, Left, LinkedList, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index bac836292f8fa..dcbed4e963ff9 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -66,6 +66,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} #[must_use = "iterators are lazy and do nothing unless consumed"] pub trait Iterator { /// The type of the elements being iterated over. + #[rustc_diagnostic_item = "IteratorItem"] #[stable(feature = "rust1", since = "1.0.0")] type Item; diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index 22fedb22d66c6..b96c527133959 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -220,3 +220,11 @@ fn value() -> Option<&'static _> { const _: Option<_> = map(value); //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants + +fn evens_squared(n: usize) -> _ { +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types + (1..n).filter(|x| x % 2 == 0).map(|x| x * x) +} + +const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); +//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index c57f71b8057a9..034bdae5f2e61 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -428,6 +428,27 @@ LL | const _: Option<_> = map(value); | not allowed in type signatures | help: replace with the correct type: `Option` +error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/typeck_type_placeholder_item.rs:224:31 + | +LL | fn evens_squared(n: usize) -> _ { + | ^ + | | + | not allowed in type signatures + | help: replace with an appropriate return type: `impl Iterator` + +error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants + --> $DIR/typeck_type_placeholder_item.rs:229:10 + | +LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); + | ^ not allowed in type signatures + | +note: however, the inferred type `Map, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>, [closure@$DIR/typeck_type_placeholder_item.rs:229:49: 229:52]>` cannot be named + --> $DIR/typeck_type_placeholder_item.rs:229:14 + | +LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions --> $DIR/typeck_type_placeholder_item.rs:140:31 | @@ -636,7 +657,7 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace with the correct type: `i32` -error: aborting due to 69 previous errors +error: aborting due to 71 previous errors Some errors have detailed explanations: E0121, E0282, E0403. For more information about an error, try `rustc --explain E0121`. From 43b2486a9589380fd10698c2169351641a142f2e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 02:10:54 +0000 Subject: [PATCH 08/13] Clean up operator type checking --- compiler/rustc_hir_typeck/src/method/mod.rs | 71 +++++---------------- compiler/rustc_hir_typeck/src/op.rs | 43 ++++--------- 2 files changed, 27 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index fddb8a458a7d5..bd3b90134d7ff 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -306,8 +306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, - opt_input_type: Option>, - opt_input_expr: Option<&'tcx hir::Expr<'tcx>>, + opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>, expected: Expectation<'tcx>, ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List>) { @@ -318,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { GenericParamDefKind::Type { .. } => { if param.index == 0 { return self_ty.into(); - } else if let Some(input_type) = opt_input_type { + } else if let Some((_, input_type)) = opt_rhs { return input_type.into(); } } @@ -339,9 +338,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, self.body_id, traits::BinOp { - rhs_span: opt_input_expr.map(|expr| expr.span), - is_lit: opt_input_expr - .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), + rhs_span: opt_rhs.map(|(expr, _)| expr.span), + is_lit: opt_rhs + .map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))), output_ty, }, ), @@ -368,15 +367,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option>> { let (obligation, substs) = self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); - self.construct_obligation_for_trait( - span, - m_name, - trait_def_id, - obligation, - substs, - None, - false, - ) + self.construct_obligation_for_trait(span, m_name, trait_def_id, obligation, substs) } pub(super) fn lookup_op_method_in_trait( @@ -385,27 +376,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { m_name: Ident, trait_def_id: DefId, self_ty: Ty<'tcx>, - opt_input_type: Option>, - opt_input_expr: Option<&'tcx hir::Expr<'tcx>>, + opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>, expected: Expectation<'tcx>, ) -> Option>> { - let (obligation, substs) = self.obligation_for_op_method( - span, - trait_def_id, - self_ty, - opt_input_type, - opt_input_expr, - expected, - ); - self.construct_obligation_for_trait( - span, - m_name, - trait_def_id, - obligation, - substs, - opt_input_expr, - true, - ) + let (obligation, substs) = + self.obligation_for_op_method(span, trait_def_id, self_ty, opt_rhs, expected); + self.construct_obligation_for_trait(span, m_name, trait_def_id, obligation, substs) } // FIXME(#18741): it seems likely that we can consolidate some of this @@ -418,8 +394,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id: DefId, obligation: traits::PredicateObligation<'tcx>, substs: &'tcx ty::List>, - opt_input_expr: Option<&'tcx hir::Expr<'tcx>>, - is_op: bool, ) -> Option>> { debug!(?obligation); @@ -463,22 +437,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fn_sig = fn_sig.subst(self.tcx, substs); let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig); - let cause = if is_op { - ObligationCause::new( - span, - self.body_id, - traits::BinOp { - rhs_span: opt_input_expr.map(|expr| expr.span), - is_lit: opt_input_expr - .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_ty: None, - }, - ) - } else { - traits::ObligationCause::misc(span, self.body_id) - }; - - let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(fn_sig); + let InferOk { value, obligations: o } = + self.at(&obligation.cause, self.param_env).normalize(fn_sig); let fn_sig = { obligations.extend(o); value @@ -494,7 +454,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // any late-bound regions appearing in its bounds. let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); - let InferOk { value, obligations: o } = self.at(&cause, self.param_env).normalize(bounds); + let InferOk { value, obligations: o } = + self.at(&obligation.cause, self.param_env).normalize(bounds); let bounds = { obligations.extend(o); value @@ -502,7 +463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(!bounds.has_escaping_bound_vars()); - let predicates_cause = cause.clone(); + let predicates_cause = obligation.cause.clone(); obligations.extend(traits::predicates_for_generics( move |_, _| predicates_cause.clone(), self.param_env, @@ -517,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); obligations.push(traits::Obligation::new( tcx, - cause, + obligation.cause, self.param_env, ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())), )); diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 9f0d175c4c669..632f4e9401e44 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -48,8 +48,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self .lookup_op_method( lhs_deref_ty, - Some(rhs_ty), - Some(rhs), + Some((rhs, rhs_ty)), Op::Binary(op, IsAssign::Yes), expected, ) @@ -60,8 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self .lookup_op_method( lhs_ty, - Some(rhs_ty), - Some(rhs), + Some((rhs, rhs_ty)), Op::Binary(op, IsAssign::Yes), expected, ) @@ -248,8 +246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let result = self.lookup_op_method( lhs_ty, - Some(rhs_ty_var), - Some(rhs_expr), + Some((rhs_expr, rhs_ty_var)), Op::Binary(op, is_assign), expected, ); @@ -382,8 +379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self .lookup_op_method( lhs_deref_ty, - Some(rhs_ty), - Some(rhs_expr), + Some((rhs_expr, rhs_ty)), Op::Binary(op, is_assign), expected, ) @@ -410,8 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_compatible = |lhs_ty, rhs_ty| { self.lookup_op_method( lhs_ty, - Some(rhs_ty), - Some(rhs_expr), + Some((rhs_expr, rhs_ty)), Op::Binary(op, is_assign), expected, ) @@ -471,8 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let errors = self .lookup_op_method( lhs_ty, - Some(rhs_ty), - Some(rhs_expr), + Some((rhs_expr, rhs_ty)), Op::Binary(op, is_assign), expected, ) @@ -625,7 +619,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { assert!(op.is_by_value()); - match self.lookup_op_method(operand_ty, None, None, Op::Unary(op, ex.span), expected) { + match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) { Ok(method) => { self.write_method_call(ex.hir_id, method); method.sig.output() @@ -712,8 +706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn lookup_op_method( &self, lhs_ty: Ty<'tcx>, - other_ty: Option>, - other_ty_expr: Option<&'tcx hir::Expr<'tcx>>, + opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>, op: Op, expected: Expectation<'tcx>, ) -> Result, Vec>> { @@ -747,15 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let opname = Ident::with_dummy_span(opname); let method = trait_did.and_then(|trait_did| { - self.lookup_op_method_in_trait( - span, - opname, - trait_did, - lhs_ty, - other_ty, - other_ty_expr, - expected, - ) + self.lookup_op_method_in_trait(span, opname, trait_did, lhs_ty, opt_rhs, expected) }); match (method, trait_did) { @@ -766,14 +751,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } (None, None) => Err(vec![]), (None, Some(trait_did)) => { - let (obligation, _) = self.obligation_for_op_method( - span, - trait_did, - lhs_ty, - other_ty, - other_ty_expr, - expected, - ); + let (obligation, _) = + self.obligation_for_op_method(span, trait_did, lhs_ty, opt_rhs, expected); Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation)) } } From 8bf7ec75343cde1c72a5e16b0171e259412b8958 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 02:40:56 +0000 Subject: [PATCH 09/13] Deduplicate more op-flavored methods --- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/method/mod.rs | 89 +++------------------ compiler/rustc_hir_typeck/src/op.rs | 26 +++++- compiler/rustc_hir_typeck/src/place_op.rs | 4 +- 4 files changed, 37 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index af14ee08a9981..829913d278d06 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -241,7 +241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if let Some(ok) = self.lookup_method_in_trait( - call_expr.span, + self.misc(call_expr.span), method_name, trait_def_id, adjusted_ty, diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index bd3b90134d7ff..b9b27e8627aff 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -11,7 +11,7 @@ pub use self::suggest::SelfSource; pub use self::MethodError::*; use crate::errors::OpMethodGenericParams; -use crate::{Expectation, FnCtxt}; +use crate::FnCtxt; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; @@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn obligation_for_method( &self, - span: Span, + cause: ObligationCause<'tcx>, trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, @@ -282,70 +282,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - self.var_for_def(span, param) - }); - - let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs); - - // Construct an obligation - let poly_trait_ref = ty::Binder::dummy(trait_ref); - ( - traits::Obligation::misc( - self.tcx, - span, - self.body_id, - self.param_env, - poly_trait_ref.without_const(), - ), - substs, - ) - } - - pub(super) fn obligation_for_op_method( - &self, - span: Span, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>, - expected: Expectation<'tcx>, - ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List>) - { - // Construct a trait-reference `self_ty : Trait` - let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { - match param.kind { - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {} - GenericParamDefKind::Type { .. } => { - if param.index == 0 { - return self_ty.into(); - } else if let Some((_, input_type)) = opt_rhs { - return input_type.into(); - } - } - } - self.var_for_def(span, param) + self.var_for_def(cause.span, param) }); let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs); // Construct an obligation let poly_trait_ref = ty::Binder::dummy(trait_ref); - let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty)); - ( traits::Obligation::new( self.tcx, - traits::ObligationCause::new( - span, - self.body_id, - traits::BinOp { - rhs_span: opt_rhs.map(|(expr, _)| expr.span), - is_lit: opt_rhs - .map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_ty, - }, - ), + cause, self.param_env, - poly_trait_ref, + poly_trait_ref.without_const(), ), substs, ) @@ -356,32 +305,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// In particular, it doesn't really do any probing: it simply constructs /// an obligation for a particular trait with the given self type and checks /// whether that trait is implemented. - #[instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self))] pub(super) fn lookup_method_in_trait( &self, - span: Span, + cause: ObligationCause<'tcx>, m_name: Ident, trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, ) -> Option>> { let (obligation, substs) = - self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); - self.construct_obligation_for_trait(span, m_name, trait_def_id, obligation, substs) - } - - pub(super) fn lookup_op_method_in_trait( - &self, - span: Span, - m_name: Ident, - trait_def_id: DefId, - self_ty: Ty<'tcx>, - opt_rhs: Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)>, - expected: Expectation<'tcx>, - ) -> Option>> { - let (obligation, substs) = - self.obligation_for_op_method(span, trait_def_id, self_ty, opt_rhs, expected); - self.construct_obligation_for_trait(span, m_name, trait_def_id, obligation, substs) + self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types); + self.construct_obligation_for_trait(m_name, trait_def_id, obligation, substs) } // FIXME(#18741): it seems likely that we can consolidate some of this @@ -389,7 +324,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // of this method is basically the same as confirmation. fn construct_obligation_for_trait( &self, - span: Span, m_name: Ident, trait_def_id: DefId, obligation: traits::PredicateObligation<'tcx>, @@ -409,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let Some(method_item) = self.associated_value(trait_def_id, m_name) else { tcx.sess.delay_span_bug( - span, + obligation.cause.span, "operator trait does not have corresponding operator method", ); return None; @@ -435,7 +369,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // with bound regions. let fn_sig = tcx.bound_fn_sig(def_id); let fn_sig = fn_sig.subst(self.tcx, substs); - let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig); + let fn_sig = + self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig); let InferOk { value, obligations: o } = self.at(&obligation.cause, self.param_env).normalize(fn_sig); diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 632f4e9401e44..34140f3e1fe3e 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -12,14 +12,16 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; +use rustc_middle::ty::{ + self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable, +}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::FulfillmentError; +use rustc_trait_selection::traits::{self, FulfillmentError}; use rustc_type_ir::sty::TyKind::*; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -486,6 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(output_def_id) = output_def_id && let Some(trait_def_id) = trait_def_id && self.tcx.parent(output_def_id) == trait_def_id + && output_ty.is_suggestable(self.tcx, false) { Some(("Output", *output_ty)) } else { @@ -735,12 +738,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Op::Unary(..) => 0, }, ) { + self.tcx + .sess + .delay_span_bug(span, "operator didn't have the right number of generic args"); return Err(vec![]); } let opname = Ident::with_dummy_span(opname); + let input_types = + opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default(); + let cause = self.cause( + span, + traits::BinOp { + rhs_span: opt_rhs.map(|(expr, _)| expr.span), + is_lit: opt_rhs + .map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))), + output_ty: expected.only_has_type(self), + }, + ); + let method = trait_did.and_then(|trait_did| { - self.lookup_op_method_in_trait(span, opname, trait_did, lhs_ty, opt_rhs, expected) + self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types)) }); match (method, trait_did) { @@ -752,7 +770,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, None) => Err(vec![]), (None, Some(trait_did)) => { let (obligation, _) = - self.obligation_for_op_method(span, trait_did, lhs_ty, opt_rhs, expected); + self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation)) } } diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 952ea14887f7b..a0f048fc09b9b 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -225,7 +225,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { imm_tr.and_then(|trait_did| { self.lookup_method_in_trait( - span, + self.misc(span), Ident::with_dummy_span(imm_op), trait_did, base_ty, @@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut_tr.and_then(|trait_did| { self.lookup_method_in_trait( - span, + self.misc(span), Ident::with_dummy_span(mut_op), trait_did, base_ty, From aff403cf689e30fdd20b96333d3a10db92086e4f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 27 Dec 2022 06:14:40 +0000 Subject: [PATCH 10/13] Recover `fn` keyword as `Fn` trait in bounds --- .../locales/en-US/parse.ftl | 3 + compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_lexer/src/lib.rs | 2 +- compiler/rustc_parse/src/errors.rs | 8 ++ compiler/rustc_parse/src/parser/ty.rs | 48 +++++++++- src/test/ui/parser/kw-in-trait-bounds.rs | 16 +--- src/test/ui/parser/kw-in-trait-bounds.stderr | 88 ++++++------------- .../ui/parser/recover-fn-trait-from-fn-kw.rs | 12 +++ .../parser/recover-fn-trait-from-fn-kw.stderr | 48 ++++++++++ 9 files changed, 148 insertions(+), 79 deletions(-) create mode 100644 src/test/ui/parser/recover-fn-trait-from-fn-kw.rs create mode 100644 src/test/ui/parser/recover-fn-trait-from-fn-kw.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/parse.ftl b/compiler/rustc_error_messages/locales/en-US/parse.ftl index b53550e5fd556..3401978caf5f0 100644 --- a/compiler/rustc_error_messages/locales/en-US/parse.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parse.ftl @@ -365,3 +365,6 @@ parse_invalid_identifier_with_leading_number = expected identifier, found number parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` .suggestion = replace `fn` with `impl` here + +parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn` + .suggestion = use `Fn` to refer to the trait diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index ef50efb81253f..406e1569a6f75 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -626,7 +626,7 @@ impl<'a> ExtCtxt<'a> { // Builds `#[name = val]`. // - // Note: `span` is used for both the identifer and the value. + // Note: `span` is used for both the identifier and the value. pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.parse_sess.attr_id_generator; attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 50d6d5b9bab91..4c65fca29b897 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -851,7 +851,7 @@ impl Cursor<'_> { } // Eats the identifier. Note: succeeds on `_`, which isn't a valid - // identifer. + // identifier. fn eat_identifier(&mut self) { if !is_id_start(self.first()) { return; diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 18a0bee9c2e5e..574591529f331 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1229,3 +1229,11 @@ pub(crate) struct FnTypoWithImpl { #[suggestion(applicability = "maybe-incorrect", code = "impl", style = "verbose")] pub fn_span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_expected_fn_path_found_fn_keyword)] +pub(crate) struct ExpectedFnPathFoundFnKeyword { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "Fn", style = "verbose")] + pub fn_token_span: Span, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index b7206b57642fc..a4b0f66e1eced 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,8 +1,9 @@ use super::{Parser, PathStyle, TokenType}; -use crate::errors::{FnPtrWithGenerics, FnPtrWithGenericsSugg}; +use crate::errors::{ExpectedFnPathFoundFnKeyword, FnPtrWithGenerics, FnPtrWithGenericsSugg}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; +use ast::DUMMY_NODE_ID; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::util::case::Case; @@ -12,7 +13,9 @@ use rustc_ast::{ }; use rustc_errors::{pluralize, struct_span_err, Applicability, PResult}; use rustc_span::source_map::Span; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::Symbol; +use thin_vec::thin_vec; /// Any `?` or `~const` modifiers that appear at the start of a bound. struct BoundModifiers { @@ -912,7 +915,14 @@ impl<'a> Parser<'a> { modifiers: BoundModifiers, ) -> PResult<'a, GenericBound> { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; + let path = if self.token.is_keyword(kw::Fn) + && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) + && let Some(path) = self.recover_path_from_fn() + { + path + } else { + self.parse_path(PathStyle::Type)? + }; if has_parens { if self.token.is_like_plus() { // Someone has written something like `&dyn (Trait + Other)`. The correct code @@ -941,6 +951,38 @@ impl<'a> Parser<'a> { Ok(GenericBound::Trait(poly_trait, modifier)) } + // recovers a `Fn(..)` parenthesized-style path from `fn(..)` + fn recover_path_from_fn(&mut self) -> Option { + let fn_token_span = self.token.span; + self.bump(); + let args_lo = self.token.span; + let snapshot = self.create_snapshot_for_diagnostic(); + match self.parse_fn_decl(|_| false, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) { + Ok(decl) => { + self.sess.emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span }); + Some(ast::Path { + span: fn_token_span.to(self.prev_token.span), + segments: thin_vec![ast::PathSegment { + ident: Ident::new(Symbol::intern("Fn"), fn_token_span), + id: DUMMY_NODE_ID, + args: Some(P(ast::GenericArgs::Parenthesized(ast::ParenthesizedArgs { + span: args_lo.to(self.prev_token.span), + inputs: decl.inputs.iter().map(|a| a.ty.clone()).collect(), + inputs_span: args_lo.until(decl.output.span()), + output: decl.output.clone(), + }))), + }], + tokens: None, + }) + } + Err(diag) => { + diag.cancel(); + self.restore_snapshot(snapshot); + None + } + } + } + /// Optionally parses `for<$generic_params>`. pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { diff --git a/src/test/ui/parser/kw-in-trait-bounds.rs b/src/test/ui/parser/kw-in-trait-bounds.rs index fa037e5937dca..e9e85339affa9 100644 --- a/src/test/ui/parser/kw-in-trait-bounds.rs +++ b/src/test/ui/parser/kw-in-trait-bounds.rs @@ -4,21 +4,13 @@ fn _f(_: impl fn(), _: &dyn fn()) //~^ ERROR expected identifier, found keyword `fn` //~| ERROR expected identifier, found keyword `fn` //~| ERROR expected identifier, found keyword `fn` -//~| ERROR cannot find trait `r#fn` in this scope -//~| ERROR cannot find trait `r#fn` in this scope -//~| ERROR cannot find trait `r#fn` in this scope -//~| HELP a trait with a similar name exists -//~| HELP a trait with a similar name exists -//~| HELP a trait with a similar name exists -//~| HELP escape `fn` to use it as an identifier -//~| HELP escape `fn` to use it as an identifier -//~| HELP escape `fn` to use it as an identifier +//~| HELP use `Fn` to refer to the trait +//~| HELP use `Fn` to refer to the trait +//~| HELP use `Fn` to refer to the trait where G: fn(), //~^ ERROR expected identifier, found keyword `fn` - //~| ERROR cannot find trait `r#fn` in this scope - //~| HELP a trait with a similar name exists - //~| HELP escape `fn` to use it as an identifier + //~| HELP use `Fn` to refer to the trait {} fn _g(_: impl struct, _: &dyn struct) diff --git a/src/test/ui/parser/kw-in-trait-bounds.stderr b/src/test/ui/parser/kw-in-trait-bounds.stderr index 79643660e8b00..2d3aad4d6baf4 100644 --- a/src/test/ui/parser/kw-in-trait-bounds.stderr +++ b/src/test/ui/parser/kw-in-trait-bounds.stderr @@ -2,48 +2,48 @@ error: expected identifier, found keyword `fn` --> $DIR/kw-in-trait-bounds.rs:3:10 | LL | fn _f(_: impl fn(), _: &dyn fn()) - | ^^ expected identifier, found keyword + | ^^ | -help: escape `fn` to use it as an identifier +help: use `Fn` to refer to the trait | -LL | fn _f(_: impl fn(), _: &dyn fn()) - | ++ +LL | fn _f(_: impl fn(), _: &dyn fn()) + | ~~ error: expected identifier, found keyword `fn` --> $DIR/kw-in-trait-bounds.rs:3:27 | LL | fn _f(_: impl fn(), _: &dyn fn()) - | ^^ expected identifier, found keyword + | ^^ | -help: escape `fn` to use it as an identifier +help: use `Fn` to refer to the trait | -LL | fn _f(_: impl r#fn(), _: &dyn fn()) - | ++ +LL | fn _f(_: impl Fn(), _: &dyn fn()) + | ~~ error: expected identifier, found keyword `fn` --> $DIR/kw-in-trait-bounds.rs:3:41 | LL | fn _f(_: impl fn(), _: &dyn fn()) - | ^^ expected identifier, found keyword + | ^^ | -help: escape `fn` to use it as an identifier +help: use `Fn` to refer to the trait | -LL | fn _f(_: impl fn(), _: &dyn r#fn()) - | ++ +LL | fn _f(_: impl fn(), _: &dyn Fn()) + | ~~ error: expected identifier, found keyword `fn` - --> $DIR/kw-in-trait-bounds.rs:17:4 + --> $DIR/kw-in-trait-bounds.rs:11:4 | LL | G: fn(), - | ^^ expected identifier, found keyword + | ^^ | -help: escape `fn` to use it as an identifier +help: use `Fn` to refer to the trait | -LL | G: r#fn(), - | ++ +LL | G: Fn(), + | ~~ error: expected identifier, found keyword `struct` - --> $DIR/kw-in-trait-bounds.rs:24:10 + --> $DIR/kw-in-trait-bounds.rs:16:10 | LL | fn _g(_: impl struct, _: &dyn struct) | ^^^^^^ expected identifier, found keyword @@ -54,7 +54,7 @@ LL | fn _g(_: impl struct, _: &dyn struct) | ++ error: expected identifier, found keyword `struct` - --> $DIR/kw-in-trait-bounds.rs:24:29 + --> $DIR/kw-in-trait-bounds.rs:16:29 | LL | fn _g(_: impl struct, _: &dyn struct) | ^^^^^^ expected identifier, found keyword @@ -65,7 +65,7 @@ LL | fn _g(_: impl r#struct, _: &dyn struct) | ++ error: expected identifier, found keyword `struct` - --> $DIR/kw-in-trait-bounds.rs:24:45 + --> $DIR/kw-in-trait-bounds.rs:16:45 | LL | fn _g(_: impl struct, _: &dyn struct) | ^^^^^^ expected identifier, found keyword @@ -76,7 +76,7 @@ LL | fn _g(_: impl struct, _: &dyn r#struct) | ++ error: expected identifier, found keyword `struct` - --> $DIR/kw-in-trait-bounds.rs:38:8 + --> $DIR/kw-in-trait-bounds.rs:30:8 | LL | B: struct, | ^^^^^^ expected identifier, found keyword @@ -86,44 +86,8 @@ help: escape `struct` to use it as an identifier LL | B: r#struct, | ++ -error[E0405]: cannot find trait `r#fn` in this scope - --> $DIR/kw-in-trait-bounds.rs:3:10 - | -LL | fn _f(_: impl fn(), _: &dyn fn()) - | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - | - = note: similarly named trait `Fn` defined here - -error[E0405]: cannot find trait `r#fn` in this scope - --> $DIR/kw-in-trait-bounds.rs:17:4 - | -LL | G: fn(), - | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - | - = note: similarly named trait `Fn` defined here - -error[E0405]: cannot find trait `r#fn` in this scope - --> $DIR/kw-in-trait-bounds.rs:3:27 - | -LL | fn _f(_: impl fn(), _: &dyn fn()) - | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - | - = note: similarly named trait `Fn` defined here - -error[E0405]: cannot find trait `r#fn` in this scope - --> $DIR/kw-in-trait-bounds.rs:3:41 - | -LL | fn _f(_: impl fn(), _: &dyn fn()) - | ^^ help: a trait with a similar name exists (notice the capitalization): `Fn` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - | - = note: similarly named trait `Fn` defined here - error[E0405]: cannot find trait `r#struct` in this scope - --> $DIR/kw-in-trait-bounds.rs:24:10 + --> $DIR/kw-in-trait-bounds.rs:16:10 | LL | fn _g(_: impl struct, _: &dyn struct) | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` @@ -132,7 +96,7 @@ LL | trait Struct {} | ------------ similarly named trait `Struct` defined here error[E0405]: cannot find trait `r#struct` in this scope - --> $DIR/kw-in-trait-bounds.rs:38:8 + --> $DIR/kw-in-trait-bounds.rs:30:8 | LL | B: struct, | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` @@ -141,7 +105,7 @@ LL | trait Struct {} | ------------ similarly named trait `Struct` defined here error[E0405]: cannot find trait `r#struct` in this scope - --> $DIR/kw-in-trait-bounds.rs:24:29 + --> $DIR/kw-in-trait-bounds.rs:16:29 | LL | fn _g(_: impl struct, _: &dyn struct) | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` @@ -150,7 +114,7 @@ LL | trait Struct {} | ------------ similarly named trait `Struct` defined here error[E0405]: cannot find trait `r#struct` in this scope - --> $DIR/kw-in-trait-bounds.rs:24:45 + --> $DIR/kw-in-trait-bounds.rs:16:45 | LL | fn _g(_: impl struct, _: &dyn struct) | ^^^^^^ help: a trait with a similar name exists (notice the capitalization): `Struct` @@ -158,6 +122,6 @@ LL | fn _g(_: impl struct, _: &dyn struct) LL | trait Struct {} | ------------ similarly named trait `Struct` defined here -error: aborting due to 16 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0405`. diff --git a/src/test/ui/parser/recover-fn-trait-from-fn-kw.rs b/src/test/ui/parser/recover-fn-trait-from-fn-kw.rs new file mode 100644 index 0000000000000..b6611e6273d37 --- /dev/null +++ b/src/test/ui/parser/recover-fn-trait-from-fn-kw.rs @@ -0,0 +1,12 @@ +fn foo(_: impl fn() -> i32) {} +//~^ ERROR expected identifier, found keyword `fn` + +fn foo2(_: T) {} +//~^ ERROR expected identifier, found keyword `fn` + +fn main() { + foo(|| ()); + //~^ mismatched types + foo2(|_: ()| {}); + //~^ type mismatch in closure arguments +} diff --git a/src/test/ui/parser/recover-fn-trait-from-fn-kw.stderr b/src/test/ui/parser/recover-fn-trait-from-fn-kw.stderr new file mode 100644 index 0000000000000..3681a796c53ed --- /dev/null +++ b/src/test/ui/parser/recover-fn-trait-from-fn-kw.stderr @@ -0,0 +1,48 @@ +error: expected identifier, found keyword `fn` + --> $DIR/recover-fn-trait-from-fn-kw.rs:1:16 + | +LL | fn foo(_: impl fn() -> i32) {} + | ^^ + | +help: use `Fn` to refer to the trait + | +LL | fn foo(_: impl Fn() -> i32) {} + | ~~ + +error: expected identifier, found keyword `fn` + --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12 + | +LL | fn foo2(_: T) {} + | ^^ + | +help: use `Fn` to refer to the trait + | +LL | fn foo2(_: T) {} + | ~~ + +error[E0308]: mismatched types + --> $DIR/recover-fn-trait-from-fn-kw.rs:8:12 + | +LL | foo(|| ()); + | ^^ expected `i32`, found `()` + +error[E0631]: type mismatch in closure arguments + --> $DIR/recover-fn-trait-from-fn-kw.rs:10:5 + | +LL | foo2(|_: ()| {}); + | ^^^^ ------- found signature defined here + | | + | expected due to this + | + = note: expected closure signature `fn(i32) -> _` + found closure signature `fn(()) -> _` +note: required by a bound in `foo2` + --> $DIR/recover-fn-trait-from-fn-kw.rs:4:12 + | +LL | fn foo2(_: T) {} + | ^^^^^^^ required by this bound in `foo2` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0631. +For more information about an error, try `rustc --explain E0308`. From 6d332c4a7148854c8efb405291fc0bf13d5e7b33 Mon Sep 17 00:00:00 2001 From: Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> Date: Tue, 27 Dec 2022 16:16:22 +0100 Subject: [PATCH 11/13] Fix `core::any` mod-level docs --- library/core/src/any.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 1a379ecc11c01..9ca4947ed8f8b 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -148,7 +148,7 @@ //! ``` //! //! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then -//! the `get_context_ref` call will return a reference to `obj.some_string` with type `&String`. +//! the `get_context_by_ref` call will return a reference to `obj.some_string` with type `&String`. #![stable(feature = "rust1", since = "1.0.0")] From df2a35ea3df2eb055ef68ba77eac6cc99e855da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 27 Dec 2022 13:44:39 -0800 Subject: [PATCH 12/13] review comments --- compiler/rustc_hir_analysis/src/collect.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0a7a3038d00d6..9e46968c40819 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -29,9 +29,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::hir::nested_filter; use rustc_middle::ty::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{ - self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeVisitable, -}; +use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::spec::abi; @@ -1270,7 +1268,7 @@ fn suggest_impl_iterator<'tcx>( if !tcx .infer_ctxt() .build() - .type_implements_trait(iter_trait, [ret_ty], tcx.param_env(iter_trait)) + .type_implements_trait(iter_trait, [ret_ty], tcx.param_env(def_id)) .must_apply_modulo_regions() { return None; @@ -1296,8 +1294,7 @@ fn suggest_impl_iterator<'tcx>( )); if ocx.select_where_possible().is_empty() && let item_ty = infcx.resolve_vars_if_possible(ty_var) - && !item_ty.references_error() - && !item_ty.has_placeholders() + && item_ty.is_suggestable(tcx, false) { return Some(item_ty); } From b400bde52a2508f966133c8cf9445ce570f08248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 27 Dec 2022 14:11:41 -0800 Subject: [PATCH 13/13] Shorten type in note --- compiler/rustc_hir_analysis/src/collect/type_of.rs | 13 +++++++------ src/test/ui/suggestions/unnamable-types.stderr | 4 ++-- .../ui/typeck/typeck_type_placeholder_item.stderr | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index b678990f94e91..4bd55a5483147 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -5,6 +5,7 @@ use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, Node}; use rustc_middle::hir::nested_filter; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; @@ -907,10 +908,10 @@ fn infer_placeholder_type<'a>( Applicability::MachineApplicable, ); } else { - err.span_note( + with_forced_trimmed_paths!(err.span_note( tcx.hir().body(body_id).value.span, - &format!("however, the inferred type `{}` cannot be named", ty), - ); + &format!("however, the inferred type `{ty}` cannot be named"), + )); } } @@ -931,10 +932,10 @@ fn infer_placeholder_type<'a>( Applicability::MaybeIncorrect, ); } else { - diag.span_note( + with_forced_trimmed_paths!(diag.span_note( tcx.hir().body(body_id).value.span, - &format!("however, the inferred type `{}` cannot be named", ty), - ); + &format!("however, the inferred type `{ty}` cannot be named"), + )); } } diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr index ede3ebfa739c4..24bedb5297b1f 100644 --- a/src/test/ui/suggestions/unnamable-types.stderr +++ b/src/test/ui/suggestions/unnamable-types.stderr @@ -19,7 +19,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures LL | const C: _ = || 42; | ^ not allowed in type signatures | -note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:16]` cannot be named +note: however, the inferred type `[closure@unnamable-types.rs:17:14]` cannot be named --> $DIR/unnamable-types.rs:17:14 | LL | const C: _ = || 42; @@ -31,7 +31,7 @@ error: missing type for `const` item LL | const D = S { t: { let i = 0; move || -> i32 { i } } }; | ^ | -note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named +note: however, the inferred type `S<[closure@unnamable-types.rs:23:31]>` cannot be named --> $DIR/unnamable-types.rs:23:11 | LL | const D = S { t: { let i = 0; move || -> i32 { i } } }; diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 034bdae5f2e61..bc02547c65eb8 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -443,7 +443,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x); | ^ not allowed in type signatures | -note: however, the inferred type `Map, [closure@$DIR/typeck_type_placeholder_item.rs:229:29: 229:32]>, [closure@$DIR/typeck_type_placeholder_item.rs:229:49: 229:52]>` cannot be named +note: however, the inferred type `Map, [closure@typeck_type_placeholder_item.rs:229:29]>, [closure@typeck_type_placeholder_item.rs:229:49]>` cannot be named --> $DIR/typeck_type_placeholder_item.rs:229:14 | LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);