mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
E0023: handle expected != pat-tup-type
This commit is contained in:
parent
aeaaf8f640
commit
4746d37339
@ -65,13 +65,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn demand_eqtype_pat(
|
||||
pub fn demand_eqtype_pat_diag(
|
||||
&self,
|
||||
cause_span: Span,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
match_expr_span: Option<Span>,
|
||||
) {
|
||||
) -> Option<DiagnosticBuilder<'tcx>> {
|
||||
let cause = if let Some(span) = match_expr_span {
|
||||
self.cause(
|
||||
cause_span,
|
||||
@ -80,9 +80,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
} else {
|
||||
self.misc(cause_span)
|
||||
};
|
||||
self.demand_eqtype_with_origin(&cause, expected, actual).map(|mut err| err.emit());
|
||||
self.demand_eqtype_with_origin(&cause, expected, actual)
|
||||
}
|
||||
|
||||
pub fn demand_eqtype_pat(
|
||||
&self,
|
||||
cause_span: Span,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
match_expr_span: Option<Span>,
|
||||
) {
|
||||
self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span)
|
||||
.map(|mut err| err.emit());
|
||||
}
|
||||
|
||||
pub fn demand_coerce(&self,
|
||||
expr: &hir::Expr,
|
||||
|
@ -703,7 +703,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let pat_ty = pat_ty.fn_sig(tcx).output();
|
||||
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
|
||||
|
||||
self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span);
|
||||
// Type-check the tuple struct pattern against the expected type.
|
||||
let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, match_arm_pat_span);
|
||||
let had_err = diag.is_some();
|
||||
diag.map(|mut err| err.emit());
|
||||
|
||||
// Type-check subpatterns.
|
||||
if subpats.len() == variant.fields.len()
|
||||
@ -721,7 +724,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
} else {
|
||||
// Pattern has wrong number of fields.
|
||||
self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected);
|
||||
self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
|
||||
on_error();
|
||||
return tcx.types.err;
|
||||
}
|
||||
@ -734,8 +737,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
res: Res,
|
||||
qpath: &hir::QPath,
|
||||
subpats: &'tcx [P<Pat>],
|
||||
fields: &[ty::FieldDef],
|
||||
expected: Ty<'tcx>
|
||||
fields: &'tcx [ty::FieldDef],
|
||||
expected: Ty<'tcx>,
|
||||
had_err: bool,
|
||||
) {
|
||||
let subpats_ending = pluralize!(subpats.len());
|
||||
let fields_ending = pluralize!(fields.len());
|
||||
@ -763,9 +767,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// 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.kind {
|
||||
ty::Adt(_, substs) if fields.len() == 1 => {
|
||||
let field_ty = fields[0].ty(self.tcx, substs);
|
||||
let missing_parenthesis = match (&expected.kind, fields, had_err) {
|
||||
// #67037: only do this if we could sucessfully type-check the expected type against
|
||||
// the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
|
||||
// `let P() = U;` where `P != U` with `struct P<T>(T);`.
|
||||
(ty::Adt(_, substs), [field], false) => {
|
||||
let field_ty = self.field_ty(pat_span, field, substs);
|
||||
match field_ty.kind {
|
||||
ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
|
||||
_ => false,
|
||||
|
@ -0,0 +1,21 @@
|
||||
// Regression test for #67037.
|
||||
//
|
||||
// In type checking patterns, E0023 occurs when the tuple pattern and the expected
|
||||
// tuple pattern have different number of fields. For example, as below, `P()`,
|
||||
// the tuple struct pattern, has 0 fields, but requires 1 field.
|
||||
//
|
||||
// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
|
||||
// the scrutinee was of type `Some((a, b, c))`, and suggest that parenthesis be added.
|
||||
//
|
||||
// However, we did not account for the expected type being different than the tuple pattern type.
|
||||
// This caused an issue when the tuple pattern type (`P<T>`) was generic.
|
||||
// Specifically, we tried deriving the 0th field's type using the `substs` of the expected type.
|
||||
// When attempting to substitute `T`, there was no such substitution, so "out of range" occured.
|
||||
|
||||
struct U {} // 0 type parameters offered
|
||||
struct P<T>(T); // 1 type parameter wanted
|
||||
|
||||
fn main() {
|
||||
let P() = U {}; //~ ERROR mismatched types
|
||||
//~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 1 field
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
|
||||
|
|
||||
LL | let P() = U {};
|
||||
| ^^^ expected struct `U`, found struct `P`
|
||||
|
|
||||
= note: expected struct `U`
|
||||
found struct `P<_>`
|
||||
|
||||
error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 1 field
|
||||
--> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
|
||||
|
|
||||
LL | struct P<T>(T); // 1 type parameter wanted
|
||||
| --------------- tuple struct defined here
|
||||
...
|
||||
LL | let P() = U {};
|
||||
| ^^^ expected 1 field, found 0
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0023, E0308.
|
||||
For more information about an error, try `rustc --explain E0023`.
|
Loading…
Reference in New Issue
Block a user