diff --git a/compiler/tests/compile_errors.rs b/compiler/tests/compile_errors.rs index ef4d266839..1d5d3ad739 100644 --- a/compiler/tests/compile_errors.rs +++ b/compiler/tests/compile_errors.rs @@ -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)) diff --git a/compiler/tests/fixtures/compile_errors/type_constructor_from_variable.fe b/compiler/tests/fixtures/compile_errors/type_constructor_from_variable.fe new file mode 100644 index 0000000000..c11b7b6fb5 --- /dev/null +++ b/compiler/tests/fixtures/compile_errors/type_constructor_from_variable.fe @@ -0,0 +1,5 @@ +contract Foo: + + pub def bar() -> u16: + x:u8 = u8(1) + return u16(x) diff --git a/semantics/src/errors.rs b/semantics/src/errors.rs index 27b92e1938..22b32ff054 100644 --- a/semantics/src/errors.rs +++ b/semantics/src/errors.rs @@ -15,6 +15,7 @@ pub enum ErrorKind { TypeError, CannotMove, NotCallable, + NumericLiteralExpected, MoreThanThreeIndexedParams, } @@ -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 { diff --git a/semantics/src/traversal/expressions.rs b/semantics/src/traversal/expressions.rs index 5e46a30b31..6c12cdd03a 100644 --- a/semantics/src/traversal/expressions.rs +++ b/semantics/src/traversal/expressions.rs @@ -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); @@ -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 { + return Err(SemanticError::numeric_literal_expected()); + } +} + fn expr_call_self( scope: Shared, _context: Shared,