Fix subtle bug in pattern rendering
When rendering missing or redundant patterns, linked-list would wrongly suggest the last nil constructor as a pattern on non-empty list. For example, before this commit, the exhaustivness checker would yield: ``` [(_, True), []] ``` as a suggestion, for being the result of being a list pattern with a single argument being `(_, True) :: Nil`. Blindly following the compiler suggestion here would cause a type unification error (since `[]` doesn't unify with a 2-tuple). Indeed, we mustn't render the Nil constructor when rendering non-empty lists! So the correct suggestion should be: ``` [(_, True)] ```
This commit is contained in:
parent
00b255e960
commit
4f7f39292d
|
@ -497,6 +497,120 @@ fn exhaustiveness_complex() {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exhaustiveness_tuple() {
|
||||||
|
let source_code = r#"
|
||||||
|
fn foo() {
|
||||||
|
when (14, True) is {
|
||||||
|
(14, True) -> Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
check(parse(source_code)),
|
||||||
|
Err((
|
||||||
|
_,
|
||||||
|
Error::NotExhaustivePatternMatch {
|
||||||
|
unmatched,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)) if unmatched[0] == "(_, _)"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exhaustiveness_nested_list_and_tuples() {
|
||||||
|
fn assert_step(step: &str, expected: &str) {
|
||||||
|
let result = check(parse(step));
|
||||||
|
println!("{result:#?}");
|
||||||
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err((
|
||||||
|
_,
|
||||||
|
Error::NotExhaustivePatternMatch {
|
||||||
|
unmatched,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)) if unmatched[0] == expected
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_step(
|
||||||
|
r#"
|
||||||
|
fn foo() {
|
||||||
|
let xs : List<(List<(Int, Bool)>, Int)> = [([(14, True)], 42)]
|
||||||
|
when xs is {
|
||||||
|
[ ] -> Void
|
||||||
|
[([(14, True)], 42), ..] -> Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"[([], _), ..]",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_step(
|
||||||
|
r#"
|
||||||
|
fn foo() {
|
||||||
|
let xs : List<(List<(Int, Bool)>, Int)> = [([(14, True)], 42)]
|
||||||
|
when xs is {
|
||||||
|
[ ] -> Void
|
||||||
|
[([(_, True)], 42), ..] -> Void
|
||||||
|
[([ ], _), ..] -> Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"[([(_, False), ..], _), ..]",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_step(
|
||||||
|
r#"
|
||||||
|
fn foo() {
|
||||||
|
let xs : List<(List<(Int, Bool)>, Int)> = [([(14, True)], 42)]
|
||||||
|
when xs is {
|
||||||
|
[ ] -> Void
|
||||||
|
[([(_, True ) ], 42), ..] -> Void
|
||||||
|
[([ ], _), ..] -> Void
|
||||||
|
[([(_, False), ..], _), ..] -> Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"[([(_, True), _, ..], _), ..]",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_step(
|
||||||
|
r#"
|
||||||
|
fn foo() {
|
||||||
|
let xs : List<(List<(Int, Bool)>, Int)> = [([(14, True)], 42)]
|
||||||
|
when xs is {
|
||||||
|
[ ] -> Void
|
||||||
|
[([(_, True ) ], 42), ..] -> Void
|
||||||
|
[([ ], _), ..] -> Void
|
||||||
|
[([(_, False) , ..], _), ..] -> Void
|
||||||
|
[([(_, True ), _, ..], _), ..] -> Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
"[([(_, True)], _), ..]",
|
||||||
|
);
|
||||||
|
|
||||||
|
let source_code = r#"
|
||||||
|
fn foo() {
|
||||||
|
let xs : List<(List<(Int, Bool)>, Int)> = [([(14, True)], 42)]
|
||||||
|
when xs is {
|
||||||
|
[ ] -> Void
|
||||||
|
[([(_, True ) ], 42), ..] -> Void
|
||||||
|
[([ ], _), ..] -> Void
|
||||||
|
[([(_, False) , ..], _), ..] -> Void
|
||||||
|
[([(_, True ), _, ..], _), ..] -> Void
|
||||||
|
[([(_, True ) ], _), ..] -> Void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert!(matches!(check(parse(source_code)), Ok(_)))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expect_sugar_correct_type() {
|
fn expect_sugar_correct_type() {
|
||||||
let source_code = r#"
|
let source_code = r#"
|
||||||
|
|
|
@ -405,11 +405,16 @@ impl Pattern {
|
||||||
let args = args
|
let args = args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, p)| {
|
.filter_map(|(index, p)| {
|
||||||
if index == 1 {
|
if index == 1 {
|
||||||
pretty_tail(p)
|
let tail = pretty_tail(p);
|
||||||
|
if tail == "[]" {
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
p.pretty()
|
Some(tail)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Some(p.pretty())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(", ");
|
.join(", ");
|
||||||
|
|
Loading…
Reference in New Issue