@@ -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