Skip to content

Commit 9bcda61

Browse files
committed
review comments
1 parent 877fc0d commit 9bcda61

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
@@ -1855,11 +1855,10 @@ rustc_queries! {
18551855
feedable
18561856
}
18571857

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

18651864
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
@@ -1970,54 +1970,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19701970
let mut err =
19711971
self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
19721972

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

20221975
let mut not_publicly_reexported = false;
20231976
if let Some((this_res, outer_ident)) = outermost_res {
@@ -2203,6 +2156,85 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
22032156
err.emit();
22042157
}
22052158

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

0 commit comments

Comments
 (0)