Rollup merge of #100309 - compiler-errors:issue-100300, r=sanxiyn

Extend comma suggestion to cases where fields arent missing

Fixes #100300
This commit is contained in:
Dylan DPC 2022-08-23 20:40:02 +05:30 committed by GitHub
commit 8733550870
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 30 deletions

View File

@ -1556,7 +1556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut error_happened = false;
// Type-check each field.
for field in ast_fields {
for (idx, field) in ast_fields.iter().enumerate() {
let ident = tcx.adjust_ident(field.ident, variant.def_id);
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
seen_fields.insert(ident, field.span);
@ -1594,7 +1594,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Make sure to give a type to the field even if there's
// an error, so we can continue type-checking.
self.check_expr_coercable_to_type(&field.expr, field_type, None);
let ty = self.check_expr_with_hint(&field.expr, field_type);
let (_, diag) =
self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No);
if let Some(mut diag) = diag {
if idx == ast_fields.len() - 1 && remaining_fields.is_empty() {
self.suggest_fru_from_range(field, variant, substs, &mut diag);
}
diag.emit();
}
}
// Make sure the programmer specified correct number of fields.
@ -1822,22 +1831,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
// If the last field is a range literal, but it isn't supposed to be, then they probably
// meant to use functional update syntax.
//
if let Some(last) = ast_fields.last() {
self.suggest_fru_from_range(last, variant, substs, &mut err);
}
err.emit();
}
/// If the last field is a range literal, but it isn't supposed to be, then they probably
/// meant to use functional update syntax.
fn suggest_fru_from_range(
&self,
last_expr_field: &hir::ExprField<'tcx>,
variant: &ty::VariantDef,
substs: SubstsRef<'tcx>,
err: &mut Diagnostic,
) {
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
if let Some((
last,
ExprKind::Struct(
if let ExprKind::Struct(
QPath::LangItem(LangItem::Range, ..),
&[ref range_start, ref range_end],
_,
),
)) = ast_fields.last().map(|last| (last, &last.expr.kind)) &&
let variant_field =
variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) &&
let range_def_id = self.tcx.lang_items().range_struct() &&
variant_field
) = last_expr_field.expr.kind
&& let variant_field =
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
&& let range_def_id = self.tcx.lang_items().range_struct()
&& variant_field
.and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
.map(|adt| adt.did())
!= range_def_id
@ -1856,8 +1875,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect,
);
}
err.emit();
}
/// Report an error for a struct field expression when there are invisible fields.

View File

@ -6,11 +6,29 @@ struct A {
d: usize,
}
fn main() {
let q = A { c: 5, .. Default::default() };
fn a() {
let q = A { c: 5,..Default::default() };
//~^ ERROR mismatched types
//~| ERROR missing fields
//~| HELP separate the last named field with a comma
let r = A { c: 5, .. Default::default() };
let r = A { c: 5, ..Default::default() };
assert_eq!(q, r);
}
#[derive(Debug, Default, Eq, PartialEq)]
struct B {
b: u32,
}
fn b() {
let q = B { b: 1,..Default::default() };
//~^ ERROR mismatched types
//~| HELP separate the last named field with a comma
let r = B { b: 1 };
assert_eq!(q, r);
}
fn main() {
a();
b();
}

View File

@ -6,11 +6,29 @@ struct A {
d: usize,
}
fn main() {
let q = A { c: 5 .. Default::default() };
fn a() {
let q = A { c: 5..Default::default() };
//~^ ERROR mismatched types
//~| ERROR missing fields
//~| HELP separate the last named field with a comma
let r = A { c: 5, .. Default::default() };
let r = A { c: 5, ..Default::default() };
assert_eq!(q, r);
}
#[derive(Debug, Default, Eq, PartialEq)]
struct B {
b: u32,
}
fn b() {
let q = B { b: 1..Default::default() };
//~^ ERROR mismatched types
//~| HELP separate the last named field with a comma
let r = B { b: 1 };
assert_eq!(q, r);
}
fn main() {
a();
b();
}

View File

@ -1,8 +1,8 @@
error[E0308]: mismatched types
--> $DIR/struct-record-suggestion.rs:10:20
|
LL | let q = A { c: 5 .. Default::default() };
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
LL | let q = A { c: 5..Default::default() };
| ^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
|
= note: expected type `u64`
found struct `std::ops::Range<{integer}>`
@ -10,15 +10,28 @@ LL | let q = A { c: 5 .. Default::default() };
error[E0063]: missing fields `b` and `d` in initializer of `A`
--> $DIR/struct-record-suggestion.rs:10:13
|
LL | let q = A { c: 5 .. Default::default() };
LL | let q = A { c: 5..Default::default() };
| ^ missing `b` and `d`
|
help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
|
LL | let q = A { c: 5, .. Default::default() };
LL | let q = A { c: 5,..Default::default() };
| +
error: aborting due to 2 previous errors
error[E0308]: mismatched types
--> $DIR/struct-record-suggestion.rs:24:20
|
LL | let q = B { b: 1..Default::default() };
| ^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `std::ops::Range`
|
= note: expected type `u32`
found struct `std::ops::Range<{integer}>`
help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
|
LL | let q = B { b: 1,..Default::default() };
| +
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0063, E0308.
For more information about an error, try `rustc --explain E0063`.