Skip to content

Commit 29d26f2

Browse files
committed
review comments
1 parent 464a6b1 commit 29d26f2

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
@@ -1864,11 +1864,10 @@ rustc_queries! {
18641864
feedable
18651865
}
18661866

1867-
/// Returns whether the impl or associated function has the `default` keyword.
1867+
/// Returns whether the field corresponding to the `DefId` has a default field value.
18681868
query default_field(def_id: DefId) -> Option<DefId> {
18691869
desc { |tcx| "looking up the `const` corresponding to the default for `{}`", tcx.def_path_str(def_id) }
18701870
separate_provide_extern
1871-
feedable
18721871
}
18731872

18741873
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
@@ -1967,54 +1967,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19671967
let mut err =
19681968
self.dcx().create_err(errors::IsPrivate { span: ident.span, ident_descr, ident });
19691969

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

20191972
let mut not_publicly_reexported = false;
20201973
if let Some((this_res, outer_ident)) = outermost_res {
@@ -2197,6 +2150,85 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
21972150
err.emit();
21982151
}
21992152

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

0 commit comments

Comments
 (0)