feat: impl infer for new validators

This commit is contained in:
rvcas 2024-07-30 17:23:09 -04:00 committed by KtorZ
parent fff90f7df5
commit 1d9034573b
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
2 changed files with 112 additions and 106 deletions

View File

@ -489,15 +489,21 @@ If you really meant to return that last expression, try to replace it with the f
name: String, name: String,
}, },
#[error("I found a multi-validator where both take the same number of arguments.\n")] #[error(
#[diagnostic(code("illegal::multi_validator"))] "I stumbled upon an invalid (non-local) clause guard '{}'.\n",
#[diagnostic(help("Multi-validators cannot take the same number of arguments. One must take 3 arguments\nand the other must take 2 arguments. Both of these take {} arguments.", count.to_string().purple()))] name.if_supports_color(Stdout, |s| s.purple())
MultiValidatorEqualArgs { )]
#[label("{} here", count)] #[diagnostic(url(
"https://aiken-lang.org/language-tour/control-flow#checking-equality-and-ordering-in-patterns"
))]
#[diagnostic(code("illegal::clause_guard"))]
#[diagnostic(help(
"There are some conditions regarding what can be used in a guard. Values must be either local to the function, or defined as module constants. You can't use functions or records in there."
))]
NonLocalClauseGuardVariable {
#[label]
location: Span, location: Span,
#[label("and {} here", count)] name: String,
other_location: Span,
count: usize,
}, },
#[error("I tripped over an attempt to access elements on something that isn't indexable.\n")] #[error("I tripped over an attempt to access elements on something that isn't indexable.\n")]
@ -1021,7 +1027,8 @@ The best thing to do from here is to remove it."#))]
))] ))]
IncorrectValidatorArity { IncorrectValidatorArity {
count: u32, count: u32,
#[label("{} arguments", if *count < 2 { "not enough" } else { "too many" })] expected: u32,
#[label("{} arguments", if count < expected { "not enough" } else { "too many" })]
location: Span, location: Span,
}, },

View File

