fix: allow spread operator on positional constructors closes #677

This commit is contained in:
rvcas 2023-11-27 23:11:17 -05:00
parent d5820bb20a
commit 6ce30bd949
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
2 changed files with 71 additions and 0 deletions

View File

@ -981,6 +981,46 @@ fn list_pattern_6() {
assert!(check(parse(source_code)).is_ok()) assert!(check(parse(source_code)).is_ok())
} }
#[test]
fn spread_with_positional_constr_args() {
let source_code = r#"
type Redeemer {
First(Int)
Second
}
fn foo(redeemer: Redeemer) {
when redeemer is {
First(..) -> True
Second -> True
}
}
"#;
assert!(check(parse(source_code)).is_ok())
}
#[test]
fn unnecessary_spread_with_positional_constr_args() {
let source_code = r#"
type Redeemer {
First(Int)
Second
}
fn foo(redeemer: Redeemer) {
when redeemer is {
First(x, ..) -> True
Second -> True
}
}
"#;
assert!(matches!(
check(parse(source_code)),
Err((_, Error::UnnecessarySpreadOperator { .. }))
))
}
#[test] #[test]
fn trace_strings() { fn trace_strings() {
let source_code = r#" let source_code = r#"

View File

@ -314,6 +314,8 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
self.environment self.environment
.get_value_constructor(module.as_ref(), &name, location)?; .get_value_constructor(module.as_ref(), &name, location)?;
let has_no_fields = cons.field_map().is_none();
match cons.field_map() { match cons.field_map() {
// The fun has a field map so labelled arguments may be present and need to be reordered. // The fun has a field map so labelled arguments may be present and need to be reordered.
Some(field_map) => { Some(field_map) => {
@ -399,8 +401,37 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
&mut HashMap::new(), &mut HashMap::new(),
self.hydrator, self.hydrator,
); );
match instantiated_constructor_type.deref() { match instantiated_constructor_type.deref() {
Type::Fn { args, ret } => { Type::Fn { args, ret } => {
if with_spread && has_no_fields {
if pattern_args.len() == args.len() {
return Err(Error::UnnecessarySpreadOperator {
location: Span {
start: location.end - 3,
end: location.end - 1,
},
arity: args.len(),
});
}
while pattern_args.len() < args.len() {
let location = Span {
start: location.end - 3,
end: location.end - 1,
};
pattern_args.push(CallArg {
value: Pattern::Discard {
name: "_".to_string(),
location,
},
location,
label: None,
});
}
}
if args.len() == pattern_args.len() { if args.len() == pattern_args.len() {
let pattern_args = pattern_args let pattern_args = pattern_args
.into_iter() .into_iter()