mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-28 04:35:33 +03:00
Merge branch 'testnet3' into feat/redesign-symbol-table
This commit is contained in:
commit
00b90c4a33
31
Cargo.lock
generated
31
Cargo.lock
generated
@ -194,9 +194,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.65"
|
||||
version = "0.3.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
|
||||
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
@ -335,6 +335,12 @@ dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
@ -497,12 +503,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.5"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
|
||||
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"cast",
|
||||
"cast 0.3.0",
|
||||
"clap 2.34.0",
|
||||
"criterion-plot",
|
||||
"csv",
|
||||
@ -527,7 +533,7 @@ version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"cast 0.2.7",
|
||||
"itertools",
|
||||
]
|
||||
|
||||
@ -1231,6 +1237,7 @@ name = "leo-passes"
|
||||
version = "1.5.3"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"leo-ast",
|
||||
"leo-core",
|
||||
"leo-errors",
|
||||
@ -1463,9 +1470,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.28.4"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
|
||||
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@ -1839,9 +1846,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.6"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
|
||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -1856,9 +1863,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.26"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
|
@ -55,7 +55,7 @@ git = "https://github.com/AleoHQ/snarkVM.git"
|
||||
rev = "51633e2"
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.65"
|
||||
version = "0.3.66"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "3.2.8"
|
||||
|
@ -43,3 +43,6 @@ version = "1.5.3"
|
||||
[dependencies.leo-core]
|
||||
path = "../core"
|
||||
version = "1.5.3"
|
||||
|
||||
[dependencies.itertools]
|
||||
version = "0.10.3"
|
@ -55,11 +55,99 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_access(&mut self, input: &'a AccessExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
// CAUTION: This implementation only allows access to core circuits.
|
||||
match input {
|
||||
AccessExpression::AssociatedFunction(access) => {
|
||||
// Check core circuit name and function.
|
||||
if let Some(core_instruction) = self.check_core_circuit_call(&access.ty, &access.name) {
|
||||
// Check num input arguments.
|
||||
if core_instruction.num_args() != access.args.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_args_to_call(
|
||||
core_instruction.num_args(),
|
||||
access.args.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
// Check first argument type.
|
||||
if let Some(first_arg) = access.args.get(0usize) {
|
||||
let first_arg_type = self.visit_expression(first_arg, &None);
|
||||
self.assert_one_of_types(&first_arg_type, core_instruction.first_arg_types(), access.span());
|
||||
}
|
||||
|
||||
// Check second argument type.
|
||||
if let Some(second_arg) = access.args.get(1usize) {
|
||||
let second_arg_type = self.visit_expression(second_arg, &None);
|
||||
self.assert_one_of_types(&second_arg_type, core_instruction.second_arg_types(), access.span());
|
||||
}
|
||||
|
||||
// Check return type.
|
||||
Some(self.assert_and_return_type(core_instruction.return_type(), expected, access.span()))
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_access_expression(access, access.span()).into());
|
||||
None
|
||||
}
|
||||
}
|
||||
_expr => None, // todo: Add support for associated constants (u8::MAX).
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit_init(
|
||||
&mut self,
|
||||
input: &'a CircuitInitExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Self::Output {
|
||||
let circ = self.symbol_table.borrow().lookup_circuit(&input.name.name).cloned();
|
||||
if let Some(circ) = circ {
|
||||
// Check circuit type name.
|
||||
let ret = self.check_expected_circuit(circ.identifier, additional, input.name.span());
|
||||
|
||||
// Check number of circuit members.
|
||||
if circ.members.len() != input.members.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_circuit_members(
|
||||
circ.members.len(),
|
||||
input.members.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
// Check circuit member types.
|
||||
circ.members
|
||||
.iter()
|
||||
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
|
||||
// Lookup circuit variable name.
|
||||
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
|
||||
if let Some(expr) = &actual.expression {
|
||||
self.visit_expression(expr, &Some(*ty));
|
||||
}
|
||||
} else {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_identifier(&mut self, var: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
if let Some(circuit) = self.symbol_table.borrow().lookup_circuit(&var.name) {
|
||||
Some(self.assert_expected_option(Type::Identifier(circuit.identifier), expected, var.span))
|
||||
Some(self.assert_and_return_type(Type::Identifier(circuit.identifier), expected, var.span))
|
||||
} else if let Some(var) = self.symbol_table.borrow().lookup_variable(&var.name) {
|
||||
Some(self.assert_expected_option(var.type_, expected, var.span))
|
||||
Some(self.assert_and_return_type(var.type_, expected, var.span))
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()).into());
|
||||
@ -69,9 +157,9 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
fn visit_literal(&mut self, input: &'a LiteralExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
Some(match input {
|
||||
LiteralExpression::Address(_, _) => self.assert_expected_option(Type::Address, expected, input.span()),
|
||||
LiteralExpression::Boolean(_, _) => self.assert_expected_option(Type::Boolean, expected, input.span()),
|
||||
LiteralExpression::Field(_, _) => self.assert_expected_option(Type::Field, expected, input.span()),
|
||||
LiteralExpression::Address(_, _) => self.assert_and_return_type(Type::Address, expected, input.span()),
|
||||
LiteralExpression::Boolean(_, _) => self.assert_and_return_type(Type::Boolean, expected, input.span()),
|
||||
LiteralExpression::Field(_, _) => self.assert_and_return_type(Type::Field, expected, input.span()),
|
||||
LiteralExpression::Integer(type_, str_content, _) => {
|
||||
match type_ {
|
||||
IntegerType::I8 => {
|
||||
@ -151,68 +239,26 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()).into()),
|
||||
_ => {}
|
||||
}
|
||||
self.assert_expected_option(Type::IntegerType(*type_), expected, input.span())
|
||||
self.assert_and_return_type(Type::IntegerType(*type_), expected, input.span())
|
||||
}
|
||||
LiteralExpression::Group(_) => self.assert_expected_option(Type::Group, expected, input.span()),
|
||||
LiteralExpression::Scalar(_, _) => self.assert_expected_option(Type::Scalar, expected, input.span()),
|
||||
LiteralExpression::String(_, _) => self.assert_expected_option(Type::String, expected, input.span()),
|
||||
LiteralExpression::Group(_) => self.assert_and_return_type(Type::Group, expected, input.span()),
|
||||
LiteralExpression::Scalar(_, _) => self.assert_and_return_type(Type::Scalar, expected, input.span()),
|
||||
LiteralExpression::String(_, _) => self.assert_and_return_type(Type::String, expected, input.span()),
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_access(&mut self, input: &'a AccessExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
// CAUTION: This implementation only allows access to core circuits.
|
||||
match input {
|
||||
AccessExpression::AssociatedFunction(access) => {
|
||||
// Check core circuit name and function.
|
||||
if let Some(core_instruction) = self.assert_core_circuit_call(&access.ty, &access.name) {
|
||||
// Check num input arguments.
|
||||
if core_instruction.num_args() != access.args.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_args_to_call(
|
||||
core_instruction.num_args(),
|
||||
access.args.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
// Check first argument type.
|
||||
if let Some(first_arg) = access.args.get(0usize) {
|
||||
let first_arg_type = self.visit_expression(first_arg, &None);
|
||||
self.assert_one_of_types(&first_arg_type, core_instruction.first_arg_types(), access.span());
|
||||
}
|
||||
|
||||
// Check second argument type.
|
||||
if let Some(second_arg) = access.args.get(1usize) {
|
||||
let second_arg_type = self.visit_expression(second_arg, &None);
|
||||
self.assert_one_of_types(&second_arg_type, core_instruction.second_arg_types(), access.span());
|
||||
}
|
||||
|
||||
// Check return type.
|
||||
Some(self.assert_expected_option(core_instruction.return_type(), expected, access.span()))
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_access_expression(access, access.span()).into());
|
||||
None
|
||||
}
|
||||
}
|
||||
_expr => None, // todo: Add support for associated constants (u8::MAX).
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
||||
match input.op {
|
||||
BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
|
||||
// Assert equal boolean types.
|
||||
self.assert_expected_option(Type::Boolean, destination, input.span());
|
||||
// Only boolean types.
|
||||
self.assert_bool_type(destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
}
|
||||
BinaryOperation::BitwiseAnd | BinaryOperation::BitwiseOr | BinaryOperation::Xor => {
|
||||
// Assert equal boolean or integer types.
|
||||
// Only boolean or integer types.
|
||||
self.assert_bool_int_type(destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
@ -220,7 +266,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
}
|
||||
BinaryOperation::Add => {
|
||||
// Assert equal field, group, scalar, or integer types.
|
||||
// Only field, group, scalar, or integer types.
|
||||
self.assert_field_group_scalar_int_type(destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
@ -228,7 +274,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
}
|
||||
BinaryOperation::Sub => {
|
||||
// Assert equal field, group, or integer types.
|
||||
// Only field, group, or integer types.
|
||||
self.assert_field_group_int_type(destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
@ -236,24 +282,34 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
}
|
||||
BinaryOperation::Mul => {
|
||||
// Assert field, group or integer types.
|
||||
// Operation returns field, group or integer types.
|
||||
self.assert_field_group_int_type(destination, input.span());
|
||||
|
||||
let t1 = self.visit_expression(&input.left, &None);
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
|
||||
// Allow `group` * `scalar` multiplication.
|
||||
// Allow group * scalar multiplication.
|
||||
match (t1, t2) {
|
||||
(Some(Type::Group), other) => {
|
||||
self.assert_expected_type(&other, Type::Scalar, input.right.span());
|
||||
Some(self.assert_expected_type(destination, Type::Group, input.span()))
|
||||
(Some(Type::Group), right) => {
|
||||
// Right type must be scalar.
|
||||
self.assert_scalar_type(&right, input.right.span());
|
||||
|
||||
// Operation returns group.
|
||||
self.assert_group_type(destination, input.span());
|
||||
|
||||
Some(Type::Group)
|
||||
}
|
||||
(other, Some(Type::Group)) => {
|
||||
self.assert_expected_type(&other, Type::Scalar, input.left.span());
|
||||
Some(self.assert_expected_type(destination, Type::Group, input.span()))
|
||||
(left, Some(Type::Group)) => {
|
||||
// Left must be scalar.
|
||||
self.assert_scalar_type(&left, input.left.span());
|
||||
|
||||
// Operation returns group.
|
||||
self.assert_group_type(destination, input.span());
|
||||
|
||||
Some(Type::Group)
|
||||
}
|
||||
(t1, t2) => {
|
||||
// Assert equal field or integer types.
|
||||
// Otherwise, only field or integer types.
|
||||
self.assert_field_int_type(destination, input.span());
|
||||
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
@ -261,7 +317,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
BinaryOperation::Div => {
|
||||
// Assert equal field or integer types.
|
||||
// Only field or integer types.
|
||||
self.assert_field_int_type(destination, input.span());
|
||||
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
@ -270,7 +326,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
}
|
||||
BinaryOperation::Pow => {
|
||||
// Assert field or integer types.
|
||||
// Operation returns field or integer types.
|
||||
self.assert_field_int_type(destination, input.span());
|
||||
|
||||
let t1 = self.visit_expression(&input.left, &None);
|
||||
@ -278,21 +334,37 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
// Allow field * field.
|
||||
match (t1, t2) {
|
||||
(Some(Type::Field), type_) => {
|
||||
self.assert_expected_type(&type_, Type::Field, input.right.span());
|
||||
Some(self.assert_expected_type(destination, Type::Field, input.span()))
|
||||
(Some(Type::Field), right) => {
|
||||
// Right must be field.
|
||||
self.assert_field_type(&right, input.right.span());
|
||||
|
||||
// Operation returns field.
|
||||
self.assert_field_type(destination, input.span());
|
||||
|
||||
Some(Type::Field)
|
||||
}
|
||||
(type_, Some(Type::Field)) => {
|
||||
self.assert_expected_type(&type_, Type::Field, input.left.span());
|
||||
Some(self.assert_expected_type(destination, Type::Field, input.span()))
|
||||
(left, Some(Type::Field)) => {
|
||||
// Left must be field.
|
||||
self.assert_field_type(&left, input.left.span());
|
||||
|
||||
// Operation returns field.
|
||||
self.assert_field_type(destination, input.span());
|
||||
|
||||
Some(Type::Field)
|
||||
}
|
||||
(Some(t1), t2) => {
|
||||
// Allow integer t2 magnitude (u8, u16, u32)
|
||||
self.assert_magnitude_type(&t2, input.right.span());
|
||||
Some(self.assert_expected_type(destination, t1, input.span()))
|
||||
(Some(left), right) => {
|
||||
// Left type is checked to be an integer by above.
|
||||
// Right type must be magnitude (u8, u16, u32).
|
||||
self.assert_magnitude_type(&right, input.right.span());
|
||||
|
||||
// Operation returns left type.
|
||||
self.assert_type(destination, &left, input.span());
|
||||
|
||||
Some(left)
|
||||
}
|
||||
(None, t2) => {
|
||||
// Allow integer t2 magnitude (u8, u16, u32)
|
||||
// Lhs type is checked to be an integer by above.
|
||||
// Rhs type must be magnitude (u8, u16, u32).
|
||||
self.assert_magnitude_type(&t2, input.right.span());
|
||||
*destination
|
||||
}
|
||||
@ -305,20 +377,22 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
match (t1, t2) {
|
||||
(Some(Type::IntegerType(_)), t2) => {
|
||||
// Assert rhs is integer.
|
||||
// Check rhs is integer and give detailed error message.
|
||||
self.assert_int_type(&t2, input.left.span());
|
||||
}
|
||||
(t1, Some(Type::IntegerType(_))) => {
|
||||
// Assert lhs is integer.
|
||||
// Check lhs is integer and give detailed error message.
|
||||
self.assert_int_type(&t1, input.right.span());
|
||||
}
|
||||
(t1, t2) => {
|
||||
self.assert_eq_types(t1, t2, input.span());
|
||||
self.check_eq_types(&t1, &t2, input.span());
|
||||
}
|
||||
}
|
||||
|
||||
// Assert destination is boolean.
|
||||
Some(self.assert_expected_type(destination, Type::Boolean, input.span()))
|
||||
// Operation returns a boolean.
|
||||
self.assert_bool_type(destination, input.span());
|
||||
|
||||
Some(Type::Boolean)
|
||||
}
|
||||
BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Lte | BinaryOperation::Gte => {
|
||||
// Assert left and right are equal field, scalar, or integer types.
|
||||
@ -333,41 +407,43 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
(Some(Type::Field), t2) => {
|
||||
// Assert rhs is field.
|
||||
self.assert_expected_type(&t2, Type::Field, input.left.span());
|
||||
self.assert_field_type(&t2, input.right.span());
|
||||
}
|
||||
(t1, Some(Type::Field)) => {
|
||||
// Assert lhs is field.
|
||||
self.assert_expected_type(&t1, Type::Field, input.right.span());
|
||||
self.assert_field_type(&t1, input.left.span());
|
||||
}
|
||||
(Some(Type::Scalar), t2) => {
|
||||
// Assert rhs is scalar.
|
||||
self.assert_expected_type(&t2, Type::Scalar, input.left.span());
|
||||
self.assert_scalar_type(&t2, input.right.span());
|
||||
}
|
||||
(t1, Some(Type::Scalar)) => {
|
||||
// Assert lhs is scalar.
|
||||
self.assert_expected_type(&t1, Type::Scalar, input.right.span());
|
||||
self.assert_scalar_type(&t1, input.left.span());
|
||||
}
|
||||
(Some(Type::IntegerType(_)), t2) => {
|
||||
// Assert rhs is integer.
|
||||
self.assert_int_type(&t2, input.left.span());
|
||||
self.assert_int_type(&t2, input.right.span());
|
||||
}
|
||||
(t1, Some(Type::IntegerType(_))) => {
|
||||
// Assert lhs is integer.
|
||||
self.assert_int_type(&t1, input.right.span());
|
||||
self.assert_int_type(&t1, input.left.span());
|
||||
}
|
||||
(_, _) => {
|
||||
// Not enough info to assert type.
|
||||
}
|
||||
}
|
||||
|
||||
// Assert destination is boolean.
|
||||
Some(self.assert_expected_type(destination, Type::Boolean, input.span()))
|
||||
// Operation returns a boolean.
|
||||
self.assert_bool_type(destination, input.span());
|
||||
|
||||
Some(Type::Boolean)
|
||||
}
|
||||
BinaryOperation::AddWrapped
|
||||
| BinaryOperation::SubWrapped
|
||||
| BinaryOperation::DivWrapped
|
||||
| BinaryOperation::MulWrapped => {
|
||||
// Assert equal integer types.
|
||||
// Only integer types.
|
||||
self.assert_int_type(destination, input.span);
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
@ -379,12 +455,14 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
| BinaryOperation::Shr
|
||||
| BinaryOperation::ShrWrapped
|
||||
| BinaryOperation::PowWrapped => {
|
||||
// Assert left and destination are equal integer types.
|
||||
self.assert_int_type(destination, input.span);
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
|
||||
// Assert left and destination are equal integer types.
|
||||
self.assert_int_type(&t1, input.left.span());
|
||||
self.assert_int_type(destination, input.span);
|
||||
|
||||
// Assert right type is a magnitude (u8, u16, u32).
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
self.assert_magnitude_type(&t2, input.right.span());
|
||||
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
@ -395,23 +473,23 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
||||
match input.op {
|
||||
UnaryOperation::Abs => {
|
||||
// Assert integer type only.
|
||||
// Only signed integer types.
|
||||
self.assert_signed_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::AbsWrapped => {
|
||||
// Assert integer type only.
|
||||
// Only signed integer types.
|
||||
self.assert_signed_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Double => {
|
||||
// Assert field and group type only.
|
||||
// Only field or group types.
|
||||
self.assert_field_group_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Inverse => {
|
||||
// Assert field type only.
|
||||
self.assert_expected_type(destination, Type::Field, input.span());
|
||||
// Only field types.
|
||||
self.assert_field_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Negate => {
|
||||
@ -420,37 +498,23 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
let type_ = self.visit_expression(&input.receiver, destination);
|
||||
self.negate = prior_negate_state;
|
||||
match type_.as_ref() {
|
||||
Some(
|
||||
Type::IntegerType(
|
||||
IntegerType::I8
|
||||
| IntegerType::I16
|
||||
| IntegerType::I32
|
||||
| IntegerType::I64
|
||||
| IntegerType::I128,
|
||||
)
|
||||
| Type::Field
|
||||
| Type::Group,
|
||||
) => {}
|
||||
Some(t) => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::type_is_not_negatable(t, input.receiver.span()).into()),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// Only field, group, or signed integer types.
|
||||
self.assert_field_group_signed_int_type(&type_, input.receiver.span());
|
||||
type_
|
||||
}
|
||||
UnaryOperation::Not => {
|
||||
// Assert boolean, integer types only.
|
||||
// Only boolean or integer types.
|
||||
self.assert_bool_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Square => {
|
||||
// Assert field type only.
|
||||
self.assert_expected_type(destination, Type::Field, input.span());
|
||||
// Only field type.
|
||||
self.assert_field_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::SquareRoot => {
|
||||
// Assert field or scalar type.
|
||||
// Only field or scalar type.
|
||||
self.assert_field_scalar_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
@ -471,7 +535,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
Expression::Identifier(ident) => {
|
||||
let func = self.symbol_table.borrow().lookup_fn(&ident.name).cloned();
|
||||
if let Some(func) = func {
|
||||
let ret = self.assert_expected_option(func.output, expected, func.span);
|
||||
let ret = self.assert_and_return_type(func.output, expected, func.span);
|
||||
|
||||
// Check number of function arguments.
|
||||
if func.input.len() != input.arguments.len() {
|
||||
@ -503,50 +567,4 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
expr => self.visit_expression(expr, expected),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit_init(
|
||||
&mut self,
|
||||
input: &'a CircuitInitExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Self::Output {
|
||||
let circ = self.symbol_table.borrow().lookup_circuit(&input.name.name).cloned();
|
||||
if let Some(circ) = circ {
|
||||
// Check circuit type name.
|
||||
let ret = self.assert_expected_circuit(circ.identifier, additional, input.name.span());
|
||||
|
||||
// Check number of circuit members.
|
||||
if circ.members.len() != input.members.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_circuit_members(
|
||||
circ.members.len(),
|
||||
input.members.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
// Check circuit member types.
|
||||
circ.members
|
||||
.iter()
|
||||
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
|
||||
// Lookup circuit variable name.
|
||||
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
|
||||
if let Some(expr) = &actual.expression {
|
||||
self.visit_expression(expr, &Some(*ty));
|
||||
}
|
||||
} else {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use leo_errors::{emitter::Handler, TypeCheckerError};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use itertools::Itertools;
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub struct TypeChecker<'a> {
|
||||
@ -34,6 +35,14 @@ pub struct TypeChecker<'a> {
|
||||
pub(crate) algorithms_types: IndexSet<Symbol>,
|
||||
}
|
||||
|
||||
const BOOLEAN_TYPE: Type = Type::Boolean;
|
||||
|
||||
const FIELD_TYPE: Type = Type::Field;
|
||||
|
||||
const GROUP_TYPE: Type = Type::Group;
|
||||
|
||||
const SCALAR_TYPE: Type = Type::Scalar;
|
||||
|
||||
const INT_TYPES: [Type; 10] = [
|
||||
Type::IntegerType(IntegerType::I8),
|
||||
Type::IntegerType(IntegerType::I16),
|
||||
@ -61,36 +70,6 @@ const MAGNITUDE_TYPES: [Type; 3] = [
|
||||
Type::IntegerType(IntegerType::U32),
|
||||
];
|
||||
|
||||
const fn create_type_superset<const S: usize, const A: usize, const O: usize>(
|
||||
subset: [Type; S],
|
||||
additional: [Type; A],
|
||||
) -> [Type; O] {
|
||||
let mut superset: [Type; O] = [Type::IntegerType(IntegerType::U8); O];
|
||||
let mut i = 0;
|
||||
while i < S {
|
||||
superset[i] = subset[i];
|
||||
i += 1;
|
||||
}
|
||||
let mut j = 0;
|
||||
while j < A {
|
||||
superset[i + j] = additional[j];
|
||||
j += 1;
|
||||
}
|
||||
superset
|
||||
}
|
||||
|
||||
const BOOL_INT_TYPES: [Type; 11] = create_type_superset(INT_TYPES, [Type::Boolean]);
|
||||
|
||||
const FIELD_INT_TYPES: [Type; 11] = create_type_superset(INT_TYPES, [Type::Field]);
|
||||
|
||||
const FIELD_GROUP_INT_TYPES: [Type; 12] = create_type_superset(FIELD_INT_TYPES, [Type::Group]);
|
||||
|
||||
const FIELD_GROUP_SCALAR_INT_TYPES: [Type; 13] = create_type_superset(FIELD_GROUP_INT_TYPES, [Type::Scalar]);
|
||||
|
||||
const FIELD_GROUP_TYPES: [Type; 2] = [Type::Field, Type::Group];
|
||||
|
||||
const FIELD_SCALAR_TYPES: [Type; 2] = [Type::Field, Type::Scalar];
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
/// Returns a new type checker given a symbol table and error handler.
|
||||
pub fn new(symbol_table: SymbolTable, handler: &'a Handler) -> Self {
|
||||
@ -110,18 +89,198 @@ impl<'a> TypeChecker<'a> {
|
||||
self.handler.emit_err(err.into());
|
||||
}
|
||||
|
||||
/// Emits an error if the given type conflicts with a core library type.
|
||||
pub(crate) fn check_ident_type(&self, type_: &Option<Type>) {
|
||||
if let Some(Type::Identifier(ident)) = type_ {
|
||||
if self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name) {
|
||||
self.emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()));
|
||||
/// Emits an error if the two given types are not equal.
|
||||
pub(crate) fn check_eq_types(&self, t1: &Option<Type>, t2: &Option<Type>, span: Span) {
|
||||
match (t1, t2) {
|
||||
(Some(t1), Some(t2)) if t1 != t2 => self.emit_err(TypeCheckerError::type_should_be(t1, t2, span)),
|
||||
(Some(type_), None) | (None, Some(type_)) => {
|
||||
self.emit_err(TypeCheckerError::type_should_be("no type", type_, span))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Use this method when you know the actual type.
|
||||
/// Emits an error to the handler if the `actual` type is not equal to the `expected` type.
|
||||
pub(crate) fn assert_and_return_type(&self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(expected) = expected {
|
||||
if !actual.eq_flat(expected) {
|
||||
self.emit_err(TypeCheckerError::type_should_be(actual, expected, span));
|
||||
}
|
||||
}
|
||||
|
||||
actual
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is invalid.
|
||||
fn check_type(&self, is_valid: impl Fn(&Type) -> bool, error_string: String, type_: &Option<Type>, span: Span) {
|
||||
if let Some(type_) = type_ {
|
||||
if !is_valid(type_) {
|
||||
self.emit_err(TypeCheckerError::expected_one_type_of(error_string, type_, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Emits an error to the error handler if the `actual` type is not equal to the `expected` type.
|
||||
pub(crate) fn assert_type(&self, actual: &Option<Type>, expected: &Type, span: Span) {
|
||||
self.check_type(
|
||||
|actual: &Type| actual.eq_flat(expected),
|
||||
expected.to_string(),
|
||||
actual,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the error handler if the actual type is not equal to any of the expected types.
|
||||
pub(crate) fn assert_one_of_types(&self, actual: &Option<Type>, expected: &[Type], span: Span) {
|
||||
self.check_type(
|
||||
|actual: &Type| expected.iter().any(|t: &Type| t == actual),
|
||||
types_to_string(expected),
|
||||
actual,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a boolean.
|
||||
pub(crate) fn assert_bool_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| BOOLEAN_TYPE.eq(type_),
|
||||
BOOLEAN_TYPE.to_string(),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field.
|
||||
pub(crate) fn assert_field_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(|type_: &Type| FIELD_TYPE.eq(type_), FIELD_TYPE.to_string(), type_, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a group.
|
||||
pub(crate) fn assert_group_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(|type_: &Type| GROUP_TYPE.eq(type_), GROUP_TYPE.to_string(), type_, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a scalar.
|
||||
pub(crate) fn assert_scalar_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| SCALAR_TYPE.eq(type_),
|
||||
SCALAR_TYPE.to_string(),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not an integer.
|
||||
pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| INT_TYPES.contains(type_),
|
||||
types_to_string(&INT_TYPES),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a signed integer.
|
||||
pub(crate) fn assert_signed_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| SIGNED_INT_TYPES.contains(type_),
|
||||
types_to_string(&SIGNED_INT_TYPES),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32).
|
||||
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| MAGNITUDE_TYPES.contains(type_),
|
||||
types_to_string(&MAGNITUDE_TYPES),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a boolean or an integer.
|
||||
pub(crate) fn assert_bool_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| BOOLEAN_TYPE.eq(type_) | INT_TYPES.contains(type_),
|
||||
format!("{}, {}", BOOLEAN_TYPE, types_to_string(&INT_TYPES)),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or integer.
|
||||
pub(crate) fn assert_field_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| FIELD_TYPE.eq(type_) | INT_TYPES.contains(type_),
|
||||
format!("{}, {}", FIELD_TYPE, types_to_string(&INT_TYPES)),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or group.
|
||||
pub(crate) fn assert_field_group_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| FIELD_TYPE.eq(type_) | GROUP_TYPE.eq(type_),
|
||||
format!("{}, {}", FIELD_TYPE, GROUP_TYPE),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or scalar.
|
||||
pub(crate) fn assert_field_scalar_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| FIELD_TYPE.eq(type_) | SCALAR_TYPE.eq(type_),
|
||||
format!("{}, {}", FIELD_TYPE, SCALAR_TYPE),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, group, or integer.
|
||||
pub(crate) fn assert_field_group_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| FIELD_TYPE.eq(type_) | GROUP_TYPE.eq(type_) | INT_TYPES.contains(type_),
|
||||
format!("{}, {}, {}", FIELD_TYPE, GROUP_TYPE, types_to_string(&INT_TYPES),),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, group, or signed integer.
|
||||
pub(crate) fn assert_field_group_signed_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| FIELD_TYPE.eq(type_) | GROUP_TYPE.eq(type_) | SIGNED_INT_TYPES.contains(type_),
|
||||
format!("{}, {}, {}", FIELD_TYPE, GROUP_TYPE, types_to_string(&SIGNED_INT_TYPES),),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, group, scalar or integer.
|
||||
pub(crate) fn assert_field_group_scalar_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| {
|
||||
FIELD_TYPE.eq(type_) | GROUP_TYPE.eq(type_) | SCALAR_TYPE.eq(type_) | INT_TYPES.contains(type_)
|
||||
},
|
||||
format!(
|
||||
"{}, {}, {}, {}",
|
||||
FIELD_TYPE,
|
||||
GROUP_TYPE,
|
||||
SCALAR_TYPE,
|
||||
types_to_string(&INT_TYPES),
|
||||
),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Emits an error if the `circuit` is not a core library circuit.
|
||||
/// Emits an error if the `function` is not supported by the circuit.
|
||||
pub(crate) fn assert_core_circuit_call(&self, circuit: &Type, function: &Identifier) -> Option<CoreInstruction> {
|
||||
pub(crate) fn check_core_circuit_call(&self, circuit: &Type, function: &Identifier) -> Option<CoreInstruction> {
|
||||
if let Type::Identifier(ident) = circuit {
|
||||
// Lookup core circuit
|
||||
match CoreInstruction::from_symbols(ident.name, function.name) {
|
||||
@ -139,19 +298,8 @@ impl<'a> TypeChecker<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Emits an error if the two given types are not equal.
|
||||
pub(crate) fn assert_eq_types(&self, t1: Option<Type>, t2: Option<Type>, span: Span) {
|
||||
match (t1, t2) {
|
||||
(Some(t1), Some(t2)) if t1 != t2 => self.emit_err(TypeCheckerError::type_should_be(t1, t2, span)),
|
||||
(Some(type_), None) | (None, Some(type_)) => {
|
||||
self.emit_err(TypeCheckerError::type_should_be("no type", type_, span))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `circuit` type and emits an error if the `expected` type does not match.
|
||||
pub(crate) fn assert_expected_circuit(&mut self, circuit: Identifier, expected: &Option<Type>, span: Span) -> Type {
|
||||
pub(crate) fn check_expected_circuit(&mut self, circuit: Identifier, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(Type::Identifier(expected)) = expected {
|
||||
if !circuit.matches(expected) {
|
||||
self.emit_err(TypeCheckerError::type_should_be(circuit.name, expected.name, span));
|
||||
@ -161,84 +309,17 @@ impl<'a> TypeChecker<'a> {
|
||||
Type::Identifier(circuit)
|
||||
}
|
||||
|
||||
/// Returns the given `actual` type and emits an error if the `expected` type does not match.
|
||||
pub(crate) fn assert_expected_option(&self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(expected) = expected {
|
||||
if !actual.eq_flat(expected) {
|
||||
self.emit_err(TypeCheckerError::type_should_be(actual, expected, span));
|
||||
/// Emits an error if the given type conflicts with a core library type.
|
||||
pub(crate) fn check_ident_type(&self, type_: &Option<Type>) {
|
||||
// todo: deprecate this method.
|
||||
if let Some(Type::Identifier(ident)) = type_ {
|
||||
if self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name) {
|
||||
self.emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()));
|
||||
}
|
||||
}
|
||||
|
||||
actual
|
||||
}
|
||||
|
||||
/// Returns the given `expected` type and emits an error if the `actual` type does not match.
|
||||
/// `span` should be the location of the expected type.
|
||||
pub(crate) fn assert_expected_type(&mut self, actual: &Option<Type>, expected: Type, span: Span) -> Type {
|
||||
if let Some(actual) = actual {
|
||||
if !actual.eq_flat(&expected) {
|
||||
self.emit_err(TypeCheckerError::type_should_be(actual, expected, span));
|
||||
}
|
||||
}
|
||||
|
||||
expected
|
||||
}
|
||||
|
||||
/// 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_ {
|
||||
if !expected.iter().any(|t: &Type| t == type_) {
|
||||
self.emit_err(TypeCheckerError::expected_one_type_of(
|
||||
expected.iter().map(|t| t.to_string() + ",").collect::<String>(),
|
||||
type_,
|
||||
span,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a boolean or an integer.
|
||||
pub(crate) fn assert_bool_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &BOOL_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or integer.
|
||||
pub(crate) fn assert_field_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or group.
|
||||
pub(crate) fn assert_field_group_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or scalar.
|
||||
pub(crate) fn assert_field_scalar_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_SCALAR_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, group, or integer.
|
||||
pub(crate) fn assert_field_group_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, group, scalar or integer.
|
||||
pub(crate) fn assert_field_group_scalar_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_SCALAR_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not an integer.
|
||||
pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a signed integer.
|
||||
pub(crate) fn assert_signed_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &SIGNED_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32).
|
||||
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &MAGNITUDE_TYPES, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn types_to_string(types: &[Type]) -> String {
|
||||
types.iter().map(|type_| type_.to_string()).join(", ")
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ edition = "2021"
|
||||
rust-version = "1.56"
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.65"
|
||||
version = "0.3.66"
|
||||
|
||||
[dependencies.leo-span]
|
||||
path = "../span"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372009]: Expected one type from `bool,i8,i16,i32,i64,u8,u16,u32,u64,string,`, but got `u128`\n --> compiler-test:4:20\n |\n 4 | let a: group = Pedersen64::hash(1u128);\n | ^^^^^^^^^^^^^^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372009]: Expected one type from `bool, i8, i16, i32, i64, u8, u16, u32, u64, string`, but got `u128`\n --> compiler-test:4:20\n |\n 4 | let a: group = Pedersen64::hash(1u128);\n | ^^^^^^^^^^^^^^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372003]: Found type `group` but type `scalar` was expected\n --> compiler-test:4:26\n |\n 4 | return (_, _)group * a;\n | ^\n"
|
||||
- "Error [ETYC0372009]: Expected one type from `scalar`, but got `group`\n --> compiler-test:4:26\n |\n 4 | return (_, _)group * a;\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:4:20\n |\n 4 | let b: bool = -a == -1u8;\n | ^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:4:26\n |\n 4 | let b: bool = -a == -1u8;\n | ^^^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:5:20\n |\n 5 | let c: bool = -a > -1u8;\n | ^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:5:25\n |\n 5 | let c: bool = -a > -1u8;\n | ^^^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:6:20\n |\n 6 | let d: bool = -a < -1u8;\n | ^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:6:25\n |\n 6 | let d: bool = -a < -1u8;\n | ^^^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:7:20\n |\n 7 | let e: bool = -a >= -1u8;\n | ^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:7:26\n |\n 7 | let e: bool = -a >= -1u8;\n | ^^^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:8:20\n |\n 8 | let f: bool = -a <= -1u8;\n | ^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:8:26\n |\n 8 | let f: bool = -a <= -1u8;\n | ^^^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:9:18\n |\n 9 | let g: u8 = -a * -1u8;\n | ^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:9:23\n |\n 9 | let g: u8 = -a * -1u8;\n | ^^^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:10:18\n |\n 10 | let h: u8 = -a ** -1u8;\n | ^\nError [ETYC0372007]: The type `u8` is not negatable\n --> compiler-test:10:24\n |\n 10 | let h: u8 = -a ** -1u8;\n | ^^^\n"
|
||||
- "Error [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:4:20\n |\n 4 | let b: bool = -a == -1u8;\n | ^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:4:26\n |\n 4 | let b: bool = -a == -1u8;\n | ^^^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:5:20\n |\n 5 | let c: bool = -a > -1u8;\n | ^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:5:25\n |\n 5 | let c: bool = -a > -1u8;\n | ^^^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:6:20\n |\n 6 | let d: bool = -a < -1u8;\n | ^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:6:25\n |\n 6 | let d: bool = -a < -1u8;\n | ^^^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:7:20\n |\n 7 | let e: bool = -a >= -1u8;\n | ^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:7:26\n |\n 7 | let e: bool = -a >= -1u8;\n | ^^^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:8:20\n |\n 8 | let f: bool = -a <= -1u8;\n | ^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:8:26\n |\n 8 | let f: bool = -a <= -1u8;\n | ^^^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:9:18\n |\n 9 | let g: u8 = -a * -1u8;\n | ^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:9:23\n |\n 9 | let g: u8 = -a * -1u8;\n | ^^^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:10:18\n |\n 10 | let h: u8 = -a ** -1u8;\n | ^\nError [ETYC0372009]: Expected one type from `field, group, i8, i16, i32, i64, i128`, but got `u8`\n --> compiler-test:10:24\n |\n 10 | let h: u8 = -a ** -1u8;\n | ^^^\n"
|
||||
|
@ -22,7 +22,7 @@ name = "leo_compiler"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
backtrace = "0.3.65"
|
||||
backtrace = "0.3.66"
|
||||
walkdir = "2.3.2"
|
||||
|
||||
[dependencies.serde]
|
||||
@ -45,7 +45,7 @@ path = "../../leo/errors"
|
||||
version = "1.5.3"
|
||||
|
||||
[dependencies.regex]
|
||||
version = "1.5"
|
||||
version = "1.6"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.3"
|
||||
|
Loading…
Reference in New Issue
Block a user