@ -9,10 +9,9 @@ use crate::{
ast::{ ast::{
Annotation, ArgName, ArgVia, DataType, Definition, Function, ModuleConstant, ModuleKind, Annotation, ArgName, ArgVia, DataType, Definition, Function, ModuleConstant, ModuleKind,
RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, TypedDefinition, RecordConstructor, RecordConstructorArg, Tracing, TypeAlias, TypedArg, TypedDefinition,
TypedFunction, TypedModule, UntypedDefinition, UntypedModule, Use, Validator, TypedFunction, TypedModule, UntypedArg, UntypedDefinition, UntypedModule, Use, Validator,
}, },
builtins, builtins::{self, fuzzer, generic_var},
builtins::{fuzzer, generic_var},
tipo::{expr::infer_function, Span, Type, TypeVar}, tipo::{expr::infer_function, Span, Type, TypeVar},
IdGenerator, IdGenerator,
}; };
@ -172,61 +171,24 @@ fn infer_definition(
doc, doc,
location, location,
end_position, end_position,
mut handlers, handlers,
fallback, mut fallback,
params, params,
name, name,
}) => { }) => {
let params_length = params.len(); let params_length = params.len();
environment.in_new_scope(|environment| { let mut typed_handlers = vec![];
let preregistered_fn = environment
.get_variable(&fun.name)
.expect("Could not find preregistered type for function");
let preregistered_type = preregistered_fn.tipo.clone(); for mut handler in handlers {
let typed_fun = environment.in_new_scope(|environment| {
let temp_params = params.iter().cloned().chain(handler.arguments);
handler.arguments = temp_params.collect();
let (args_types, _return_type) = preregistered_type put_params_in_scope(&handler.name, environment, &params);
.function_types()
.expect("Preregistered type for fn was not a fn");
for (ix, (arg, t)) in params
.iter()
.zip(args_types[0..params.len()].iter())
.enumerate()
{
match &arg.arg_name(ix) {
ArgName::Named {
name,
label: _,
location: _,
} if arg.is_validator_param => {
environment.insert_variable(
name.to_string(),
ValueConstructorVariant::LocalVariable {
location: arg.location,
},
t.clone(),
);
environment.init_usage(
name.to_string(),
EntityKind::Variable,
arg.location,
);
}
ArgName::Named { .. } | ArgName::Discarded { .. } => (),
};
}
let typed_handlers = vec![];
for handler in handlers {
let temp_params = params.iter().cloned().chain(fun.arguments);
fun.arguments = temp_params.collect();
let mut typed_fun = let mut typed_fun =
infer_function(&fun, module_name, hydrators, environment, lines, tracing)?; infer_function(&handler, module_name, hydrators, environment, tracing)?;
if !typed_fun.return_type.is_bool() { if !typed_fun.return_type.is_bool() {
return Err(Error::ValidatorMustReturnBool { return Err(Error::ValidatorMustReturnBool {
@ -235,9 +197,13 @@ fn infer_definition(
}); });
} }
typed_fun.arguments.drain(0..params_length);
// TODO: the expected number of args comes from the script purpose
if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 { if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 {
return Err(Error::IncorrectValidatorArity { return Err(Error::IncorrectValidatorArity {
count: typed_fun.arguments.len() as u32, count: typed_fun.arguments.len() as u32,
expected: 3,
location: typed_fun.location, location: typed_fun.location,
}); });
} }
@ -247,65 +213,61 @@ fn infer_definition(
arg.tipo = builtins::data(); arg.tipo = builtins::data();
} }
} }
}
let params = params.into_iter().chain(other.arguments); Ok(typed_fun)
other.arguments = params.collect(); })?;
let mut typed_fallback = typed_handlers.push(typed_fun);
infer_function(&other, module_name, hydrators, environment, lines, tracing)?; }
if !typed_fallback.return_type.is_bool() { let params = params.into_iter().chain(fallback.arguments);
return Err(Error::ValidatorMustReturnBool { fallback.arguments = params.collect();
return_type: typed_fallback.return_type.clone(),
location: typed_fallback.location,
});
}
typed_fallback.arguments.drain(0..params_length); let mut typed_fallback =
infer_function(&fallback, module_name, hydrators, environment, tracing)?;
if typed_fallback.arguments.len() < 2 || typed_fallback.arguments.len() > 3 { if !typed_fallback.return_type.is_bool() {
return Err(Error::IncorrectValidatorArity { return Err(Error::ValidatorMustReturnBool {
count: typed_fallback.arguments.len() as u32, return_type: typed_fallback.return_type.clone(),
location: typed_fallback.location, location: typed_fallback.location,
}); });
} }
if typed_fun.arguments.len() == typed_fallback.arguments.len() { let typed_params = typed_fallback
return Err(Error::MultiValidatorEqualArgs { .arguments
location: typed_fun.location, .drain(0..params_length)
other_location: typed_fallback.location, .map(|mut arg| {
count: typed_fallback.arguments.len(),
});
}
for arg in typed_fallback.arguments.iter_mut() {
if arg.tipo.is_unbound() { if arg.tipo.is_unbound() {
arg.tipo = builtins::data(); arg.tipo = builtins::data();
} }
arg
})
.collect();
if typed_fallback.arguments.len() != 1 {
return Err(Error::IncorrectValidatorArity {
count: typed_fallback.arguments.len() as u32,
expected: 1,
location: typed_fallback.location,
});
}
for arg in typed_fallback.arguments.iter_mut() {
if arg.tipo.is_unbound() {
arg.tipo = builtins::data();
} }
}
let typed_params = params Ok(Definition::Validator(Validator {
.into_iter() doc,
.map(|mut arg| { end_position,
if arg.tipo.is_unbound() { handlers: typed_handlers,
arg.tipo = builtins::data(); fallback: typed_fallback,
} name,
location,
arg params: typed_params,
}) }))
.collect();
Ok(Definition::Validator(Validator {
doc,
end_position,
handlers: typed_handlers,
fallback: typed_fallback,
name,
location,
params: typed_params,
}))
})
} }
Definition::Test(f) => { Definition::Test(f) => {
@ -777,3 +739,40 @@ fn annotate_fuzzer(tipo: &Type, location: &Span) -> Result<Annotation, Error> {
} }
} }
} }
fn put_params_in_scope(name: &str, environment: &mut Environment, params: &[UntypedArg]) {
let preregistered_fn = environment
.get_variable(&name)
.expect("Could not find preregistered type for function");
let preregistered_type = preregistered_fn.tipo.clone();
let (args_types, _return_type) = preregistered_type
.function_types()
.expect("Preregistered type for fn was not a fn");
for (ix, (arg, t)) in params
.iter()
.zip(args_types[0..params.len()].iter())
.enumerate()
{
match &arg.arg_name(ix) {
ArgName::Named {
name,
label: _,
location: _,
} if arg.is_validator_param => {
environment.insert_variable(
name.to_string(),
ValueConstructorVariant::LocalVariable {
location: arg.location,
},
t.clone(),
);
environment.init_usage(name.to_string(), EntityKind::Variable, arg.location);
}
ArgName::Named { .. } | ArgName::Discarded { .. } => (),
};
}
}