use more clear type checking methods

This commit is contained in:
collin 2022-06-13 14:53:01 -07:00
parent 02e3313d59
commit 831e011f42
17 changed files with 61 additions and 76 deletions

View File

@ -231,30 +231,30 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
let t2 = self.visit_expression(&input.right, &None);
// Allow `group` * `scalar` multiplication.
match (t1.as_ref(), t2.as_ref()) {
(Some(Type::Group), Some(other)) => {
self.visitor.assert_type(Type::Group, destination, input.left.span());
match (t1, t2) {
(Some(Type::Group), other) => {
self.visitor.assert_type_exact(destination, &Type::Group, input.span());
self.visitor
.assert_type(*other, &Some(Type::Scalar), input.right.span());
.assert_type_exact(&other, &Type::Scalar, input.right.span());
Some(Type::Group)
}
(Some(other), Some(Type::Group)) => {
self.visitor.assert_type(*other, &Some(Type::Scalar), input.left.span());
self.visitor.assert_type(Type::Group, destination, input.right.span());
(other, Some(Type::Group)) => {
self.visitor.assert_type_exact(destination, &Type::Group, input.span());
self.visitor.assert_type_exact(&other, &Type::Scalar, input.left.span());
Some(Type::Group)
}
(Some(t1), Some(t2)) => {
// Assert equal field or integer types.
self.visitor.assert_type(*t1, destination, input.left.span());
self.visitor.assert_type(*t2, destination, input.right.span());
return_incorrect_type(Some(*t1), Some(*t2), destination)
self.visitor.assert_type(t1, destination, input.left.span());
self.visitor.assert_type(t2, destination, input.right.span());
return_incorrect_type(Some(t1), Some(t2), destination)
}
(Some(type_), None) => {
self.visitor.assert_type(*type_, destination, input.left.span());
self.visitor.assert_type(type_, destination, input.left.span());
None
}
(None, Some(type_)) => {
self.visitor.assert_type(*type_, destination, input.right.span());
self.visitor.assert_type(type_, destination, input.right.span());
None
}
(None, None) => None,
@ -279,25 +279,25 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
// Allow field * field.
match (t1, t2) {
(Some(Type::Field), type_) => {
self.visitor.assert_type(Type::Field, &type_, input.left.span());
self.visitor.assert_type(Type::Field, destination, input.left.span());
self.visitor.assert_type_exact(&type_, &Type::Field, input.right.span());
self.visitor.assert_type_exact(destination, &Type::Field, input.span());
Some(Type::Field)
}
(type_, Some(Type::Field)) => {
self.visitor.assert_type(Type::Field, &type_, input.right.span());
self.visitor.assert_type(Type::Field, destination, input.right.span());
self.visitor.assert_type_exact(&type_, &Type::Field, input.left.span());
self.visitor.assert_type_exact(destination, &Type::Field, input.span());
Some(Type::Field)
}
(Some(t1), t2) => {
// Allow integer magnitude (u8, u16, u32)
self.visitor.assert_magnitude_type(&t2, input.left.span());
Some(self.visitor.assert_type(t1, destination, input.left.span()))
// Allow integer t2 magnitude (u8, u16, u32)
self.visitor.assert_magnitude_type(&t2, input.right.span());
self.visitor.assert_type_exact(destination, &t1, input.span());
Some(t1)
}
(t1, t2) => {
// Allow integer magnitude (u8, u16, u32)
self.visitor.assert_magnitude_type(&t2, input.span());
self.visitor.assert_eq_types(t1, *destination, input.span());
t1
(None, t2) => {
// Allow integer t2 magnitude (u8, u16, u32)
self.visitor.assert_magnitude_type(&t2, input.right.span());
*destination
}
}
}
@ -312,7 +312,8 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
}
BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Le | BinaryOperation::Ge => {
// Assert the destination type is boolean.
self.visitor.assert_type(Type::Boolean, destination, input.span());
self.visitor
.assert_type_exact(destination, &Type::Boolean, input.span());
// Assert left and right are equal field, scalar, or integer types.
let t1 = self.visit_expression(&input.left, &None);

View File

@ -117,6 +117,7 @@ impl<'a> TypeChecker<'a> {
}
/// Returns the given type if it equals the expected type or the expected type is none.
/// Use this method if the expected type is an unknown Option.
pub(crate) fn assert_type(&mut self, type_: Type, expected: &Option<Type>, span: Span) -> Type {
if let Some(expected) = expected {
if &type_ != expected {
@ -128,6 +129,17 @@ impl<'a> TypeChecker<'a> {
type_
}
/// Emits an error if the given type_ does not match the expected type.
/// Use this method if the expected type is known.
pub(crate) fn assert_type_exact(&mut self, type_: &Option<Type>, expected: &Type, span: Span) {
if let Some(type_) = type_ {
if type_ != expected {
self.handler
.emit_err(TypeCheckerError::type_should_be(type_, expected, span).into());
}
}
}
/// Emits an error to the error handler if the given type is not equal to any of the expected types.
pub(crate) fn assert_one_of_types(&self, type_: &Option<Type>, expected: &[Type], span: Span) {
if let Some(type_) = type_ {

View File

@ -137,7 +137,7 @@ symbols! {
sub_wrapped,
xor,
// arity three operators 33-44
// algorithm operator names 33-44
bhp256,
bhp512,
bhp768,

View File

@ -7,5 +7,5 @@ input_file:
function main(a: field) -> bool {
const negOneField: field = -1field;
return negOneField ** 2i8 == 1field;
return negOneField ** 2field == 1field;
}

View File

@ -1,11 +0,0 @@
/*
namespace: Compile
expectation: Pass
input_file:
- inputs/fields.in
*/
function main(a: field) -> bool {
const negOneField: field = -1field;
return negOneField ** 2u8 == 1field;
}

View File

@ -1,10 +1,8 @@
/*
namespace: Compile
expectation: Pass
input_file: inputs/pow.in
expectation: Fail
# This test might take to long to fully compile.
# If necessary we could move it to disabled_tests.
# The exponent must be u8, u16, or u32
*/
function main(a: u128, b: u128, c: u128) -> bool {

View File

@ -1,10 +1,9 @@
/*
namespace: Compile
expectation: Pass
expectation: Fail
input_file: inputs/pow.in
# This test might take to long to fully compile.
# If necessary we could move it to disabled_tests.
# The exponent must be u8, u16, or u32
*/
function main(a: u64, b: u64, c: u64) -> bool {

View File

@ -0,0 +1,8 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: ff3a3f5067b97fc7ac387dbfbb940a8c04f5755783dbf848f661d1962a594bb3
initial_ast: 7d70280165206bb1163aa18f521a649b83d6193ecec6328bf329074f32c308f7
symbol_table: 3b803544d5d80d914d6d8a04d9fd0dea5ee371845d5c03af5899d751187f8201

View File

@ -1,8 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 195a6921720db473ae0b5093da0353391308e0e31a698e5ef105127e94113ff6
initial_ast: 66e17dd0b33e9a4f2e4312c5d6605a5d63e5bdf537df5f08f1a2fdc30f24c3f5
symbol_table: 5e271a21555ca024865f1857d212de20903c307db62862b7a0ba486fd77854e3

View File

@ -1,8 +0,0 @@
---
namespace: Compile
expectation: Pass
outputs:
- output:
- initial_input_ast: 195a6921720db473ae0b5093da0353391308e0e31a698e5ef105127e94113ff6
initial_ast: b4e5d9d62d4ed1e5f963b0d957c9be73b8ebe09e749d1658396672ea7d938454
symbol_table: 34a7c1477e5cb3d23a4ce2fbc78487444e3a8ff3e6948b620fec27ac7b439c24

View File

@ -2,4 +2,4 @@
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372010]: The second operand must be a unsigned int but got type `i128`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"
- "Error [ETYC0372008]: Expected one type from `u8,u16,u32,`, but got `i128`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"

View File

@ -2,4 +2,4 @@
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372010]: The second operand must be a unsigned int but got type `i16`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"
- "Error [ETYC0372008]: Expected one type from `u8,u16,u32,`, but got `i16`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"

View File

@ -2,4 +2,4 @@
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372010]: The second operand must be a unsigned int but got type `i32`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"
- "Error [ETYC0372008]: Expected one type from `u8,u16,u32,`, but got `i32`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"

View File

@ -2,4 +2,4 @@
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372010]: The second operand must be a unsigned int but got type `i64`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"
- "Error [ETYC0372008]: Expected one type from `u8,u16,u32,`, but got `i64`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"

View File

@ -2,4 +2,4 @@
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372010]: The second operand must be a unsigned int but got type `i8`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"
- "Error [ETYC0372008]: Expected one type from `u8,u16,u32,`, but got `i8`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"

View File

@ -1,8 +1,5 @@
---
namespace: Compile
expectation: Pass
expectation: Fail
outputs:
- output:
- initial_input_ast: f7022770406b07fcb59e741b04516838beabbaf118f1cf2c72501cf477a695ef
initial_ast: 5c54a5764d818cb3c119b4a11838429264a322b6b5e0f3704023d0c3b574fca1
symbol_table: 0116b72430652b485c5d4280152302b99593576ff5b7d12e8aeff94716e4fac3
- "Error [ETYC0372008]: Expected one type from `u8,u16,u32,`, but got `u128`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"

View File

@ -1,8 +1,5 @@
---
namespace: Compile
expectation: Pass
expectation: Fail
outputs:
- output:
- initial_input_ast: dc741dca85c7ced073969a884df08515f767765ad7dcc43f285b77a87cb97de7
initial_ast: 1f704360566c3d8bfc9b0ac406fa21fdb19e03c5cf35371b7cfa40568d23dc65
symbol_table: 654d7f1e81fea92b17f7b5b232c9ebc63a471df086b31450036a3cc312f24c42
- "Error [ETYC0372008]: Expected one type from `u8,u16,u32,`, but got `u64`\n --> compiler-test:4:17\n |\n 4 | return a ** b == c;\n | ^\n"