mirror of
https://github.com/AleoHQ/leo.git
synced 2024-09-22 04:27:25 +03:00
impl unary
This commit is contained in:
parent
831e011f42
commit
6c759b7174
@ -15,22 +15,57 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
use leo_span::Symbol;
|
||||
|
||||
/// A unary operator for a unary expression.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum UnaryOperation {
|
||||
/// The logical negation operator, i.e., `!`.
|
||||
/// For example, it transforms `true` to `false`.
|
||||
Not,
|
||||
/// The arithmetic negation operator, i.e., `-`.
|
||||
/// Absolute value checking for overflow, i.e. `.abs()`.
|
||||
Abs,
|
||||
/// Absolute value wrapping around at the boundary of the type, i.e. `.abs_wrapped()`.
|
||||
AbsWrapped,
|
||||
/// Double operation, i.e. `.double()`.
|
||||
Double,
|
||||
/// Multiplicative inverse, i.e. `.inv()`.
|
||||
Inverse,
|
||||
/// Negate operation, i.e. `.neg()`.
|
||||
Negate,
|
||||
/// Bitwise NOT, i.e. `!`, `.not()`.
|
||||
Not,
|
||||
/// Square operation, i.e. `.square()`.
|
||||
Square,
|
||||
/// Square root operation, i.e. `.sqrt()`.
|
||||
SquareRoot,
|
||||
}
|
||||
|
||||
impl UnaryOperation {
|
||||
/// Returns a `UnaryOperation` from the given `Symbol`.
|
||||
pub fn from_symbol(symbol: &Symbol) -> Option<UnaryOperation> {
|
||||
Some(match symbol.as_u32() {
|
||||
0 => UnaryOperation::Abs,
|
||||
1 => UnaryOperation::AbsWrapped,
|
||||
2 => UnaryOperation::Double,
|
||||
3 => UnaryOperation::Inverse,
|
||||
4 => UnaryOperation::Negate,
|
||||
5 => UnaryOperation::Not,
|
||||
6 => UnaryOperation::Square,
|
||||
7 => UnaryOperation::SquareRoot,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for UnaryOperation {
|
||||
fn as_ref(&self) -> &'static str {
|
||||
match self {
|
||||
UnaryOperation::Not => "!",
|
||||
UnaryOperation::Abs => "abs",
|
||||
UnaryOperation::AbsWrapped => "abs_wrapped",
|
||||
UnaryOperation::Double => "double",
|
||||
UnaryOperation::Inverse => "inv",
|
||||
UnaryOperation::Negate => "-",
|
||||
UnaryOperation::Not => "!",
|
||||
UnaryOperation::Square => ".square",
|
||||
UnaryOperation::SquareRoot => "sqrt"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,7 +74,7 @@ impl AsRef<str> for UnaryOperation {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct UnaryExpression {
|
||||
/// The inner expression `op` is applied to.
|
||||
pub inner: Box<Expression>,
|
||||
pub receiver: Box<Expression>,
|
||||
/// The unary operator to apply to `inner`.
|
||||
pub op: UnaryOperation,
|
||||
/// The span covering `op inner`.
|
||||
@ -48,7 +83,7 @@ pub struct UnaryExpression {
|
||||
|
||||
impl fmt::Display for UnaryExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}{}", self.op.as_ref(), self.inner)
|
||||
write!(f, "{}{}", self.op.as_ref(), self.receiver)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ impl TryFrom<(Type, Expression)> for InputValue {
|
||||
}
|
||||
}
|
||||
(type_, Expression::Unary(unary)) if unary.op == UnaryOperation::Negate => {
|
||||
InputValue::try_from((type_, *unary.inner))?
|
||||
InputValue::try_from((type_, *unary.receiver))?
|
||||
}
|
||||
(_type_, expr) => return Err(InputError::illegal_expression(&expr, expr.span()).into()),
|
||||
})
|
||||
|
@ -93,7 +93,7 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
|
||||
}
|
||||
|
||||
pub fn reduce_unary(&mut self, unary: &UnaryExpression) -> Result<UnaryExpression> {
|
||||
let inner = self.reduce_expression(&unary.inner)?;
|
||||
let inner = self.reduce_expression(&unary.receiver)?;
|
||||
|
||||
self.reducer.reduce_unary(unary, inner, unary.op.clone())
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ pub trait ReconstructingReducer {
|
||||
op: UnaryOperation,
|
||||
) -> Result<UnaryExpression> {
|
||||
Ok(UnaryExpression {
|
||||
inner: Box::new(inner),
|
||||
receiver: Box::new(inner),
|
||||
op,
|
||||
span: unary.span,
|
||||
})
|
||||
|
@ -72,7 +72,7 @@ pub trait ExpressionVisitorDirector<'a>: VisitorDirector<'a> {
|
||||
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_unary(input) {
|
||||
self.visit_expression(&input.inner, additional);
|
||||
self.visit_expression(&input.receiver, additional);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ impl ParserContext<'_> {
|
||||
inner = Expression::Unary(UnaryExpression {
|
||||
span: op_span + inner.span(),
|
||||
op,
|
||||
inner: Box::new(inner),
|
||||
receiver: Box::new(inner),
|
||||
});
|
||||
}
|
||||
Ok(inner)
|
||||
@ -236,7 +236,22 @@ impl ParserContext<'_> {
|
||||
self.bump();
|
||||
|
||||
// Check if the method exists.
|
||||
if let Some(operator) = BinaryOperation::from_symbol(&method) {
|
||||
if let Some(operator) = UnaryOperation::from_symbol(&method) {
|
||||
// Handle unary operators.
|
||||
|
||||
// Parse left parenthesis `(`.
|
||||
self.expect(&Token::LeftParen)?;
|
||||
|
||||
// Parse right parenthesis `)`.
|
||||
let right_span = self.expect(&Token::RightParen)?;
|
||||
|
||||
return Ok(Expression::Unary(UnaryExpression {
|
||||
span: receiver.span() + right_span,
|
||||
op: operator,
|
||||
receiver: Box::new(receiver),
|
||||
}));
|
||||
|
||||
} else if let Some(operator) = BinaryOperation::from_symbol(&method) {
|
||||
// Handle binary operators.
|
||||
|
||||
// Parse left parenthesis `(`.
|
||||
@ -245,7 +260,7 @@ impl ParserContext<'_> {
|
||||
// Parse operand.
|
||||
let operand = self.parse_expression()?;
|
||||
|
||||
// Parse close parenthesis `)`.
|
||||
// Parse right parenthesis `)`.
|
||||
let right_span = self.expect(&Token::RightParen)?;
|
||||
|
||||
return Ok(Expression::Binary(BinaryExpression {
|
||||
|
@ -64,7 +64,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
fn visit_identifier(&mut self, input: &'a Identifier, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_identifier(input) {
|
||||
return if let Some(var) = self.visitor.symbol_table.clone().lookup_variable(&input.name) {
|
||||
Some(self.visitor.assert_type(*var.type_, expected, var.span))
|
||||
Some(self.visitor.assert_expected_option(*var.type_, expected, var.span))
|
||||
} else {
|
||||
self.visitor
|
||||
.handler
|
||||
@ -79,9 +79,9 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
fn visit_value(&mut self, input: &'a ValueExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_value(input) {
|
||||
return Some(match input {
|
||||
ValueExpression::Address(_, _) => self.visitor.assert_type(Type::Address, expected, input.span()),
|
||||
ValueExpression::Boolean(_, _) => self.visitor.assert_type(Type::Boolean, expected, input.span()),
|
||||
ValueExpression::Field(_, _) => self.visitor.assert_type(Type::Field, expected, input.span()),
|
||||
ValueExpression::Address(_, _) => self.visitor.assert_expected_option(Type::Address, expected, input.span()),
|
||||
ValueExpression::Boolean(_, _) => self.visitor.assert_expected_option(Type::Boolean, expected, input.span()),
|
||||
ValueExpression::Field(_, _) => self.visitor.assert_expected_option(Type::Field, expected, input.span()),
|
||||
ValueExpression::Integer(type_, str_content, _) => {
|
||||
match type_ {
|
||||
IntegerType::I8 => {
|
||||
@ -172,11 +172,11 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
_ => {}
|
||||
}
|
||||
self.visitor
|
||||
.assert_type(Type::IntegerType(*type_), expected, input.span())
|
||||
.assert_expected_option(Type::IntegerType(*type_), expected, input.span())
|
||||
}
|
||||
ValueExpression::Group(_) => self.visitor.assert_type(Type::Group, expected, input.span()),
|
||||
ValueExpression::Scalar(_, _) => self.visitor.assert_type(Type::Scalar, expected, input.span()),
|
||||
ValueExpression::String(_, _) => self.visitor.assert_type(Type::String, expected, input.span()),
|
||||
ValueExpression::Group(_) => self.visitor.assert_expected_option(Type::Group, expected, input.span()),
|
||||
ValueExpression::Scalar(_, _) => self.visitor.assert_expected_option(Type::Scalar, expected, input.span()),
|
||||
ValueExpression::String(_, _) => self.visitor.assert_expected_option(Type::String, expected, input.span()),
|
||||
});
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
return match input.op {
|
||||
BinaryOperation::Nand | BinaryOperation::Nor => {
|
||||
// Assert equal boolean types.
|
||||
self.visitor.assert_type(Type::Boolean, destination, input.span());
|
||||
self.visitor.assert_expected_option(Type::Boolean, destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
|
||||
@ -233,31 +233,22 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
// Allow `group` * `scalar` multiplication.
|
||||
match (t1, t2) {
|
||||
(Some(Type::Group), other) => {
|
||||
self.visitor.assert_type_exact(destination, &Type::Group, input.span());
|
||||
self.visitor
|
||||
.assert_type_exact(&other, &Type::Scalar, input.right.span());
|
||||
Some(Type::Group)
|
||||
.assert_expected_type(&other, Type::Scalar, input.right.span());
|
||||
Some(self.visitor.assert_expected_type(destination, Type::Group, input.span()))
|
||||
}
|
||||
(other, Some(Type::Group)) => {
|
||||
self.visitor.assert_type_exact(destination, &Type::Group, input.span());
|
||||
self.visitor.assert_type_exact(&other, &Type::Scalar, input.left.span());
|
||||
Some(Type::Group)
|
||||
self.visitor.assert_expected_type(&other, Type::Scalar, input.left.span());
|
||||
Some(self.visitor.assert_expected_type(destination, Type::Group, input.span()))
|
||||
}
|
||||
(Some(t1), Some(t2)) => {
|
||||
(t1, t2) => {
|
||||
// Assert equal field or integer types.
|
||||
self.visitor.assert_type(t1, destination, input.left.span());
|
||||
self.visitor.assert_type(t2, destination, input.right.span());
|
||||
return_incorrect_type(Some(t1), Some(t2), destination)
|
||||
self.visitor.assert_field_int_type(destination, input.span());
|
||||
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
|
||||
|
||||
}
|
||||
(Some(type_), None) => {
|
||||
self.visitor.assert_type(type_, destination, input.left.span());
|
||||
None
|
||||
}
|
||||
(None, Some(type_)) => {
|
||||
self.visitor.assert_type(type_, destination, input.right.span());
|
||||
None
|
||||
}
|
||||
(None, None) => None,
|
||||
}
|
||||
}
|
||||
BinaryOperation::Div => {
|
||||
@ -279,20 +270,17 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
// Allow field * field.
|
||||
match (t1, t2) {
|
||||
(Some(Type::Field), type_) => {
|
||||
self.visitor.assert_type_exact(&type_, &Type::Field, input.right.span());
|
||||
self.visitor.assert_type_exact(destination, &Type::Field, input.span());
|
||||
Some(Type::Field)
|
||||
self.visitor.assert_expected_type(&type_, Type::Field, input.right.span());
|
||||
Some(self.visitor.assert_expected_type(destination, Type::Field, input.span()))
|
||||
}
|
||||
(type_, Some(Type::Field)) => {
|
||||
self.visitor.assert_type_exact(&type_, &Type::Field, input.left.span());
|
||||
self.visitor.assert_type_exact(destination, &Type::Field, input.span());
|
||||
Some(Type::Field)
|
||||
self.visitor.assert_expected_type(&type_, Type::Field, input.left.span());
|
||||
Some(self.visitor.assert_expected_type(destination, Type::Field, input.span()))
|
||||
}
|
||||
(Some(t1), t2) => {
|
||||
// Allow integer t2 magnitude (u8, u16, u32)
|
||||
self.visitor.assert_magnitude_type(&t2, input.right.span());
|
||||
self.visitor.assert_type_exact(destination, &t1, input.span());
|
||||
Some(t1)
|
||||
Some(self.visitor.assert_expected_type(destination, t1, input.span()))
|
||||
}
|
||||
(None, t2) => {
|
||||
// Allow integer t2 magnitude (u8, u16, u32)
|
||||
@ -302,19 +290,16 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
}
|
||||
BinaryOperation::Eq | BinaryOperation::Neq => {
|
||||
// Assert equal address, boolean, field, group, scalar, or integer types.
|
||||
// Assert first and second address, boolean, field, group, scalar, or integer types.
|
||||
let t1 = self.visit_expression(&input.left, &None);
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
|
||||
self.visitor.assert_eq_types(t1, t2, input.span());
|
||||
|
||||
Some(Type::Boolean)
|
||||
// Assert destination is boolean.
|
||||
Some(self.visitor.assert_expected_type(destination, Type::Boolean, input.span()))
|
||||
}
|
||||
BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Le | BinaryOperation::Ge => {
|
||||
// Assert the destination type is boolean.
|
||||
self.visitor
|
||||
.assert_type_exact(destination, &Type::Boolean, input.span());
|
||||
|
||||
// Assert left and right are equal field, scalar, or integer types.
|
||||
let t1 = self.visit_expression(&input.left, &None);
|
||||
self.visitor.assert_field_scalar_int_type(&t1, input.left.span());
|
||||
@ -324,7 +309,9 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
|
||||
self.visitor.assert_eq_types(t1, t2, input.span());
|
||||
|
||||
Some(Type::Boolean)
|
||||
// Assert destination is boolean.
|
||||
Some(self.visitor
|
||||
.assert_expected_type(destination, Type::Boolean, input.span()))
|
||||
}
|
||||
BinaryOperation::AddWrapped
|
||||
| BinaryOperation::SubWrapped
|
||||
@ -358,17 +345,33 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
match input.op {
|
||||
UnaryOperation::Not => {
|
||||
self.visitor.assert_type(Type::Boolean, expected, input.span());
|
||||
self.visit_expression(&input.inner, expected)
|
||||
UnaryOperation::Abs => {
|
||||
// Assert integer type only.
|
||||
self.visitor.assert_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::AbsWrapped => {
|
||||
// Assert integer type only.
|
||||
self.visitor.assert_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Double => {
|
||||
// Assert field and group type only.
|
||||
self.visitor.assert_field_group_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Inverse => {
|
||||
// Assert field type only.
|
||||
self.visitor.assert_expected_type(destination, Type::Field, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Negate => {
|
||||
let prior_negate_state = self.visitor.negate;
|
||||
self.visitor.negate = true;
|
||||
|
||||
let type_ = self.visit_expression(&input.inner, expected);
|
||||
let type_ = self.visit_expression(&input.receiver, destination);
|
||||
self.visitor.negate = prior_negate_state;
|
||||
match type_.as_ref() {
|
||||
Some(
|
||||
@ -385,11 +388,26 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
Some(t) => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::type_is_not_negatable(t, input.inner.span()).into()),
|
||||
.emit_err(TypeCheckerError::type_is_not_negatable(t, input.receiver.span()).into()),
|
||||
_ => {}
|
||||
};
|
||||
type_
|
||||
}
|
||||
UnaryOperation::Not => {
|
||||
// Assert boolean, integer types only.
|
||||
self.visitor.assert_bool_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Square => {
|
||||
// Assert field type only.
|
||||
self.visitor.assert_expected_type(destination, Type::Field, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::SquareRoot => {
|
||||
// Assert field and scalar types only.
|
||||
self.visitor.assert_field_scalar_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,7 +432,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
match &*input.function {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(func) = self.visitor.symbol_table.clone().lookup_fn(&ident.name) {
|
||||
let ret = self.visitor.assert_type(func.output, expected, func.span());
|
||||
let ret = self.visitor.assert_expected_option(func.output, expected, func.span());
|
||||
|
||||
if func.input.len() != input.arguments.len() {
|
||||
self.visitor.handler.emit_err(
|
||||
|
@ -79,6 +79,10 @@ const FIELD_GROUP_INT_TYPES: [Type; 12] = create_type_superset(FIELD_INT_TYPES,
|
||||
|
||||
const FIELD_GROUP_SCALAR_INT_TYPES: [Type; 13] = create_type_superset(FIELD_GROUP_INT_TYPES, [Type::Scalar]);
|
||||
|
||||
const FIELD_GROUP_TYPES: [Type; 2] = [Type::Field, Type::Group];
|
||||
|
||||
const FIELD_SCALAR_TYPES: [Type; 2] = [Type::Field, Type::Scalar];
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
/// Returns a new type checker given a symbol table and error handler.
|
||||
pub fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self {
|
||||
@ -116,28 +120,28 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the given type if it equals the expected type or the expected type is none.
|
||||
/// Use this method if the expected type is an unknown Option.
|
||||
pub(crate) fn assert_type(&mut self, type_: Type, expected: &Option<Type>, span: Span) -> Type {
|
||||
/// Returns the given `actual` type and emits an error if the `expected` type does not match.
|
||||
pub(crate) fn assert_expected_option(&mut self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(expected) = expected {
|
||||
if &type_ != expected {
|
||||
if &actual != expected {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(type_, expected, span).into());
|
||||
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
|
||||
}
|
||||
}
|
||||
|
||||
type_
|
||||
actual
|
||||
}
|
||||
|
||||
/// Emits an error if the given type_ does not match the expected type.
|
||||
/// Use this method if the expected type is known.
|
||||
pub(crate) fn assert_type_exact(&mut self, type_: &Option<Type>, expected: &Type, span: Span) {
|
||||
if let Some(type_) = type_ {
|
||||
if type_ != expected {
|
||||
/// Returns the given `expected` type and emits an error if the `actual` type does not match.
|
||||
pub(crate) fn assert_expected_type(&mut self, actual: &Option<Type>, expected: Type, span: Span) -> Type {
|
||||
if let Some(actual) = actual {
|
||||
if actual != &expected {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(type_, expected, span).into());
|
||||
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
|
||||
}
|
||||
}
|
||||
|
||||
expected
|
||||
}
|
||||
|
||||
/// Emits an error to the error handler if the given type is not equal to any of the expected types.
|
||||
@ -161,24 +165,15 @@ impl<'a> TypeChecker<'a> {
|
||||
self.assert_one_of_types(type_, &BOOL_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not an integer.
|
||||
pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32).
|
||||
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &MAGNITUDE_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or integer.
|
||||
pub(crate) fn assert_field_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, scalar, or integer.
|
||||
pub(crate) fn assert_field_scalar_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_SCALAR_INT_TYPES, span)
|
||||
/// Emits an error to the handler if the given type is not a field or group.
|
||||
pub(crate) fn assert_field_group_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, group, or integer.
|
||||
@ -190,4 +185,23 @@ impl<'a> TypeChecker<'a> {
|
||||
pub(crate) fn assert_field_group_scalar_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_SCALAR_INT_TYPES, span)
|
||||
}
|
||||
/// Emits an error to the handler if the given type is not a field or scalar.
|
||||
pub(crate) fn assert_field_scalar_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_SCALAR_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, scalar, or integer.
|
||||
pub(crate) fn assert_field_scalar_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_SCALAR_INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not an integer.
|
||||
pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &INT_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32).
|
||||
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &MAGNITUDE_TYPES, span)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user