Type-check variadic traces & desugarize them.

This commit is contained in:
KtorZ 2024-07-18 10:02:23 +02:00
parent f9719af23e
commit 754ed07408
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
1 changed files with 75 additions and 7 deletions

View File

@ -19,12 +19,14 @@ use crate::{
UntypedRecordUpdateArg, UntypedRecordUpdateArg,
}, },
builtins::{ builtins::{
bool, byte_array, function, g1_element, g2_element, int, list, pair, string, tuple, void, bool, byte_array, from_default_function, function, g1_element, g2_element, int, list, pair,
string, tuple, void, BUILTIN,
}, },
expr::{FnStyle, TypedExpr, UntypedExpr}, expr::{FnStyle, TypedExpr, UntypedExpr},
format, format,
line_numbers::LineNumbers, line_numbers::LineNumbers,
tipo::{fields::FieldMap, PatternConstructor, TypeVar}, tipo::{fields::FieldMap, DefaultFunction, PatternConstructor, TypeVar},
IdGenerator,
}; };
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
@ -513,14 +515,14 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
self.infer_assignment(pattern, *value, kind, &annotation, location) self.infer_assignment(pattern, *value, kind, &annotation, location)
} }
// TODO: Trace.arguments
UntypedExpr::Trace { UntypedExpr::Trace {
location, location,
then, then,
label, label,
arguments,
kind, kind,
.. ..
} => self.infer_trace(kind, *then, location, *label), } => self.infer_trace(kind, *then, location, *label, arguments),
UntypedExpr::When { UntypedExpr::When {
location, location,
@ -2410,10 +2412,33 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
kind: TraceKind, kind: TraceKind,
then: UntypedExpr, then: UntypedExpr,
location: Span, location: Span,
text: UntypedExpr, label: UntypedExpr,
arguments: Vec<UntypedExpr>,
) -> Result<TypedExpr, Error> { ) -> Result<TypedExpr, Error> {
let text = self.infer(text)?; let label = self.infer(label)?;
self.unify(string(), text.tipo(), text.location(), false)?; self.unify(string(), label.tipo(), label.location(), false)?;
let typed_arguments = arguments
.into_iter()
.map(|arg| {
let arg = self.infer(arg)?;
self.unify(string(), arg.tipo(), arg.location(), false)?;
Ok(arg)
})
.collect::<Result<Vec<_>, Error>>()?;
let text = if typed_arguments.is_empty() {
label
} else {
let delimiter = |ix| TypedExpr::String {
location: Span::empty(),
tipo: string(),
value: if ix == 0 { ": " } else { ", " }.to_string(),
};
typed_arguments.into_iter().enumerate().fold(label, |text, (ix, arg)| {
append_string_expr(append_string_expr(text, delimiter(ix)), arg)
})
};
let then = self.infer(then)?; let then = self.infer(then)?;
let tipo = then.tipo(); let tipo = then.tipo();
@ -2786,3 +2811,46 @@ pub fn ensure_serialisable(is_top_level: bool, t: Rc<Type>, location: Span) -> R
} }
} }
} }
pub fn append_string_expr(left: TypedExpr, right: TypedExpr) -> TypedExpr {
let value_constructor = from_default_function(DefaultFunction::AppendString, &IdGenerator::new());
let append_string = TypedExpr::ModuleSelect {
location: Span::empty(),
tipo: value_constructor.tipo,
label: DefaultFunction::AppendString.aiken_name(),
module_name: BUILTIN.to_string(),
module_alias: BUILTIN.to_string(),
// NOTE: The IdGenerator is unused here, as it's only necessary for generic builtin
// functions such as if_then_else or head_list. However, if such functions were needed,
// passing a brand new IdGenerator here would be WRONG and cause issues down the line.
//
// So this is merely a small work-around for convenience. The proper way here would be to
// pull the function definition for append_string from the pre-registered builtins
// functions somewhere in the environment.
constructor: value_constructor
.variant
.to_module_value_constructor(
string(),
BUILTIN,
&DefaultFunction::AppendString.aiken_name(),
),
};
TypedExpr::Call {
location: Span::empty(),
tipo: string(),
fun: Box::new(append_string.clone()),
args: vec![
CallArg {
label: None,
location: left.location(),
value: left,
},
CallArg {
label: None,
location: right.location(),
value: right,
},
],
}
}