Suggest builder functions on struct literal with private fields
This commit is contained in:
parent
1dfec45dc9
commit
be0958f5ab
@ -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::<Vec<_>>();
|
||||
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::<Vec<_>>().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::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
})
|
||||
.collect::<Vec<String>>(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -50,6 +50,43 @@ help: consider using the `Default` trait
|
||||
LL | wtf: Some(<Box as std::default::Default>::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`.
|
||||
|
Loading…
Reference in New Issue
Block a user