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