mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-27 02:24:15 +03:00
Restrict tuples in parser; cleanup
This commit is contained in:
parent
d705fd1cce
commit
f606a8b74a
@ -14,8 +14,12 @@
|
||||
// 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 leo_errors::{AstError, Result};
|
||||
use crate::{Tuple, Type};
|
||||
use super::*;
|
||||
|
||||
// TODO: Consider a safe interface for constructing a tuple expression.
|
||||
|
||||
/// A tuple expression, e.g., `(foo, false, 42)`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TupleExpression {
|
||||
|
@ -16,26 +16,16 @@
|
||||
|
||||
use crate::Type;
|
||||
use leo_errors::{AstError, Result};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt, ops::Deref};
|
||||
|
||||
// TODO: Consider defining a safe interface for constructing a tuple type.
|
||||
|
||||
/// A type list of at least two types.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Tuple(pub Vec<Type>);
|
||||
|
||||
impl Tuple {
|
||||
/// Returns a new `Type::Tuple` enumeration.
|
||||
pub fn try_new(elements: Vec<Type>, span: Span) -> Result<Type> {
|
||||
match elements.len() {
|
||||
0 => Err(AstError::empty_tuple(span).into()),
|
||||
1 => Err(AstError::one_element_tuple(span).into()),
|
||||
_ => Ok(Type::Tuple(Tuple(elements))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Tuple {
|
||||
type Target = Vec<Type>;
|
||||
|
||||
|
@ -428,9 +428,14 @@ impl ParserContext<'_> {
|
||||
match elements.len() {
|
||||
// If the tuple expression is empty, return a `UnitExpression`.
|
||||
0 => Ok(Expression::Unit(UnitExpression { span })),
|
||||
// If there is one element in the tuple but no trailing comma, e.g `(foo)`, return the element.
|
||||
1 if !trailing => Ok(elements.swap_remove(0)),
|
||||
1 => match trailing {
|
||||
// If there is one element in the tuple but no trailing comma, e.g `(foo)`, return the element.
|
||||
false => Ok(elements.swap_remove(0)),
|
||||
// If there is one element in the tuple and a trailing comma, e.g `(foo,)`, emit an error since tuples must have at least two elements.
|
||||
true => Err(ParserError::tuple_must_have_at_least_two_elements("expression", span).into()),
|
||||
}
|
||||
// Otherwise, return a tuple expression.
|
||||
// Note: This is the only place where `TupleExpression` is constructed in the parser.
|
||||
_ => Ok(Expression::Tuple(TupleExpression { elements, span })),
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
use leo_errors::Result;
|
||||
use leo_errors::{ParserError, Result};
|
||||
|
||||
pub(super) const TYPE_TOKENS: &[Token] = &[
|
||||
Token::Address,
|
||||
@ -83,7 +83,10 @@ impl ParserContext<'_> {
|
||||
match types.len() {
|
||||
// If the parenthetical block is empty, e.g. `()` or `( )`, it should be parsed into `Unit` types.
|
||||
0 => Ok((Type::Unit, span)),
|
||||
// If the parenthetical block contains a single type, e.g. `(u8)`, emit an error, since tuples must have at least two elements.
|
||||
1 => Err(ParserError::tuple_must_have_at_least_two_elements("type", span).into()),
|
||||
// Otherwise, parse it into a `Tuple` type.
|
||||
// Note: This is the only place where `Tuple` type is constructed in the parser.
|
||||
_ => Ok((Type::Tuple(Tuple(types.into_iter().map(|t| t.0).collect())), span)),
|
||||
}
|
||||
} else {
|
||||
|
@ -307,8 +307,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
match return_type {
|
||||
Type::Unit => (String::new(), instructions), // Do nothing
|
||||
Type::Tuple(tuple) => match tuple.len() {
|
||||
0 => unreachable!("Parsing guarantees that a tuple type has at least one element"),
|
||||
1 => unreachable!("Type checking disallows singleton tuples."),
|
||||
0 | 1 => unreachable!("Parsing guarantees that a tuple type has at least two elements"),
|
||||
len => {
|
||||
let mut destinations = Vec::new();
|
||||
for _ in 0..len {
|
||||
|
@ -33,7 +33,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
unreachable!("Mapping types are not supported at this phase of compilation")
|
||||
}
|
||||
Type::Tuple(_) => {
|
||||
unreachable!("Tuple types are not supported at this phase of compilation")
|
||||
unreachable!("Tuple types should not be visited at this phase of compilation")
|
||||
}
|
||||
Type::Err => unreachable!("Error types should not exist at this phase of compilation"),
|
||||
Type::Unit => unreachable!("Unit types are not supported at this phase of compilation"),
|
||||
|
@ -627,11 +627,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
fn visit_tuple(&mut self, input: &'a TupleExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
match input.elements.len() {
|
||||
0 => unreachable!("Parsing guarantees that tuple expressions have at least one element."),
|
||||
1 => {
|
||||
self.emit_err(TypeCheckerError::singleton_tuple(input.span()));
|
||||
None
|
||||
}
|
||||
0 | 1 => unreachable!("Parsing guarantees that tuple expressions have at least two elements."),
|
||||
_ => {
|
||||
// Check the expected tuple types if they are known.
|
||||
if let Some(Type::Tuple(expected_types)) = expected {
|
||||
@ -716,7 +712,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_unit(&mut self, input: &'a UnitExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
// Unit expression are only allowed inside a return statement.
|
||||
if !self.is_return {
|
||||
self.emit_err(TypeCheckerError::unit_tuple(input.span()));
|
||||
self.emit_err(TypeCheckerError::unit_expression_only_in_return_statements(input.span()));
|
||||
}
|
||||
Some(Type::Unit)
|
||||
}
|
||||
|
@ -195,11 +195,10 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// 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)),
|
||||
Type::Unit => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.span)),
|
||||
// If the type is a singleton tuple, return an error.
|
||||
Type::Tuple(tuple) => match tuple.len() {
|
||||
0 => unreachable!("Parsing guarantees that tuples have a length of at least one."),
|
||||
1 => self.emit_err(TypeCheckerError::singleton_tuple(input.span)),
|
||||
0 | 1 => unreachable!("Parsing guarantees that tuple types have at least two elements."),
|
||||
_ => {
|
||||
if tuple.iter().any(|type_| matches!(type_, Type::Tuple(_))) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_type(input.span))
|
||||
|
@ -74,22 +74,6 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when a user tries to define an empty tuple.
|
||||
@formatted
|
||||
empty_tuple {
|
||||
args: (),
|
||||
msg: "Tuples of zero elements are not allowed.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when a user tries to define a tuple dimension of one.
|
||||
@formatted
|
||||
one_element_tuple {
|
||||
args: (),
|
||||
msg: "Tuples of one element are not allowed.",
|
||||
help: Some("Try defining a single type by removing the parenthesis `( )`".to_string()),
|
||||
}
|
||||
|
||||
/// For when a user shadows a function.
|
||||
@formatted
|
||||
shadowed_function {
|
||||
|
@ -262,4 +262,11 @@ create_messages!(
|
||||
msg: "Invalid network identifier. The only supported identifier is `aleo`.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
tuple_must_have_at_least_two_elements {
|
||||
args: (kind: impl Display),
|
||||
msg: format!("A tuple {kind} must have at least two elements."),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -447,7 +447,8 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
// TODO: Eventually update to warnings.
|
||||
// TODO: Consider chainging this to a warning.
|
||||
|
||||
@formatted
|
||||
assign_unit_expression_to_variable {
|
||||
args: (),
|
||||
@ -455,22 +456,6 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
// TODO: Better error messages for each tuple case. e.g tuple in function parameter, tuple in assignment, tuple in return, etc.
|
||||
|
||||
@formatted
|
||||
singleton_tuple {
|
||||
args: (),
|
||||
msg: format!("Singleton tuple expressions and tuple types are not allowed."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
unit_tuple {
|
||||
args: (),
|
||||
msg: format!("Empty tuple expressions and tuple types are not allowed."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
nested_tuple_type {
|
||||
args: (),
|
||||
@ -488,7 +473,7 @@ create_messages!(
|
||||
@formatted
|
||||
function_cannot_take_tuple_as_input {
|
||||
args: (),
|
||||
msg: format!("A function cannot take in tuples as input."),
|
||||
msg: format!("A function cannot take in a tuple as input."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -530,7 +515,14 @@ create_messages!(
|
||||
@formatted
|
||||
lhs_must_be_identifier_or_tuple {
|
||||
args: (),
|
||||
msg: format!("The left-hand side of a `DefinitionStatement` can only be a tuple or identifier."),
|
||||
msg: format!("The left-hand side of a `DefinitionStatement` can only be an identifier or tuple. Note that a tuple must contain at least two elements."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
unit_expression_only_in_return_statements {
|
||||
args: (),
|
||||
msg: format!("Unit expressions can only be used in return statements."),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user