Skip to content

Commit

Permalink
Rollup merge of #100309 - compiler-errors:issue-100300, r=sanxiyn
Browse files Browse the repository at this point in the history
Extend comma suggestion to cases where fields arent missing

Fixes #100300
  • Loading branch information
Dylan-DPC committed Aug 23, 2022
2 parents 4d1c273 + f4bf8cd commit 8733550
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 30 deletions.
55 changes: 36 additions & 19 deletions compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1822,25 +1831,35 @@ 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
.and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
.map(|adt| adt.did())
!= range_def_id
) = 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
{
let instead = self
.tcx
Expand All @@ -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.
Expand Down
24 changes: 21 additions & 3 deletions src/test/ui/structs/struct-record-suggestion.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
24 changes: 21 additions & 3 deletions src/test/ui/structs/struct-record-suggestion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
23 changes: 18 additions & 5 deletions src/test/ui/structs/struct-record-suggestion.stderr
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
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}>`

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`.

0 comments on commit 8733550

Please sign in to comment.