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

View File

@ -47,6 +47,9 @@ pub enum Error {
name: String, 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())] #[error("I saw a {} fields in a context where there should be {}.\n", given.purple(), expected.purple())]
IncorrectFieldsArity { IncorrectFieldsArity {
location: Span, location: Span,
@ -365,6 +368,7 @@ impl Diagnostic for Error {
Self::DuplicateField { .. } => Some(Box::new("duplicate_field")), Self::DuplicateField { .. } => Some(Box::new("duplicate_field")),
Self::DuplicateName { .. } => Some(Box::new("duplicate_name")), Self::DuplicateName { .. } => Some(Box::new("duplicate_name")),
Self::DuplicateTypeName { .. } => Some(Box::new("duplicate_type_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::IncorrectFieldsArity { .. } => Some(Box::new("incorrect_fields_arity")),
Self::IncorrectFunctionCallArity { .. } => Some(Box::new("incorrect_fn_arity")), Self::IncorrectFunctionCallArity { .. } => Some(Box::new("incorrect_fn_arity")),
Self::IncorrectPatternArity { .. } => Some(Box::new("incorrect_pattern_arity")), Self::IncorrectPatternArity { .. } => Some(Box::new("incorrect_pattern_arity")),
@ -478,6 +482,8 @@ impl Diagnostic for Error {
, cannot = "cannot".red() , 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::IncorrectFieldsArity { .. } => None,
Self::IncorrectFunctionCallArity { expected, .. } => Some(Box::new(formatdoc! { Self::IncorrectFunctionCallArity { expected, .. } => Some(Box::new(formatdoc! {
@ -1134,6 +1140,9 @@ impl Diagnostic for Error {
Self::DuplicateTypeName { location, .. } => Some(Box::new( Self::DuplicateTypeName { location, .. } => Some(Box::new(
vec![LabeledSpan::new_with_span(None, *location)].into_iter(), 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( Self::IncorrectFieldsArity { location, .. } => Some(Box::new(
vec![LabeledSpan::new_with_span(None, *location)].into_iter(), vec![LabeledSpan::new_with_span(None, *location)].into_iter(),
)), )),
@ -1262,6 +1271,7 @@ impl Diagnostic for Error {
Self::DuplicateField { .. } => None, Self::DuplicateField { .. } => None,
Self::DuplicateName { .. } => None, Self::DuplicateName { .. } => None,
Self::DuplicateTypeName { .. } => None, Self::DuplicateTypeName { .. } => None,
Self::FunctionTypeInData { .. } => None,
Self::IncorrectFieldsArity { .. } => Some(Box::new( Self::IncorrectFieldsArity { .. } => Some(Box::new(
"https://aiken-lang.org/language-tour/custom-types", "https://aiken-lang.org/language-tour/custom-types",
)), )),

View File

@ -281,10 +281,10 @@ fn infer_definition(
opaque, opaque,
name, name,
parameters, parameters,
constructors, constructors: untyped_constructors,
.. ..
}) => { }) => {
let constructors = constructors let constructors = untyped_constructors
.into_iter() .into_iter()
.map( .map(
|RecordConstructor { |RecordConstructor {
@ -346,7 +346,7 @@ fn infer_definition(
.parameters .parameters
.clone(); .clone();
Ok(Definition::DataType(DataType { let typed_data = DataType {
doc, doc,
location, location,
public, public,
@ -355,7 +355,19 @@ fn infer_definition(
parameters, parameters,
constructors, constructors,
typed_parameters, 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 { Definition::Use(Use {