diff --git a/crates/aiken-lang/src/tipo.rs b/crates/aiken-lang/src/tipo.rs index 102baeb3..a60a5183 100644 --- a/crates/aiken-lang/src/tipo.rs +++ b/crates/aiken-lang/src/tipo.rs @@ -73,6 +73,10 @@ impl Type { matches!(self, Self::Var { tipo } if tipo.borrow().is_unbound()) } + pub fn is_function(&self) -> bool { + matches!(self, Self::Fn { .. }) + } + pub fn return_type(&self) -> Option> { match self { Self::Fn { ret, .. } => Some(ret.clone()), diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 7a816c46..50e8fb96 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -47,6 +47,9 @@ pub enum Error { name: String, }, + #[error("I found a data type that has a function type in it. This is not allowed.")] + FunctionTypeInData { location: Span }, + #[error("I saw a {} fields in a context where there should be {}.\n", given.purple(), expected.purple())] IncorrectFieldsArity { location: Span, @@ -365,6 +368,7 @@ impl Diagnostic for Error { Self::DuplicateField { .. } => Some(Box::new("duplicate_field")), Self::DuplicateName { .. } => Some(Box::new("duplicate_name")), Self::DuplicateTypeName { .. } => Some(Box::new("duplicate_type_name")), + Self::FunctionTypeInData { .. } => Some(Box::new("function_type_in_data")), Self::IncorrectFieldsArity { .. } => Some(Box::new("incorrect_fields_arity")), Self::IncorrectFunctionCallArity { .. } => Some(Box::new("incorrect_fn_arity")), Self::IncorrectPatternArity { .. } => Some(Box::new("incorrect_pattern_arity")), @@ -478,6 +482,8 @@ impl Diagnostic for Error { , cannot = "cannot".red() })), + Self::FunctionTypeInData { .. } => Some(Box::new("Data types can't have functions in them due to how Plutus Data works.")), + Self::IncorrectFieldsArity { .. } => None, Self::IncorrectFunctionCallArity { expected, .. } => Some(Box::new(formatdoc! { @@ -1134,6 +1140,9 @@ impl Diagnostic for Error { Self::DuplicateTypeName { location, .. } => Some(Box::new( vec![LabeledSpan::new_with_span(None, *location)].into_iter(), )), + Self::FunctionTypeInData { location } => Some(Box::new( + vec![LabeledSpan::new_with_span(None, *location)].into_iter(), + )), Self::IncorrectFieldsArity { location, .. } => Some(Box::new( vec![LabeledSpan::new_with_span(None, *location)].into_iter(), )), @@ -1262,6 +1271,7 @@ impl Diagnostic for Error { Self::DuplicateField { .. } => None, Self::DuplicateName { .. } => None, Self::DuplicateTypeName { .. } => None, + Self::FunctionTypeInData { .. } => None, Self::IncorrectFieldsArity { .. } => Some(Box::new( "https://aiken-lang.org/language-tour/custom-types", )), diff --git a/crates/aiken-lang/src/tipo/infer.rs b/crates/aiken-lang/src/tipo/infer.rs index d164ce3b..4cce3df4 100644 --- a/crates/aiken-lang/src/tipo/infer.rs +++ b/crates/aiken-lang/src/tipo/infer.rs @@ -281,10 +281,10 @@ fn infer_definition( opaque, name, parameters, - constructors, + constructors: untyped_constructors, .. }) => { - let constructors = constructors + let constructors = untyped_constructors .into_iter() .map( |RecordConstructor { @@ -346,7 +346,7 @@ fn infer_definition( .parameters .clone(); - Ok(Definition::DataType(DataType { + let typed_data = DataType { doc, location, public, @@ -355,7 +355,19 @@ fn infer_definition( parameters, constructors, typed_parameters, - })) + }; + + for constr in &typed_data.constructors { + for RecordConstructorArg { tipo, location, .. } in &constr.arguments { + if tipo.is_function() { + return Err(Error::FunctionTypeInData { + location: *location, + }); + } + } + } + + Ok(Definition::DataType(typed_data)) } Definition::Use(Use {