diff options
author | Lukas Wirth <[email protected]> | 2020-11-24 15:43:28 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2020-11-24 15:43:28 +0000 |
commit | a4b52756562d4f4c9e658d0bca4b3e62ac6ebd95 (patch) | |
tree | 6114219f8e14121c92d54ecb117fc234a2221af7 /crates/hir_ty | |
parent | 67d45851bf2257f6f255fb6863163a6836816cff (diff) |
Handle ellipsis in tuple patterns in match exhaustiveness checking
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check.rs | 83 |
1 files changed, 41 insertions, 42 deletions
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 5bd03f2ac..78e207f86 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -216,7 +216,7 @@ | |||
216 | //! U(P, p) := U(P, (r_1, p_2, .., p_n)) | 216 | //! U(P, p) := U(P, (r_1, p_2, .., p_n)) |
217 | //! || U(P, (r_2, p_2, .., p_n)) | 217 | //! || U(P, (r_2, p_2, .., p_n)) |
218 | //! ``` | 218 | //! ``` |
219 | use std::sync::Arc; | 219 | use std::{iter, sync::Arc}; |
220 | 220 | ||
221 | use arena::Idx; | 221 | use arena::Idx; |
222 | use hir_def::{ | 222 | use hir_def::{ |
@@ -366,16 +366,17 @@ impl PatStack { | |||
366 | 366 | ||
367 | let head_pat = head.as_pat(cx); | 367 | let head_pat = head.as_pat(cx); |
368 | let result = match (head_pat, constructor) { | 368 | let result = match (head_pat, constructor) { |
369 | (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { | 369 | (Pat::Tuple { args: pat_ids, ellipsis }, &Constructor::Tuple { arity }) => { |
370 | if ellipsis.is_some() { | 370 | if let Some(ellipsis) = ellipsis { |
371 | // If there are ellipsis here, we should add the correct number of | 371 | let (pre, post) = pat_ids.split_at(ellipsis); |
372 | // Pat::Wild patterns to `pat_ids`. We should be able to use the | 372 | let n_wild_pats = arity.saturating_sub(pat_ids.len()); |
373 | // constructors arity for this, but at the time of writing we aren't | 373 | let pre_iter = pre.iter().map(Into::into); |
374 | // correctly calculating this arity when ellipsis are present. | 374 | let wildcards = iter::repeat(PatIdOrWild::Wild).take(n_wild_pats); |
375 | return Err(MatchCheckErr::NotImplemented); | 375 | let post_iter = post.iter().map(Into::into); |
376 | Some(self.replace_head_with(pre_iter.chain(wildcards).chain(post_iter))) | ||
377 | } else { | ||
378 | Some(self.replace_head_with(pat_ids.iter())) | ||
376 | } | 379 | } |
377 | |||
378 | Some(self.replace_head_with(pat_ids.iter())) | ||
379 | } | 380 | } |
380 | (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => { | 381 | (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => { |
381 | match cx.body.exprs[lit_expr] { | 382 | match cx.body.exprs[lit_expr] { |
@@ -767,10 +768,11 @@ impl Constructor { | |||
767 | fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { | 768 | fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { |
768 | let res = match pat.as_pat(cx) { | 769 | let res = match pat.as_pat(cx) { |
769 | Pat::Wild => None, | 770 | Pat::Wild => None, |
770 | // FIXME somehow create the Tuple constructor with the proper arity. If there are | 771 | Pat::Tuple { .. } => { |
771 | // ellipsis, the arity is not equal to the number of patterns. | 772 | let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); |
772 | Pat::Tuple { args: pats, ellipsis } if ellipsis.is_none() => { | 773 | Some(Constructor::Tuple { |
773 | Some(Constructor::Tuple { arity: pats.len() }) | 774 | arity: cx.infer.type_of_pat[pat_id].as_tuple().ok_or(MatchCheckErr::Unknown)?.len(), |
775 | }) | ||
774 | } | 776 | } |
775 | Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { | 777 | Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { |
776 | Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), | 778 | Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), |
@@ -1352,6 +1354,31 @@ fn main() { | |||
1352 | ); | 1354 | ); |
1353 | } | 1355 | } |
1354 | 1356 | ||
1357 | #[test] | ||
1358 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
1359 | check_diagnostics( | ||
1360 | r#" | ||
1361 | fn main() { | ||
1362 | match (false, true, false) { | ||
1363 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1364 | (false, ..) => (), | ||
1365 | } | ||
1366 | }"#, | ||
1367 | ); | ||
1368 | } | ||
1369 | |||
1370 | #[test] | ||
1371 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
1372 | check_diagnostics( | ||
1373 | r#" | ||
1374 | fn main() { | ||
1375 | match (false, true, false) { | ||
1376 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1377 | (.., false) => (), | ||
1378 | } | ||
1379 | }"#, | ||
1380 | ); | ||
1381 | } | ||
1355 | mod false_negatives { | 1382 | mod false_negatives { |
1356 | //! The implementation of match checking here is a work in progress. As we roll this out, we | 1383 | //! The implementation of match checking here is a work in progress. As we roll this out, we |
1357 | //! prefer false negatives to false positives (ideally there would be no false positives). This | 1384 | //! prefer false negatives to false positives (ideally there would be no false positives). This |
@@ -1395,34 +1422,6 @@ fn main() { | |||
1395 | } | 1422 | } |
1396 | 1423 | ||
1397 | #[test] | 1424 | #[test] |
1398 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
1399 | // We don't currently handle tuple patterns with ellipsis. | ||
1400 | check_diagnostics( | ||
1401 | r#" | ||
1402 | fn main() { | ||
1403 | match (false, true, false) { | ||
1404 | (false, ..) => (), | ||
1405 | } | ||
1406 | } | ||
1407 | "#, | ||
1408 | ); | ||
1409 | } | ||
1410 | |||
1411 | #[test] | ||
1412 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
1413 | // We don't currently handle tuple patterns with ellipsis. | ||
1414 | check_diagnostics( | ||
1415 | r#" | ||
1416 | fn main() { | ||
1417 | match (false, true, false) { | ||
1418 | (.., false) => (), | ||
1419 | } | ||
1420 | } | ||
1421 | "#, | ||
1422 | ); | ||
1423 | } | ||
1424 | |||
1425 | #[test] | ||
1426 | fn struct_missing_arm() { | 1425 | fn struct_missing_arm() { |
1427 | // We don't currently handle structs. | 1426 | // We don't currently handle structs. |
1428 | check_diagnostics( | 1427 | check_diagnostics( |