mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
Rollup merge of #99986 - WaffleLapkin:record_struct_wrap_suggestion, r=compiler-errors
Add wrap suggestions for record variants This PR adds a suggestions to wrap an expression in a record struct/variant when encountering mismatched types, similarly to a suggestion to wrap expression in a tuple struct that was added before. An example: ```rust struct B { f: u8, } enum E { A(u32), B { f: u8 }, } fn main() { let _: B = 1; let _: E = 1; } ``` ```text error[E0308]: mismatched types --> ./t.rs:11:16 | 11 | let _: B = 1; | - ^ expected struct `B`, found integer | | | expected due to this | help: try wrapping the expression in `B` | 11 | let _: B = B { f: 1 }; | ++++++ + error[E0308]: mismatched types --> ./t.rs:12:16 | 12 | let _: E = 1; | - ^ expected enum `E`, found integer | | | expected due to this | help: try wrapping the expression in a variant of `E` | 12 | let _: E = E::A(1); | +++++ + 12 | let _: E = E::B { f: 1 }; | +++++++++ + ``` r? `@compiler-errors`
This commit is contained in:
commit
20a5e9fd7c
@ -1,5 +1,6 @@
|
||||
use crate::check::FnCtxt;
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::ObligationCause;
|
||||
|
||||
@ -363,18 +364,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let compatible_variants: Vec<(String, Option<String>)> = expected_adt
|
||||
let compatible_variants: Vec<(String, _, _, Option<String>)> = expected_adt
|
||||
.variants()
|
||||
.iter()
|
||||
.filter(|variant| {
|
||||
variant.fields.len() == 1 && variant.ctor_kind == hir::def::CtorKind::Fn
|
||||
variant.fields.len() == 1
|
||||
})
|
||||
.filter_map(|variant| {
|
||||
let sole_field = &variant.fields[0];
|
||||
|
||||
let field_is_local = sole_field.did.is_local();
|
||||
let field_is_accessible =
|
||||
sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx);
|
||||
sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
|
||||
// Skip suggestions for unstable public fields (for example `Pin::pointer`)
|
||||
&& matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
|
||||
|
||||
if !field_is_local && !field_is_accessible {
|
||||
return None;
|
||||
@ -391,33 +394,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if let Some(path) = variant_path.strip_prefix("std::prelude::")
|
||||
&& let Some((_, path)) = path.split_once("::")
|
||||
{
|
||||
return Some((path.to_string(), note_about_variant_field_privacy));
|
||||
return Some((path.to_string(), variant.ctor_kind, sole_field.name, note_about_variant_field_privacy));
|
||||
}
|
||||
Some((variant_path, note_about_variant_field_privacy))
|
||||
Some((variant_path, variant.ctor_kind, sole_field.name, note_about_variant_field_privacy))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
|
||||
Some(ident) => format!("{ident}: "),
|
||||
None => String::new(),
|
||||
let suggestions_for = |variant: &_, ctor, field_name| {
|
||||
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
|
||||
Some(ident) => format!("{ident}: "),
|
||||
None => String::new(),
|
||||
};
|
||||
|
||||
let (open, close) = match ctor {
|
||||
hir::def::CtorKind::Fn => ("(".to_owned(), ")"),
|
||||
hir::def::CtorKind::Fictive => (format!(" {{ {field_name}: "), " }"),
|
||||
|
||||
// unit variants don't have fields
|
||||
hir::def::CtorKind::Const => unreachable!(),
|
||||
};
|
||||
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
|
||||
(expr.span.shrink_to_hi(), close.to_owned()),
|
||||
]
|
||||
};
|
||||
|
||||
match &compatible_variants[..] {
|
||||
[] => { /* No variants to format */ }
|
||||
[(variant, note)] => {
|
||||
[(variant, ctor_kind, field_name, note)] => {
|
||||
// Just a single matching variant.
|
||||
err.multipart_suggestion_verbose(
|
||||
&format!(
|
||||
"try wrapping the expression in `{variant}`{note}",
|
||||
note = note.as_deref().unwrap_or("")
|
||||
),
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), format!("{prefix}{variant}(")),
|
||||
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
suggestions_for(&**variant, *ctor_kind, *field_name),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
@ -428,12 +443,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
"try wrapping the expression in a variant of `{}`",
|
||||
self.tcx.def_path_str(expected_adt.did())
|
||||
),
|
||||
compatible_variants.into_iter().map(|(variant, _)| {
|
||||
vec![
|
||||
(expr.span.shrink_to_lo(), format!("{prefix}{variant}(")),
|
||||
(expr.span.shrink_to_hi(), ")".to_string()),
|
||||
]
|
||||
}),
|
||||
compatible_variants.into_iter().map(
|
||||
|(variant, ctor_kind, field_name, _)| {
|
||||
suggestions_for(&variant, ctor_kind, field_name)
|
||||
},
|
||||
),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ fn main() {
|
||||
}
|
||||
|
||||
enum A {
|
||||
B { b: B},
|
||||
B { b: B },
|
||||
}
|
||||
|
||||
struct A2(B);
|
||||
@ -77,13 +77,12 @@ enum B {
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
// We don't want to suggest `A::B(B::Fst)` here.
|
||||
let a: A = B::Fst;
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP try wrapping
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
// But we _do_ want to suggest `A2(B::Fst)` here!
|
||||
let a: A2 = B::Fst;
|
||||
//~^ ERROR mismatched types
|
||||
//~| HELP try wrapping
|
||||
|
@ -191,15 +191,20 @@ LL | let _ = Foo { bar: Some(bar) };
|
||||
| ++++++++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:81:16
|
||||
--> $DIR/compatible-variants.rs:80:16
|
||||
|
|
||||
LL | let a: A = B::Fst;
|
||||
| - ^^^^^^ expected enum `A`, found enum `B`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
help: try wrapping the expression in `A::B`
|
||||
|
|
||||
LL | let a: A = A::B { b: B::Fst };
|
||||
| +++++++++ +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/compatible-variants.rs:87:17
|
||||
--> $DIR/compatible-variants.rs:86:17
|
||||
|
|
||||
LL | let a: A2 = B::Fst;
|
||||
| -- ^^^^^^ expected struct `A2`, found enum `B`
|
||||
|
@ -26,4 +26,5 @@ struct Context { wrapper: Wrapper }
|
||||
fn overton() {
|
||||
let _c = Context { wrapper: Payload{} };
|
||||
//~^ ERROR mismatched types
|
||||
//~| try wrapping the expression in `Wrapper`
|
||||
}
|
||||
|
@ -25,6 +25,11 @@ error[E0308]: mismatched types
|
||||
|
|
||||
LL | let _c = Context { wrapper: Payload{} };
|
||||
| ^^^^^^^^^ expected struct `Wrapper`, found struct `Payload`
|
||||
|
|
||||
help: try wrapping the expression in `Wrapper`
|
||||
|
|
||||
LL | let _c = Context { wrapper: Wrapper { payload: Payload{} } };
|
||||
| ++++++++++++++++++ +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user