Skip to content

Commit a4f47de

Browse files
committed
On private tuple struct, suggest Default::default when possible
1 parent f1ae02f commit a4f47de

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
22
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
33
use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
4+
use crate::ty::fast_reject::SimplifiedType;
45
use crate::{errors, path_names_to_string};
56
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
67
use crate::{PathResult, PathSource, Segment};
@@ -1595,7 +1596,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
15951596
Some(Vec::from(pattern_spans))
15961597
}
15971598
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
1598-
PathSource::Expr(Some(Expr { kind: ExprKind::Call(_, ref args), .. })) => {
1599+
PathSource::Expr(Some(Expr {
1600+
kind: ExprKind::Call(path, ref args),
1601+
span: call_span,
1602+
..
1603+
})) => {
15991604
err.set_primary_message(
16001605
"cannot initialize a tuple struct which contains private fields",
16011606
);
@@ -1675,6 +1680,56 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
16751680
);
16761681
}
16771682
}
1683+
// We'd ideally use `type_implements_trait` but don't have access to
1684+
// the trait solver here. We can't use `get_diagnostic_item` or
1685+
// `all_traits` in resolve either. So instead we abuse the import
1686+
// suggestion machinery to get `std::default::Default` and perform some
1687+
// checks to confirm that we got *only* that trait. We then see if the
1688+
// Adt we have has a direct implementation of `Default`. If so, we
1689+
// provide a structured suggestion.
1690+
let default_trait = self
1691+
.r
1692+
.lookup_import_candidates(
1693+
Ident::with_dummy_span(sym::Default),
1694+
Namespace::TypeNS,
1695+
&self.parent_scope,
1696+
&|res: Res| matches!(res, Res::Def(DefKind::Trait, _)),
1697+
)
1698+
.iter()
1699+
.filter_map(|candidate| candidate.did)
1700+
.filter(|did| {
1701+
self.r
1702+
.tcx
1703+
.get_attrs(*did, sym::rustc_diagnostic_item)
1704+
.any(|attr| attr.value_str() == Some(sym::Default))
1705+
})
1706+
.next();
1707+
if let Some(default_trait) = default_trait
1708+
&& self.r.extern_crate_map.iter().flat_map(|(_, crate_)| {
1709+
self
1710+
.r
1711+
.tcx
1712+
.implementations_of_trait((*crate_, default_trait))
1713+
})
1714+
.filter_map(|(_, simplified_self_ty)| *simplified_self_ty)
1715+
.filter_map(|simplified_self_ty| match simplified_self_ty {
1716+
SimplifiedType::Adt(did) => Some(did),
1717+
_ => None
1718+
})
1719+
.any(|did| did == def_id)
1720+
{
1721+
err.multipart_suggestion(
1722+
"consider using the `Default` trait",
1723+
vec![
1724+
(path.span.shrink_to_lo(), "<".to_string()),
1725+
(
1726+
path.span.shrink_to_hi().with_hi(call_span.hi()),
1727+
" as std::default::Default>::default()".to_string(),
1728+
),
1729+
],
1730+
Applicability::MaybeIncorrect,
1731+
);
1732+
}
16781733
}
16791734
// Use spans of the tuple struct definition.
16801735
self.r.field_def_ids(def_id).map(|field_ids| {

tests/ui/privacy/suggest-box-new.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ LL | wtf: Some(Box::new_zeroed_in(U {
2121
LL | wtf: Some(Box::new_uninit_slice(U {
2222
| ++++++++++++++++++
2323
and 10 other candidates
24+
help: consider using the `Default` trait
25+
|
26+
LL | wtf: Some(<Box as std::default::Default>::default()),
27+
| + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2428

2529
error: aborting due to previous error
2630

0 commit comments

Comments
 (0)