Add Task as a built-in module/type

This commit is contained in:
Sam Mohr 2024-06-25 00:03:56 -07:00
parent d47a073634
commit 700c7ae9aa
No known key found for this signature in database
GPG key ID: EA41D161A3C1BC99
86 changed files with 925 additions and 2670 deletions

View file

@ -0,0 +1,210 @@
use crate::def::Def;
use crate::expr::{AnnotatedMark, ClosureData, Expr, Recursive};
use crate::pattern::Pattern;
use crate::scope::Scope;
use roc_collections::SendMap;
use roc_module::symbol::Symbol;
use roc_region::all::{Loc, Region};
use roc_types::subs::{VarStore, Variable};
use roc_types::types::{LambdaSet, OptAbleVar, Type};
pub fn build_host_exposed_def(
scope: &mut Scope,
symbol: Symbol,
ident: &str,
var_store: &mut VarStore,
annotation: crate::annotation::Annotation,
) -> Def {
if symbol.contains("PlatformTask") {
dbg!(symbol, ident, &annotation);
}
let expr_var = var_store.fresh();
let pattern = Pattern::Identifier(symbol);
let mut pattern_vars = SendMap::default();
pattern_vars.insert(symbol, expr_var);
let mut arguments: Vec<(Variable, AnnotatedMark, Loc<Pattern>)> = Vec::new();
let mut linked_symbol_arguments: Vec<(Variable, Expr)> = Vec::new();
let mut captured_symbols: Vec<(Symbol, Variable)> = Vec::new();
let crate::annotation::Annotation {
introduced_variables,
typ,
aliases,
..
} = annotation;
let def_body = {
match typ.shallow_structural_dealias() {
Type::Function(args, _, _) => {
for i in 0..args.len() {
let name = format!("closure_arg_{ident}_{i}");
let arg_symbol = {
let ident = name.clone().into();
scope.introduce(ident, Region::zero()).unwrap()
};
let arg_var = var_store.fresh();
arguments.push((
arg_var,
AnnotatedMark::new(var_store),
Loc::at_zero(Pattern::Identifier(arg_symbol)),
));
captured_symbols.push((arg_symbol, arg_var));
linked_symbol_arguments.push((arg_var, Expr::Var(arg_symbol, arg_var)));
}
let foreign_symbol_name = format!("roc_fx_{ident}");
let low_level_call = Expr::ForeignCall {
foreign_symbol: foreign_symbol_name.into(),
args: linked_symbol_arguments,
ret_var: var_store.fresh(),
};
let task_closure_symbol = {
let name = format!("task_closure_{ident}");
let ident = name.into();
scope.introduce(ident, Region::zero()).unwrap()
};
let task_closure = Expr::Closure(ClosureData {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
name: task_closure_symbol,
captured_symbols,
recursive: Recursive::NotRecursive,
arguments: vec![(
var_store.fresh(),
AnnotatedMark::new(var_store),
Loc::at_zero(empty_record_pattern(var_store)),
)],
loc_body: Box::new(Loc::at_zero(low_level_call)),
});
let (specialized_def_type, type_arguments, lambda_set_variables) =
build_fresh_opaque_variables(var_store);
let body = Expr::OpaqueRef {
opaque_var: var_store.fresh(),
name: Symbol::TASK_TASK,
argument: Box::new((var_store.fresh(), Loc::at_zero(task_closure))),
specialized_def_type,
type_arguments,
lambda_set_variables,
};
Expr::Closure(ClosureData {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
name: symbol,
captured_symbols: std::vec::Vec::new(),
recursive: Recursive::NotRecursive,
arguments,
loc_body: Box::new(Loc::at_zero(body)),
})
}
_ => {
// not a function
let foreign_symbol_name = format!("roc_fx_{ident}");
let low_level_call = Expr::ForeignCall {
foreign_symbol: foreign_symbol_name.into(),
args: linked_symbol_arguments,
ret_var: var_store.fresh(),
};
let task_closure_symbol = {
let name = format!("task_closure_{ident}");
let ident = name.into();
scope.introduce(ident, Region::zero()).unwrap()
};
let task_closure = Expr::Closure(ClosureData {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
name: task_closure_symbol,
captured_symbols,
recursive: Recursive::NotRecursive,
arguments: vec![(
var_store.fresh(),
AnnotatedMark::new(var_store),
Loc::at_zero(empty_record_pattern(var_store)),
)],
loc_body: Box::new(Loc::at_zero(low_level_call)),
});
let (specialized_def_type, type_arguments, lambda_set_variables) =
build_fresh_opaque_variables(var_store);
Expr::OpaqueRef {
opaque_var: var_store.fresh(),
name: Symbol::TASK_TASK,
argument: Box::new((var_store.fresh(), Loc::at_zero(task_closure))),
specialized_def_type,
type_arguments,
lambda_set_variables,
}
}
}
};
let def_annotation = crate::def::Annotation {
signature: typ,
introduced_variables,
aliases,
region: Region::zero(),
};
let def = Def {
loc_pattern: Loc::at_zero(pattern),
loc_expr: Loc::at_zero(def_body),
expr_var,
pattern_vars,
annotation: Some(def_annotation),
};
if symbol.contains("PlatformTask") {
dbg!(&def);
}
def
}
fn build_fresh_opaque_variables(
var_store: &mut VarStore,
) -> (Box<Type>, Vec<OptAbleVar>, Vec<LambdaSet>) {
let closure_var = var_store.fresh();
// NB: if there are bugs, check whether not introducing variables is a problem!
// introduced_variables.insert_wildcard(Loc::at_zero(closure_var));
let a_var = var_store.fresh();
let actual = Type::Function(
vec![Type::EmptyRec],
Box::new(Type::Variable(closure_var)),
Box::new(Type::Variable(a_var)),
);
let type_arguments = vec![OptAbleVar {
var: a_var,
opt_abilities: None,
}];
let lambda_set_variables = vec![roc_types::types::LambdaSet(Type::Variable(closure_var))];
(Box::new(actual), type_arguments, lambda_set_variables)
}
#[inline(always)]
fn empty_record_pattern(var_store: &mut VarStore) -> Pattern {
Pattern::RecordDestructure {
whole_var: var_store.fresh(),
ext_var: var_store.fresh(),
destructs: vec![],
}
}