mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-20 10:18:35 +03:00
More tyc restricting nested tuples
This commit is contained in:
parent
2839de13c6
commit
4963a11ee7
@ -674,6 +674,10 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
.iter()
|
||||
.zip(input.elements.iter())
|
||||
.for_each(|(expected, expr)| {
|
||||
// Check that the component expression is not a tuple.
|
||||
if matches!(expr, Expression::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()))
|
||||
}
|
||||
self.visit_expression(expr, &Some(expected.clone()));
|
||||
});
|
||||
|
||||
|
@ -30,6 +30,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_struct(&mut self, input: &'a Struct) {
|
||||
// Check for conflicting struct/record member names.
|
||||
let mut used = HashSet::new();
|
||||
// TODO: Better span to target duplicate member.
|
||||
if !input.members.iter().all(|Member { identifier, type_ }| {
|
||||
// Check that the member types are defined.
|
||||
self.assert_type_is_defined(type_, identifier.span);
|
||||
@ -109,6 +110,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
// Check that the function's annotations are valid.
|
||||
// Note that Leo does not natively support any specific annotations.
|
||||
for annotation in function.annotations.iter() {
|
||||
// TODO: Change to compiler warning.
|
||||
self.emit_err(TypeCheckerError::unknown_annotation(annotation, annotation.span))
|
||||
}
|
||||
|
||||
@ -146,7 +148,6 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
if matches!(input_var.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::function_cannot_take_tuple_as_input(input_var.span()))
|
||||
}
|
||||
self.assert_valid_declaration_or_parameter_type(&input_var.type_(), input_var.span());
|
||||
|
||||
match self.is_transition_function {
|
||||
// If the function is a transition function, then check that the parameter mode is not a constant.
|
||||
@ -174,8 +175,10 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
});
|
||||
|
||||
// Type check the function's return type.
|
||||
// Note that checking that each of the component types are defined is sufficient to check that `output_type` is defined.
|
||||
function.output.iter().for_each(|output_type| {
|
||||
match output_type {
|
||||
// TODO: Verify that this is not needed when the import system is updated.
|
||||
Output::External(_) => {} // Do not type check external record function outputs.
|
||||
Output::Internal(output_type) => {
|
||||
// Check that the type of output is defined.
|
||||
@ -184,9 +187,8 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
if matches!(&output_type.type_, Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(output_type.span))
|
||||
}
|
||||
self.assert_valid_declaration_or_parameter_type(&output_type.type_, output_type.span);
|
||||
|
||||
// Check that the mode of the output is valid.
|
||||
// For functions, only public and private outputs are allowed
|
||||
if output_type.mode == Mode::Const {
|
||||
self.emit_err(TypeCheckerError::cannot_have_constant_output_mode(output_type.span));
|
||||
}
|
||||
@ -196,9 +198,6 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
self.visit_block(&function.block);
|
||||
|
||||
// Check that the return type is defined. Note that the component types are already checked.
|
||||
self.assert_type_is_defined(&function.output_type, function.span);
|
||||
|
||||
// If the function has a return type, then check that it has a return.
|
||||
if function.output_type != Type::Unit && !self.has_return {
|
||||
self.emit_err(TypeCheckerError::missing_return(function.span));
|
||||
@ -250,7 +249,6 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
if input_var.mode() == Mode::Const || input_var.mode() == Mode::Private {
|
||||
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span()));
|
||||
}
|
||||
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
input_var.identifier().name,
|
||||
@ -265,6 +263,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
});
|
||||
|
||||
// Type check the function's return type.
|
||||
// Note that checking that each of the component types are defined is sufficient to guarantee that the `output_type` is defined.
|
||||
finalize.output.iter().for_each(|output_type| {
|
||||
// Check that the type of output is defined.
|
||||
self.assert_type_is_defined(&output_type.type_(), output_type.span());
|
||||
@ -272,14 +271,16 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
if matches!(&output_type.type_(), Type::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(output_type.span()))
|
||||
}
|
||||
|
||||
// Check that the mode of the output is valid.
|
||||
if output_type.mode() == Mode::Const {
|
||||
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(output_type.span()));
|
||||
// Note that a finalize block can have only public outputs.
|
||||
if matches!(output_type.mode(), Mode::Const | Mode::Private) {
|
||||
self.emit_err(TypeCheckerError::finalize_output_mode_must_be_public(
|
||||
output_type.span(),
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: Remove when this restriction is removed.
|
||||
// TODO: Remove if this restriction is relaxed at Aleo instructions level.
|
||||
// Check that the finalize block is not empty.
|
||||
if finalize.block.statements.is_empty() {
|
||||
self.emit_err(TypeCheckerError::finalize_block_must_not_be_empty(finalize.span));
|
||||
|
@ -189,8 +189,24 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// Check that the type of the definition is defined.
|
||||
self.assert_type_is_defined(&input.type_, input.span);
|
||||
|
||||
// Check that the type of the definition is valid.
|
||||
self.assert_valid_declaration_or_parameter_type(&input.type_, input.span);
|
||||
// Check that the type of the definition is not a unit type, singleton tuple type, or nested tuple type.
|
||||
match &input.type_ {
|
||||
// If the type is an empty tuple, return an error.
|
||||
Type::Unit => self.emit_err(TypeCheckerError::unit_tuple(input.span)),
|
||||
// If the type is a singleton tuple, return an error.
|
||||
Type::Tuple(tuple) => match tuple.len() {
|
||||
0 => unreachable!("Tuples must have a length of at least one."),
|
||||
1 => self.emit_err(TypeCheckerError::singleton_tuple(input.span)),
|
||||
_ => {
|
||||
if tuple.iter().any(|type_| matches!(type_, Type::Tuple(_))) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
|
||||
}
|
||||
}
|
||||
},
|
||||
Type::Mapping(_) | Type::Err => unreachable!(),
|
||||
// Otherwise, the type is valid.
|
||||
_ => (), // Do nothing
|
||||
}
|
||||
|
||||
// Check the expression on the left-hand side.
|
||||
self.visit_expression(&input.value, &Some(input.type_.clone()));
|
||||
@ -244,6 +260,12 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
.iter()
|
||||
.zip(input.arguments.iter())
|
||||
.for_each(|(expected, argument)| {
|
||||
// Check that none of the arguments are tuple expressions.
|
||||
if matches!(argument, Expression::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::finalize_statement_cannot_contain_tuples(
|
||||
argument.span(),
|
||||
));
|
||||
}
|
||||
self.visit_expression(argument, &Some(expected.type_()));
|
||||
});
|
||||
}
|
||||
@ -358,6 +380,13 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
self.has_return = true;
|
||||
|
||||
// Check that the return expression is not a tuple.
|
||||
if matches!(&input.expression, Expression::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::finalize_statement_cannot_contain_tuples(
|
||||
input.expression.span(),
|
||||
))
|
||||
}
|
||||
|
||||
self.visit_expression(&input.expression, return_type);
|
||||
}
|
||||
}
|
||||
|
@ -415,22 +415,6 @@ impl<'a> TypeChecker<'a> {
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Fuse with defined check
|
||||
// TODO: Do we need to check that an identifier does not correspond to a mapping type?
|
||||
/// Emits an error if the type on the left-hand side of the assignment is invalid.
|
||||
pub(crate) fn assert_valid_declaration_or_parameter_type(&self, type_: &Type, span: Span) {
|
||||
match type_ {
|
||||
// If the type is an empty tuple, return an error.
|
||||
Type::Unit => self.emit_err(TypeCheckerError::unit_tuple(span)),
|
||||
// If the type is a singleton tuple, return an error.
|
||||
Type::Tuple(tuple) if tuple.len() == 1 => self.emit_err(TypeCheckerError::singleton_tuple(span)),
|
||||
// The type can never be a mapping or error type.
|
||||
Type::Mapping(_) | Type::Err => unreachable!(),
|
||||
// Otherwise, the type is valid.
|
||||
_ => (), // Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn types_to_string(types: &[Type]) -> String {
|
||||
|
@ -312,6 +312,13 @@ create_messages!(
|
||||
help: Some("Add a `public` modifier to the input variable declaration or remove the visibility modifier entirely.".to_string()),
|
||||
}
|
||||
|
||||
@formatted
|
||||
finalize_output_mode_must_be_public {
|
||||
args: (),
|
||||
msg: format!("An output of a finalize block must be public."),
|
||||
help: Some("Add a `public` modifier to the output type declaration or remove the visibility modifier entirely.".to_string()),
|
||||
}
|
||||
|
||||
@formatted
|
||||
finalize_in_finalize {
|
||||
args: (),
|
||||
@ -467,7 +474,7 @@ create_messages!(
|
||||
@formatted
|
||||
nested_tuple_type {
|
||||
args: (),
|
||||
msg: format!("Nested tuple types are not supported."),
|
||||
msg: format!("A tuple type cannot contain a tuple."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -498,4 +505,18 @@ create_messages!(
|
||||
msg: format!("A finalize block cannot take in a tuple as input."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
nested_tuple_expression {
|
||||
args: (),
|
||||
msg: format!("A tuple expression cannot contain another tuple expression."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
finalize_statement_cannot_contain_tuples {
|
||||
args: (),
|
||||
msg: format!("A finalize statement cannot contain tuple expressions."),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user