Skip to content

Commit

Permalink
Ensure integer type constructor reject every expression that isn't a …
Browse files Browse the repository at this point in the history
…numeric literal

Related to #145
  • Loading branch information
cburgdorf committed Dec 15, 2020
1 parent 0620670 commit 220185f
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 1 deletion.
3 changes: 2 additions & 1 deletion compiler/tests/compile_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ use std::fs;
case("return_addition_with_mixed_types.fe", "TypeError"),
case("return_lt_mixed_types.fe", "TypeError"),
case("indexed_event.fe", "MoreThanThreeIndexedParams"),
case("unary_minus_on_bool.fe", "TypeError")
case("unary_minus_on_bool.fe", "TypeError"),
case("type_constructor_from_variable.fe", "NumericLiteralExpected")
)]
fn test_compile_errors(fixture_file: &str, expected_error: &str) {
let src = fs::read_to_string(format!("tests/fixtures/compile_errors/{}", fixture_file))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
contract Foo:

pub def bar(val: u8) -> u16:
return u16(val)
9 changes: 9 additions & 0 deletions newsfragments/163.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Ensure integer type constructor reject all expressions that aren't a numeric literal.
For instance, previously the compiler would not reject the following code even though it could not be guaranteed that `val` would fit into an `u16`.

```
pub def bar(val: u8) -> u16:
return u16(val)
```

Now such code is rejected and integer type constructor do only work with numeric literals such as `1` or `-3`.
9 changes: 9 additions & 0 deletions semantics/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum ErrorKind {
TypeError,
CannotMove,
NotCallable,
NumericLiteralExpected,
MoreThanThreeIndexedParams,
}

Expand Down Expand Up @@ -99,6 +100,14 @@ impl SemanticError {
}
}

/// Create a new error with kind `NumericLiteralExpected`
pub fn numeric_literal_expected() -> Self {
SemanticError {
kind: ErrorKind::NumericLiteralExpected,
context: vec![],
}
}

/// Create a new error with kind `MoreThanThreeIndexedParams`
pub fn more_than_three_indexed_params() -> Self {
SemanticError {
Expand Down
18 changes: 18 additions & 0 deletions semantics/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ fn expr_call(
return Err(SemanticError::type_error());
}

// Ensure something like u8(x) fails, only literals allowed e.g u8(1)
validate_is_numeric_literal(&args.node[0].node)?;

context
.borrow_mut()
.add_call(exp, CallType::TypeConstructor);
Expand All @@ -364,6 +367,21 @@ fn expr_call(
unreachable!()
}

fn validate_is_numeric_literal(call_arg: &fe::CallArg) -> Result<(), SemanticError> {
let is_numeric_literal =
if let fe::CallArg::Arg(fe::Expr::UnaryOperation { operand, op: _ }) = call_arg {
matches!((*operand).node, fe::Expr::Num(_))
} else {
matches!(call_arg, fe::CallArg::Arg(fe::Expr::Num(_)))
};

if is_numeric_literal {
Ok(())
} else {
Err(SemanticError::numeric_literal_expected())
}
}

fn expr_call_self(
scope: Shared<BlockScope>,
_context: Shared<Context>,
Expand Down

0 comments on commit 220185f

Please sign in to comment.