mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-27 12:17:35 +03:00
merge testnet3
This commit is contained in:
commit
a15fce710c
@ -18,9 +18,9 @@ use crate::GroupLiteral;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A literal expression.
|
/// A literal.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum LiteralExpression {
|
pub enum Literal {
|
||||||
// todo: deserialize values here
|
// todo: deserialize values here
|
||||||
/// An address literal, e.g., `aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8s7pyjh9`.
|
/// An address literal, e.g., `aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8s7pyjh9`.
|
||||||
Address(String, #[serde(with = "leo_span::span_json")] Span),
|
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),
|
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 {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match &self {
|
match &self {
|
||||||
Self::Address(address, _) => write!(f, "{}", address),
|
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 {
|
fn span(&self) -> Span {
|
||||||
match &self {
|
match &self {
|
||||||
Self::Address(_, span)
|
Self::Address(_, span)
|
@ -44,8 +44,8 @@ pub use tuple_init::*;
|
|||||||
mod unary;
|
mod unary;
|
||||||
pub use unary::*;
|
pub use unary::*;
|
||||||
|
|
||||||
mod value;
|
mod literal;
|
||||||
pub use value::*;
|
pub use literal::*;
|
||||||
|
|
||||||
/// Expression that evaluates to a value.
|
/// Expression that evaluates to a value.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
@ -64,7 +64,7 @@ pub enum Expression {
|
|||||||
/// An identifier.
|
/// An identifier.
|
||||||
Identifier(Identifier),
|
Identifier(Identifier),
|
||||||
/// A literal expression.
|
/// A literal expression.
|
||||||
Literal(LiteralExpression),
|
Literal(Literal),
|
||||||
/// A ternary conditional expression `cond ? if_expr : else_expr`.
|
/// A ternary conditional expression `cond ? if_expr : else_expr`.
|
||||||
Ternary(TernaryExpression),
|
Ternary(TernaryExpression),
|
||||||
/// A tuple expression e.g., `(foo, 42, true)`.
|
/// A tuple expression e.g., `(foo, 42, true)`.
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// 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 leo_errors::{InputError, LeoError, Result};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -34,11 +34,11 @@ impl TryFrom<(Type, Expression)> for InputValue {
|
|||||||
fn try_from(value: (Type, Expression)) -> Result<Self> {
|
fn try_from(value: (Type, Expression)) -> Result<Self> {
|
||||||
Ok(match value {
|
Ok(match value {
|
||||||
(type_, Expression::Literal(lit)) => match (type_, lit) {
|
(type_, Expression::Literal(lit)) => match (type_, lit) {
|
||||||
(Type::Address, LiteralExpression::Address(value, _)) => Self::Address(value),
|
(Type::Address, Literal::Address(value, _)) => Self::Address(value),
|
||||||
(Type::Boolean, LiteralExpression::Boolean(value, _)) => Self::Boolean(value),
|
(Type::Boolean, Literal::Boolean(value, _)) => Self::Boolean(value),
|
||||||
(Type::Field, LiteralExpression::Field(value, _)) => Self::Field(value),
|
(Type::Field, Literal::Field(value, _)) => Self::Field(value),
|
||||||
(Type::Group, LiteralExpression::Group(value)) => Self::Group(*value),
|
(Type::Group, Literal::Group(value)) => Self::Group(*value),
|
||||||
(Type::IntegerType(expected), LiteralExpression::Integer(actual, value, span)) => {
|
(Type::IntegerType(expected), Literal::Integer(actual, value, span)) => {
|
||||||
if expected == actual {
|
if expected == actual {
|
||||||
Self::Integer(expected, value)
|
Self::Integer(expected, value)
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,7 +109,7 @@ pub trait ExpressionReconstructor {
|
|||||||
(Expression::Identifier(input), Default::default())
|
(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())
|
(Expression::Literal(input), Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,17 +72,6 @@ pub trait ExpressionVisitor<'a> {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_err(&mut self, _input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_circuit_init(
|
fn visit_circuit_init(
|
||||||
&mut self,
|
&mut self,
|
||||||
_input: &'a CircuitExpression,
|
_input: &'a CircuitExpression,
|
||||||
@ -91,6 +80,18 @@ pub trait ExpressionVisitor<'a> {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_err(&mut self, _input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_literal(&mut self, _input: &'a Literal, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||||
self.visit_expression(&input.condition, additional);
|
self.visit_expression(&input.condition, additional);
|
||||||
self.visit_expression(&input.if_true, additional);
|
self.visit_expression(&input.if_true, additional);
|
||||||
|
@ -53,6 +53,7 @@ impl Type {
|
|||||||
///
|
///
|
||||||
/// Flattens array syntax: `[[u8; 1]; 2] == [u8; (2, 1)] == true`
|
/// Flattens array syntax: `[[u8; 1]; 2] == [u8; (2, 1)] == true`
|
||||||
///
|
///
|
||||||
|
// TODO: Does not seem to flatten?
|
||||||
pub fn eq_flat(&self, other: &Self) -> bool {
|
pub fn eq_flat(&self, other: &Self) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Type::Address, Type::Address)
|
(Type::Address, Type::Address)
|
||||||
|
@ -120,7 +120,7 @@ impl<'a> ParserContext<'a> {
|
|||||||
|
|
||||||
/// Emit the error `err`.
|
/// Emit the error `err`.
|
||||||
pub(super) fn emit_err(&self, err: ParserError) {
|
pub(super) fn emit_err(&self, err: ParserError) {
|
||||||
self.handler.emit_err(err.into());
|
self.handler.emit_err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit the error `err`.
|
/// Emit the error `err`.
|
||||||
|
@ -384,9 +384,7 @@ impl ParserContext<'_> {
|
|||||||
/// tuple initialization expression or an affine group literal.
|
/// tuple initialization expression or an affine group literal.
|
||||||
fn parse_tuple_expression(&mut self) -> Result<Expression> {
|
fn parse_tuple_expression(&mut self) -> Result<Expression> {
|
||||||
if let Some(gt) = self.eat_group_partial().transpose()? {
|
if let Some(gt) = self.eat_group_partial().transpose()? {
|
||||||
return Ok(Expression::Literal(LiteralExpression::Group(Box::new(
|
return Ok(Expression::Literal(Literal::Group(Box::new(GroupLiteral::Tuple(gt)))));
|
||||||
GroupLiteral::Tuple(gt),
|
|
||||||
))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut tuple, trailing, span) = self.parse_expr_tuple()?;
|
let (mut tuple, trailing, span) = self.parse_expr_tuple()?;
|
||||||
@ -475,7 +473,7 @@ impl ParserContext<'_> {
|
|||||||
/// Returns an [`Expression`] AST node if the next tokens represent a
|
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||||
/// circuit initialization expression.
|
/// circuit initialization expression.
|
||||||
/// let foo = Foo { x: 1u8 };
|
/// 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| {
|
let (members, _, end) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| {
|
||||||
p.parse_circuit_member().map(Some)
|
p.parse_circuit_member().map(Some)
|
||||||
})?;
|
})?;
|
||||||
@ -511,44 +509,42 @@ impl ParserContext<'_> {
|
|||||||
// Literal followed by `field`, e.g., `42field`.
|
// Literal followed by `field`, e.g., `42field`.
|
||||||
Some(Token::Field) => {
|
Some(Token::Field) => {
|
||||||
assert_no_whitespace("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`.
|
// Literal followed by `group`, e.g., `42group`.
|
||||||
Some(Token::Group) => {
|
Some(Token::Group) => {
|
||||||
assert_no_whitespace("group")?;
|
assert_no_whitespace("group")?;
|
||||||
Expression::Literal(LiteralExpression::Group(Box::new(GroupLiteral::Single(
|
Expression::Literal(Literal::Group(Box::new(GroupLiteral::Single(value, full_span))))
|
||||||
value, full_span,
|
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
// Literal followed by `scalar` e.g., `42scalar`.
|
// Literal followed by `scalar` e.g., `42scalar`.
|
||||||
Some(Token::Scalar) => {
|
Some(Token::Scalar) => {
|
||||||
assert_no_whitespace("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`.
|
// Literal followed by other type suffix, e.g., `42u8`.
|
||||||
Some(suffix) => {
|
Some(suffix) => {
|
||||||
assert_no_whitespace(&suffix.to_string())?;
|
assert_no_whitespace(&suffix.to_string())?;
|
||||||
let int_ty = Self::token_to_int_type(suffix).expect("unknown int type token");
|
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()),
|
None => return Err(ParserError::implicit_values_not_allowed(value, span).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::True => Expression::Literal(LiteralExpression::Boolean(true, span)),
|
Token::True => Expression::Literal(Literal::Boolean(true, span)),
|
||||||
Token::False => Expression::Literal(LiteralExpression::Boolean(false, span)),
|
Token::False => Expression::Literal(Literal::Boolean(false, span)),
|
||||||
Token::AddressLit(addr) => {
|
Token::AddressLit(addr) => {
|
||||||
if addr.parse::<Address<Testnet2>>().is_err() {
|
if addr.parse::<Address<Testnet2>>().is_err() {
|
||||||
self.emit_err(ParserError::invalid_address_lit(&addr, span));
|
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::Identifier(name) => {
|
Token::Identifier(name) => {
|
||||||
let ident = Identifier { name, span };
|
let ident = Identifier { name, span };
|
||||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
||||||
// Parse circuit and records inits as circuit expressions.
|
// Parse circuit and records inits as circuit expressions.
|
||||||
// Enforce circuit or record type later at type checking.
|
// Enforce circuit or record type later at type checking.
|
||||||
self.parse_circuit_expression(ident)?
|
self.parse_circuit_init_expression(ident)?
|
||||||
} else {
|
} else {
|
||||||
Expression::Identifier(ident)
|
Expression::Identifier(ident)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
|||||||
// Check return type.
|
// Check return type.
|
||||||
return Some(self.assert_and_return_type(core_instruction.return_type(), expected, access.span()));
|
return Some(self.assert_and_return_type(core_instruction.return_type(), expected, access.span()));
|
||||||
} else {
|
} else {
|
||||||
self.emit_err(TypeCheckerError::invalid_access_expression(access, access.span()));
|
self.emit_err(TypeCheckerError::invalid_core_circuit_call(access, access.span()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AccessExpression::Tuple(access) => {
|
AccessExpression::Tuple(access) => {
|
||||||
@ -118,13 +118,199 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
|||||||
self.emit_err(TypeCheckerError::type_should_be(type_, "tuple", access.span()));
|
self.emit_err(TypeCheckerError::type_should_be(type_, "tuple", access.span()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.emit_err(TypeCheckerError::invalid_core_circuit_call(access, access.span()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_expr => {} // 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_)) => return Some(type_.clone()),
|
||||||
|
// Case where `access.name` is not a member of the circuit.
|
||||||
|
None => {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_circuit_variable(
|
||||||
|
&access.name,
|
||||||
|
&circ,
|
||||||
|
access.name.span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_circuit(&access.inner, access.inner.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(type_) => {
|
||||||
|
self.emit_err(TypeCheckerError::type_should_be(type_, "circuit", access.inner.span()));
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.emit_err(TypeCheckerError::could_not_determine_type(
|
||||||
|
&access.inner,
|
||||||
|
access.inner.span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AccessExpression::AssociatedConstant(..) => {} // todo: Add support for associated constants (u8::MAX).
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_circuit_init(
|
||||||
|
&mut self,
|
||||||
|
input: &'a CircuitExpression,
|
||||||
|
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.emit_err(TypeCheckerError::incorrect_num_circuit_members(
|
||||||
|
circ.members.len(),
|
||||||
|
input.members.len(),
|
||||||
|
input.span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.clone()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.emit_err(TypeCheckerError::missing_circuit_member(
|
||||||
|
circ.identifier,
|
||||||
|
name,
|
||||||
|
input.span(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(ret)
|
||||||
|
} else {
|
||||||
|
self.emit_err(TypeCheckerError::unknown_sym(
|
||||||
|
"circuit",
|
||||||
|
&input.name.name,
|
||||||
|
input.name.span(),
|
||||||
|
));
|
||||||
|
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_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_and_return_type(var.type_.clone(), expected, var.span))
|
||||||
|
} else {
|
||||||
|
self.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_literal(&mut self, input: &'a Literal, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
|
Some(match input {
|
||||||
|
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 {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i8>().is_err() {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I16 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i16>().is_err() {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I32 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i32>().is_err() {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I64 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i64>().is_err() {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::I128 => {
|
||||||
|
let int = if self.negate {
|
||||||
|
format!("-{str_content}")
|
||||||
|
} else {
|
||||||
|
str_content.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if int.parse::<i128>().is_err() {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IntegerType::U8 if str_content.parse::<u8>().is_err() => {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()))
|
||||||
|
}
|
||||||
|
IntegerType::U16 if str_content.parse::<u16>().is_err() => {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()))
|
||||||
|
}
|
||||||
|
IntegerType::U32 if str_content.parse::<u32>().is_err() => {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()))
|
||||||
|
}
|
||||||
|
IntegerType::U64 if str_content.parse::<u64>().is_err() => {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()))
|
||||||
|
}
|
||||||
|
IntegerType::U128 if str_content.parse::<u128>().is_err() => {
|
||||||
|
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()))
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.assert_and_return_type(Type::IntegerType(*type_), 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()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
||||||
match input.op {
|
match input.op {
|
||||||
BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
|
BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
|
||||||
@ -350,13 +536,15 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
|||||||
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
match &*input.function {
|
match &*input.function {
|
||||||
Expression::Identifier(ident) => {
|
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();
|
let func = self.symbol_table.borrow().lookup_fn(&ident.name).cloned();
|
||||||
if let Some(func) = func {
|
if let Some(func) = func {
|
||||||
let ret = self.assert_and_return_type(func.output, expected, func.span);
|
let ret = self.assert_and_return_type(func.output, expected, func.span);
|
||||||
|
|
||||||
// Check number of function arguments.
|
// Check number of function arguments.
|
||||||
if func.input.len() != input.arguments.len() {
|
if func.input.len() != input.arguments.len() {
|
||||||
self.emit_err(TypeCheckerError::incorrect_num_args_to_call(
|
self.handler.emit_err(TypeCheckerError::incorrect_num_args_to_call(
|
||||||
func.input.len(),
|
func.input.len(),
|
||||||
input.arguments.len(),
|
input.arguments.len(),
|
||||||
input.span(),
|
input.span(),
|
||||||
@ -377,152 +565,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: Is this case sufficient?
|
||||||
expr => self.visit_expression(expr, expected),
|
expr => self.visit_expression(expr, expected),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_circuit_init(&mut self, input: &'a CircuitExpression, 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.emit_err(TypeCheckerError::incorrect_num_circuit_members(
|
|
||||||
circ.members.len(),
|
|
||||||
input.members.len(),
|
|
||||||
input.span(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.clone()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.emit_err(TypeCheckerError::unknown_sym(
|
|
||||||
"circuit member variable",
|
|
||||||
name,
|
|
||||||
name.span(),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(ret)
|
|
||||||
} else {
|
|
||||||
self.emit_err(TypeCheckerError::unknown_sym(
|
|
||||||
"circuit",
|
|
||||||
&input.name.name,
|
|
||||||
input.name.span(),
|
|
||||||
));
|
|
||||||
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_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_and_return_type(var.type_.clone(), expected, var.span))
|
|
||||||
} else {
|
|
||||||
self.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_literal(&mut self, input: &'a LiteralExpression, 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, _) => {
|
|
||||||
match type_ {
|
|
||||||
IntegerType::I8 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i8>().is_err() {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I16 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i16>().is_err() {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I32 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i32>().is_err() {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I64 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i64>().is_err() {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::I128 => {
|
|
||||||
let int = if self.negate {
|
|
||||||
format!("-{str_content}")
|
|
||||||
} else {
|
|
||||||
str_content.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if int.parse::<i128>().is_err() {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IntegerType::U8 if str_content.parse::<u8>().is_err() => {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()))
|
|
||||||
}
|
|
||||||
IntegerType::U16 if str_content.parse::<u16>().is_err() => {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()))
|
|
||||||
}
|
|
||||||
IntegerType::U32 if str_content.parse::<u32>().is_err() => {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()))
|
|
||||||
}
|
|
||||||
IntegerType::U64 if str_content.parse::<u64>().is_err() => {
|
|
||||||
self.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()))
|
|
||||||
}
|
|
||||||
IntegerType::U128 if str_content.parse::<u128>().is_err() => {
|
|
||||||
self.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()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||||
self.visit_expression(&input.condition, &Some(Type::Boolean));
|
self.visit_expression(&input.condition, &Some(Type::Boolean));
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
|||||||
self.parent = Some(input.name());
|
self.parent = Some(input.name());
|
||||||
input.input.iter().for_each(|i| {
|
input.input.iter().for_each(|i| {
|
||||||
let input_var = i.get_variable();
|
let input_var = i.get_variable();
|
||||||
self.check_ident_type(&Some(input_var.type_.clone()));
|
self.check_core_type_conflict(&Some(input_var.type_.clone()));
|
||||||
|
|
||||||
// Check for conflicting variable names.
|
// Check for conflicting variable names.
|
||||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||||
|
@ -26,9 +26,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
|||||||
// we can safely unwrap all self.parent instances because
|
// we can safely unwrap all self.parent instances because
|
||||||
// statements should always have some parent block
|
// statements should always have some parent block
|
||||||
let parent = self.parent.unwrap();
|
let parent = self.parent.unwrap();
|
||||||
|
|
||||||
let return_type = &self.symbol_table.borrow().lookup_fn(&parent).map(|f| f.output.clone());
|
let return_type = &self.symbol_table.borrow().lookup_fn(&parent).map(|f| f.output.clone());
|
||||||
self.check_ident_type(return_type);
|
self.check_core_type_conflict(return_type);
|
||||||
|
|
||||||
self.has_return = true;
|
self.has_return = true;
|
||||||
|
|
||||||
self.visit_expression(&input.expression, return_type);
|
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| {
|
input.variable_names.iter().for_each(|v| {
|
||||||
self.check_ident_type(&Some(input.type_.clone()));
|
self.check_core_type_conflict(&Some(input.type_.clone()));
|
||||||
|
|
||||||
self.visit_expression(&input.value, &Some(input.type_.clone()));
|
self.visit_expression(&input.value, &Some(input.type_.clone()));
|
||||||
|
|
||||||
@ -71,9 +71,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
|||||||
let var_type = if let Some(var) = self.symbol_table.borrow_mut().lookup_variable(&var_name.name) {
|
let var_type = if let Some(var) = self.symbol_table.borrow_mut().lookup_variable(&var_name.name) {
|
||||||
// TODO: Check where this check is moved to in `improved-flattening`.
|
// TODO: Check where this check is moved to in `improved-flattening`.
|
||||||
match &var.declaration {
|
match &var.declaration {
|
||||||
Declaration::Const => self.emit_err(TypeCheckerError::cannont_assign_to_const_var(var_name, var.span)),
|
Declaration::Const => self.emit_err(TypeCheckerError::cannot_assign_to_const_var(var_name, var.span)),
|
||||||
Declaration::Input(ParamMode::Const) => {
|
Declaration::Input(ParamMode::Const) => {
|
||||||
self.emit_err(TypeCheckerError::cannont_assign_to_const_input(var_name, var.span))
|
self.emit_err(TypeCheckerError::cannot_assign_to_const_input(var_name, var.span))
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if var_type.is_some() {
|
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);
|
self.visit_expression(&input.value, &var_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,7 +101,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
|||||||
|
|
||||||
fn visit_iteration(&mut self, input: &'a IterationStatement) {
|
fn visit_iteration(&mut self, input: &'a IterationStatement) {
|
||||||
let iter_type = &Some(input.type_.clone());
|
let iter_type = &Some(input.type_.clone());
|
||||||
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(
|
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||||
input.variable.name,
|
input.variable.name,
|
||||||
@ -132,10 +133,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
|||||||
fn visit_block(&mut self, input: &'a Block) {
|
fn visit_block(&mut self, input: &'a Block) {
|
||||||
// Creates a new sub-scope since we are in a block.
|
// Creates a new sub-scope since we are in a block.
|
||||||
let scope_index = self.symbol_table.borrow_mut().insert_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
|
self.symbol_table
|
||||||
.swap(prev_st.borrow().get_block_scope(scope_index).unwrap());
|
.swap(previous_symbol_table.borrow().get_block_scope(scope_index).unwrap());
|
||||||
self.symbol_table.borrow_mut().parent = Some(Box::new(prev_st.into_inner()));
|
self.symbol_table.borrow_mut().parent = Some(Box::new(previous_symbol_table.into_inner()));
|
||||||
|
|
||||||
input.statements.iter().for_each(|stmt| {
|
input.statements.iter().for_each(|stmt| {
|
||||||
match stmt {
|
match stmt {
|
||||||
@ -149,8 +150,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
let prev_st = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
let previous_symbol_table = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
||||||
self.symbol_table.swap(prev_st.get_block_scope(scope_index).unwrap());
|
// TODO: Is this swap necessary?
|
||||||
self.symbol_table = RefCell::new(prev_st);
|
self.symbol_table
|
||||||
|
.swap(previous_symbol_table.get_block_scope(scope_index).unwrap());
|
||||||
|
self.symbol_table = RefCell::new(previous_symbol_table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,8 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Emits a type checker error.
|
/// Emits a type checker error.
|
||||||
pub fn emit_err(&self, err: TypeCheckerError) {
|
pub(crate) fn emit_err(&self, err: TypeCheckerError) {
|
||||||
self.handler.emit_err(err.into());
|
self.handler.emit_err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emits an error to the handler if the given type is invalid.
|
/// Emits an error to the handler if the given type is invalid.
|
||||||
@ -311,7 +311,7 @@ impl<'a> TypeChecker<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Emits an error if the given type conflicts with a core library type.
|
/// 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.
|
// todo: deprecate this method.
|
||||||
if let Some(Type::Identifier(ident)) = type_ {
|
if let Some(Type::Identifier(ident)) = type_ {
|
||||||
if self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name) {
|
if self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name) {
|
||||||
|
@ -205,8 +205,8 @@ impl Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Emit the error `err`.
|
/// Emit the error `err`.
|
||||||
pub fn emit_err(&self, err: LeoError) {
|
pub fn emit_err<E: Into<LeoError>>(&self, err: E) {
|
||||||
self.inner.borrow_mut().emit_err(err);
|
self.inner.borrow_mut().emit_err(err.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit the error `err`.
|
/// Emit the error `err`.
|
||||||
@ -282,9 +282,9 @@ mod tests {
|
|||||||
let res: Result<(), _> = Handler::with(|h| {
|
let res: Result<(), _> = Handler::with(|h| {
|
||||||
let s = Span::default();
|
let s = Span::default();
|
||||||
assert_eq!(h.err_count(), 0);
|
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);
|
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);
|
assert_eq!(h.err_count(), 2);
|
||||||
Err(ParserError::spread_in_array_init(s).into())
|
Err(ParserError::spread_in_array_init(s).into())
|
||||||
});
|
});
|
||||||
@ -293,8 +293,8 @@ mod tests {
|
|||||||
|
|
||||||
let res: Result<(), _> = Handler::with(|h| {
|
let res: Result<(), _> = Handler::with(|h| {
|
||||||
let s = Span::default();
|
let s = Span::default();
|
||||||
h.emit_err(ParserError::invalid_import_list(s).into());
|
h.emit_err(ParserError::invalid_import_list(s));
|
||||||
h.emit_err(ParserError::unexpected_eof(s).into());
|
h.emit_err(ParserError::unexpected_eof(s));
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
assert_eq!(count_err(res.unwrap_err().to_string()), 2);
|
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.
|
/// For when the user tries to assign to a const input.
|
||||||
@formatted
|
@formatted
|
||||||
cannont_assign_to_const_input {
|
cannot_assign_to_const_input {
|
||||||
args: (input: impl Display),
|
args: (input: impl Display),
|
||||||
msg: format!(
|
msg: format!(
|
||||||
"Cannot assign to const input `{input}`",
|
"Cannot assign to const input `{input}`",
|
||||||
@ -43,7 +43,7 @@ create_messages!(
|
|||||||
|
|
||||||
/// For when the user tries to assign to a const input.
|
/// For when the user tries to assign to a const input.
|
||||||
@formatted
|
@formatted
|
||||||
cannont_assign_to_const_var {
|
cannot_assign_to_const_var {
|
||||||
args: (var: impl Display),
|
args: (var: impl Display),
|
||||||
msg: format!(
|
msg: format!(
|
||||||
"Cannot assign to const variable `{var}`",
|
"Cannot assign to const variable `{var}`",
|
||||||
@ -61,6 +61,16 @@ create_messages!(
|
|||||||
help: None,
|
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.
|
/// The method name is known but not supported for the given type.
|
||||||
@formatted
|
@formatted
|
||||||
type_method_not_supported {
|
type_method_not_supported {
|
||||||
@ -201,12 +211,22 @@ create_messages!(
|
|||||||
help: None,
|
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`
|
/// An invalid access call is made e.g., `bool::MAX`
|
||||||
@formatted
|
@formatted
|
||||||
invalid_access_expression {
|
invalid_core_circuit_call {
|
||||||
args: (expr: impl Display),
|
args: (expr: impl Display),
|
||||||
msg: format!(
|
msg: format!(
|
||||||
"Invalid method call to {expr}."
|
"{expr} is not a valid core circuit call."
|
||||||
),
|
),
|
||||||
help: None,
|
help: None,
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Pass
|
expectation: Fail
|
||||||
inputs:
|
inputs:
|
||||||
- inline.in: |
|
- inline.in: |
|
||||||
[main]
|
[main]
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Pass
|
expectation: Fail
|
||||||
outputs:
|
outputs:
|
||||||
- output:
|
- "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"
|
||||||
- initial_input_ast: no input
|
|
||||||
initial_ast: d040a3a4f2be00b8123a1cbdbfe08a651526c76f12b24e0378f4f11fa7ded820
|
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
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"
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
namespace: Compile
|
namespace: Compile
|
||||||
expectation: Fail
|
expectation: Fail
|
||||||
outputs:
|
outputs:
|
||||||
- "Error [ETYC0372028]: Tuple index `2` out of range for a tuple with length `2`\n --> compiler-test:6:21\n |\n 6 | return (t.0, t.2); // Index `t.2` is out of bounds.\n | ^\n"
|
- "Error [ETYC0372030]: Tuple index `2` out of range for a tuple with length `2`\n --> compiler-test:6:21\n |\n 6 | return (t.0, t.2); // Index `t.2` is out of bounds.\n | ^\nError [ETYC0372020]: t.2 is not a valid core circuit call.\n --> compiler-test:6:21\n |\n 6 | return (t.0, t.2); // Index `t.2` is out of bounds.\n | ^\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user