summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/demand.rs16
-rw-r--r--src/librustc_typeck/check/pat.rs21
-rw-r--r--src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs21
-rw-r--r--src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr22
4 files changed, 70 insertions, 10 deletions
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 4331d44..32df6c4 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -65,13 +65,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
65 } 65 }
66 } 66 }
67 67
68 pub fn demand_eqtype_pat( 68 pub fn demand_eqtype_pat_diag(
69 &self, 69 &self,
70 cause_span: Span, 70 cause_span: Span,
71 expected: Ty<'tcx>, 71 expected: Ty<'tcx>,
72 actual: Ty<'tcx>, 72 actual: Ty<'tcx>,
73 match_expr_span: Option<Span>, 73 match_expr_span: Option<Span>,
74 ) { 74 ) -> Option<DiagnosticBuilder<'tcx>> {
75 let cause = if let Some(span) = match_expr_span { 75 let cause = if let Some(span) = match_expr_span {
76 self.cause( 76 self.cause(
77 cause_span, 77 cause_span,
@@ -80,9 +80,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
80 } else { 80 } else {
81 self.misc(cause_span) 81 self.misc(cause_span)
82 }; 82 };
83 self.demand_eqtype_with_origin(&cause, expected, actual).map(|mut err| err.emit()); 83 self.demand_eqtype_with_origin(&cause, expected, actual)
84 } 84 }
85 85
86 pub fn demand_eqtype_pat(
87 &self,
88 cause_span: Span,
89 expected: Ty<'tcx>,
90 actual: Ty<'tcx>,
91 match_expr_span: Option<Span>,
92 ) {
93 self.demand_eqtype_pat_diag(cause_span, expected, actual, match_expr_span)
94 .map(|mut err| err.emit());
95 }
86 96
87 pub fn demand_coerce(&self, 97 pub fn demand_coerce(&self,
88 expr: &hir::Expr, 98 expr: &hir::Expr,
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 9dd3bc6..71d1cd8 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -703,7 +703,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
703 let pat_ty = pat_ty.fn_sig(tcx).output(); 703 let pat_ty = pat_ty.fn_sig(tcx).output();
704 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); 704 let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
705 705
706 self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span); 706 // Type-check the tuple struct pattern against the expected type.
707 let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, match_arm_pat_span);
708 let had_err = diag.is_some();
709 diag.map(|mut err| err.emit());
707 710
708 // Type-check subpatterns. 711 // Type-check subpatterns.
709 if subpats.len() == variant.fields.len() 712 if subpats.len() == variant.fields.len()
@@ -721,7 +724,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
721 } 724 }
722 } else { 725 } else {
723 // Pattern has wrong number of fields. 726 // Pattern has wrong number of fields.
724 self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected); 727 self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err);
725 on_error(); 728 on_error();
726 return tcx.types.err; 729 return tcx.types.err;
727 } 730 }
@@ -734,8 +737,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
734 res: Res, 737 res: Res,
735 qpath: &hir::QPath, 738 qpath: &hir::QPath,
736 subpats: &'tcx [P<Pat>], 739 subpats: &'tcx [P<Pat>],
737 fields: &[ty::FieldDef], 740 fields: &'tcx [ty::FieldDef],
738 expected: Ty<'tcx> 741 expected: Ty<'tcx>,
742 had_err: bool,
739 ) { 743 ) {
740 let subpats_ending = pluralize!(subpats.len()); 744 let subpats_ending = pluralize!(subpats.len());
741 let fields_ending = pluralize!(fields.len()); 745 let fields_ending = pluralize!(fields.len());
@@ -763,9 +767,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
763 // More generally, the expected type wants a tuple variant with one field of an 767 // More generally, the expected type wants a tuple variant with one field of an
764 // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern 768 // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
765 // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. 769 // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
766 let missing_parenthesis = match expected.kind { 770 let missing_parenthesis = match (&expected.kind, fields, had_err) {
767 ty::Adt(_, substs) if fields.len() == 1 => { 771 // #67037: only do this if we could sucessfully type-check the expected type against
768 let field_ty = fields[0].ty(self.tcx, substs); 772 // the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
773 // `let P() = U;` where `P != U` with `struct P<T>(T);`.
774 (ty::Adt(_, substs), [field], false) => {
775 let field_ty = self.field_ty(pat_span, field, substs);
769 match field_ty.kind { 776 match field_ty.kind {
770 ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(), 777 ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(),
771 _ => false, 778 _ => false,
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
new file mode 100644
index 0000000..44bd645
--- /dev/null
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
@@ -0,0 +1,21 @@
1// Regression test for #67037.
2//
3// In type checking patterns, E0023 occurs when the tuple pattern and the expected
4// tuple pattern have different number of fields. For example, as below, `P()`,
5// the tuple struct pattern, has 0 fields, but requires 1 field.
6//
7// In emitting E0023, we try to see if this is a case of e.g., `Some(a, b, c)` but where
8// the scrutinee was of type `Some((a, b, c))`, and suggest that parenthesis be added.
9//
10// However, we did not account for the expected type being different than the tuple pattern type.
11// This caused an issue when the tuple pattern type (`P<T>`) was generic.
12// Specifically, we tried deriving the 0th field's type using the `substs` of the expected type.
13// When attempting to substitute `T`, there was no such substitution, so "out of range" occured.
14
15struct U {} // 0 type parameters offered
16struct P<T>(T); // 1 type parameter wanted
17
18fn main() {
19 let P() = U {}; //~ ERROR mismatched types
20 //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 1 field
21}
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
new file mode 100644
index 0000000..521dd02
--- /dev/null
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
@@ -0,0 +1,22 @@
1error[E0308]: mismatched types
2 --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
3 |
4LL | let P() = U {};
5 | ^^^ expected struct `U`, found struct `P`
6 |
7 = note: expected struct `U`
8 found struct `P<_>`
9
10error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 1 field
11 --> $DIR/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs:19:9
12 |
13LL | struct P<T>(T); // 1 type parameter wanted
14 | --------------- tuple struct defined here
15...
16LL | let P() = U {};
17 | ^^^ expected 1 field, found 0
18
19error: aborting due to 2 previous errors
20
21Some errors have detailed explanations: E0023, E0308.
22For more information about an error, try `rustc --explain E0023`.