mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
When encountering struct fn call literal with private fields, suggest all builders
When encountering code like `Box(42)`, suggest `Box::new(42)` and *all* other associated functions that return `-> Box<T>`.
This commit is contained in:
parent
27794f95fd
commit
42aa1273b0
@ -759,6 +759,9 @@ impl Diagnostic {
|
||||
suggestions: impl IntoIterator<Item = String>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
let mut suggestions: Vec<_> = suggestions.into_iter().collect();
|
||||
suggestions.sort();
|
||||
|
||||
self.span_suggestions_with_style(
|
||||
sp,
|
||||
msg,
|
||||
@ -768,7 +771,9 @@ impl Diagnostic {
|
||||
)
|
||||
}
|
||||
|
||||
/// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`].
|
||||
/// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`]. This version
|
||||
/// *doesn't* sort the suggestions, so the caller has control of the order in which they are
|
||||
/// presented.
|
||||
pub fn span_suggestions_with_style(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
@ -777,9 +782,7 @@ impl Diagnostic {
|
||||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
) -> &mut Self {
|
||||
let mut suggestions: Vec<_> = suggestions.into_iter().collect();
|
||||
suggestions.sort();
|
||||
|
||||
let suggestions: Vec<_> = suggestions.into_iter().collect();
|
||||
debug_assert!(
|
||||
!(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
|
||||
"Span must not be empty and have no suggestion"
|
||||
|
@ -442,10 +442,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
|
||||
|
||||
self.formatting_init.extend(code_init);
|
||||
Ok(quote! {
|
||||
let mut code: Vec<_> = #code_field.into_iter().collect();
|
||||
code.sort();
|
||||
#diag.span_suggestions_with_style(
|
||||
#span_field,
|
||||
crate::fluent_generated::#slug,
|
||||
#code_field,
|
||||
code,
|
||||
#applicability,
|
||||
#style
|
||||
);
|
||||
|
@ -2608,6 +2608,7 @@ fn show_candidates(
|
||||
path_strings.extend(core_path_strings);
|
||||
path_strings.dedup_by(|a, b| a.0 == b.0);
|
||||
}
|
||||
accessible_path_strings.sort();
|
||||
|
||||
if !accessible_path_strings.is_empty() {
|
||||
let (determiner, kind, name, through) =
|
||||
|
@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{
|
||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
MultiSpan,
|
||||
MultiSpan, SuggestionStyle,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
|
||||
@ -29,6 +29,8 @@ use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use rustc_middle::ty;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
@ -1593,29 +1595,85 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
Some(Vec::from(pattern_spans))
|
||||
}
|
||||
// e.g. `let _ = Enum::TupleVariant(field1, field2);`
|
||||
_ if source.is_call() => {
|
||||
PathSource::Expr(Some(Expr { kind: ExprKind::Call(_, ref args), .. })) => {
|
||||
err.set_primary_message(
|
||||
"cannot initialize a tuple struct which contains private fields",
|
||||
);
|
||||
if !def_id.is_local()
|
||||
&& self
|
||||
if !def_id.is_local() {
|
||||
// Look at all the associated functions without receivers in the type's
|
||||
// inherent impls to look for builders that return `Self`
|
||||
let mut items = self
|
||||
.r
|
||||
.tcx
|
||||
.inherent_impls(def_id)
|
||||
.iter()
|
||||
.flat_map(|impl_def_id| {
|
||||
self.r.tcx.provided_trait_methods(*impl_def_id)
|
||||
.flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
|
||||
// Only assoc fn with no receivers.
|
||||
.filter(|item| {
|
||||
matches!(item.kind, ty::AssocKind::Fn)
|
||||
&& !item.fn_has_self_parameter
|
||||
})
|
||||
.any(|assoc| !assoc.fn_has_self_parameter && assoc.name == sym::new)
|
||||
{
|
||||
// FIXME: look for associated functions with Self return type,
|
||||
// instead of relying only on the name and lack of self receiver.
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"you might have meant to use the `new` associated function",
|
||||
"::new".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
.filter_map(|item| {
|
||||
// Only assoc fns that return `Self`
|
||||
let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
|
||||
let ret_ty = fn_sig.output();
|
||||
let ret_ty = self.r.tcx.erase_late_bound_regions(ret_ty);
|
||||
let ty::Adt(def, _args) = ret_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
// Check for `-> Self`
|
||||
if def.did() == def_id {
|
||||
let order = if item.name.as_str().starts_with("new")
|
||||
&& fn_sig.inputs().skip_binder().len() == args.len()
|
||||
{
|
||||
0
|
||||
} else if item.name.as_str().starts_with("new")
|
||||
|| item.name.as_str().starts_with("default")
|
||||
{
|
||||
// Give higher precedence to functions with a name that
|
||||
// imply construction.
|
||||
1
|
||||
} else if fn_sig.inputs().skip_binder().len() == args.len()
|
||||
{
|
||||
2
|
||||
} else {
|
||||
3
|
||||
};
|
||||
return Some((order, item.name));
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
items.sort_by_key(|(order, _)| *order);
|
||||
match &items[..] {
|
||||
[] => {}
|
||||
[(_, name)] => {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
format!(
|
||||
"you might have meant to use the `{name}` associated \
|
||||
function",
|
||||
),
|
||||
format!("::{name}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
// We use this instead of `span_suggestions` to retain output
|
||||
// sort order.
|
||||
err.span_suggestions_with_style(
|
||||
span.shrink_to_hi(),
|
||||
"you might have meant to use an associated function to \
|
||||
build this type",
|
||||
items
|
||||
.iter()
|
||||
.map(|(_, name)| format!("::{name}"))
|
||||
.collect::<Vec<String>>(),
|
||||
Applicability::MaybeIncorrect,
|
||||
SuggestionStyle::ShowAlways,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Use spans of the tuple struct definition.
|
||||
self.r.field_def_ids(def_id).map(|field_ids| {
|
||||
|
@ -25,8 +25,8 @@ LL | a!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= help: consider importing one of these items:
|
||||
std::mem
|
||||
core::mem
|
||||
std::mem
|
||||
= note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0433]: failed to resolve: use of undeclared crate or module `my_core`
|
||||
|
@ -1,15 +0,0 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
struct U <T> {
|
||||
wtf: Option<Box<U<T>>>,
|
||||
x: T,
|
||||
}
|
||||
fn main() {
|
||||
U {
|
||||
wtf: Some(Box::new(U { //~ ERROR cannot initialize a tuple struct which contains private fields
|
||||
wtf: None,
|
||||
x: (),
|
||||
})),
|
||||
x: ()
|
||||
};
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
struct U <T> {
|
||||
wtf: Option<Box<U<T>>>,
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0423]: cannot initialize a tuple struct which contains private fields
|
||||
--> $DIR/suggest-box-new.rs:9:19
|
||||
--> $DIR/suggest-box-new.rs:8:19
|
||||
|
|
||||
LL | wtf: Some(Box(U {
|
||||
| ^^^
|
||||
@ -10,10 +10,17 @@ note: constructor is not visible here due to private fields
|
||||
= note: private field
|
||||
|
|
||||
= note: private field
|
||||
help: you might have meant to use the `new` associated function
|
||||
help: you might have meant to use an associated function to build this type
|
||||
|
|
||||
LL | wtf: Some(Box::new(U {
|
||||
| +++++
|
||||
LL | wtf: Some(Box::new_uninit_in(U {
|
||||
| +++++++++++++++
|
||||
LL | wtf: Some(Box::new_zeroed_in(U {
|
||||
| +++++++++++++++
|
||||
LL | wtf: Some(Box::new_uninit_slice(U {
|
||||
| ++++++++++++++++++
|
||||
and 10 other candidates
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -4,8 +4,8 @@ error[E0433]: failed to resolve: use of undeclared type `TryFrom`
|
||||
LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap();
|
||||
| ^^^^^^^ use of undeclared type `TryFrom`
|
||||
|
|
||||
= note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
|
||||
= note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
|
||||
= note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
|
||||
help: consider importing one of these items
|
||||
|
|
||||
LL + use core::convert::TryFrom;
|
||||
@ -19,8 +19,8 @@ error[E0433]: failed to resolve: use of undeclared type `TryInto`
|
||||
LL | let _i: i16 = TryInto::try_into(0_i32).unwrap();
|
||||
| ^^^^^^^ use of undeclared type `TryInto`
|
||||
|
|
||||
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
|
||||
= note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
|
||||
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
|
||||
help: consider importing one of these items
|
||||
|
|
||||
LL + use core::convert::TryInto;
|
||||
@ -34,8 +34,8 @@ error[E0433]: failed to resolve: use of undeclared type `FromIterator`
|
||||
LL | let _v: Vec<_> = FromIterator::from_iter(&[1]);
|
||||
| ^^^^^^^^^^^^ use of undeclared type `FromIterator`
|
||||
|
|
||||
= note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
|
||||
= note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
|
||||
= note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
|
||||
help: a trait with a similar name exists
|
||||
|
|
||||
LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]);
|
||||
|
Loading…
Reference in New Issue
Block a user