feat: return err if data type contains functions

Due to how PlutusData works it doesn't make sense
to allow user defined types to contain
functions.

```
type Foo {
  bar: fn(Int) -> Int
}
```

The above definition will now return an error.
This commit is contained in:
rvcas 2023-01-14 20:25:46 -05:00 committed by Lucas
parent 95c9be5c52
commit b69c1f66d7
3 changed files with 30 additions and 4 deletions

View File

@ -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<Arc<Self>> {
match self {
Self::Fn { ret, .. } => Some(ret.clone()),

View File

@ -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",
)),

View File

@ -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 {