mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 23:23:50 +03:00
Merge pull request #1925 from AleoHQ/fix/tyc-member-access-and-cleanup
Type-checking fixes and cleanup
This commit is contained in:
commit
1c88ea938b
@ -18,9 +18,9 @@ use crate::GroupLiteral;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A literal expression.
|
||||
/// A literal.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum LiteralExpression {
|
||||
pub enum Literal {
|
||||
// todo: deserialize values here
|
||||
/// An address literal, e.g., `aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8s7pyjh9`.
|
||||
Address(String, #[serde(with = "leo_span::span_json")] Span),
|
||||
@ -41,7 +41,7 @@ pub enum LiteralExpression {
|
||||
String(String, #[serde(with = "leo_span::span_json")] Span),
|
||||
}
|
||||
|
||||
impl fmt::Display for LiteralExpression {
|
||||
impl fmt::Display for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self {
|
||||
Self::Address(address, _) => write!(f, "{}", address),
|
||||
@ -55,7 +55,7 @@ impl fmt::Display for LiteralExpression {
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for LiteralExpression {
|
||||
impl Node for Literal {
|
||||
fn span(&self) -> Span {
|
||||
match &self {
|
||||
Self::Address(_, span)
|
@ -41,8 +41,8 @@ pub use ternary::*;
|
||||
mod unary;
|
||||
pub use unary::*;
|
||||
|
||||
mod value;
|
||||
pub use value::*;
|
||||
mod literal;
|
||||
pub use literal::*;
|
||||
|
||||
/// Expression that evaluates to a value.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@ -52,7 +52,7 @@ pub enum Expression {
|
||||
/// An identifier expression.
|
||||
Identifier(Identifier),
|
||||
/// A literal expression.
|
||||
Literal(LiteralExpression),
|
||||
Literal(Literal),
|
||||
/// A binary expression, e.g., `42 + 24`.
|
||||
Binary(BinaryExpression),
|
||||
/// A call expression, e.g., `my_fun(args)`.
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, GroupLiteral, IntegerType, LiteralExpression, Node, Type, UnaryOperation};
|
||||
use crate::{Expression, GroupLiteral, IntegerType, Literal, Node, Type, UnaryOperation};
|
||||
use leo_errors::{InputError, LeoError, Result};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -34,11 +34,11 @@ impl TryFrom<(Type, Expression)> for InputValue {
|
||||
fn try_from(value: (Type, Expression)) -> Result<Self> {
|
||||
Ok(match value {
|
||||
(type_, Expression::Literal(lit)) => match (type_, lit) {
|
||||
(Type::Address, LiteralExpression::Address(value, _)) => Self::Address(value),
|
||||
(Type::Boolean, LiteralExpression::Boolean(value, _)) => Self::Boolean(value),
|
||||
(Type::Field, LiteralExpression::Field(value, _)) => Self::Field(value),
|
||||
(Type::Group, LiteralExpression::Group(value)) => Self::Group(*value),
|
||||
(Type::IntegerType(expected), LiteralExpression::Integer(actual, value, span)) => {
|
||||
(Type::Address, Literal::Address(value, _)) => Self::Address(value),
|
||||
(Type::Boolean, Literal::Boolean(value, _)) => Self::Boolean(value),
|
||||
(Type::Field, Literal::Field(value, _)) => Self::Field(value),
|
||||
(Type::Group, Literal::Group(value)) => Self::Group(*value),
|
||||
(Type::IntegerType(expected), Literal::Integer(actual, value, span)) => {
|
||||
if expected == actual {
|
||||
Self::Integer(expected, value)
|
||||
} else {
|
||||
|
@ -42,7 +42,7 @@ pub trait ExpressionReconstructor {
|
||||
(Expression::Identifier(input), Default::default())
|
||||
}
|
||||
|
||||
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
fn reconstruct_literal(&mut self, input: Literal) -> (Expression, Self::AdditionalOutput) {
|
||||
(Expression::Literal(input), Default::default())
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ pub trait ExpressionVisitor<'a> {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
fn visit_literal(&mut self, _input: &'a Literal, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ impl Type {
|
||||
///
|
||||
/// Flattens array syntax: `[[u8; 1]; 2] == [u8; (2, 1)] == true`
|
||||
///
|
||||
// TODO: Does not seem to flatten?
|
||||
pub fn eq_flat(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Type::Address, Type::Address)
|
||||
|
@ -115,7 +115,7 @@ impl<'a> ParserContext<'a> {
|
||||
|
||||
/// Emit the error `err`.
|
||||
pub(super) fn emit_err(&self, err: ParserError) {
|
||||
self.handler.emit_err(err.into());
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
|
||||
/// Emit the error `err`.
|
||||
|
@ -374,9 +374,7 @@ impl ParserContext<'_> {
|
||||
/// tuple initialization expression or an affine group literal.
|
||||
fn parse_tuple_expression(&mut self) -> Result<Expression> {
|
||||
if let Some(gt) = self.eat_group_partial().transpose()? {
|
||||
return Ok(Expression::Literal(LiteralExpression::Group(Box::new(
|
||||
GroupLiteral::Tuple(gt),
|
||||
))));
|
||||
return Ok(Expression::Literal(Literal::Group(Box::new(GroupLiteral::Tuple(gt)))));
|
||||
}
|
||||
|
||||
let (mut tuple, trailing, span) = self.parse_expr_tuple()?;
|
||||
@ -465,7 +463,7 @@ impl ParserContext<'_> {
|
||||
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||
/// circuit initialization expression.
|
||||
/// let foo = Foo { x: 1u8 };
|
||||
pub fn parse_circuit_expression(&mut self, identifier: Identifier) -> Result<Expression> {
|
||||
pub fn parse_circuit_init_expression(&mut self, identifier: Identifier) -> Result<Expression> {
|
||||
let (members, _, end) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| {
|
||||
p.parse_circuit_member().map(Some)
|
||||
})?;
|
||||
@ -501,44 +499,42 @@ impl ParserContext<'_> {
|
||||
// Literal followed by `field`, e.g., `42field`.
|
||||
Some(Token::Field) => {
|
||||
assert_no_whitespace("field")?;
|
||||
Expression::Literal(LiteralExpression::Field(value, full_span))
|
||||
Expression::Literal(Literal::Field(value, full_span))
|
||||
}
|
||||
// Literal followed by `group`, e.g., `42group`.
|
||||
Some(Token::Group) => {
|
||||
assert_no_whitespace("group")?;
|
||||
Expression::Literal(LiteralExpression::Group(Box::new(GroupLiteral::Single(
|
||||
value, full_span,
|
||||
))))
|
||||
Expression::Literal(Literal::Group(Box::new(GroupLiteral::Single(value, full_span))))
|
||||
}
|
||||
// Literal followed by `scalar` e.g., `42scalar`.
|
||||
Some(Token::Scalar) => {
|
||||
assert_no_whitespace("scalar")?;
|
||||
Expression::Literal(LiteralExpression::Scalar(value, full_span))
|
||||
Expression::Literal(Literal::Scalar(value, full_span))
|
||||
}
|
||||
// Literal followed by other type suffix, e.g., `42u8`.
|
||||
Some(suffix) => {
|
||||
assert_no_whitespace(&suffix.to_string())?;
|
||||
let int_ty = Self::token_to_int_type(suffix).expect("unknown int type token");
|
||||
Expression::Literal(LiteralExpression::Integer(int_ty, value, full_span))
|
||||
Expression::Literal(Literal::Integer(int_ty, value, full_span))
|
||||
}
|
||||
None => return Err(ParserError::implicit_values_not_allowed(value, span).into()),
|
||||
}
|
||||
}
|
||||
Token::True => Expression::Literal(LiteralExpression::Boolean(true, span)),
|
||||
Token::False => Expression::Literal(LiteralExpression::Boolean(false, span)),
|
||||
Token::True => Expression::Literal(Literal::Boolean(true, span)),
|
||||
Token::False => Expression::Literal(Literal::Boolean(false, span)),
|
||||
Token::AddressLit(addr) => {
|
||||
if addr.parse::<Address<Testnet2>>().is_err() {
|
||||
self.emit_err(ParserError::invalid_address_lit(&addr, span));
|
||||
}
|
||||
Expression::Literal(LiteralExpression::Address(addr, span))
|
||||
Expression::Literal(Literal::Address(addr, span))
|
||||
}
|
||||
Token::StaticString(value) => Expression::Literal(LiteralExpression::String(value, span)),
|
||||
Token::StaticString(value) => Expression::Literal(Literal::String(value, span)),
|
||||
Token::Ident(name) => {
|
||||
let ident = Identifier { name, span };
|
||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
||||
// Parse circuit and records inits as circuit expressions.
|
||||
// Enforce circuit or record type later at type checking.
|
||||
self.parse_circuit_expression(ident)?
|
||||
self.parse_circuit_init_expression(ident)?
|
||||
} else {
|
||||
Expression::Identifier(ident)
|
||||
}
|
||||
|
@ -63,14 +63,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
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(
|
||||
self.handler.emit_err(TypeCheckerError::incorrect_num_args_to_call(
|
||||
core_instruction.num_args(),
|
||||
access.args.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
// Check first argument type.
|
||||
@ -89,11 +86,56 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
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());
|
||||
.emit_err(TypeCheckerError::invalid_core_circuit_call(access, access.span()));
|
||||
None
|
||||
}
|
||||
}
|
||||
_expr => None, // todo: Add support for associated constants (u8::MAX).
|
||||
AccessExpression::Member(access) => {
|
||||
// Check that the type of `inner` in `inner.name` is a circuit.
|
||||
match self.visit_expression(&access.inner, &None) {
|
||||
Some(Type::Identifier(identifier)) => {
|
||||
// Retrieve the circuit definition associated with `identifier`.
|
||||
let circ = self.symbol_table.borrow().lookup_circuit(&identifier.name).cloned();
|
||||
if let Some(circ) = circ {
|
||||
// Check that `access.name` is a member of the circuit.
|
||||
match circ
|
||||
.members
|
||||
.iter()
|
||||
.find(|circuit_member| circuit_member.name() == access.name.name)
|
||||
{
|
||||
// Case where `access.name` is a member of the circuit.
|
||||
Some(CircuitMember::CircuitVariable(_, type_)) => Some(*type_),
|
||||
// Case where `access.name` is not a member of the circuit.
|
||||
None => {
|
||||
self.handler.emit_err(TypeCheckerError::invalid_circuit_variable(
|
||||
&access.name,
|
||||
&circ,
|
||||
access.name.span(),
|
||||
));
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_circuit(&access.inner, access.inner.span()));
|
||||
None
|
||||
}
|
||||
}
|
||||
Some(type_) => {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(type_, "circuit", access.inner.span()));
|
||||
None
|
||||
}
|
||||
None => {
|
||||
self.handler.emit_err(TypeCheckerError::could_not_determine_type(
|
||||
&access.inner,
|
||||
access.inner.span(),
|
||||
));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
AccessExpression::AssociatedConstant(..) => None, // todo: Add support for associated constants (u8::MAX).
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,14 +151,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
// Check number of circuit members.
|
||||
if circ.members.len() != input.members.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_circuit_members(
|
||||
self.handler.emit_err(TypeCheckerError::incorrect_num_circuit_members(
|
||||
circ.members.len(),
|
||||
input.members.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
// Check circuit member types.
|
||||
@ -129,16 +168,21 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
self.visit_expression(expr, &Some(*ty));
|
||||
}
|
||||
} else {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
||||
);
|
||||
self.handler.emit_err(TypeCheckerError::missing_circuit_member(
|
||||
circ.identifier,
|
||||
name,
|
||||
input.span(),
|
||||
));
|
||||
};
|
||||
});
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
|
||||
self.handler.emit_err(TypeCheckerError::unknown_sym(
|
||||
"circuit",
|
||||
&input.name.name,
|
||||
input.name.span(),
|
||||
));
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -150,17 +194,17 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
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());
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()));
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_literal(&mut self, input: &'a LiteralExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
fn visit_literal(&mut self, input: &'a Literal, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
Some(match input {
|
||||
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, _) => {
|
||||
Literal::Address(_, _) => self.assert_and_return_type(Type::Address, expected, input.span()),
|
||||
Literal::Boolean(_, _) => self.assert_and_return_type(Type::Boolean, expected, input.span()),
|
||||
Literal::Field(_, _) => self.assert_and_return_type(Type::Field, expected, input.span()),
|
||||
Literal::Integer(type_, str_content, _) => {
|
||||
match type_ {
|
||||
IntegerType::I8 => {
|
||||
let int = if self.negate {
|
||||
@ -171,7 +215,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
if int.parse::<i8>().is_err() {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()).into());
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()));
|
||||
}
|
||||
}
|
||||
IntegerType::I16 => {
|
||||
@ -183,7 +227,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
if int.parse::<i16>().is_err() {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()).into());
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()));
|
||||
}
|
||||
}
|
||||
IntegerType::I32 => {
|
||||
@ -195,7 +239,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
if int.parse::<i32>().is_err() {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()).into());
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()));
|
||||
}
|
||||
}
|
||||
IntegerType::I64 => {
|
||||
@ -207,7 +251,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
if int.parse::<i64>().is_err() {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()).into());
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()));
|
||||
}
|
||||
}
|
||||
IntegerType::I128 => {
|
||||
@ -219,31 +263,31 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
if int.parse::<i128>().is_err() {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()).into());
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()));
|
||||
}
|
||||
}
|
||||
IntegerType::U8 if str_content.parse::<u8>().is_err() => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()).into()),
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span())),
|
||||
IntegerType::U16 if str_content.parse::<u16>().is_err() => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()).into()),
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span())),
|
||||
IntegerType::U32 if str_content.parse::<u32>().is_err() => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()).into()),
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span())),
|
||||
IntegerType::U64 if str_content.parse::<u64>().is_err() => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()).into()),
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span())),
|
||||
IntegerType::U128 if str_content.parse::<u128>().is_err() => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()).into()),
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span())),
|
||||
_ => {}
|
||||
}
|
||||
self.assert_and_return_type(Type::IntegerType(*type_), 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()),
|
||||
Literal::Group(_) => self.assert_and_return_type(Type::Group, expected, input.span()),
|
||||
Literal::Scalar(_, _) => self.assert_and_return_type(Type::Scalar, expected, input.span()),
|
||||
Literal::String(_, _) => self.assert_and_return_type(Type::String, expected, input.span()),
|
||||
})
|
||||
}
|
||||
|
||||
@ -403,7 +447,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
(Some(Type::Address), _) | (_, Some(Type::Address)) => {
|
||||
// Emit an error for address comparison.
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::compare_address(input.op, input.span()).into());
|
||||
.emit_err(TypeCheckerError::compare_address(input.op, input.span()));
|
||||
}
|
||||
(Some(Type::Field), t2) => {
|
||||
// Assert rhs is field.
|
||||
@ -533,20 +577,19 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
match &*input.function {
|
||||
Expression::Identifier(ident) => {
|
||||
// Note: The function symbol lookup is performed outside of the `if let Some(func) ...` block to avoid a RefCell lifetime bug in Rust.
|
||||
// Do not move it into the `if let Some(func) ...` block or it will keep `self.symbol_table` alive for the entire block and will be very memory inefficient!
|
||||
let func = self.symbol_table.borrow().lookup_fn(&ident.name).cloned();
|
||||
if let Some(func) = func {
|
||||
let ret = self.assert_and_return_type(func.output, expected, func.span);
|
||||
|
||||
// Check number of function arguments.
|
||||
if func.input.len() != input.arguments.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_args_to_call(
|
||||
self.handler.emit_err(TypeCheckerError::incorrect_num_args_to_call(
|
||||
func.input.len(),
|
||||
input.arguments.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
// Check function argument types.
|
||||
@ -560,10 +603,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
Some(ret)
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()).into());
|
||||
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()));
|
||||
None
|
||||
}
|
||||
}
|
||||
// TODO: Is this case sufficient?
|
||||
expr => self.visit_expression(expr, expected),
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
self.parent = Some(input.name());
|
||||
input.input.iter().for_each(|i| {
|
||||
let input_var = i.get_variable();
|
||||
self.check_ident_type(&Some(input_var.type_));
|
||||
self.check_core_type_conflict(&Some(input_var.type_));
|
||||
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
@ -53,7 +53,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
if !self.has_return {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
|
||||
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()));
|
||||
}
|
||||
|
||||
let prev_st = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
||||
@ -66,9 +66,9 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
let mut used = HashSet::new();
|
||||
if !input.members.iter().all(|member| used.insert(member.name())) {
|
||||
self.handler.emit_err(if input.is_record {
|
||||
TypeCheckerError::duplicate_record_variable(input.name(), input.span()).into()
|
||||
TypeCheckerError::duplicate_record_variable(input.name(), input.span())
|
||||
} else {
|
||||
TypeCheckerError::duplicate_circuit_member(input.name(), input.span()).into()
|
||||
TypeCheckerError::duplicate_circuit_member(input.name(), input.span())
|
||||
});
|
||||
}
|
||||
|
||||
@ -81,12 +81,18 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
{
|
||||
Some((_, actual_ty)) if expected_ty.eq_flat(actual_ty) => {} // All good, found + right type!
|
||||
Some((field, _)) => {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::record_var_wrong_type(field, expected_ty, input.span()).into());
|
||||
self.handler.emit_err(TypeCheckerError::record_var_wrong_type(
|
||||
field,
|
||||
expected_ty,
|
||||
input.span(),
|
||||
));
|
||||
}
|
||||
None => {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::required_record_variable(need, expected_ty, input.span()).into());
|
||||
self.handler.emit_err(TypeCheckerError::required_record_variable(
|
||||
need,
|
||||
expected_ty,
|
||||
input.span(),
|
||||
));
|
||||
}
|
||||
};
|
||||
check_has_field(sym::owner, Type::Address);
|
||||
|
@ -28,7 +28,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
let parent = self.parent.unwrap();
|
||||
|
||||
let return_type = &self.symbol_table.borrow().lookup_fn(&parent).map(|f| f.output);
|
||||
self.check_ident_type(return_type);
|
||||
self.check_core_type_conflict(return_type);
|
||||
self.has_return = true;
|
||||
|
||||
self.visit_expression(&input.expression, return_type);
|
||||
@ -42,7 +42,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
};
|
||||
|
||||
input.variable_names.iter().for_each(|v| {
|
||||
self.check_ident_type(&Some(input.type_));
|
||||
self.check_core_type_conflict(&Some(input.type_));
|
||||
|
||||
self.visit_expression(&input.value, &Some(input.type_));
|
||||
|
||||
@ -64,7 +64,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
Expression::Identifier(id) => id,
|
||||
_ => {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_assignment_target(input.place.span()).into());
|
||||
.emit_err(TypeCheckerError::invalid_assignment_target(input.place.span()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
@ -74,23 +74,22 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
match &var.declaration {
|
||||
Declaration::Const => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::cannont_assign_to_const_var(var_name, var.span).into()),
|
||||
.emit_err(TypeCheckerError::cannot_assign_to_const_var(var_name, var.span)),
|
||||
Declaration::Input(ParamMode::Const) => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::cannont_assign_to_const_input(var_name, var.span).into()),
|
||||
.emit_err(TypeCheckerError::cannot_assign_to_const_input(var_name, var.span)),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Some(var.type_)
|
||||
} else {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
|
||||
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span));
|
||||
None
|
||||
};
|
||||
|
||||
if var_type.is_some() {
|
||||
self.check_ident_type(&var_type);
|
||||
self.check_core_type_conflict(&var_type);
|
||||
self.visit_expression(&input.value, &var_type);
|
||||
}
|
||||
}
|
||||
@ -105,7 +104,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
fn visit_iteration(&mut self, input: &'a IterationStatement) {
|
||||
let iter_type = &Some(input.type_);
|
||||
self.check_ident_type(iter_type);
|
||||
self.assert_int_type(iter_type, input.variable.span);
|
||||
self.check_core_type_conflict(iter_type);
|
||||
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
input.variable.name,
|
||||
@ -136,10 +136,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_block(&mut self, input: &'a Block) {
|
||||
// Creates a new sub-scope since we are in a block.
|
||||
let scope_index = self.symbol_table.borrow_mut().insert_block();
|
||||
let prev_st = std::mem::take(&mut self.symbol_table);
|
||||
let previous_symbol_table = std::mem::take(&mut self.symbol_table);
|
||||
self.symbol_table
|
||||
.swap(prev_st.borrow().get_block_scope(scope_index).unwrap());
|
||||
self.symbol_table.borrow_mut().parent = Some(Box::new(prev_st.into_inner()));
|
||||
.swap(previous_symbol_table.borrow().get_block_scope(scope_index).unwrap());
|
||||
self.symbol_table.borrow_mut().parent = Some(Box::new(previous_symbol_table.into_inner()));
|
||||
|
||||
input.statements.iter().for_each(|stmt| {
|
||||
match stmt {
|
||||
@ -153,8 +153,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
};
|
||||
});
|
||||
|
||||
let prev_st = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
||||
self.symbol_table.swap(prev_st.get_block_scope(scope_index).unwrap());
|
||||
self.symbol_table = RefCell::new(prev_st);
|
||||
let previous_symbol_table = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
||||
// TODO: Is this swap necessary?
|
||||
self.symbol_table
|
||||
.swap(previous_symbol_table.get_block_scope(scope_index).unwrap());
|
||||
self.symbol_table = RefCell::new(previous_symbol_table);
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ impl<'a> TypeChecker<'a> {
|
||||
|
||||
/// Emits a type checker error.
|
||||
pub(crate) fn emit_err(&self, err: TypeCheckerError) {
|
||||
self.handler.emit_err(err.into());
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
|
||||
/// Emits an error if the two given types are not equal.
|
||||
@ -310,7 +310,7 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
|
||||
/// Emits an error if the given type conflicts with a core library type.
|
||||
pub(crate) fn check_ident_type(&self, type_: &Option<Type>) {
|
||||
pub(crate) fn check_core_type_conflict(&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) {
|
||||
|
@ -205,8 +205,8 @@ impl Handler {
|
||||
}
|
||||
|
||||
/// Emit the error `err`.
|
||||
pub fn emit_err(&self, err: LeoError) {
|
||||
self.inner.borrow_mut().emit_err(err);
|
||||
pub fn emit_err<E: Into<LeoError>>(&self, err: E) {
|
||||
self.inner.borrow_mut().emit_err(err.into());
|
||||
}
|
||||
|
||||
/// Emit the error `err`.
|
||||
@ -282,9 +282,9 @@ mod tests {
|
||||
let res: Result<(), _> = Handler::with(|h| {
|
||||
let s = Span::default();
|
||||
assert_eq!(h.err_count(), 0);
|
||||
h.emit_err(ParserError::invalid_import_list(s).into());
|
||||
h.emit_err(ParserError::invalid_import_list(s));
|
||||
assert_eq!(h.err_count(), 1);
|
||||
h.emit_err(ParserError::unexpected_eof(s).into());
|
||||
h.emit_err(ParserError::unexpected_eof(s));
|
||||
assert_eq!(h.err_count(), 2);
|
||||
Err(ParserError::spread_in_array_init(s).into())
|
||||
});
|
||||
@ -293,8 +293,8 @@ mod tests {
|
||||
|
||||
let res: Result<(), _> = Handler::with(|h| {
|
||||
let s = Span::default();
|
||||
h.emit_err(ParserError::invalid_import_list(s).into());
|
||||
h.emit_err(ParserError::unexpected_eof(s).into());
|
||||
h.emit_err(ParserError::invalid_import_list(s));
|
||||
h.emit_err(ParserError::unexpected_eof(s));
|
||||
Ok(())
|
||||
});
|
||||
assert_eq!(count_err(res.unwrap_err().to_string()), 2);
|
||||
|
@ -33,7 +33,7 @@ create_messages!(
|
||||
|
||||
/// For when the user tries to assign to a const input.
|
||||
@formatted
|
||||
cannont_assign_to_const_input {
|
||||
cannot_assign_to_const_input {
|
||||
args: (input: impl Display),
|
||||
msg: format!(
|
||||
"Cannot assign to const input `{input}`",
|
||||
@ -43,7 +43,7 @@ create_messages!(
|
||||
|
||||
/// For when the user tries to assign to a const input.
|
||||
@formatted
|
||||
cannont_assign_to_const_var {
|
||||
cannot_assign_to_const_var {
|
||||
args: (var: impl Display),
|
||||
msg: format!(
|
||||
"Cannot assign to const variable `{var}`",
|
||||
@ -61,6 +61,16 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the type checker cannot determine the type of an expression.
|
||||
@formatted
|
||||
could_not_determine_type {
|
||||
args: (expr: impl Display),
|
||||
msg: format!(
|
||||
"Could not determine the type of `{expr}`",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// The method name is known but not supported for the given type.
|
||||
@formatted
|
||||
type_method_not_supported {
|
||||
@ -201,12 +211,22 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user is missing a circuit member during initialization.
|
||||
@formatted
|
||||
missing_circuit_member {
|
||||
args: (circuit: impl Display, member: impl Display),
|
||||
msg: format!(
|
||||
"Circuit initialization expression for `{circuit}` is missing member `{member}`.",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// An invalid access call is made e.g., `bool::MAX`
|
||||
@formatted
|
||||
invalid_access_expression {
|
||||
invalid_core_circuit_call {
|
||||
args: (expr: impl Display),
|
||||
msg: format!(
|
||||
"Invalid method call to {expr}."
|
||||
"{expr} is not a valid core circuit call."
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
expectation: Fail
|
||||
inputs:
|
||||
- inline.in: |
|
||||
[main]
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372025]: Comparison `>` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x > sender;\n | ^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372027]: Comparison `>` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x > sender;\n | ^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372025]: Comparison `>=` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x >= sender;\n | ^^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372027]: Comparison `>=` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x >= sender;\n | ^^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372025]: Comparison `<` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x < sender;\n | ^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372027]: Comparison `<` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x < sender;\n | ^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372025]: Comparison `<=` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x <= sender;\n | ^^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372027]: Comparison `<=` is not supported for the address type.\n --> compiler-test:6:12\n |\n 6 | return x <= sender;\n | ^^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372019]: Circuit Bar defined with more than one member with the same name.\n --> compiler-test:3:1\n |\n 3 | circuit Bar {\n 4 | x: u32,\n 5 | x: u32,\n 6 | }\n | ^\n"
|
||||
- "Error [ETYC0372021]: Circuit Bar defined with more than one member with the same name.\n --> compiler-test:3:1\n |\n 3 | circuit Bar {\n 4 | x: u32,\n 5 | x: u32,\n 6 | }\n | ^\n"
|
||||
|
@ -1,7 +1,5 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- output:
|
||||
- initial_input_ast: no input
|
||||
initial_ast: 9489ab9b78bd31ac516e1674a83c6b35708238174df88374a7b19cef3d4a8e8a
|
||||
- "Error [ETYC0372006]: Unknown variable `b`\n --> compiler-test:10:13\n |\n 10 | return (b.x == a.x) == y;\n | ^\nError [ETYC0372004]: Could not determine the type of `b`\n --> compiler-test:10:13\n |\n 10 | return (b.x == a.x) == y;\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372014]: The type ComputeKey is a reserved core type name.\n --> compiler-test:4:35\n |\n 4 | function main(public compute_key: ComputeKey, a: bool) -> bool {\n | ^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372015]: The type ComputeKey is a reserved core type name.\n --> compiler-test:4:35\n |\n 4 | function main(public compute_key: ComputeKey, a: bool) -> bool {\n | ^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372014]: The type PrivateKey is a reserved core type name.\n --> compiler-test:4:35\n |\n 4 | function main(public private_key: PrivateKey, a: bool) -> bool {\n | ^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372015]: The type PrivateKey is a reserved core type name.\n --> compiler-test:4:35\n |\n 4 | function main(public private_key: PrivateKey, a: bool) -> bool {\n | ^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372014]: The type Signature is a reserved core type name.\n --> compiler-test:4:33\n |\n 4 | function main(public signature: Signature, a: bool) -> bool {\n | ^^^^^^^^^\n"
|
||||
- "Error [ETYC0372015]: The type Signature is a reserved core type name.\n --> compiler-test:4:33\n |\n 4 | function main(public signature: Signature, a: bool) -> bool {\n | ^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372014]: The type ViewKey is a reserved core type name.\n --> compiler-test:4:32\n |\n 4 | function main(public view_key: ViewKey, a: bool) -> bool {\n | ^^^^^^^\n"
|
||||
- "Error [ETYC0372015]: The type ViewKey is a reserved core type name.\n --> compiler-test:4:32\n |\n 4 | function main(public view_key: ViewKey, a: bool) -> bool {\n | ^^^^^^^\n"
|
||||
|
@ -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 [ETYC0372010]: 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 [ETYC0372005]: Unknown variable `b`\n --> compiler-test:4:14\n |\n 4 | \tlet b: u8 = b;\n | ^\n"
|
||||
- "Error [ETYC0372006]: Unknown variable `b`\n --> compiler-test:4:14\n |\n 4 | \tlet b: u8 = b;\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372015]: The function main has no return statement.\n --> compiler-test:3:1\n |\n 3 | function main() -> u8 {}\n | ^^^^^^^^^^^^^^^^^^^^^^^^\n"
|
||||
- "Error [ETYC0372016]: The function main has no return statement.\n --> compiler-test:3:1\n |\n 3 | function main() -> u8 {}\n | ^^^^^^^^^^^^^^^^^^^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372009]: Expected one type from `scalar`, but got `group`\n --> compiler-test:4:26\n |\n 4 | return (_, _)group * a;\n | ^\n"
|
||||
- "Error [ETYC0372010]: 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 [ETYC0372024]: The field `balance` in a `record` must have type `u64`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | balance: address,\n 6 | owner: address,\n 7 | }\n | ^\n"
|
||||
- "Error [ETYC0372026]: The field `balance` in a `record` must have type `u64`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | balance: address,\n 6 | owner: address,\n 7 | }\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372020]: Record Token defined with more than one variable with the same name.\n --> compiler-test:3:1\n |\n 3 | record Token {\n 4 | // The token owner.\n 5 | owner: address,\n 6 | // The token owner.\n 7 | owner: address, // Cannot define two record variables with the same name.\n 8 | // The Aleo balance (in gates).\n 9 | balance: u64,\n 10 | // The token amount.\n 11 | amount: u64,\n 12 | }\n | ^\n"
|
||||
- "Error [ETYC0372022]: Record Token defined with more than one variable with the same name.\n --> compiler-test:3:1\n |\n 3 | record Token {\n 4 | // The token owner.\n 5 | owner: address,\n 6 | // The token owner.\n 7 | owner: address, // Cannot define two record variables with the same name.\n 8 | // The Aleo balance (in gates).\n 9 | balance: u64,\n 10 | // The token amount.\n 11 | amount: u64,\n 12 | }\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372005]: Unknown circuit member variable `owner`\n --> compiler-test:5:5\n |\n 5 | owner: address,\n | ^^^^^\n"
|
||||
- "Error [ETYC0372019]: Circuit initialization expression for `Token` is missing member `owner`.\n --> compiler-test:13:12\n |\n 13 | return Token {\n 14 | sender: r0, // This variable should be named `owner`.\n 15 | balance: 0u64,\n 16 | amount: r1,\n 17 | };\n | ^^^^^^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372023]: The `record` type requires the variable `owner: address`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | // The Aleo balance (in gates).\n 6 | balance: u64,\n 7 | // The token amount.\n 8 | amount: u64,\n 9 | }\n | ^\n"
|
||||
- "Error [ETYC0372025]: The `record` type requires the variable `owner: address`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | // The Aleo balance (in gates).\n 6 | balance: u64,\n 7 | // The token amount.\n 8 | amount: u64,\n 9 | }\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372024]: The field `owner` in a `record` must have type `address`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | balance: u64,\n 6 | owner: bool,\n 7 | }\n | ^\n"
|
||||
- "Error [ETYC0372026]: The field `owner` in a `record` must have type `address`.\n --> compiler-test:4:1\n |\n 4 | record Token {\n 5 | balance: u64,\n 6 | owner: bool,\n 7 | }\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "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"
|
||||
- "Error [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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 [ETYC0372010]: 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"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372005]: Unknown variable `z`\n --> compiler-test:4:19\n |\n 4 | \tlet b: u8 = 1u8**z;\n | ^\n"
|
||||
- "Error [ETYC0372006]: Unknown variable `z`\n --> compiler-test:4:19\n |\n 4 | \tlet b: u8 = 1u8**z;\n | ^\n"
|
||||
|
@ -2,4 +2,4 @@
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [ETYC0372005]: Unknown variable `x`\n --> compiler-test:4:14\n |\n 4 | \tlet b: u8 = x*z;\n | ^\nError [ETYC0372005]: Unknown variable `z`\n --> compiler-test:4:16\n |\n 4 | \tlet b: u8 = x*z;\n | ^\n"
|
||||
- "Error [ETYC0372006]: Unknown variable `x`\n --> compiler-test:4:14\n |\n 4 | \tlet b: u8 = x*z;\n | ^\nError [ETYC0372006]: Unknown variable `z`\n --> compiler-test:4:16\n |\n 4 | \tlet b: u8 = x*z;\n | ^\n"
|
||||
|
Loading…
Reference in New Issue
Block a user