Skip to content

Commit a4b5275

Browse files
committed
Handle ellipsis in tuple patterns in match exhaustiveness checking
1 parent 67d4585 commit a4b5275

File tree

1 file changed

+41
-42
lines changed

1 file changed

+41
-42
lines changed

crates/hir_ty/src/diagnostics/match_check.rs

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@
216216
//! U(P, p) := U(P, (r_1, p_2, .., p_n))
217217
//! || U(P, (r_2, p_2, .., p_n))
218218
//! ```
219-
use std::sync::Arc;
219+
use std::{iter, sync::Arc};
220220

221221
use arena::Idx;
222222
use hir_def::{
@@ -366,16 +366,17 @@ impl PatStack {
366366

367367
let head_pat = head.as_pat(cx);
368368
let result = match (head_pat, constructor) {
369-
(Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => {
370-
if ellipsis.is_some() {
371-
// If there are ellipsis here, we should add the correct number of
372-
// Pat::Wild patterns to `pat_ids`. We should be able to use the
373-
// constructors arity for this, but at the time of writing we aren't
374-
// correctly calculating this arity when ellipsis are present.
375-
return Err(MatchCheckErr::NotImplemented);
369+
(Pat::Tuple { args: pat_ids, ellipsis }, &Constructor::Tuple { arity }) => {
370+
if let Some(ellipsis) = ellipsis {
371+
let (pre, post) = pat_ids.split_at(ellipsis);
372+
let n_wild_pats = arity.saturating_sub(pat_ids.len());
373+
let pre_iter = pre.iter().map(Into::into);
374+
let wildcards = iter::repeat(PatIdOrWild::Wild).take(n_wild_pats);
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()))
376379
}
377-
378-
Some(self.replace_head_with(pat_ids.iter()))
379380
}
380381
(Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => {
381382
match cx.body.exprs[lit_expr] {
@@ -767,10 +768,11 @@ impl Constructor {
767768
fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> {
768769
let res = match pat.as_pat(cx) {
769770
Pat::Wild => None,
770-
// FIXME somehow create the Tuple constructor with the proper arity. If there are
771-
// ellipsis, the arity is not equal to the number of patterns.
772-
Pat::Tuple { args: pats, ellipsis } if ellipsis.is_none() => {
773-
Some(Constructor::Tuple { arity: pats.len() })
771+
Pat::Tuple { .. } => {
772+
let pat_id = pat.as_id().expect("we already know this pattern is not a wild");
773+
Some(Constructor::Tuple {
774+
arity: cx.infer.type_of_pat[pat_id].as_tuple().ok_or(MatchCheckErr::Unknown)?.len(),
775+
})
774776
}
775777
Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
776778
Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
@@ -1352,6 +1354,31 @@ fn main() {
13521354
);
13531355
}
13541356

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+
}
13551382
mod false_negatives {
13561383
//! The implementation of match checking here is a work in progress. As we roll this out, we
13571384
//! prefer false negatives to false positives (ideally there would be no false positives). This
@@ -1394,34 +1421,6 @@ fn main() {
13941421
);
13951422
}
13961423

1397-
#[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-
14251424
#[test]
14261425
fn struct_missing_arm() {
14271426
// We don't currently handle structs.

0 commit comments

Comments
 (0)