vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
Applicability::MachineApplicable,
);
- } else if fields.len() > subpats.len() {
- let after_fields_span = if pat_span == DUMMY_SP {
- pat_span
- } else {
- pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi()
- };
+ } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
+ let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
let all_fields_span = match subpats {
[] => after_fields_span,
[field] => field.span,
// Check if all the fields in the pattern are wildcards.
let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
+ let first_tail_wildcard =
+ subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
+ (None, PatKind::Wild) => Some(pos),
+ (Some(_), PatKind::Wild) => acc,
+ _ => None,
+ });
+ let tail_span = match first_tail_wildcard {
+ None => after_fields_span,
+ Some(0) => subpats[0].span.to(after_fields_span),
+ Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
+ };
+ // FIXME: heuristic-based suggestion to check current types for where to add `_`.
let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
if !subpats.is_empty() {
wildcard_sugg = String::from(", ") + &wildcard_sugg;
}
- err.span_suggestion(
+ err.span_suggestion_verbose(
after_fields_span,
"use `_` to explicitly ignore each field",
wildcard_sugg,
Applicability::MaybeIncorrect,
);
- if subpats.is_empty() || all_wildcards {
- err.span_suggestion(
- all_fields_span,
- "use `..` to ignore all unmentioned fields",
- String::from(".."),
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_suggestion(
- after_fields_span,
- "use `..` to ignore all unmentioned fields",
- String::from(", .."),
- Applicability::MaybeIncorrect,
- );
+ // Only suggest `..` if more than one field is missing
+ // or the pattern consists of all wildcards.
+ if fields.len() - subpats.len() > 1 || all_wildcards {
+ if subpats.is_empty() || all_wildcards {
+ err.span_suggestion_verbose(
+ all_fields_span,
+ "use `..` to ignore all fields",
+ String::from(".."),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ tail_span,
+ "use `..` to ignore the rest of the fields",
+ String::from(", .."),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
/// Returns a diagnostic reporting a struct pattern which does not mention some fields.
///
/// ```text
- /// error[E0027]: pattern does not mention field `you_cant_use_this_field`
+ /// error[E0027]: pattern does not mention field `bar`
/// --> src/main.rs:15:9
/// |
/// LL | let foo::Foo {} = foo::Foo::new();
- /// | ^^^^^^^^^^^ missing field `you_cant_use_this_field`
+ /// | ^^^^^^^^^^^ missing field `bar`
/// ```
fn error_unmentioned_fields(
&self,
}
_ => return err,
},
- [.., field] => (
- match pat.kind {
- PatKind::Struct(_, [_, ..], _) => ", ",
- _ => "",
- },
- "",
- field.span.shrink_to_hi(),
- ),
+ [.., field] => {
+ // if last field has a trailing comma, use the comma
+ // as the span to avoid trailing comma in ultimate
+ // suggestion (Issue #78511)
+ let tail = field.span.shrink_to_hi().until(pat.span.shrink_to_hi());
+ let tail_through_comma = self.tcx.sess.source_map().span_through_char(tail, ',');
+ let sp = if tail_through_comma == tail {
+ field.span.shrink_to_hi()
+ } else {
+ tail_through_comma
+ };
+ (
+ match pat.kind {
+ PatKind::Struct(_, [_, ..], _) => ", ",
+ _ => "",
+ },
+ "",
+ sp,
+ )
+ }
};
err.span_suggestion(
sp,