fix: more test and issues with scoping/names

This commit is contained in:
rvcas 2024-08-08 14:37:14 -04:00 committed by KtorZ
parent cf3180996a
commit f94e40daf4
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
6 changed files with 137 additions and 127 deletions

View File

@ -241,6 +241,10 @@ impl TypedExpr {
)
}
pub fn is_error_term(&self) -> bool {
matches!(self, Self::ErrorTerm { .. })
}
/// Returns `true` if the typed expr is [`Assignment`].
pub fn is_assignment(&self) -> bool {
matches!(self, Self::Assignment { .. })

View File

@ -318,19 +318,17 @@ fn mark_constructors_as_used_via_field_access() {
bar: Int,
}
validator foo {
spend(d: Datum, _r, _c) {
when d is {
D0(params) -> params.foo == 1
D1(_params) -> False
}
fn spend(d: Datum, _r, _c) {
when d is {
D0(params) -> params.foo == 1
D1(_params) -> False
}
}
"#;
let (warnings, _) = check_validator(parse(source_code)).unwrap();
let (warnings, _) = check(parse(source_code)).unwrap();
assert_eq!(warnings.len(), 1)
assert_eq!(warnings.len(), 2)
}
#[test]
@ -2506,27 +2504,6 @@ fn validator_public() {
assert!(check_validator(parse(source_code)).is_ok())
}
#[test]
fn validator_private_everything() {
let source_code = r#"
type Datum {
foo: Int,
}
type Redeemer {
bar: Int,
}
validator bar {
spend(datum: Datum, redeemer: Redeemer, _ctx) {
datum.foo == redeemer.bar
}
}
"#;
assert!(check_validator(parse(source_code)).is_ok())
}
#[test]
fn tuple_access_on_call() {
let source_code = r#"

View File

@ -309,29 +309,43 @@ impl<'a> Environment<'a> {
end_position,
handlers,
name,
fallback,
mut fallback,
location,
params,
}) => {
let handlers = handlers
.into_iter()
.map(|fun| {
let Definition::Fn(fun) =
.map(|mut fun| {
let handler_name = format!("{}_{}", &name, &fun.name);
let old_name = fun.name;
fun.name = handler_name;
let Definition::Fn(mut fun) =
self.generalise_definition(Definition::Fn(fun), module_name)
else {
unreachable!()
};
fun.name = old_name;
fun
})
.collect();
let Definition::Fn(fallback) =
let fallback_name = format!("{}_{}", &name, &fallback.name);
let old_name = fallback.name;
fallback.name = fallback_name;
let Definition::Fn(mut fallback) =
self.generalise_definition(Definition::Fn(fallback), module_name)
else {
unreachable!()
};
fallback.name = old_name;
Definition::Validator(Validator {
doc,
name,

View File

@ -178,102 +178,117 @@ fn infer_definition(
}) => {
let params_length = params.len();
let mut typed_handlers = vec![];
environment.in_new_scope(|environment| {
let fallback_name = format!("{}_{}", &name, &fallback.name);
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();
put_params_in_scope(&fallback_name, environment, &params);
put_params_in_scope(&handler.name, environment, &params);
let mut typed_handlers = vec![];
let mut typed_fun =
infer_function(&handler, module_name, hydrators, environment, tracing)?;
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();
if !typed_fun.return_type.is_bool() {
let handler_name = format!("{}_{}", &name, &handler.name);
let old_name = handler.name;
handler.name = handler_name;
let mut typed_fun =
infer_function(&handler, module_name, hydrators, environment, tracing)?;
typed_fun.name = old_name;
if !typed_fun.return_type.is_bool() {
return Err(Error::ValidatorMustReturnBool {
return_type: typed_fun.return_type.clone(),
location: typed_fun.location,
});
}
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 {
return Err(Error::IncorrectValidatorArity {
count: typed_fun.arguments.len() as u32,
expected: 3,
location: typed_fun.location,
});
}
for arg in typed_fun.arguments.iter_mut() {
if arg.tipo.is_unbound() {
arg.tipo = builtins::data();
}
}
Ok(typed_fun)
})?;
typed_handlers.push(typed_fun);
}
let (typed_params, typed_fallback) = environment.in_new_scope(|environment| {
let temp_params = params.iter().cloned().chain(fallback.arguments);
fallback.arguments = temp_params.collect();
let old_name = fallback.name;
fallback.name = fallback_name;
let mut typed_fallback =
infer_function(&fallback, module_name, hydrators, environment, tracing)?;
typed_fallback.name = old_name;
if !typed_fallback.body.is_error_term() && !typed_fallback.return_type.is_bool()
{
return Err(Error::ValidatorMustReturnBool {
return_type: typed_fun.return_type.clone(),
location: typed_fun.location,
return_type: typed_fallback.return_type.clone(),
location: typed_fallback.location,
});
}
typed_fun.arguments.drain(0..params_length);
let typed_params = typed_fallback
.arguments
.drain(0..params_length)
.map(|mut arg| {
if arg.tipo.is_unbound() {
arg.tipo = builtins::data();
}
// TODO: the expected number of args comes from the script purpose
if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 {
arg
})
.collect();
if typed_fallback.arguments.len() != 1 {
return Err(Error::IncorrectValidatorArity {
count: typed_fun.arguments.len() as u32,
expected: 3,
location: typed_fun.location,
count: typed_fallback.arguments.len() as u32,
expected: 1,
location: typed_fallback.location,
});
}
for arg in typed_fun.arguments.iter_mut() {
for arg in typed_fallback.arguments.iter_mut() {
if arg.tipo.is_unbound() {
arg.tipo = builtins::data();
}
}
Ok(typed_fun)
Ok((typed_params, typed_fallback))
})?;
typed_handlers.push(typed_fun);
}
let (typed_params, typed_fallback) = environment.in_new_scope(|environment| {
let temp_params = params.iter().cloned().chain(fallback.arguments);
fallback.arguments = temp_params.collect();
put_params_in_scope(&fallback.name, environment, &params);
let mut typed_fallback =
infer_function(&fallback, module_name, hydrators, environment, tracing)?;
if !typed_fallback.return_type.is_bool() {
return Err(Error::ValidatorMustReturnBool {
return_type: typed_fallback.return_type.clone(),
location: typed_fallback.location,
});
}
let typed_params = typed_fallback
.arguments
.drain(0..params_length)
.map(|mut arg| {
if arg.tipo.is_unbound() {
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();
}
}
Ok((typed_params, typed_fallback))
})?;
Ok(Definition::Validator(Validator {
doc,
end_position,
handlers: typed_handlers,
fallback: typed_fallback,
name,
location,
params: typed_params,
}))
Ok(Definition::Validator(Validator {
doc,
end_position,
handlers: typed_handlers,
fallback: typed_fallback,
name,
location,
params: typed_params,
}))
})
}
Definition::Test(f) => {

View File

@ -550,8 +550,8 @@ mod tests {
type UUID { UUID }
validator {
fn opaque_singleton_variants(redeemer: Dict<UUID, Int>, ctx: Void) {
validator opaque_singleton_variants {
spend(redeemer: Dict<UUID, Int>, ctx: Void) {
True
}
}
@ -568,8 +568,8 @@ mod tests {
denominator: Int,
}
validator {
fn opaque_singleton_multi_variants(redeemer: Rational, ctx: Void) {
validator opaque_singleton_multi_variants {
spend(redeemer: Rational, ctx: Void) {
True
}
}
@ -585,8 +585,8 @@ mod tests {
foo: Data
}
validator {
fn nested_data(datum: Foo, redeemer: Int, ctx: Void) {
validator nested_data {
spend(datum: Foo, redeemer: Int, ctx: Void) {
True
}
}
@ -604,8 +604,8 @@ mod tests {
Mul(Expr, Expr)
}
validator {
fn recursive_types(redeemer: Expr, ctx: Void) {
validator recursive_types {
spend(redeemer: Expr, ctx: Void) {
True
}
}
@ -632,8 +632,8 @@ mod tests {
}
}
validator {
fn recursive_generic_types(datum: Foo, redeemer: LinkedList<Int>, ctx: Void) {
validator recursive_generic_types {
spend(datum: Foo, redeemer: LinkedList<Int>, ctx: Void) {
True
}
}
@ -649,8 +649,8 @@ mod tests {
foo: Int
}
validator {
fn annotated_data(datum: Data<Foo>, redeemer: Data, ctx: Void) {
validator annotated_data {
spend(datum: Data<Foo>, redeemer: Data, ctx: Void) {
True
}
}

View File

@ -3687,8 +3687,8 @@ fn when_tuple_deconstruction() {
Buy
}
validator {
fn spend(dat: Datum, red: RedSpend, ctx: Data) {
validator thing {
spend(dat: Datum, red: RedSpend, ctx: Data) {
when (dat, red) is {
(A(a), Spend(x)) ->
(a.idx == x)?
@ -4046,8 +4046,8 @@ fn generic_validator_type_test() {
something: Void,
}
validator {
fn err_example(r: A<B>, _ctx: Data) -> Bool {
validator err_example {
spend(r: A<B>, _ctx: Data) -> Bool {
when r is {
NoA ->
False
@ -5562,8 +5562,8 @@ fn opaque_value_in_datum() {
}
validator {
fn spend(dat: Dat, red: Data, ctx: Data) {
validator foo {
spend(dat: Dat, red: Data, ctx: Data) {
let val = dat.a
expect [Pair(_, amount)] = val.inner.inner