-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Detect struct construction with private field in field with default #135846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1719,6 +1719,13 @@ rustc_queries! { | |
feedable | ||
} | ||
|
||
/// Returns whether the impl or associated function has the `default` keyword. | ||
query default_field(def_id: DefId) -> Option<DefId> { | ||
desc { |tcx| "looking up the `const` corresponding to the default for `{}`", tcx.def_path_str(def_id) } | ||
separate_provide_extern | ||
feedable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this feedable? Also, why does this query exist at all, do we not already have a way of determining if a field has a default? I would have thought we need some way of doing that in order for type checking/mir building/codegen/that whole set of things to know whether |
||
} | ||
|
||
query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> { | ||
desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) } | ||
return_result_from_ensure_ok | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1750,8 +1750,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | |
} | ||
|
||
fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { | ||
let PrivacyError { ident, binding, outermost_res, parent_scope, single_nested, dedup_span } = | ||
*privacy_error; | ||
let PrivacyError { | ||
ident, | ||
binding, | ||
outermost_res, | ||
parent_scope, | ||
single_nested, | ||
dedup_span, | ||
ref source, | ||
} = *privacy_error; | ||
|
||
let res = binding.res(); | ||
let ctor_fields_span = self.ctor_fields_span(binding); | ||
|
@@ -1767,6 +1774,55 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | |
let mut err = | ||
self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident }); | ||
|
||
if let Some(expr) = source | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you move this whole bit of logic out to a separate function? this function's already massive without another pile of logic for another special case in our diagnostics. At the very least there should be a comment saying what case we're handling here so its obvious you can skip over it if you don't care about this. |
||
&& let ast::ExprKind::Struct(struct_expr) = &expr.kind | ||
&& let Some(Res::Def(_, def_id)) = self.partial_res_map | ||
[&struct_expr.path.segments.iter().last().unwrap().id] | ||
.full_res() | ||
Comment on lines
+1779
to
+1781
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't have to handle type-relative paths because they're forbidden in adt exprs. Except I guess they're allowed under |
||
&& let Some(default_fields) = self.field_defaults(def_id) | ||
&& !struct_expr.fields.is_empty() | ||
{ | ||
let last_span = struct_expr.fields.iter().last().unwrap().span; | ||
let mut iter = struct_expr.fields.iter().peekable(); | ||
let mut prev: Option<Span> = None; | ||
while let Some(field) = iter.next() { | ||
if field.expr.span.overlaps(ident.span) { | ||
err.span_label(field.ident.span, "while setting this field"); | ||
if default_fields.contains(&field.ident.name) { | ||
let sugg = if last_span == field.span { | ||
vec![(field.span, "..".to_string())] | ||
} else { | ||
vec![ | ||
( | ||
// Account for trailing commas and ensure we remove them. | ||
match (prev, iter.peek()) { | ||
(_, Some(next)) => field.span.with_hi(next.span.lo()), | ||
(Some(prev), _) => field.span.with_lo(prev.hi()), | ||
(None, None) => field.span, | ||
}, | ||
String::new(), | ||
), | ||
(last_span.shrink_to_hi(), ", ..".to_string()), | ||
] | ||
}; | ||
err.multipart_suggestion_verbose( | ||
format!( | ||
"the type `{ident}` of field `{}` is private, but you can \ | ||
construct the default value defined for it in `{}` using `..` in \ | ||
the struct initializer expression", | ||
field.ident, | ||
self.tcx.item_name(def_id), | ||
), | ||
sugg, | ||
Applicability::MachineApplicable, | ||
); | ||
break; | ||
} | ||
} | ||
prev = Some(field.span); | ||
} | ||
} | ||
|
||
let mut not_publicly_reexported = false; | ||
if let Some((this_res, outer_ident)) = outermost_res { | ||
let import_suggestions = self.lookup_import_candidates( | ||
|
Uh oh!
There was an error while loading. Please reload this page.