Skip to content

Commit

Permalink
Merge pull request #162 from sine-fdn/fix-type-checking
Browse files Browse the repository at this point in the history
Fix type checking broken by num type inference
  • Loading branch information
fkettelhoit authored Dec 10, 2024
2 parents 4f4bbf8 + 749af4b commit 675807e
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ jobs:
Cargo.lock
~/.rustup
key: ${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}
- run: cargo build --all-features
- run: cargo build --features="bin"
- run: cargo test
- run: cargo clippy -- -Dwarnings
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ required-features = ["bin"]
[dependencies]
clap = { version = "4.5.17", features = ["derive"], optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
plotters = { version = "0.3.7", optional = true }

[features]
bin = ["clap"]
plot = []
plot = ["plotters"]

[dev-dependencies]
quickcheck = "1"
quickcheck_macros = "1"
plotters = "0.3.7"
46 changes: 44 additions & 2 deletions src/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2207,20 +2207,62 @@ pub(crate) fn check_or_constrain_signed(
}

pub(crate) fn constrain_type(expr: &mut TypedExpr, expected: &Type) -> Result<(), TypeErrors> {
fn overwrite_ty_if_necessary(actual: &mut Type, expected: &Type) {
match expected {
Type::Unsigned(_) => {
if actual == &Type::Unsigned(UnsignedNumType::Unspecified) {
*actual = expected.clone();
}
}
Type::Signed(_) => {
if actual == &Type::Unsigned(UnsignedNumType::Unspecified)
|| actual == &Type::Signed(SignedNumType::Unspecified)
{
*actual = expected.clone();
}
}
_ => {}
}
}
match (&mut expr.inner, expected) {
(ExprEnum::ArrayLiteral(elems), Type::Array(elem_ty, _) | Type::ArrayConst(elem_ty, _)) => {
for elem in elems {
constrain_type(elem, elem_ty)?;
}
if let Type::Array(actual, _) | Type::ArrayConst(actual, _) = &mut expr.ty {
overwrite_ty_if_necessary(actual, elem_ty);
}
}
(
ExprEnum::ArrayRepeatLiteral(elem, _) | ExprEnum::ArrayRepeatLiteralConst(elem, _),
Type::Array(elem_ty, _) | Type::ArrayConst(elem_ty, _),
) => constrain_type(elem, elem_ty)?,
) => {
constrain_type(elem, elem_ty)?;
if let Type::Array(actual, _) | Type::ArrayConst(actual, _) = &mut expr.ty {
overwrite_ty_if_necessary(actual, elem_ty);
}
}
(ExprEnum::TupleLiteral(elems), Type::Tuple(elem_tys)) if elems.len() == elem_tys.len() => {
for (elem, elem_ty) in elems.iter_mut().zip(elem_tys) {
constrain_type(elem, elem_ty)?;
}
if let Type::Tuple(actual_elem_tys) = &mut expr.ty {
for (actual, expected) in actual_elem_tys.iter_mut().zip(elem_tys) {
overwrite_ty_if_necessary(actual, expected);
}
}
}
(ExprEnum::Identifier(_), Type::Array(elem_ty, _) | Type::ArrayConst(elem_ty, _)) => {
if let Type::Array(actual, _) | Type::ArrayConst(actual, _) = &mut expr.ty {
overwrite_ty_if_necessary(actual, elem_ty);
}
}
(ExprEnum::Identifier(_), Type::Tuple(elem_tys)) => {
if let Type::Tuple(actual_elem_tys) = &mut expr.ty {
for (actual, expected) in actual_elem_tys.iter_mut().zip(elem_tys) {
overwrite_ty_if_necessary(actual, expected);
}
}
}
(ExprEnum::Match(_, clauses), ty) => {
for (_, body) in clauses {
Expand Down Expand Up @@ -2265,7 +2307,7 @@ pub(crate) fn constrain_type(expr: &mut TypedExpr, expected: &Type) -> Result<()
(_, Type::Signed(ty)) => check_or_constrain_signed(expr, *ty)?,
_ => {}
}
expr.ty = expected.clone();
overwrite_ty_if_necessary(&mut expr.ty, expected);
Ok(())
}

Expand Down
19 changes: 19 additions & 0 deletions tests/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,25 @@ pub fn main(x: i32) -> i32 {
Ok(())
}

#[test]
fn reject_different_array_size() -> Result<(), Error> {
let prg = "
pub fn main(x: bool) -> [bool; 3] {
[x, x]
}
";
let e = scan(prg)?.parse()?.type_check();
let e = assert_single_type_error(e);
assert!(matches!(
e,
TypeErrorEnum::UnexpectedType {
expected: Type::Array(_, 3),
actual: Type::Array(_, 2),
}
));
Ok(())
}

fn assert_single_type_error(e: Result<TypedProgram, Vec<TypeError>>) -> TypeErrorEnum {
if let Err(mut e) = e {
if e.len() == 1 {
Expand Down

0 comments on commit 675807e

Please sign in to comment.