aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-11-24 15:43:28 +0000
committerLukas Wirth <[email protected]>2020-11-24 15:43:28 +0000
commita4b52756562d4f4c9e658d0bca4b3e62ac6ebd95 (patch)
tree6114219f8e14121c92d54ecb117fc234a2221af7 /crates
parent67d45851bf2257f6f255fb6863163a6836816cff (diff)
Handle ellipsis in tuple patterns in match exhaustiveness checking
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs83
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//! ```
219use std::sync::Arc; 219use std::{iter, sync::Arc};
220 220
221use arena::Idx; 221use arena::Idx;
222use hir_def::{ 222use 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 {
767fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { 768fn 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#"
1361fn 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#"
1374fn 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#"
1402fn 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#"
1416fn 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(