1
0
dust/dust-lang/src/type.rs

790 lines
24 KiB
Rust
Raw Normal View History

2024-08-09 02:44:34 +00:00
//! Description of a kind of value.
//!
//! Most types are concrete and specific, the exceptions are the Generic and Any types.
//!
//! Generic types are temporary placeholders that describe a type that will be defined later. The
//! interpreter should use the analysis phase to enforce that all Generic types have a concrete
//! type assigned to them before the program is run.
//!
//! The Any type is used in cases where a value's type does not matter. For example, the standard
//! library's "length" function does not care about the type of item in the list, only the list
//! itself. So the input is defined as `[any]`, i.e. `Type::ListOf(Box::new(Type::Any))`.
2024-06-24 08:02:44 +00:00
use std::{
2024-08-17 08:06:13 +00:00
cmp::Ordering,
collections::HashMap,
2024-06-24 08:02:44 +00:00
fmt::{self, Display, Formatter},
};
2024-03-07 03:15:35 +00:00
2024-06-04 18:47:15 +00:00
use serde::{Deserialize, Serialize};
2024-03-20 12:36:18 +00:00
2024-08-20 04:15:19 +00:00
use crate::{Enum, Identifier, Struct, Value};
2024-07-15 19:49:34 +00:00
/// Description of a kind of value.
///
/// See the [module documentation](index.html) for more information.
2024-08-17 14:07:38 +00:00
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Type {
2024-03-06 17:15:03 +00:00
Any,
Boolean,
2024-08-16 21:07:49 +00:00
Byte,
Character,
Enum(EnumType),
Float,
2024-08-16 21:07:49 +00:00
Function(FunctionType),
2024-06-19 04:05:58 +00:00
Generic {
identifier: Identifier,
concrete_type: Option<Box<Type>>,
},
Integer,
2024-06-17 14:10:06 +00:00
List {
item_type: Box<Type>,
length: usize,
},
2024-08-16 21:07:49 +00:00
ListEmpty,
ListOf {
item_type: Box<Type>,
2024-06-17 14:10:06 +00:00
},
2024-08-17 14:07:38 +00:00
Map {
pairs: HashMap<Identifier, Type>,
},
2024-08-11 23:00:37 +00:00
Number,
2024-08-17 14:07:38 +00:00
Range {
r#type: RangeableType,
},
String,
2024-08-13 17:28:22 +00:00
Struct(StructType),
2024-08-20 04:15:19 +00:00
Tuple(Vec<Type>),
}
2024-03-06 17:15:03 +00:00
impl Type {
/// Returns a concrete type, either the type itself or the concrete type of a generic type.
pub fn concrete_type(&self) -> &Type {
match self {
Type::Generic {
concrete_type: Some(concrete_type),
..
} => concrete_type.concrete_type(),
_ => self,
}
}
/// Checks that the type is compatible with another type.
2024-03-17 04:49:01 +00:00
pub fn check(&self, other: &Type) -> Result<(), TypeConflict> {
match (self.concrete_type(), other.concrete_type()) {
2024-03-06 17:15:03 +00:00
(Type::Any, _)
| (_, Type::Any)
| (Type::Boolean, Type::Boolean)
| (Type::Float, Type::Float)
| (Type::Integer, Type::Integer)
2024-03-20 05:29:07 +00:00
| (Type::String, Type::String) => return Ok(()),
2024-06-19 04:05:58 +00:00
(
Type::Generic {
concrete_type: left,
..
},
Type::Generic {
concrete_type: right,
..
},
) => match (left, right) {
2024-06-17 21:38:24 +00:00
(Some(left), Some(right)) => {
2024-07-12 14:20:52 +00:00
if left.check(right).is_ok() {
2024-06-17 21:38:24 +00:00
return Ok(());
}
}
(None, None) => {
return Ok(());
}
_ => {}
},
2024-06-19 04:05:58 +00:00
(Type::Generic { concrete_type, .. }, other)
| (other, Type::Generic { concrete_type, .. }) => {
if let Some(concrete_type) = concrete_type {
if other == concrete_type.as_ref() {
return Ok(());
}
}
}
2024-08-13 17:28:22 +00:00
(Type::Struct(left_struct_type), Type::Struct(right_struct_type)) => {
if left_struct_type == right_struct_type {
2024-03-20 05:29:07 +00:00
return Ok(());
}
}
2024-06-17 15:02:13 +00:00
(
Type::List {
item_type: left_type,
length: left_length,
2024-06-17 15:02:13 +00:00
},
Type::List {
item_type: right_type,
length: right_length,
2024-06-17 15:02:13 +00:00
},
) => {
if left_length != right_length {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
2024-08-11 23:18:13 +00:00
if left_type.check(right_type).is_err() {
2024-06-17 15:02:13 +00:00
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
return Ok(());
}
(
Type::ListOf {
item_type: left_type,
},
Type::ListOf {
item_type: right_type,
},
) => {
if left_type.check(right_type).is_err() {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
}
(
Type::List {
item_type: list_item_type,
..
},
Type::ListOf {
item_type: list_of_item_type,
},
)
| (
Type::ListOf {
item_type: list_of_item_type,
},
Type::List {
item_type: list_item_type,
..
},
) => {
// TODO: This is a hack, remove it.
if let Type::Any = **list_of_item_type {
return Ok(());
}
if list_item_type.check(list_of_item_type).is_err() {
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
}
2024-03-20 05:29:07 +00:00
(
2024-08-16 21:07:49 +00:00
Type::Function(FunctionType {
name: left_name,
2024-06-17 14:10:06 +00:00
type_parameters: left_type_parameters,
value_parameters: left_value_parameters,
2024-03-20 12:36:18 +00:00
return_type: left_return,
2024-08-16 21:07:49 +00:00
}),
Type::Function(FunctionType {
name: right_name,
2024-06-17 14:10:06 +00:00
type_parameters: right_type_parameters,
value_parameters: right_value_parameters,
2024-03-20 12:36:18 +00:00
return_type: right_return,
2024-08-16 21:07:49 +00:00
}),
2024-03-20 05:29:07 +00:00
) => {
2024-08-17 14:07:38 +00:00
if left_name != right_name
|| left_return != right_return
|| left_type_parameters != right_type_parameters
|| left_value_parameters != right_value_parameters
{
2024-08-16 21:07:49 +00:00
return Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
});
}
2024-08-17 14:07:38 +00:00
return Ok(());
}
(Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => {
if left_type == right_type {
2024-03-20 05:29:07 +00:00
return Ok(());
}
}
2024-08-11 23:00:37 +00:00
(Type::Number, Type::Number | Type::Integer | Type::Float)
| (Type::Integer | Type::Float, Type::Number) => {
return Ok(());
}
2024-03-20 05:29:07 +00:00
_ => {}
2024-03-06 17:15:03 +00:00
}
2024-03-20 05:29:07 +00:00
Err(TypeConflict {
actual: other.clone(),
expected: self.clone(),
})
2024-03-06 17:15:03 +00:00
}
}
2024-03-07 03:15:35 +00:00
impl Display for Type {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Type::Any => write!(f, "any"),
2024-03-23 21:07:41 +00:00
Type::Boolean => write!(f, "bool"),
2024-08-16 21:07:49 +00:00
Type::Byte => write!(f, "byte"),
Type::Character => write!(f, "char"),
2024-08-17 14:07:38 +00:00
Type::Enum(EnumType { name, .. }) => write!(f, "{name}"),
2024-03-07 03:15:35 +00:00
Type::Float => write!(f, "float"),
2024-08-16 21:07:49 +00:00
Type::Function(function_type) => write!(f, "{function_type}"),
2024-06-19 04:05:58 +00:00
Type::Generic { concrete_type, .. } => {
2024-06-26 15:35:39 +00:00
match concrete_type.clone().map(|r#box| *r#box) {
Some(Type::Generic { identifier, .. }) => write!(f, "{identifier}"),
Some(concrete_type) => write!(f, "implied to be {concrete_type}"),
None => write!(f, "unknown"),
2024-06-17 21:38:24 +00:00
}
}
2024-03-23 21:07:41 +00:00
Type::Integer => write!(f, "int"),
Type::List { item_type, length } => write!(f, "[{item_type}; {length}]"),
2024-08-16 21:07:49 +00:00
Type::ListEmpty => write!(f, "[]"),
2024-08-16 09:14:00 +00:00
Type::ListOf { item_type } => write!(f, "[{item_type}]"),
2024-08-17 14:07:38 +00:00
Type::Map { pairs } => {
write!(f, "map ")?;
write!(f, "{{")?;
for (index, (key, value)) in pairs.iter().enumerate() {
write!(f, "{key}: {value}")?;
if index != pairs.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
2024-08-16 21:07:49 +00:00
Type::Number => write!(f, "num"),
2024-08-17 14:07:38 +00:00
Type::Range { r#type } => write!(f, "{type} range"),
2024-08-16 21:07:49 +00:00
Type::String => write!(f, "str"),
2024-08-20 04:15:19 +00:00
Type::Struct(struct_type) => write!(f, "{struct_type}"),
Type::Tuple(fields) => {
2024-08-16 21:07:49 +00:00
write!(f, "(")?;
2024-06-24 08:02:44 +00:00
2024-08-16 21:07:49 +00:00
for (index, r#type) in fields.iter().enumerate() {
write!(f, "{type}")?;
2024-06-24 08:16:05 +00:00
2024-08-16 21:07:49 +00:00
if index != fields.len() - 1 {
2024-06-24 08:16:05 +00:00
write!(f, ", ")?;
}
2024-06-24 08:02:44 +00:00
}
2024-08-16 21:07:49 +00:00
write!(f, ")")
2024-06-24 08:02:44 +00:00
}
2024-08-16 21:07:49 +00:00
}
}
}
2024-03-09 02:26:49 +00:00
2024-08-17 14:07:38 +00:00
impl PartialOrd for Type {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Type {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Type::Any, Type::Any) => Ordering::Equal,
(Type::Any, _) => Ordering::Greater,
(Type::Boolean, Type::Boolean) => Ordering::Equal,
(Type::Boolean, _) => Ordering::Greater,
(Type::Byte, Type::Byte) => Ordering::Equal,
(Type::Byte, _) => Ordering::Greater,
(Type::Character, Type::Character) => Ordering::Equal,
(Type::Character, _) => Ordering::Greater,
(Type::Enum(left_enum), Type::Enum(right_enum)) => left_enum.cmp(right_enum),
(Type::Enum(_), _) => Ordering::Greater,
(Type::Float, Type::Float) => Ordering::Equal,
(Type::Float, _) => Ordering::Greater,
(Type::Function(left_function), Type::Function(right_function)) => {
left_function.cmp(right_function)
}
(Type::Function(_), _) => Ordering::Greater,
(Type::Generic { .. }, Type::Generic { .. }) => Ordering::Equal,
(Type::Generic { .. }, _) => Ordering::Greater,
(Type::Integer, Type::Integer) => Ordering::Equal,
(Type::Integer, _) => Ordering::Greater,
(
Type::List {
item_type: left_item_type,
length: left_length,
},
Type::List {
item_type: right_item_type,
length: right_length,
},
) => {
if left_length == right_length {
left_item_type.cmp(right_item_type)
} else {
left_length.cmp(right_length)
}
}
(Type::List { .. }, _) => Ordering::Greater,
(Type::ListEmpty, Type::ListEmpty) => Ordering::Equal,
(Type::ListEmpty, _) => Ordering::Greater,
(
Type::ListOf {
item_type: left_item_type,
},
Type::ListOf {
item_type: right_item_type,
},
) => left_item_type.cmp(right_item_type),
(Type::ListOf { .. }, _) => Ordering::Greater,
(Type::Map { pairs: left_pairs }, Type::Map { pairs: right_pairs }) => {
left_pairs.iter().cmp(right_pairs.iter())
}
(Type::Map { .. }, _) => Ordering::Greater,
(Type::Number, Type::Number) => Ordering::Equal,
(Type::Number, _) => Ordering::Greater,
(Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => {
left_type.cmp(right_type)
}
(Type::Range { .. }, _) => Ordering::Greater,
(Type::String, Type::String) => Ordering::Equal,
(Type::String, _) => Ordering::Greater,
(Type::Struct(left_struct), Type::Struct(right_struct)) => {
left_struct.cmp(right_struct)
}
(Type::Struct(_), _) => Ordering::Greater,
(Type::Tuple(left_tuple), Type::Tuple(right_tuple)) => left_tuple.cmp(right_tuple),
(Type::Tuple(_), _) => Ordering::Greater,
}
}
}
2024-08-16 21:07:49 +00:00
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionType {
pub name: Identifier,
pub type_parameters: Option<Vec<Type>>,
pub value_parameters: Option<Vec<(Identifier, Type)>>,
pub return_type: Option<Box<Type>>,
}
2024-06-26 18:44:23 +00:00
2024-08-16 21:07:49 +00:00
impl Display for FunctionType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "fn ")?;
2024-06-17 14:10:06 +00:00
2024-08-16 21:07:49 +00:00
if let Some(type_parameters) = &self.type_parameters {
write!(f, "<")?;
2024-06-17 14:10:06 +00:00
2024-08-16 21:07:49 +00:00
for (index, type_parameter) in type_parameters.iter().enumerate() {
write!(f, "{type_parameter}")?;
2024-06-26 18:44:23 +00:00
2024-08-16 21:07:49 +00:00
if index != type_parameters.len() - 1 {
write!(f, ", ")?;
2024-03-09 02:26:49 +00:00
}
2024-08-16 21:07:49 +00:00
}
2024-03-09 02:26:49 +00:00
2024-08-16 21:07:49 +00:00
write!(f, ">")?;
}
write!(f, "(")?;
if let Some(value_parameters) = &self.value_parameters {
for (index, (identifier, r#type)) in value_parameters.iter().enumerate() {
write!(f, "{identifier}: {type}")?;
2024-06-22 04:58:30 +00:00
2024-08-16 21:07:49 +00:00
if index != value_parameters.len() - 1 {
write!(f, ", ")?;
2024-06-22 04:58:30 +00:00
}
2024-03-09 02:26:49 +00:00
}
2024-08-13 17:28:22 +00:00
}
2024-08-16 21:07:49 +00:00
write!(f, ")")?;
if let Some(return_type) = &self.return_type {
write!(f, " -> {return_type}")?;
}
Ok(())
2024-08-13 17:28:22 +00:00
}
}
2024-08-20 04:15:19 +00:00
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
2024-08-13 17:28:22 +00:00
pub enum StructType {
2024-08-20 04:15:19 +00:00
Unit {
name: Identifier,
},
Tuple {
name: Identifier,
fields: Vec<Type>,
},
Fields {
name: Identifier,
fields: HashMap<Identifier, Type>,
},
2024-08-13 17:28:22 +00:00
}
2024-08-20 04:15:19 +00:00
impl StructType {
pub fn name(&self) -> &Identifier {
2024-08-13 17:28:22 +00:00
match self {
2024-08-20 04:15:19 +00:00
StructType::Unit { name } => name,
StructType::Tuple { name, .. } => name,
StructType::Fields { name, .. } => name,
2024-03-07 03:15:35 +00:00
}
}
2024-08-20 04:15:19 +00:00
pub fn constructor(&self) -> Option<Constructor> {
let constructor = match self {
StructType::Unit { name } => Constructor::Unit { name: name.clone() },
StructType::Tuple { name, fields } => Constructor::Tuple(TupleConstructor {
name: name.clone(),
tuple_arguments: Vec::with_capacity(fields.len()),
}),
StructType::Fields { name, fields } => Constructor::Fields {
name: name.clone(),
field_arguments: HashMap::with_capacity(fields.len()),
},
};
Some(constructor)
}
2024-08-17 08:06:13 +00:00
}
2024-08-20 04:15:19 +00:00
impl Display for StructType {
2024-08-17 14:07:38 +00:00
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
2024-08-20 04:15:19 +00:00
match self {
StructType::Unit { name } => write!(f, "{name}"),
StructType::Tuple { name, fields } => {
write!(f, "{name}(")?;
2024-08-17 14:07:38 +00:00
2024-08-20 04:15:19 +00:00
for (index, field) in fields.iter().enumerate() {
write!(f, "{field}")?;
2024-08-17 14:07:38 +00:00
2024-08-20 04:15:19 +00:00
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
2024-08-17 14:07:38 +00:00
}
2024-08-20 04:15:19 +00:00
StructType::Fields { name, fields } => {
write!(f, "{name} {{")?;
for (index, (identifier, r#type)) in fields.iter().enumerate() {
write!(f, "{identifier}: {type}")?;
if index != fields.len() - 1 {
write!(f, ", ")?;
}
}
2024-08-17 14:07:38 +00:00
2024-08-20 04:15:19 +00:00
write!(f, "}}")
}
}
2024-08-17 14:07:38 +00:00
}
}
2024-08-20 04:15:19 +00:00
impl PartialOrd for StructType {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
2024-08-17 08:06:13 +00:00
}
2024-08-20 04:15:19 +00:00
impl Ord for StructType {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(StructType::Unit { name: left_name }, StructType::Unit { name: right_name }) => {
left_name.cmp(right_name)
}
(StructType::Unit { .. }, _) => Ordering::Greater,
(
StructType::Tuple {
name: left_name,
fields: left_fields,
},
StructType::Tuple {
name: right_name,
fields: right_fields,
},
) => {
let name_cmp = left_name.cmp(right_name);
if name_cmp == Ordering::Equal {
left_fields.cmp(right_fields)
} else {
name_cmp
}
}
(StructType::Tuple { .. }, _) => Ordering::Greater,
(
StructType::Fields {
name: left_name,
fields: left_fields,
},
StructType::Fields {
name: right_name,
fields: right_fields,
},
) => {
let name_cmp = left_name.cmp(right_name);
2024-08-17 14:07:38 +00:00
2024-08-20 04:15:19 +00:00
if name_cmp == Ordering::Equal {
let len_cmp = left_fields.len().cmp(&right_fields.len());
2024-08-17 14:07:38 +00:00
2024-08-20 04:15:19 +00:00
if len_cmp == Ordering::Equal {
left_fields.iter().cmp(right_fields.iter())
} else {
len_cmp
}
} else {
name_cmp
}
2024-08-17 14:07:38 +00:00
}
2024-08-20 04:15:19 +00:00
(StructType::Fields { .. }, _) => Ordering::Greater,
2024-08-17 14:07:38 +00:00
}
}
}
2024-08-20 04:15:19 +00:00
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Constructor {
Unit {
name: Identifier,
},
Tuple(TupleConstructor),
Fields {
name: Identifier,
field_arguments: HashMap<Identifier, Value>,
},
Enum {
name: Identifier,
r#type: EnumType,
variant_constructor: Box<Constructor>,
},
}
impl Constructor {
pub fn construct(self) -> Value {
match self {
Constructor::Unit { name } => Value::Struct(Struct::Unit { name }),
Constructor::Tuple(tuple_constructor) => tuple_constructor.construct(),
Constructor::Fields {
name,
field_arguments,
} => Value::Struct(Struct::Fields {
name,
fields: field_arguments,
}),
Constructor::Enum {
name,
r#type,
variant_constructor,
} => Value::Enum(Enum {
name,
r#type,
variant_data: Self::make_struct(*variant_constructor),
}),
}
}
fn make_struct(this: Self) -> Struct {
match this {
Constructor::Unit { name } => Struct::Unit { name },
Constructor::Tuple(TupleConstructor {
name,
tuple_arguments,
}) => Struct::Tuple {
name,
fields: tuple_arguments,
},
Constructor::Fields {
name,
field_arguments,
} => Struct::Fields {
name,
fields: field_arguments,
},
Constructor::Enum {
variant_constructor,
..
} => Self::make_struct(*variant_constructor),
}
2024-08-17 08:06:13 +00:00
}
}
2024-08-20 04:15:19 +00:00
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TupleConstructor {
pub name: Identifier,
pub tuple_arguments: Vec<Value>,
}
impl TupleConstructor {
pub fn push_argument(&mut self, value: Value) {
self.tuple_arguments.push(value);
}
pub fn construct(self) -> Value {
Value::Struct(Struct::Tuple {
name: self.name,
fields: self.tuple_arguments,
})
2024-08-17 08:06:13 +00:00
}
}
2024-08-16 21:07:49 +00:00
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct EnumType {
2024-08-20 04:15:19 +00:00
pub name: Identifier,
pub variants: Vec<StructType>,
}
impl EnumType {
pub fn constructor(&self) -> Option<Constructor> {
let get_variant_constructor = self
.variants
.iter()
.find_map(|struct_type| struct_type.constructor());
if let Some(variant_constructor) = get_variant_constructor {
Some(Constructor::Enum {
name: self.name.clone(),
r#type: self.clone(),
variant_constructor: Box::new(variant_constructor),
})
} else {
None
}
}
2024-08-16 21:07:49 +00:00
}
impl Display for EnumType {
2024-08-17 14:07:38 +00:00
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let EnumType { name, variants } = self;
2024-08-20 04:15:19 +00:00
write!(f, "enum {name} {{ ")?;
2024-08-17 14:07:38 +00:00
for (index, variant) in variants.iter().enumerate() {
write!(f, "{variant}")?;
if index != self.variants.len() - 1 {
write!(f, ", ")?;
}
}
2024-08-20 04:15:19 +00:00
write!(f, " }}")
2024-08-17 14:07:38 +00:00
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum RangeableType {
Byte,
Character,
Float,
Integer,
}
impl Display for RangeableType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
RangeableType::Byte => Type::Byte.fmt(f),
RangeableType::Character => Type::Character.fmt(f),
RangeableType::Float => Type::Float.fmt(f),
RangeableType::Integer => Type::Integer.fmt(f),
}
2024-08-16 21:07:49 +00:00
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TypeConflict {
pub expected: Type,
pub actual: Type,
}
2024-03-06 17:15:03 +00:00
#[cfg(test)]
mod tests {
use super::*;
#[test]
2024-08-16 21:07:49 +00:00
fn check_type_any() {
let foo = Type::Any;
let bar = Type::Any;
foo.check(&bar).unwrap();
}
2024-06-17 14:10:06 +00:00
2024-08-16 21:07:49 +00:00
#[test]
fn check_type_boolean() {
let foo = Type::Boolean;
let bar = Type::Boolean;
foo.check(&bar).unwrap();
}
2024-06-24 08:02:44 +00:00
2024-08-16 21:07:49 +00:00
#[test]
fn check_type_byte() {
let foo = Type::Byte;
let bar = Type::Byte;
foo.check(&bar).unwrap();
}
#[test]
fn check_type_character() {
let foo = Type::Character;
let bar = Type::Character;
2024-06-24 08:02:44 +00:00
2024-08-16 21:07:49 +00:00
foo.check(&bar).unwrap();
}
2024-03-06 17:15:03 +00:00
#[test]
fn errors() {
2024-03-19 21:18:36 +00:00
let foo = Type::Integer;
let bar = Type::String;
2024-03-06 17:15:03 +00:00
assert_eq!(
foo.check(&bar),
2024-03-17 04:49:01 +00:00
Err(TypeConflict {
2024-03-06 17:15:03 +00:00
actual: bar.clone(),
expected: foo.clone()
})
);
assert_eq!(
bar.check(&foo),
2024-03-17 04:49:01 +00:00
Err(TypeConflict {
2024-03-06 17:15:03 +00:00
actual: foo.clone(),
expected: bar.clone()
})
);
let types = [
Type::Boolean,
Type::Float,
Type::Integer,
2024-06-17 14:10:06 +00:00
Type::List {
item_type: Box::new(Type::Integer),
length: 42,
2024-06-17 14:10:06 +00:00
},
2024-08-17 14:07:38 +00:00
Type::Range {
r#type: RangeableType::Integer,
},
2024-03-06 17:15:03 +00:00
Type::String,
];
2024-06-22 04:58:30 +00:00
for left in types.clone() {
for right in types.clone() {
if left == right {
continue;
}
2024-03-06 17:15:03 +00:00
2024-06-22 04:58:30 +00:00
assert_eq!(
left.check(&right),
Err(TypeConflict {
actual: right.clone(),
expected: left.clone()
})
);
}
2024-03-06 17:15:03 +00:00
}
}
}