mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Handle ellipsis in tuple patterns in match exhaustiveness checking
This commit is contained in:
parent
67d45851bf
commit
a4b5275656
1 changed files with 41 additions and 42 deletions
|
@ -216,7 +216,7 @@
|
||||||
//! U(P, p) := U(P, (r_1, p_2, .., p_n))
|
//! U(P, p) := U(P, (r_1, p_2, .., p_n))
|
||||||
//! || U(P, (r_2, p_2, .., p_n))
|
//! || U(P, (r_2, p_2, .., p_n))
|
||||||
//! ```
|
//! ```
|
||||||
use std::sync::Arc;
|
use std::{iter, sync::Arc};
|
||||||
|
|
||||||
use arena::Idx;
|
use arena::Idx;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
@ -366,16 +366,17 @@ impl PatStack {
|
||||||
|
|
||||||
let head_pat = head.as_pat(cx);
|
let head_pat = head.as_pat(cx);
|
||||||
let result = match (head_pat, constructor) {
|
let result = match (head_pat, constructor) {
|
||||||
(Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => {
|
(Pat::Tuple { args: pat_ids, ellipsis }, &Constructor::Tuple { arity }) => {
|
||||||
if ellipsis.is_some() {
|
if let Some(ellipsis) = ellipsis {
|
||||||
// If there are ellipsis here, we should add the correct number of
|
let (pre, post) = pat_ids.split_at(ellipsis);
|
||||||
// Pat::Wild patterns to `pat_ids`. We should be able to use the
|
let n_wild_pats = arity.saturating_sub(pat_ids.len());
|
||||||
// constructors arity for this, but at the time of writing we aren't
|
let pre_iter = pre.iter().map(Into::into);
|
||||||
// correctly calculating this arity when ellipsis are present.
|
let wildcards = iter::repeat(PatIdOrWild::Wild).take(n_wild_pats);
|
||||||
return Err(MatchCheckErr::NotImplemented);
|
let post_iter = post.iter().map(Into::into);
|
||||||
|
Some(self.replace_head_with(pre_iter.chain(wildcards).chain(post_iter)))
|
||||||
|
} else {
|
||||||
|
Some(self.replace_head_with(pat_ids.iter()))
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(self.replace_head_with(pat_ids.iter()))
|
|
||||||
}
|
}
|
||||||
(Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => {
|
(Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => {
|
||||||
match cx.body.exprs[lit_expr] {
|
match cx.body.exprs[lit_expr] {
|
||||||
|
@ -767,10 +768,11 @@ impl Constructor {
|
||||||
fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> {
|
fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> {
|
||||||
let res = match pat.as_pat(cx) {
|
let res = match pat.as_pat(cx) {
|
||||||
Pat::Wild => None,
|
Pat::Wild => None,
|
||||||
// FIXME somehow create the Tuple constructor with the proper arity. If there are
|
Pat::Tuple { .. } => {
|
||||||
// ellipsis, the arity is not equal to the number of patterns.
|
let pat_id = pat.as_id().expect("we already know this pattern is not a wild");
|
||||||
Pat::Tuple { args: pats, ellipsis } if ellipsis.is_none() => {
|
Some(Constructor::Tuple {
|
||||||
Some(Constructor::Tuple { arity: pats.len() })
|
arity: cx.infer.type_of_pat[pat_id].as_tuple().ok_or(MatchCheckErr::Unknown)?.len(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
|
Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
|
||||||
Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
|
Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
|
||||||
|
@ -1352,6 +1354,31 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
match (false, true, false) {
|
||||||
|
//^^^^^^^^^^^^^^^^^^^^ Missing match arm
|
||||||
|
(false, ..) => (),
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
|
||||||
|
check_diagnostics(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
match (false, true, false) {
|
||||||
|
//^^^^^^^^^^^^^^^^^^^^ Missing match arm
|
||||||
|
(.., false) => (),
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
mod false_negatives {
|
mod false_negatives {
|
||||||
//! The implementation of match checking here is a work in progress. As we roll this out, we
|
//! The implementation of match checking here is a work in progress. As we roll this out, we
|
||||||
//! prefer false negatives to false positives (ideally there would be no false positives). This
|
//! prefer false negatives to false positives (ideally there would be no false positives). This
|
||||||
|
@ -1394,34 +1421,6 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
|
|
||||||
// We don't currently handle tuple patterns with ellipsis.
|
|
||||||
check_diagnostics(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
|
||||||
match (false, true, false) {
|
|
||||||
(false, ..) => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
|
|
||||||
// We don't currently handle tuple patterns with ellipsis.
|
|
||||||
check_diagnostics(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
|
||||||
match (false, true, false) {
|
|
||||||
(.., false) => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn struct_missing_arm() {
|
fn struct_missing_arm() {
|
||||||
// We don't currently handle structs.
|
// We don't currently handle structs.
|
||||||
|
|
Loading…
Reference in a new issue