diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 9180d4aad32..9f27a6e5d84 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1897,7 +1897,7 @@ fn check_expr_struct_fields( .collect(); if !private_fields.is_empty() { - self.report_private_fields(adt_ty, span, private_fields, ast_fields); + self.report_private_fields(adt_ty, span, expr.span, private_fields, ast_fields); } else { self.report_missing_fields( adt_ty, @@ -2056,6 +2056,7 @@ fn report_private_fields( &self, adt_ty: Ty<'tcx>, span: Span, + expr_span: Span, private_fields: Vec<&ty::FieldDef>, used_fields: &'tcx [hir::ExprField<'tcx>], ) { @@ -2100,6 +2101,72 @@ fn report_private_fields( were = pluralize!("was", remaining_private_fields_len), )); } + + if let ty::Adt(def, _) = adt_ty.kind() { + let def_id = def.did(); + let mut items = self + .tcx + .inherent_impls(def_id) + .iter() + .flat_map(|i| self.tcx.associated_items(i).in_definition_order()) + // Only assoc fn with no receivers. + .filter(|item| { + matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter + }) + .filter_map(|item| { + // Only assoc fns that return `Self` + let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder(); + let ret_ty = fn_sig.output(); + let ret_ty = self.tcx.erase_late_bound_regions(ret_ty); + if !self.can_eq(self.param_env, ret_ty, adt_ty) { + return None; + } + // Check for `-> Self` + let input_len = fn_sig.inputs().skip_binder().len(); + if def.did() == def_id { + let order = if item.name.as_str().starts_with("new") { 0 } else { 1 }; + Some((order, item.name, input_len)) + } else { + None + } + }) + .collect::>(); + items.sort_by_key(|(order, _, _)| *order); + match &items[..] { + [] => {} + [(_, name, args)] => { + err.span_suggestion_verbose( + span.shrink_to_hi().with_hi(expr_span.hi()), + format!("you might have meant to use the `{name}` associated function",), + format!( + "::{name}({})", + std::iter::repeat("_").take(*args).collect::>().join(", ") + ), + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_suggestions( + span.shrink_to_hi().with_hi(expr_span.hi()), + "you might have meant to use an associated function to build this type", + items + .iter() + .map(|(_, name, args)| { + format!( + "::{name}({})", + std::iter::repeat("_") + .take(*args) + .collect::>() + .join(", ") + ) + }) + .collect::>(), + Applicability::MaybeIncorrect, + ); + } + } + } + err.emit(); } diff --git a/tests/ui/privacy/suggest-box-new.rs b/tests/ui/privacy/suggest-box-new.rs index 657dd37dc68..7125285fc77 100644 --- a/tests/ui/privacy/suggest-box-new.rs +++ b/tests/ui/privacy/suggest-box-new.rs @@ -13,4 +13,7 @@ fn main() { }; let _ = std::collections::HashMap(); //~^ ERROR expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` + let _ = std::collections::HashMap {}; + //~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + let _ = Box {}; //~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields } diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index f58f661a468..79629dab6be 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -50,6 +50,43 @@ help: consider using the `Default` trait LL | wtf: Some(::default()), | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 2 previous errors +error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + --> $DIR/suggest-box-new.rs:16:13 + | +LL | let _ = std::collections::HashMap {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: ... and other private field `base` that was not provided +help: you might have meant to use an associated function to build this type + | +LL | let _ = std::collections::HashMap::new(); + | ~~~~~~~ +LL | let _ = std::collections::HashMap::with_capacity(_); + | ~~~~~~~~~~~~~~~~~~ +LL | let _ = std::collections::HashMap::with_hasher(_); + | ~~~~~~~~~~~~~~~~ +LL | let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: cannot construct `Box<_, _>` with struct literal syntax due to private fields + --> $DIR/suggest-box-new.rs:18:13 + | +LL | let _ = Box {}; + | ^^^ + | + = note: ... and other private fields `0` and `1` that were not provided +help: you might have meant to use an associated function to build this type + | +LL | let _ = Box::new(_); + | ~~~~~~~~ +LL | let _ = Box::new_uninit(); + | ~~~~~~~~~~~~~~ +LL | let _ = Box::new_zeroed(); + | ~~~~~~~~~~~~~~ +LL | let _ = Box::new_in(_, _); + | ~~~~~~~~~~~~~~ + and 10 other candidates + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0423`.