about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs57
-rw-r--r--tests/ui/privacy/suggest-box-new.stderr4
2 files changed, 60 insertions, 1 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index ce4e0eecf39..71732261efc 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,6 +1,7 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
 use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
 use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
+use crate::ty::fast_reject::SimplifiedType;
 use crate::{errors, path_names_to_string};
 use crate::{Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
@@ -1595,7 +1596,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                         Some(Vec::from(pattern_spans))
                     }
                     // e.g. `let _ = Enum::TupleVariant(field1, field2);`
-                    PathSource::Expr(Some(Expr { kind: ExprKind::Call(_, ref args), .. })) => {
+                    PathSource::Expr(Some(Expr {
+                        kind: ExprKind::Call(path, ref args),
+                        span: call_span,
+                        ..
+                    })) => {
                         err.set_primary_message(
                             "cannot initialize a tuple struct which contains private fields",
                         );
@@ -1675,6 +1680,56 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                                     );
                                 }
                             }
+                            // We'd ideally use `type_implements_trait` but don't have access to
+                            // the trait solver here.  We can't use `get_diagnostic_item` or
+                            // `all_traits` in resolve either. So instead we abuse the import
+                            // suggestion machinery to get `std::default::Default` and perform some
+                            // checks to confirm that we got *only* that trait. We then see if the
+                            // Adt we have has a direct implementation of `Default`. If so, we
+                            // provide a structured suggestion.
+                            let default_trait = self
+                                .r
+                                .lookup_import_candidates(
+                                    Ident::with_dummy_span(sym::Default),
+                                    Namespace::TypeNS,
+                                    &self.parent_scope,
+                                    &|res: Res| matches!(res, Res::Def(DefKind::Trait, _)),
+                                )
+                                .iter()
+                                .filter_map(|candidate| candidate.did)
+                                .filter(|did| {
+                                    self.r
+                                        .tcx
+                                        .get_attrs(*did, sym::rustc_diagnostic_item)
+                                        .any(|attr| attr.value_str() == Some(sym::Default))
+                                })
+                                .next();
+                            if let Some(default_trait) = default_trait
+                                && self.r.extern_crate_map.iter().flat_map(|(_, crate_)| {
+                                    self
+                                        .r
+                                        .tcx
+                                        .implementations_of_trait((*crate_, default_trait))
+                                })
+                                .filter_map(|(_, simplified_self_ty)| *simplified_self_ty)
+                                .filter_map(|simplified_self_ty| match simplified_self_ty {
+                                    SimplifiedType::Adt(did) => Some(did),
+                                    _ => None
+                                })
+                                .any(|did| did == def_id)
+                            {
+                                err.multipart_suggestion(
+                                    "consider using the `Default` trait",
+                                    vec![
+                                        (path.span.shrink_to_lo(), "<".to_string()),
+                                        (
+                                            path.span.shrink_to_hi().with_hi(call_span.hi()),
+                                            " as std::default::Default>::default()".to_string(),
+                                        ),
+                                    ],
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                         }
                         // Use spans of the tuple struct definition.
                         self.r.field_def_ids(def_id).map(|field_ids| {
diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr
index dbed66d0ae4..46fb860eb70 100644
--- a/tests/ui/privacy/suggest-box-new.stderr
+++ b/tests/ui/privacy/suggest-box-new.stderr
@@ -21,6 +21,10 @@ LL |         wtf: Some(Box::new_zeroed_in(U {
 LL |         wtf: Some(Box::new_uninit_slice(U {
    |                      ++++++++++++++++++
      and 10 other candidates
+help: consider using the `Default` trait
+   |
+LL |         wtf: Some(<Box as std::default::Default>::default()),
+   |                   +    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to previous error