Skip to content

Commit c41fee3

Browse files
committed
review comments
1 parent 4828fc9 commit c41fee3

File tree

2 files changed

+81
-50
lines changed

2 files changed

+81
-50
lines changed

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,11 +1854,10 @@ rustc_queries! {
18541854
feedable
18551855
}
18561856

1857-
/// Returns whether the impl or associated function has the `default` keyword.
1857+
/// Returns whether the field corresponding to the `DefId` has a default field value.
18581858
query default_field(def_id: DefId) -> Option<DefId> {
18591859
desc { |tcx| "looking up the `const` corresponding to the default for `{}`", tcx.def_path_str(def_id) }
18601860
separate_provide_extern
1861-
feedable
18621861
}
18631862

18641863
query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> {

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 80 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,54 +1974,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19741974
let mut err =
19751975
self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
19761976

1977-
if let Some(expr) = source
1978-
&& let ast::ExprKind::Struct(struct_expr) = &expr.kind
1979-
&& let Some(Res::Def(_, def_id)) = self.partial_res_map
1980-
[&struct_expr.path.segments.iter().last().unwrap().id]
1981-
.full_res()
1982-
&& let Some(default_fields) = self.field_defaults(def_id)
1983-
&& !struct_expr.fields.is_empty()
1984-
{
1985-
let last_span = struct_expr.fields.iter().last().unwrap().span;
1986-
let mut iter = struct_expr.fields.iter().peekable();
1987-
let mut prev: Option<Span> = None;
1988-
while let Some(field) = iter.next() {
1989-
if field.expr.span.overlaps(ident.span) {
1990-
err.span_label(field.ident.span, "while setting this field");
1991-
if default_fields.contains(&field.ident.name) {
1992-
let sugg = if last_span == field.span {
1993-
vec![(field.span, "..".to_string())]
1994-
} else {
1995-
vec![
1996-
(
1997-
// Account for trailing commas and ensure we remove them.
1998-
match (prev, iter.peek()) {
1999-
(_, Some(next)) => field.span.with_hi(next.span.lo()),
2000-
(Some(prev), _) => field.span.with_lo(prev.hi()),
2001-
(None, None) => field.span,
2002-
},
2003-
String::new(),
2004-
),
2005-
(last_span.shrink_to_hi(), ", ..".to_string()),
2006-
]
2007-
};
2008-
err.multipart_suggestion_verbose(
2009-
format!(
2010-
"the type `{ident}` of field `{}` is private, but you can \
2011-
construct the default value defined for it in `{}` using `..` in \
2012-
the struct initializer expression",
2013-
field.ident,
2014-
self.tcx.item_name(def_id),
2015-
),
2016-
sugg,
2017-
Applicability::MachineApplicable,
2018-
);
2019-
break;
2020-
}
2021-
}
2022-
prev = Some(field.span);
2023-
}
2024-
}
1977+
self.mention_default_field_values(source, ident, &mut err);
20251978

20261979
let mut not_publicly_reexported = false;
20271980
if let Some((this_res, outer_ident)) = outermost_res {
@@ -2204,6 +2157,85 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
22042157
err.emit();
22052158
}
22062159

2160+
/// When a private field is being set that has a default field value, we suggest using `..` and
2161+
/// setting the value of that field implicitly with its default.
2162+
///
2163+
/// If we encounter code like
2164+
/// ```text
2165+
/// struct Priv;
2166+
/// pub struct S {
2167+
/// pub field: Priv = Priv,
2168+
/// }
2169+
/// ```
2170+
/// which is used from a place where `Priv` isn't accessible
2171+
/// ```text
2172+
/// let _ = S { field: m::Priv1 {} };
2173+
/// // ^^^^^ private struct
2174+
/// ```
2175+
/// we will suggest instead using the `default_field_values` syntax instead:
2176+
/// ```text
2177+
/// let _ = S { .. };
2178+
/// ```
2179+
fn mention_default_field_values(
2180+
&self,
2181+
source: &Option<ast::Expr>,
2182+
ident: Ident,
2183+
err: &mut Diag<'_>,
2184+
) {
2185+
let Some(expr) = source else { return };
2186+
let ast::ExprKind::Struct(struct_expr) = &expr.kind else { return };
2187+
// We don't have to handle type-relative paths because they're forbidden in ADT
2188+
// expressions, but that would change with `#[feature(more_qualified_paths)]`.
2189+
let Some(Res::Def(_, def_id)) =
2190+
self.partial_res_map[&struct_expr.path.segments.iter().last().unwrap().id].full_res()
2191+
else {
2192+
return;
2193+
};
2194+
let Some(default_fields) = self.field_defaults(def_id) else { return };
2195+
if struct_expr.fields.is_empty() {
2196+
return;
2197+
}
2198+
let last_span = struct_expr.fields.iter().last().unwrap().span;
2199+
let mut iter = struct_expr.fields.iter().peekable();
2200+
let mut prev: Option<Span> = None;
2201+
while let Some(field) = iter.next() {
2202+
if field.expr.span.overlaps(ident.span) {
2203+
err.span_label(field.ident.span, "while setting this field");
2204+
if default_fields.contains(&field.ident.name) {
2205+
let sugg = if last_span == field.span {
2206+
vec![(field.span, "..".to_string())]
2207+
} else {
2208+
vec![
2209+
(
2210+
// Account for trailing commas and ensure we remove them.
2211+
match (prev, iter.peek()) {
2212+
(_, Some(next)) => field.span.with_hi(next.span.lo()),
2213+
(Some(prev), _) => field.span.with_lo(prev.hi()),
2214+
(None, None) => field.span,
2215+
},
2216+
String::new(),
2217+
),
2218+
(last_span.shrink_to_hi(), ", ..".to_string()),
2219+
]
2220+
};
2221+
err.multipart_suggestion_verbose(
2222+
format!(
2223+
"the type `{ident}` of field `{}` is private, but you can construct \
2224+
the default value defined for it in `{}` using `..` in the struct \
2225+
initializer expression",
2226+
field.ident,
2227+
self.tcx.item_name(def_id),
2228+
),
2229+
sugg,
2230+
Applicability::MachineApplicable,
2231+
);
2232+
break;
2233+
}
2234+
}
2235+
prev = Some(field.span);
2236+
}
2237+
}
2238+
22072239
pub(crate) fn find_similarly_named_module_or_crate(
22082240
&self,
22092241
ident: Symbol,

0 commit comments

Comments
 (0)