From 6ee7e8c978b1e354e210de6abe50d6d5bc1a77cb Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 6 Apr 2020 15:18:05 +0200 Subject: [PATCH 01/10] Remove the Ord bound that was plaguing drain_filter, and superfluous lifetimes --- src/liballoc/collections/btree/map.rs | 41 ++++++++------------------- src/liballoc/collections/btree/set.rs | 25 ++++++---------- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 70968964f476e..7809a70c4c733 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1699,28 +1699,22 @@ impl Clone for Values<'_, K, V> { #[unstable(feature = "btree_drain_filter", issue = "70530")] pub struct DrainFilter<'a, K, V, F> where - K: 'a + Ord, // This Ord bound should be removed before stabilization. + K: 'a, V: 'a, F: 'a + FnMut(&K, &mut V) -> bool, { pred: F, inner: DrainFilterInner<'a, K, V>, } -pub(super) struct DrainFilterInner<'a, K, V> -where - K: 'a + Ord, - V: 'a, -{ +pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> { length: &'a mut usize, cur_leaf_edge: Option, K, V, marker::Leaf>, marker::Edge>>, } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, K, V, F> Drop for DrainFilter<'a, K, V, F> +impl Drop for DrainFilter<'_, K, V, F> where - K: 'a + Ord, - V: 'a, - F: 'a + FnMut(&K, &mut V) -> bool, + F: FnMut(&K, &mut V) -> bool, { fn drop(&mut self) { self.for_each(drop); @@ -1728,11 +1722,11 @@ where } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F> +impl fmt::Debug for DrainFilter<'_, K, V, F> where - K: 'a + fmt::Debug + Ord, - V: 'a + fmt::Debug, - F: 'a + FnMut(&K, &mut V) -> bool, + K: fmt::Debug, + V: fmt::Debug, + F: FnMut(&K, &mut V) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("DrainFilter").field(&self.inner.peek()).finish() @@ -1740,11 +1734,9 @@ where } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, K, V, F> Iterator for DrainFilter<'a, K, V, F> +impl Iterator for DrainFilter<'_, K, V, F> where - K: 'a + Ord, - V: 'a, - F: 'a + FnMut(&K, &mut V) -> bool, + F: FnMut(&K, &mut V) -> bool, { type Item = (K, V); @@ -1757,11 +1749,7 @@ where } } -impl<'a, K, V> DrainFilterInner<'a, K, V> -where - K: 'a + Ord, - V: 'a, -{ +impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { /// Allow Debug implementations to predict the next element. pub(super) fn peek(&self) -> Option<(&K, &V)> { let edge = self.cur_leaf_edge.as_ref()?; @@ -1800,12 +1788,7 @@ where } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl FusedIterator for DrainFilter<'_, K, V, F> -where - K: Ord, - F: FnMut(&K, &mut V) -> bool, -{ -} +impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} #[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for Range<'a, K, V> { diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 0b02223def4f8..9bf483f269f6e 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -1094,7 +1094,7 @@ impl<'a, T> IntoIterator for &'a BTreeSet { #[unstable(feature = "btree_drain_filter", issue = "70530")] pub struct DrainFilter<'a, T, F> where - T: 'a + Ord, + T: 'a, F: 'a + FnMut(&T) -> bool, { pred: F, @@ -1102,10 +1102,9 @@ where } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, T, F> Drop for DrainFilter<'a, T, F> +impl Drop for DrainFilter<'_, T, F> where - T: 'a + Ord, - F: 'a + FnMut(&T) -> bool, + F: FnMut(&T) -> bool, { fn drop(&mut self) { self.for_each(drop); @@ -1113,10 +1112,10 @@ where } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, T, F> fmt::Debug for DrainFilter<'a, T, F> +impl fmt::Debug for DrainFilter<'_, T, F> where - T: 'a + Ord + fmt::Debug, - F: 'a + FnMut(&T) -> bool, + T: fmt::Debug, + F: FnMut(&T) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("DrainFilter").field(&self.inner.peek().map(|(k, _)| k)).finish() @@ -1124,10 +1123,9 @@ where } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, 'f, T, F> Iterator for DrainFilter<'a, T, F> +impl<'a, T, F> Iterator for DrainFilter<'_, T, F> where - T: 'a + Ord, - F: 'a + 'f + FnMut(&T) -> bool, + F: 'a + FnMut(&T) -> bool, { type Item = T; @@ -1143,12 +1141,7 @@ where } #[unstable(feature = "btree_drain_filter", issue = "70530")] -impl<'a, T, F> FusedIterator for DrainFilter<'a, T, F> -where - T: 'a + Ord, - F: 'a + FnMut(&T) -> bool, -{ -} +impl FusedIterator for DrainFilter<'_, T, F> where F: FnMut(&T) -> bool {} #[stable(feature = "rust1", since = "1.0.0")] impl Extend for BTreeSet { From 9d13520a6b00fe239c3990e487cd7449722c0c74 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 8 Apr 2020 04:26:48 +0300 Subject: [PATCH 02/10] Replace "rc"/"arc" lang items with Rc/Arc diagnostic items. --- src/liballoc/rc.rs | 3 +- src/liballoc/sync.rs | 3 +- src/librustc_error_codes/error_codes/E0152.md | 4 +-- src/librustc_error_codes/error_codes/E0718.md | 2 +- src/librustc_hir/lang_items.rs | 3 -- src/librustc_middle/ty/context.rs | 6 ++++ src/librustc_middle/ty/mod.rs | 23 +------------- src/librustc_middle/ty/sty.rs | 18 ----------- .../borrow_check/diagnostics/mod.rs | 30 +++++++++---------- .../borrow_check/diagnostics/move_errors.rs | 5 +++- .../diagnostics/mutability_errors.rs | 2 +- src/librustc_span/symbol.rs | 2 ++ src/librustc_typeck/check/expr.rs | 12 ++++---- src/test/ui/error-codes/E0152.rs | 2 +- src/test/ui/error-codes/E0152.stderr | 2 +- src/test/ui/error-codes/E0718.rs | 4 +-- src/test/ui/error-codes/E0718.stderr | 6 ++-- 17 files changed, 49 insertions(+), 78 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 9db997e864170..abc4056cf5695 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -279,7 +279,8 @@ struct RcBox { /// type `T`. /// /// [get_mut]: #method.get_mut -#[cfg_attr(not(test), lang = "rc")] +#[cfg_attr(all(bootstrap, not(test)), lang = "rc")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { ptr: NonNull>, diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 1cfb26eb35a11..b1b22e46a7c2f 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -207,7 +207,8 @@ macro_rules! acquire { /// counting in general. /// /// [rc_examples]: ../../std/rc/index.html#examples -#[cfg_attr(not(test), lang = "arc")] +#[cfg_attr(all(bootstrap, not(test)), lang = "arc")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { ptr: NonNull>, diff --git a/src/librustc_error_codes/error_codes/E0152.md b/src/librustc_error_codes/error_codes/E0152.md index 602dcb6e2c5b7..120c96b421104 100644 --- a/src/librustc_error_codes/error_codes/E0152.md +++ b/src/librustc_error_codes/error_codes/E0152.md @@ -5,8 +5,8 @@ Erroneous code example: ```compile_fail,E0152 #![feature(lang_items)] -#[lang = "arc"] -struct Foo; // error: duplicate lang item found: `arc` +#[lang = "owned_box"] +struct Foo; // error: duplicate lang item found: `owned_box` ``` Lang items are already implemented in the standard library. Unless you are diff --git a/src/librustc_error_codes/error_codes/E0718.md b/src/librustc_error_codes/error_codes/E0718.md index 8548ff0c15011..e7ae51ca58835 100644 --- a/src/librustc_error_codes/error_codes/E0718.md +++ b/src/librustc_error_codes/error_codes/E0718.md @@ -6,6 +6,6 @@ Examples of erroneous code: ```compile_fail,E0718 #![feature(lang_items)] -#[lang = "arc"] +#[lang = "owned_box"] static X: u32 = 42; ``` diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 89457009a8bfa..5a3a9cabeb450 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -254,7 +254,4 @@ language_item_table! { AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; TerminationTraitLangItem, "termination", termination, Target::Trait; - - Arc, "arc", arc, Target::Struct; - Rc, "rc", rc, Target::Struct; } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 95d0c758d08de..076134b8e9462 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -2213,6 +2213,12 @@ impl<'tcx> TyCtxt<'tcx> { Some(self.mk_generic_adt(def_id, ty)) } + #[inline] + pub fn mk_diagnostic_item(self, ty: Ty<'tcx>, name: Symbol) -> Option> { + let def_id = self.get_diagnostic_item(name)?; + Some(self.mk_generic_adt(def_id, ty)) + } + #[inline] pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None); diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 1870856150f50..3683ea3288feb 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1856,14 +1856,9 @@ bitflags! { const IS_BOX = 1 << 6; /// Indicates whether the type is `ManuallyDrop`. const IS_MANUALLY_DROP = 1 << 7; - // FIXME(matthewjasper) replace these with diagnostic items - /// Indicates whether the type is an `Arc`. - const IS_ARC = 1 << 8; - /// Indicates whether the type is an `Rc`. - const IS_RC = 1 << 9; /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// (i.e., this flag is never set unless this ADT is an enum). - const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 10; + const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; } } @@ -2248,12 +2243,6 @@ impl<'tcx> AdtDef { if Some(did) == tcx.lang_items().manually_drop() { flags |= AdtFlags::IS_MANUALLY_DROP; } - if Some(did) == tcx.lang_items().arc() { - flags |= AdtFlags::IS_ARC; - } - if Some(did) == tcx.lang_items().rc() { - flags |= AdtFlags::IS_RC; - } AdtDef { did, variants, flags, repr } } @@ -2332,16 +2321,6 @@ impl<'tcx> AdtDef { self.flags.contains(AdtFlags::IS_PHANTOM_DATA) } - /// Returns `true` if this is `Arc`. - pub fn is_arc(&self) -> bool { - self.flags.contains(AdtFlags::IS_ARC) - } - - /// Returns `true` if this is `Rc`. - pub fn is_rc(&self) -> bool { - self.flags.contains(AdtFlags::IS_RC) - } - /// Returns `true` if this is Box. #[inline] pub fn is_box(&self) -> bool { diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index f09327886872c..fbd5049b0fbcb 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -1865,24 +1865,6 @@ impl<'tcx> TyS<'tcx> { self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() } - /// Returns `true` if this type is an `Arc`. - #[inline] - pub fn is_arc(&self) -> bool { - match self.kind { - Adt(def, _) => def.is_arc(), - _ => false, - } - } - - /// Returns `true` if this type is an `Rc`. - #[inline] - pub fn is_rc(&self) -> bool { - match self.kind { - Adt(def, _) => def.is_rc(), - _ => false, - } - } - #[inline] pub fn is_box(&self) -> bool { match self.kind { diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index 619ae0ff8faa1..404cc0c74679f 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{symbol::sym, Span}; use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; @@ -632,20 +632,20 @@ pub(super) enum BorrowedContentSource<'tcx> { } impl BorrowedContentSource<'tcx> { - pub(super) fn describe_for_unnamed_place(&self) -> String { + pub(super) fn describe_for_unnamed_place(&self, tcx: TyCtxt<'_>) -> String { match *self { BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), - BorrowedContentSource::OverloadedDeref(ty) => { - if ty.is_rc() { + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind { + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { "an `Rc`".to_string() - } else if ty.is_arc() { + } + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { "an `Arc`".to_string() - } else { - format!("dereference of `{}`", ty) } - } + _ => format!("dereference of `{}`", ty), + }, BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty), } } @@ -662,22 +662,22 @@ impl BorrowedContentSource<'tcx> { } } - pub(super) fn describe_for_immutable_place(&self) -> String { + pub(super) fn describe_for_immutable_place(&self, tcx: TyCtxt<'_>) -> String { match *self { BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(), BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(), BorrowedContentSource::DerefMutableRef => { bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") } - BorrowedContentSource::OverloadedDeref(ty) => { - if ty.is_rc() { + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind { + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { "an `Rc`".to_string() - } else if ty.is_arc() { + } + ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => { "an `Arc`".to_string() - } else { - format!("a dereference of `{}`", ty) } - } + _ => format!("a dereference of `{}`", ty), + }, BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty), } } diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index d32533b6ce9a1..1fbecb75dff53 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -377,7 +377,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { span, &format!("`{}` which is behind a {}", place_desc, source_desc), ), - (_, _) => self.cannot_move_out_of(span, &source.describe_for_unnamed_place()), + (_, _) => self.cannot_move_out_of( + span, + &source.describe_for_unnamed_place(self.infcx.tcx), + ), } } }; diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index 35edd3d803db9..635c299cf8136 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { local: the_place_err.local, projection: proj_base, }); - let pointer_type = source.describe_for_immutable_place(); + let pointer_type = source.describe_for_immutable_place(self.infcx.tcx); opt_source = Some(source); if let Some(desc) = access_place_desc { item_msg = format!("`{}`", desc); diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 54b404e1161b9..6845cb3b9a352 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -144,6 +144,7 @@ symbols! { any, arbitrary_enum_discriminant, arbitrary_self_types, + Arc, Arguments, ArgumentV1, arm_target_feature, @@ -582,6 +583,7 @@ symbols! { raw_dylib, raw_identifiers, raw_ref_op, + Rc, Ready, reason, recursion_limit, diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 9c57ffaf055ac..57e2349bb2e80 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -902,8 +902,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error: MethodError<'tcx>, ) { let rcvr = &args[0]; - let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, rcvr_t, lang_item| { - if let Some(new_rcvr_t) = self.tcx.mk_lang_item(rcvr_t, lang_item) { + let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| { + if let Some(new_rcvr_t) = new_rcvr_t { if let Ok(pick) = self.lookup_probe( span, segment.ident, @@ -931,10 +931,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Try alternative arbitrary self types that could fulfill this call. // FIXME: probe for all types that *could* be arbitrary self-types, not // just this whitelist. - try_alt_rcvr(&mut err, rcvr_t, lang_items::OwnedBoxLangItem); - try_alt_rcvr(&mut err, rcvr_t, lang_items::PinTypeLangItem); - try_alt_rcvr(&mut err, rcvr_t, lang_items::Arc); - try_alt_rcvr(&mut err, rcvr_t, lang_items::Rc); + try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, lang_items::OwnedBoxLangItem)); + try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, lang_items::PinTypeLangItem)); + try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc)); + try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc)); } err.emit(); } diff --git a/src/test/ui/error-codes/E0152.rs b/src/test/ui/error-codes/E0152.rs index dcaf920883543..94467b9bddeb0 100644 --- a/src/test/ui/error-codes/E0152.rs +++ b/src/test/ui/error-codes/E0152.rs @@ -1,6 +1,6 @@ #![feature(lang_items)] -#[lang = "arc"] +#[lang = "owned_box"] struct Foo; //~ ERROR E0152 fn main() { diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index 29981991ee02b..fbaa276ce1093 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -1,4 +1,4 @@ -error[E0152]: found duplicate lang item `arc` +error[E0152]: found duplicate lang item `owned_box` --> $DIR/E0152.rs:4:1 | LL | struct Foo; diff --git a/src/test/ui/error-codes/E0718.rs b/src/test/ui/error-codes/E0718.rs index 82ab2d4af1ba8..909cae0ba25a2 100644 --- a/src/test/ui/error-codes/E0718.rs +++ b/src/test/ui/error-codes/E0718.rs @@ -1,7 +1,7 @@ #![feature(lang_items)] -// Arc is expected to be a struct, so this will error. -#[lang = "arc"] //~ ERROR language item must be applied to a struct +// Box is expected to be a struct, so this will error. +#[lang = "owned_box"] //~ ERROR language item must be applied to a struct static X: u32 = 42; fn main() {} diff --git a/src/test/ui/error-codes/E0718.stderr b/src/test/ui/error-codes/E0718.stderr index 412c856ce065a..30378dd167457 100644 --- a/src/test/ui/error-codes/E0718.stderr +++ b/src/test/ui/error-codes/E0718.stderr @@ -1,8 +1,8 @@ -error[E0718]: `arc` language item must be applied to a struct +error[E0718]: `owned_box` language item must be applied to a struct --> $DIR/E0718.rs:4:1 | -LL | #[lang = "arc"] - | ^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static item +LL | #[lang = "owned_box"] + | ^^^^^^^^^^^^^^^^^^^^^ attribute should be applied to a struct, not a static item error: aborting due to previous error From f9a691faac43f838a16aa872101b0277dbf2e25f Mon Sep 17 00:00:00 2001 From: mark Date: Wed, 8 Apr 2020 12:43:43 -0500 Subject: [PATCH 03/10] de-abuse TyKind::Error: handle empty slices in array patterns --- src/librustc_typeck/check/pat.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index b3cace8298a92..5dcb6d8fdc787 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1353,23 +1353,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { - let err = self.tcx.types.err; let expected = self.structurally_resolved_type(span, expected); - let (element_ty, slice_ty, inferred) = match expected.kind { + let (element_ty, opt_slice_ty, inferred) = match expected.kind { // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. ty::Array(element_ty, len) => { let min = before.len() as u64 + after.len() as u64; - let (slice_ty, expected) = + let (opt_slice_ty, expected) = self.check_array_pat_len(span, element_ty, expected, slice, len, min); - (element_ty, slice_ty, expected) + // we can get opt_slice_ty == None in cases that are not an error, e.g. if the + // slice covers 0 elements or if slice is None. + (element_ty, opt_slice_ty, expected) } - ty::Slice(element_ty) => (element_ty, expected, expected), + ty::Slice(element_ty) => (element_ty, Some(expected), expected), // The expected type must be an array or slice, but was neither, so error. _ => { if !expected.references_error() { self.error_expected_array_or_slice(span, expected); } - (err, err, err) + let err = self.tcx.types.err; + (err, None, err) } }; @@ -1377,8 +1379,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for elt in before { self.check_pat(&elt, element_ty, def_bm, ti); } - // Type check the `slice`, if present, against its expected type. - if let Some(slice) = slice { + // Type check the `slice`, if present, against its expected type, if there is one. + if let (Some(slice), Some(slice_ty)) = (slice, opt_slice_ty) { self.check_pat(&slice, slice_ty, def_bm, ti); } // Type check the elements after `slice`, if present. @@ -1390,9 +1392,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check the length of an array pattern. /// - /// Returns both the type of the variable length pattern - /// (or `tcx.err` in case there is none), - /// and the potentially inferred array type. + /// Returns both the type of the variable length pattern (or `None`), and the potentially + /// inferred array type. fn check_array_pat_len( &self, span: Span, @@ -1401,7 +1402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, len: &ty::Const<'tcx>, min_len: u64, - ) -> (Ty<'tcx>, Ty<'tcx>) { + ) -> (Option>, Ty<'tcx>) { if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) { // Now we know the length... if slice.is_none() { @@ -1414,7 +1415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if let Some(pat_len) = len.checked_sub(min_len) { // The variable-length pattern was there, // so it has an array type with the remaining elements left as its size... - return (self.tcx.mk_array(element_ty, pat_len), arr_ty); + return (Some(self.tcx.mk_array(element_ty, pat_len)), arr_ty); } else { // ...however, in this case, there were no remaining elements. // That is, the slice pattern requires more than the array type offers. @@ -1425,14 +1426,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // which we can use to infer the length of the array. let updated_arr_ty = self.tcx.mk_array(element_ty, min_len); self.demand_eqtype(span, updated_arr_ty, arr_ty); - return (self.tcx.types.err, updated_arr_ty); + return (None, updated_arr_ty); } else { // We have a variable-length pattern and don't know the array length. // This happens if we have e.g., // `let [a, b, ..] = arr` where `arr: [T; N]` where `const N: usize`. self.error_scrutinee_unfixed_length(span); } - (self.tcx.types.err, arr_ty) + (None, arr_ty) } fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { From e1c838d737ffd30172e394eaf64dd087529a2b6f Mon Sep 17 00:00:00 2001 From: mark Date: Wed, 8 Apr 2020 16:02:31 -0500 Subject: [PATCH 04/10] de-abuse TyKind::Error: ice on missing slice type --- src/librustc_typeck/check/pat.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 5dcb6d8fdc787..37f0efd4064c0 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1360,8 +1360,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let min = before.len() as u64 + after.len() as u64; let (opt_slice_ty, expected) = self.check_array_pat_len(span, element_ty, expected, slice, len, min); - // we can get opt_slice_ty == None in cases that are not an error, e.g. if the - // slice covers 0 elements or if slice is None. + // opt_slice_ty.is_none() => slice.is_none() + // Note, though, that opt_slice_ty could be Some(error_ty). + assert!(opt_slice_ty.is_some() || slice.is_none()); (element_ty, opt_slice_ty, expected) } ty::Slice(element_ty) => (element_ty, Some(expected), expected), @@ -1371,7 +1372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.error_expected_array_or_slice(span, expected); } let err = self.tcx.types.err; - (err, None, err) + (err, Some(err), err) } }; @@ -1379,9 +1380,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for elt in before { self.check_pat(&elt, element_ty, def_bm, ti); } - // Type check the `slice`, if present, against its expected type, if there is one. - if let (Some(slice), Some(slice_ty)) = (slice, opt_slice_ty) { - self.check_pat(&slice, slice_ty, def_bm, ti); + // Type check the `slice`, if present, against its expected type. + if let Some(slice) = slice { + self.check_pat(&slice, opt_slice_ty.unwrap(), def_bm, ti); } // Type check the elements after `slice`, if present. for elt in after { @@ -1393,7 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check the length of an array pattern. /// /// Returns both the type of the variable length pattern (or `None`), and the potentially - /// inferred array type. + /// inferred array type. We should only return `None` for the slice type if `slice.is_none()`. fn check_array_pat_len( &self, span: Span, @@ -1409,9 +1410,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ...and since there is no variable-length pattern, // we require an exact match between the number of elements // in the array pattern and as provided by the matched type. - if min_len != len { - self.error_scrutinee_inconsistent_length(span, min_len, len); + if min_len == len { + return (None, arr_ty); } + + self.error_scrutinee_inconsistent_length(span, min_len, len); } else if let Some(pat_len) = len.checked_sub(min_len) { // The variable-length pattern was there, // so it has an array type with the remaining elements left as its size... @@ -1433,7 +1436,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `let [a, b, ..] = arr` where `arr: [T; N]` where `const N: usize`. self.error_scrutinee_unfixed_length(span); } - (None, arr_ty) + + // If we get here, we must have emitted an error. + (Some(self.tcx.types.err), arr_ty) } fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { From 44daa4521a6952fba012fa80c28845caf1b99ae3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 9 Apr 2020 13:48:11 +0200 Subject: [PATCH 05/10] Clean up E0511 explanation --- src/librustc_error_codes/error_codes/E0511.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0511.md b/src/librustc_error_codes/error_codes/E0511.md index 4f6644f358291..5351a685eb512 100644 --- a/src/librustc_error_codes/error_codes/E0511.md +++ b/src/librustc_error_codes/error_codes/E0511.md @@ -1,5 +1,6 @@ -Invalid monomorphization of an intrinsic function was used. Erroneous code -example: +Invalid monomorphization of an intrinsic function was used. + +Erroneous code example: ```compile_fail,E0511 #![feature(platform_intrinsics)] From f2e4709f2252103a2461991dba209f8ab4d76aca Mon Sep 17 00:00:00 2001 From: mark Date: Thu, 9 Apr 2020 09:31:52 -0500 Subject: [PATCH 06/10] improve comments --- src/librustc_typeck/check/pat.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 37f0efd4064c0..0335aba914460 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1360,8 +1360,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let min = before.len() as u64 + after.len() as u64; let (opt_slice_ty, expected) = self.check_array_pat_len(span, element_ty, expected, slice, len, min); - // opt_slice_ty.is_none() => slice.is_none() - // Note, though, that opt_slice_ty could be Some(error_ty). + // `opt_slice_ty.is_none()` => `slice.is_none()`. + // Note, though, that opt_slice_ty could be `Some(error_ty)`. assert!(opt_slice_ty.is_some() || slice.is_none()); (element_ty, opt_slice_ty, expected) } @@ -1394,7 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check the length of an array pattern. /// /// Returns both the type of the variable length pattern (or `None`), and the potentially - /// inferred array type. We should only return `None` for the slice type if `slice.is_none()`. + /// inferred array type. We only return `None` for the slice type if `slice.is_none()`. fn check_array_pat_len( &self, span: Span, From 1761a65ebadd3c4125fa80c0f5570b24429bafff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Apr 2020 23:02:13 +0200 Subject: [PATCH 07/10] mark a temporary hack as such --- src/librustc_session/config.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 4e2423bc3b114..aaf30c583e263 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1019,7 +1019,9 @@ pub fn get_cmd_lint_options( for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) { let arg_pos = if let lint::Forbid = level { - // forbid is always specified last, so it can't be overridden + // HACK: forbid is always specified last, so it can't be overridden. + // FIXME: remove this once is + // fixed and `forbid` works as expected. usize::max_value() } else { passed_arg_pos From a2a65a88fc009dfd156a9de446e1bca2747493fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 4 Apr 2020 11:38:22 -0700 Subject: [PATCH 08/10] Consider methods on fundamental `impl` when method is not found on numeric type Fix #47759. --- src/librustc_typeck/check/method/suggest.rs | 28 +++++++++++++++++++-- src/test/ui/issues/issue-29181.rs | 2 ++ src/test/ui/issues/issue-29181.stderr | 16 ++++++++++-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index add706b5fcc9a..f075d1e74d455 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -271,11 +271,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| { self.associated_item(info.def_id, item_name, Namespace::ValueNS) }); - if let (true, false, SelfSource::MethodCall(expr), Some(_)) = ( + // There are methods that are defined on the primitive types and won't be + // found when exploring `all_traits`, but we also need them to be acurate on + // our suggestions (#47759). + let fund_assoc = |opt_def_id: Option| { + opt_def_id + .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS)) + .is_some() + }; + let lang_items = tcx.lang_items(); + let found_candidate = candidates.next().is_some() + || fund_assoc(lang_items.i8_impl()) + || fund_assoc(lang_items.i16_impl()) + || fund_assoc(lang_items.i32_impl()) + || fund_assoc(lang_items.i64_impl()) + || fund_assoc(lang_items.i128_impl()) + || fund_assoc(lang_items.u8_impl()) + || fund_assoc(lang_items.u16_impl()) + || fund_assoc(lang_items.u32_impl()) + || fund_assoc(lang_items.u64_impl()) + || fund_assoc(lang_items.u128_impl()) + || fund_assoc(lang_items.f32_impl()) + || fund_assoc(lang_items.f32_runtime_impl()) + || fund_assoc(lang_items.f64_impl()) + || fund_assoc(lang_items.f64_runtime_impl()); + if let (true, false, SelfSource::MethodCall(expr), true) = ( actual.is_numeric(), actual.has_concrete_skeleton(), source, - candidates.next(), + found_candidate, ) { let mut err = struct_span_err!( tcx.sess, diff --git a/src/test/ui/issues/issue-29181.rs b/src/test/ui/issues/issue-29181.rs index 45752ad4f62b6..70e5bc0192086 100644 --- a/src/test/ui/issues/issue-29181.rs +++ b/src/test/ui/issues/issue-29181.rs @@ -4,4 +4,6 @@ extern crate issue_29181 as foo; fn main() { 0.homura(); //~ ERROR no method named `homura` found + // Issue #47759, detect existing method on the fundamental impl: + let _ = |x: f64| x * 2.0.exp(); //~ ERROR can't call method `exp` on ambiguous numeric type } diff --git a/src/test/ui/issues/issue-29181.stderr b/src/test/ui/issues/issue-29181.stderr index 250b158ab8e33..b66dcb88d0062 100644 --- a/src/test/ui/issues/issue-29181.stderr +++ b/src/test/ui/issues/issue-29181.stderr @@ -4,6 +4,18 @@ error[E0599]: no method named `homura` found for type `{integer}` in the current LL | 0.homura(); | ^^^^^^ method not found in `{integer}` -error: aborting due to previous error +error[E0689]: can't call method `exp` on ambiguous numeric type `{float}` + --> $DIR/issue-29181.rs:8:30 + | +LL | let _ = |x: f64| x * 2.0.exp(); + | ^^^ + | +help: you must specify a concrete type for this numeric value, like `f32` + | +LL | let _ = |x: f64| x * 2.0_f32.exp(); + | ^^^^^^^ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0599`. +Some errors have detailed explanations: E0599, E0689. +For more information about an error, try `rustc --explain E0599`. From d6d0799abf99d54278ff45f188d6c5d6dcd2f718 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 9 Apr 2020 18:54:53 -0700 Subject: [PATCH 09/10] Fix JSON file_name documentation for macros. --- src/doc/rustc/src/json.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md index c46380f1505df..5dee603142dcd 100644 --- a/src/doc/rustc/src/json.md +++ b/src/doc/rustc/src/json.md @@ -59,8 +59,11 @@ Diagnostics have the following format: "spans": [ { /* The file where the span is located. - For spans located within a macro expansion, this will be the - name of the expanded macro in the format "". + Note that this path may not exist. For example, if the path + points to the standard library, and the rust src is not + available in the sysroot, then it may point to a non-existent + file. Beware that this may also point to the source of an + external crate. */ "file_name": "lib.rs", /* The byte offset where the span starts (0-based, inclusive). */ From e39d958b8eba240b806761c2972009c7bfcee24f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 10 Apr 2020 07:04:11 +0200 Subject: [PATCH 10/10] words --- src/librustc_typeck/check/mod.rs | 8 ++++---- src/librustc_typeck/check/writeback.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eebc34d3db8ea..a5490696ba0b4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1161,7 +1161,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { match ty_opt { None => { - // infer the variable's type + // Infer the variable's type. let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span, @@ -1173,7 +1173,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { var_ty } Some(typ) => { - // take type that the user specified + // Take type that the user specified. self.fcx.locals.borrow_mut().insert(nid, typ); typ.revealed_ty } @@ -1244,7 +1244,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { intravisit::walk_pat(self, p); } - // Don't descend into the bodies of nested closures + // Don't descend into the bodies of nested closures. fn visit_fn( &mut self, _: intravisit::FnKind<'tcx>, @@ -1292,7 +1292,7 @@ fn check_fn<'a, 'tcx>( debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); - // Create the function context. This is either derived from scratch or, + // Create the function context. This is either derived from scratch or, // in the case of closures, based on the outer context. let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 28574c68e941a..146fc04bc27cb 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -40,7 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_def_id = self.tcx.hir().local_def_id(item_id); // This attribute causes us to dump some writeback information - // in the form of errors, which is uSymbolfor unit tests. + // in the form of errors, which is uSymbol for unit tests. let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs);