diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e66d2426047906dffe5101a9f19590bd4d894c..958271da7be4cbb0e6e32a66211d217c48c77507 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - [!365][!365] Fix a few codegen bugs around enums with 1 variant and no members - [!365][!365] Correctly generate code for memories with bool elements +- [!368][!368] Fix panic when pattern matching arrays of integers with more than 4 elements +- [!368][!368] Report error when integer patterns are out of bounds ### Changed @@ -27,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). <!--Links:--> [!365]: https://gitlab.com/spade-lang/spade/-/merge_requests/365 +[!368]: https://gitlab.com/spade-lang/spade/-/merge_requests/368 [!370]: https://gitlab.com/spade-lang/spade/-/merge_requests/370 [!371]: https://gitlab.com/spade-lang/spade/-/merge_requests/371 diff --git a/spade-tests/src/snapshots/spade_tests__typeinference__integer_patterns_are_bounds_checked.snap b/spade-tests/src/snapshots/spade_tests__typeinference__integer_patterns_are_bounds_checked.snap new file mode 100644 index 0000000000000000000000000000000000000000..88dc32e8cf1022e06f27e804f36d47e66ccecbcf --- /dev/null +++ b/spade-tests/src/snapshots/spade_tests__typeinference__integer_patterns_are_bounds_checked.snap @@ -0,0 +1,19 @@ +--- +source: spade-tests/src/typeinference.rs +snapshot_kind: text +--- +fn test(x: uint<8>) -> bool { + match x { + 512 => false, + _ => false, + } +} + + +error: Integer value does not fit in int<8> + ┌─ testinput:3:9 + │ +3 │ 512 => false, + │ ^^^ 512 does not fit in an uint<8> + │ + = note: uint<8> fits unsigned integers in the range (0, 255) diff --git a/spade-tests/src/typeinference.rs b/spade-tests/src/typeinference.rs index 5c2b36375fa619e108ea40af7ea34ece0a547c76..6b297a5c29f80eda837cf0b6312316c14e338d9e 100644 --- a/spade-tests/src/typeinference.rs +++ b/spade-tests/src/typeinference.rs @@ -1916,3 +1916,39 @@ code_compiles! { } " } + +code_compiles! { + array_match_correctly_propagates_types, + " + entity buggy(clk: clock, a: [uint<8>; 5]) -> bool { + match a { + [1,2,3,4,5] => false, + _ => false + } + } + " +} + +code_compiles! { + big_array_match_correctly_propagates_types, + " + entity buggy(clk: clock, a: [uint<8>; 32]) -> bool { + match a { + [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8] => false, + _ => false + } + } + " +} + +snapshot_error! { + integer_patterns_are_bounds_checked, + " + fn test(x: uint<8>) -> bool { + match x { + 512 => false, + _ => false, + } + } + " +} diff --git a/spade-typeinference/src/lib.rs b/spade-typeinference/src/lib.rs index 010f52f0f615ebbae7f0b12e65fcebcf9198c07a..19152b9819eda284d143379dc08b7f0e0d198a3e 100644 --- a/spade-typeinference/src/lib.rs +++ b/spade-typeinference/src/lib.rs @@ -1234,8 +1234,12 @@ impl TypeState { let new_type = self.new_generic_type(pattern.loc()); self.add_equation(TypedExpression::Id(pattern.inner.id), new_type); match &pattern.inner.kind { - hir::PatternKind::Integer(_) => { + hir::PatternKind::Integer(val) => { let (num_t, _) = &self.new_generic_number(pattern.loc(), ctx); + self.add_requirement(Requirement::FitsIntLiteral { + value: ConstantInt::Literal(val.clone()), + target_type: num_t.clone().at_loc(pattern), + }); self.unify(pattern, num_t, ctx) .expect("Failed to unify new_generic with int"); } @@ -1292,9 +1296,6 @@ impl TypeState { .into_default_diagnostic(pattern)?; } - // The for loop may give us a more refined type which we need to inherit here. - let inner_t = inner[0].get_type(self)?; - self.unify( pattern, &TypeVar::Known( @@ -1841,7 +1842,8 @@ impl TypeState { fn check_var_for_replacement(&self, var: TypeVar) -> TypeVar { if let Some(new) = self.replacements.get(&var) { - return new.clone(); + // We need to do this recursively if we have multiple long lived vars + return self.check_var_for_replacement(new.clone()); }; match var { TypeVar::Known(loc, base, params) => TypeVar::Known(