diff options
Diffstat (limited to 'compiler')
23 files changed, 277 insertions, 75 deletions
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 0e395d70335..cd77dbca3c4 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -145,7 +145,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::Reg(s) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { asm::InlineAsmReg::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register `{}`: {}", s.as_str(), e); + let msg = format!("invalid register `{}`: {}", s, e); sess.struct_span_err(*op_sp, &msg).emit(); asm::InlineAsmReg::Err }) @@ -156,7 +156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { InlineAsmRegOrRegClass::RegClass(s) => { asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch { asm::InlineAsmRegClass::parse(asm_arch, s).unwrap_or_else(|e| { - let msg = format!("invalid register class `{}`: {}", s.as_str(), e); + let msg = format!("invalid register class `{}`: {}", s, e); sess.struct_span_err(*op_sp, &msg).emit(); asm::InlineAsmRegClass::Err }) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 57c39671c35..22cb27af4fb 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -62,9 +62,9 @@ impl<'a> PostExpansionVisitor<'a> { let ast::StrLit { symbol_unescaped, span, .. } = abi; if let ast::Const::Yes(_) = constness { - match symbol_unescaped.as_str() { + match symbol_unescaped { // Stable - "Rust" | "C" => {} + sym::Rust | sym::C => {} abi => gate_feature_post!( &self, const_extern_fn, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 5186aee57fb..80fd9726fc7 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -55,7 +55,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, ' // The initial byte `4` instructs GDB that the following pretty printer // is defined inline as opposed to in a standalone file. section_contents.extend_from_slice(b"\x04"); - let vis_name = format!("pretty-printer-{}-{}\n", crate_name.as_str(), index); + let vis_name = format!("pretty-printer-{}-{}\n", crate_name, index); section_contents.extend_from_slice(vis_name.as_bytes()); section_contents.extend_from_slice(&visualizer.src); diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index cf0940df9e4..52952a7932d 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -146,7 +146,7 @@ cfg_if! { t.into_iter() } - pub fn par_for_each_in<T: IntoIterator>(t: T, for_each: impl Fn(T::Item) + Sync + Send) { + pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) { // We catch panics here ensuring that all the loop iterations execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 977318b8589..97766b8368a 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -492,6 +492,7 @@ E0785: include_str!("./error_codes/E0785.md"), E0786: include_str!("./error_codes/E0786.md"), E0787: include_str!("./error_codes/E0787.md"), E0788: include_str!("./error_codes/E0788.md"), +E0790: include_str!("./error_codes/E0790.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0283.md b/compiler/rustc_error_codes/src/error_codes/E0283.md index 6885f9a486d..79d2c8204f9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0283.md +++ b/compiler/rustc_error_codes/src/error_codes/E0283.md @@ -3,48 +3,27 @@ An implementation cannot be chosen unambiguously because of lack of information. Erroneous code example: ```compile_fail,E0283 -trait Generator { - fn create() -> u32; -} - -struct Impl; - -impl Generator for Impl { - fn create() -> u32 { 1 } -} - -struct AnotherImpl; +struct Foo; -impl Generator for AnotherImpl { - fn create() -> u32 { 2 } +impl Into<u32> for Foo { + fn into(self) -> u32 { 1 } } -fn main() { - let cont: u32 = Generator::create(); - // error, impossible to choose one of Generator trait implementation - // Should it be Impl or AnotherImpl, maybe something else? -} +let foo = Foo; +let bar: u32 = foo.into() * 1u32; ``` This error can be solved by adding type annotations that provide the missing -information to the compiler. In this case, the solution is to use a concrete -type: +information to the compiler. In this case, the solution is to specify the +trait's type parameter: ``` -trait Generator { - fn create() -> u32; -} - -struct AnotherImpl; +struct Foo; -impl Generator for AnotherImpl { - fn create() -> u32 { 2 } +impl Into<u32> for Foo { + fn into(self) -> u32 { 1 } } -fn main() { - let gen1 = AnotherImpl::create(); - - // if there are multiple methods with same name (different traits) - let gen2 = <AnotherImpl as Generator>::create(); -} +let foo = Foo; +let bar: u32 = Into::<u32>::into(foo) * 1u32; ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0790.md b/compiler/rustc_error_codes/src/error_codes/E0790.md new file mode 100644 index 00000000000..2aee9dfbdbd --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0790.md @@ -0,0 +1,47 @@ +You need to specify a specific implementation of the trait in order to call the +method. + +Erroneous code example: + +```compile_fail,E0790 +trait Generator { + fn create() -> u32; +} + +struct Impl; + +impl Generator for Impl { + fn create() -> u32 { 1 } +} + +struct AnotherImpl; + +impl Generator for AnotherImpl { + fn create() -> u32 { 2 } +} + +let cont: u32 = Generator::create(); +// error, impossible to choose one of Generator trait implementation +// Should it be Impl or AnotherImpl, maybe something else? +``` + +This error can be solved by adding type annotations that provide the missing +information to the compiler. In this case, the solution is to use a concrete +type: + +``` +trait Generator { + fn create() -> u32; +} + +struct AnotherImpl; + +impl Generator for AnotherImpl { + fn create() -> u32 { 2 } +} + +let gen1 = AnotherImpl::create(); + +// if there are multiple methods with same name (different traits) +let gen2 = <AnotherImpl as Generator>::create(); +``` diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index d4b8563a036..707cb73f097 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -234,6 +234,8 @@ fn parse_tree( sess, &Token { kind: token::Dollar, span }, ); + } else { + maybe_emit_macro_metavar_expr_feature(features, sess, span); } TokenTree::token(token::Dollar, span) } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index b744594ddb7..9a2ab3e3224 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -228,7 +228,7 @@ pub fn suggest_adding_lifetime_params<'tcx>( if is_impl { sugg.push_str(" and update trait if needed"); } - err.multipart_suggestion(sugg.as_str(), suggestions, Applicability::MaybeIncorrect); + err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect); true } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3a59b2069b3..0001e1aa53e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -491,9 +491,7 @@ impl<'hir> Map<'hir> { } pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) { - use rustc_data_structures::sync::{par_iter, ParallelIterator}; - - par_iter(&self.tcx.hir_crate_items(()).body_owners[..]).for_each(|&def_id| f(def_id)); + par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); } pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 826c16dda4a..541dace5cc2 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -74,6 +74,10 @@ impl TraitImpls { pub fn blanket_impls(&self) -> &[DefId] { self.blanket_impls.as_slice() } + + pub fn non_blanket_impls(&self) -> &FxIndexMap<SimplifiedType, Vec<DefId>> { + &self.non_blanket_impls + } } impl<'tcx> TraitDef { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 89f60902cf9..1f0d0ce04aa 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -431,9 +431,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { let lhs = &self.thir[lhs]; if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() { if let Some((assigned_ty, assignment_span)) = self.assignment_info { - if assigned_ty.needs_drop(self.tcx, self.tcx.param_env(adt_def.did())) { + if assigned_ty.needs_drop(self.tcx, self.param_env) { // This would be unsafe, but should be outright impossible since we reject such unions. - self.tcx.sess.delay_span_bug(assignment_span, "union fields that need dropping should be impossible"); + self.tcx.sess.delay_span_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}")); } } else { self.requires_unsafe(expr.span, AccessToUnionField); diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index ded1f0462cb..a2ad96cfc16 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -219,14 +219,11 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // We have to check the actual type of the assignment, as that determines if the // old value is being dropped. let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty; - if assigned_ty.needs_drop( - self.tcx, - self.tcx.param_env(base_ty.ty_adt_def().unwrap().did()), - ) { + if assigned_ty.needs_drop(self.tcx, self.param_env) { // This would be unsafe, but should be outright impossible since we reject such unions. self.tcx.sess.delay_span_bug( self.source_info.span, - "union fields that need dropping should be impossible", + format!("union fields that need dropping should be impossible: {assigned_ty}") ); } } else { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index d9fa4d65b3a..e3cfb034e40 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -180,7 +180,7 @@ //! regardless of whether it is actually needed or not. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; +use rustc_data_structures::sync::{par_for_each_in, MTLock, MTRef}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; @@ -346,7 +346,7 @@ pub fn collect_crate_mono_items( let inlining_map: MTRef<'_, _> = &mut inlining_map; tcx.sess.time("monomorphization_collector_graph_walk", || { - par_iter(roots).for_each(|root| { + par_for_each_in(roots, |root| { let mut recursion_depths = DefIdMap::default(); collect_items_rec( tcx, diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 1add91fc9c5..7381019a620 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -77,7 +77,7 @@ fn err_if_attr_found(ctxt: &EntryContext<'_>, attrs: &[Attribute], sym: Symbol) .sess .struct_span_err( attr.span, - &format!("`{}` attribute can only be used on functions", sym.as_str()), + &format!("`{}` attribute can only be used on functions", sym), ) .emit(); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index a820f700869..7a1695fc862 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1627,7 +1627,7 @@ impl<'a> Resolver<'a> { "{}{} `{}` defined here", prefix, suggestion.res.descr(), - suggestion.candidate.as_str(), + suggestion.candidate, ), ); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1e53c73620a..e428bae479b 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -83,7 +83,7 @@ impl ForLifetimeSpanType { } } - pub(crate) fn suggestion(&self, sugg: &str) -> String { + pub(crate) fn suggestion(&self, sugg: impl std::fmt::Display) -> String { match self { Self::BoundEmpty | Self::TypeEmpty => format!("for<{}> ", sugg), Self::ClosureEmpty => format!("for<{}>", sugg), @@ -2313,8 +2313,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let suggest_existing = |err: &mut Diagnostic, - name: &str, - formatters: Vec<Option<Box<dyn Fn(&str) -> String>>>| { + name: Symbol, + formatters: Vec<Option<Box<dyn Fn(Symbol) -> String>>>| { if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) = self.missing_named_lifetime_spots.iter().rev().next() { @@ -2334,7 +2334,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { // If all single char lifetime names are present, we wrap around and double the chars. let lt_name = (1..) .flat_map(a_to_z_repeat_n) - .find(|lt| !lifetime_names.contains(&Symbol::intern(<))) + .map(|lt| Symbol::intern(<)) + .find(|lt| !lifetime_names.contains(lt)) .unwrap(); let msg = format!( "consider making the {} lifetime-generic with a new `{}` lifetime", @@ -2361,7 +2362,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { introduce_suggestion.push((*for_span, for_sugg)); for ((span, _), formatter) in spans_with_counts.iter().zip(formatters.iter()) { if let Some(formatter) = formatter { - introduce_suggestion.push((*span, formatter(<_name))); + introduce_suggestion.push((*span, formatter(lt_name))); } } err.multipart_suggestion_verbose( @@ -2584,7 +2585,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let lifetime_names: Vec<_> = lifetime_names.iter().collect(); match &lifetime_names[..] { [name] => { - let mut suggs: Vec<Option<Box<dyn Fn(&str) -> String>>> = Vec::new(); + let mut suggs: Vec<Option<Box<dyn Fn(Symbol) -> String>>> = Vec::new(); for (snippet, (_, count)) in snippets.iter().zip(spans_with_counts.iter().copied()) { suggs.push(match snippet.as_deref() { @@ -2592,7 +2593,11 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { Some("'_") => Some(Box::new(|n| n.to_string())), Some("") => Some(Box::new(move |n| format!("{}, ", n).repeat(count))), Some("<") => Some(Box::new(move |n| { - std::iter::repeat(n).take(count).collect::<Vec<_>>().join(", ") + std::iter::repeat(n) + .take(count) + .map(|n| n.to_string()) + .collect::<Vec<_>>() + .join(", ") })), Some(snippet) if !snippet.ends_with('>') => Some(Box::new(move |name| { format!( @@ -2607,7 +2612,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { _ => None, }); } - suggest_existing(err, name.as_str(), suggs); + suggest_existing(err, **name, suggs); } [] => { let mut suggs = Vec::new(); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4210560f531..54dd15270a1 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -325,7 +325,7 @@ impl<'a> ResolverExpand for Resolver<'a> { UNUSED_MACROS, node_id, ident.span, - &format!("unused macro definition: `{}`", ident.as_str()), + &format!("unused macro definition: `{}`", ident.name), ); } for (&(def_id, arm_i), &(ident, rule_span)) in self.unused_macro_rules.iter() { @@ -341,7 +341,7 @@ impl<'a> ResolverExpand for Resolver<'a> { &format!( "{} rule of macro `{}` is never used", crate::diagnostics::ordinalize(arm_i + 1), - ident.as_str() + ident.name ), ); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d5e65c0b442..3ccd3fcbafa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -223,6 +223,16 @@ symbols! { LintPass, Mutex, N, + NonZeroI128, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI8, + NonZeroU128, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU8, None, Ok, Option, @@ -257,6 +267,7 @@ symbols! { Result, Return, Right, + Rust, RustcDecodable, RustcEncodable, Send, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 8a679ca005f..29df771b957 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -474,7 +474,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(ref s) = label { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! - err.span_label(span, s.as_str()); + err.span_label(span, s); if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point @@ -531,7 +531,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let enclosing_scope_span = tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body)); - err.span_label(enclosing_scope_span, s.as_str()); + err.span_label(enclosing_scope_span, s); } self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); @@ -2104,6 +2104,98 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { ); } } + + if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) = + (body_id, subst.map(|subst| subst.unpack())) + { + struct FindExprBySpan<'hir> { + span: Span, + result: Option<&'hir hir::Expr<'hir>>, + } + + impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if self.span == ex.span { + self.result = Some(ex); + } else { + hir::intravisit::walk_expr(self, ex); + } + } + } + + let mut expr_finder = FindExprBySpan { span, result: None }; + + expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); + + if let Some(hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. } + ) = expr_finder.result + && let [ + .., + trait_path_segment @ hir::PathSegment { + res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)), + .. + }, + hir::PathSegment { + ident: assoc_item_name, + res: Some(rustc_hir::def::Res::Def(_, item_id)), + .. + } + ] = path.segments + && data.trait_ref.def_id == *trait_id + && self.tcx.trait_of_item(item_id) == Some(*trait_id) + && !self.is_tainted_by_errors() + { + let (verb, noun) = match self.tcx.associated_item(item_id).kind { + ty::AssocKind::Const => ("refer to the", "constant"), + ty::AssocKind::Fn => ("call", "function"), + ty::AssocKind::Type => ("refer to the", "type"), // this is already covered by E0223, but this single match arm doesn't hurt here + }; + + // Replace the more general E0283 with a more specific error + err.cancel(); + err = self.tcx.sess.struct_span_err_with_code( + span, + &format!( + "cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type", + ), + rustc_errors::error_code!(E0790), + ); + + if let Some(local_def_id) = data.trait_ref.def_id.as_local() + && let Some(hir::Node::Item(hir::Item { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. })) = self.tcx.hir().find_by_def_id(local_def_id) + && let Some(method_ref) = trait_item_refs.iter().find(|item_ref| item_ref.ident == *assoc_item_name) { + err.span_label(method_ref.span, format!("`{}::{}` defined here", trait_name, assoc_item_name)); + } + + err.span_label(span, format!("cannot {verb} associated {noun} of trait")); + + let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id); + + if trait_impls.blanket_impls().is_empty() + && let Some((impl_ty, _)) = trait_impls.non_blanket_impls().iter().next() + && let Some(impl_def_id) = impl_ty.def() { + let message = if trait_impls.non_blanket_impls().len() == 1 { + "use the fully-qualified path to the only available implementation".to_string() + } else { + format!( + "use a fully-qualified path to a specific available implementation ({} found)", + trait_impls.non_blanket_impls().len() + ) + }; + + err.multipart_suggestion( + message, + vec![ + (trait_path_segment.ident.span.shrink_to_lo(), format!("<{} as ", self.tcx.def_path(impl_def_id).to_string_no_crate_verbose())), + (trait_path_segment.ident.span.shrink_to_hi(), format!(">")) + ], + Applicability::MaybeIncorrect + ); + } + } + }; + err } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 7795e65132f..c733f0d3c86 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -259,7 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, &mut |err| { if let Some((span, msg)) = &ret_reason { - err.span_label(*span, msg.as_str()); + err.span_label(*span, msg); } else if let ExprKind::Block(block, _) = &then_expr.kind && let Some(expr) = &block.expr { diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 740261cfe74..a2d8765289c 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -33,6 +33,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_expected_due_to_let_ty(err, expr, error); self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr); self.suggest_compatible_variants(err, expr, expected, expr_ty); + self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty); if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) { return; } @@ -347,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let compatible_variants: Vec<String> = expected_adt + let compatible_variants: Vec<(String, Option<String>)> = expected_adt .variants() .iter() .filter(|variant| { @@ -355,6 +356,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .filter_map(|variant| { let sole_field = &variant.fields[0]; + + let field_is_local = sole_field.did.is_local(); + let field_is_accessible = + sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx); + + if !field_is_local && !field_is_accessible { + return None; + } + + let note_about_variant_field_privacy = (field_is_local && !field_is_accessible) + .then(|| format!(" (its field is private, but it's local to this crate and its privacy can be changed)")); + let sole_field_ty = sole_field.ty(self.tcx, substs); if self.can_coerce(expr_ty, sole_field_ty) { let variant_path = @@ -363,9 +376,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(path) = variant_path.strip_prefix("std::prelude::") && let Some((_, path)) = path.split_once("::") { - return Some(path.to_string()); + return Some((path.to_string(), note_about_variant_field_privacy)); } - Some(variant_path) + Some((variant_path, note_about_variant_field_privacy)) } else { None } @@ -379,10 +392,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &compatible_variants[..] { [] => { /* No variants to format */ } - [variant] => { + [(variant, note)] => { // Just a single matching variant. err.multipart_suggestion_verbose( - &format!("try wrapping the expression in `{variant}`"), + &format!( + "try wrapping the expression in `{variant}`{note}", + note = note.as_deref().unwrap_or("") + ), vec![ (expr.span.shrink_to_lo(), format!("{prefix}{variant}(")), (expr.span.shrink_to_hi(), ")".to_string()), @@ -397,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "try wrapping the expression in a variant of `{}`", self.tcx.def_path_str(expected_adt.did()) ), - compatible_variants.into_iter().map(|variant| { + compatible_variants.into_iter().map(|(variant, _)| { vec![ (expr.span.shrink_to_lo(), format!("{prefix}{variant}(")), (expr.span.shrink_to_hi(), ")".to_string()), @@ -410,6 +426,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn suggest_non_zero_new_unwrap( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + expr_ty: Ty<'tcx>, + ) { + let tcx = self.tcx; + let (adt, unwrap) = match expected.kind() { + // In case Option<NonZero*> is wanted, but * is provided, suggest calling new + ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { + // Unwrap option + let ty::Adt(adt, _) = substs.type_at(0).kind() else { return }; + + (adt, "") + } + // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types + ty::Adt(adt, _) => (adt, ".unwrap()"), + _ => return, + }; + + let map = [ + (sym::NonZeroU8, tcx.types.u8), + (sym::NonZeroU16, tcx.types.u16), + (sym::NonZeroU32, tcx.types.u32), + (sym::NonZeroU64, tcx.types.u64), + (sym::NonZeroU128, tcx.types.u128), + (sym::NonZeroI8, tcx.types.i8), + (sym::NonZeroI16, tcx.types.i16), + (sym::NonZeroI32, tcx.types.i32), + (sym::NonZeroI64, tcx.types.i64), + (sym::NonZeroI128, tcx.types.i128), + ]; + + let Some((s, _)) = map + .iter() + .find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t)) + else { return }; + + let path = self.tcx.def_path_str(adt.non_enum_variant().def_id); + + err.multipart_suggestion( + format!("consider calling `{s}::new`"), + vec![ + (expr.span.shrink_to_lo(), format!("{path}::new(")), + (expr.span.shrink_to_hi(), format!("){unwrap}")), + ], + Applicability::MaybeIncorrect, + ); + } + pub fn get_conversion_methods( &self, span: Span, diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index d4bb3d43eff..a2daf6886f1 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -408,8 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false, ), }; - let mut err = - struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str()); + let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}"); if !lhs_expr.span.eq(&rhs_expr.span) { self.add_type_neq_err_label( &mut err, |
