Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 46 additions & 13 deletions src/librustc_typeck/check/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
} else {
// Pattern has wrong number of fields.
self.e0023(pat.span, res, &subpats, &variant.fields, expected);
self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
on_error();
return tcx.types.err;
}
Expand All @@ -687,22 +687,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
pat_span: Span,
res: Res,
qpath: &hir::QPath,
subpats: &'tcx [P<Pat>],
fields: &[ty::FieldDef],
expected: Ty<'tcx>
) {
let subpats_ending = pluralise!(subpats.len());
let fields_ending = pluralise!(fields.len());
let missing_parenthesis = match expected.sty {
ty::Adt(_, substs) if fields.len() == 1 => {
let field_ty = fields[0].ty(self.tcx, substs);
match field_ty.sty {
ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
_ => false,
}
}
_ => false,
};
let res_span = self.tcx.def_span(res.def_id());
let mut err = struct_span_err!(
self.tcx.sess,
Expand All @@ -723,11 +714,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
))
.span_label(res_span, format!("{} defined here", res.descr()));

// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
// More generally, the expected type wants a tuple variant with one field of an
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
let missing_parenthesis = match expected.sty {
ty::Adt(_, substs) if fields.len() == 1 => {
let field_ty = fields[0].ty(self.tcx, substs);
match field_ty.sty {
ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
_ => false,
}
}
_ => false,
};
if missing_parenthesis {
let (left, right) = match subpats {
// This is the zero case; we aim to get the "hi" part of the `QPath`'s
// span as the "lo" and then the "hi" part of the pattern's span as the "hi".
// This looks like:
//
// help: missing parenthesis
// |
// L | let A(()) = A(());
// | ^ ^
[] => {
let qpath_span = match qpath {
hir::QPath::Resolved(_, path) => path.span,
hir::QPath::TypeRelative(_, ps) => ps.ident.span,
};
(qpath_span.shrink_to_hi(), pat_span)
},
// Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
// last sub-pattern. In the case of `A(x)` the first and last may coincide.
// This looks like:
//
// help: missing parenthesis
// |
// L | let A((x, y)) = A((1, 2));
// | ^ ^
[first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
};
err.multipart_suggestion(
"missing parenthesis",
vec![(subpats[0].span.shrink_to_lo(), "(".to_string()),
(subpats[subpats.len()-1].span.shrink_to_hi(), ")".to_string())],
vec![
(left, "(".to_string()),
(right.shrink_to_hi(), ")".to_string()),
],
Applicability::MachineApplicable,
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/error-codes/E0023.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ enum Fruit {
Apple(String, String),
Pear(u32),
Orange((String, String)),
Banana(()),
}


fn main() {
let x = Fruit::Apple(String::new(), String::new());
match x {
Fruit::Apple(a) => {}, //~ ERROR E0023
Fruit::Apple(a, b, c) => {}, //~ ERROR E0023
Fruit::Pear(1, 2) => {}, //~ ERROR E0023
Fruit::Orange(a, b) => {}, //~ ERROR E0023
Fruit::Banana() => {}, //~ ERROR E0023
}
}
15 changes: 14 additions & 1 deletion src/test/ui/error-codes/E0023.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ help: missing parenthesis
LL | Fruit::Orange((a, b)) => {},
| ^ ^

error: aborting due to 4 previous errors
error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 1 field
--> $DIR/E0023.rs:15:9
|
LL | Banana(()),
| ---------- tuple variant defined here
...
LL | Fruit::Banana() => {},
| ^^^^^^^^^^^^^^^ expected 1 field, found 0
help: missing parenthesis
|
LL | Fruit::Banana(()) => {},
| ^ ^

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0023`.