Lower passed imported functions

This commit is contained in:
Agus Zubiaga 2024-08-26 23:21:18 -03:00
parent 2f4e80b696
commit 0bf833dae9
No known key found for this signature in database
4 changed files with 63 additions and 20 deletions

View file

@ -18,7 +18,7 @@ use roc_can::constraint::{Constraint as ConstraintSoa, Constraints, TypeOrVar};
use roc_can::expr::{DbgLookup, Declarations, ExpectLookup, PendingDerives};
use roc_can::module::{
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
ResolvedImplementations, TypeState,
ModuleParams, ResolvedImplementations, TypeState,
};
use roc_collections::{default_hasher, BumpMap, MutMap, MutSet, VecMap, VecSet};
use roc_constrain::module::constrain_module;
@ -251,6 +251,7 @@ fn start_phase<'a>(
let mut aliases = MutMap::default();
let mut abilities_store = PendingAbilitiesStore::default();
let mut imported_module_params = VecMap::default();
for imported in parsed.available_modules.keys() {
match state.module_cache.aliases.get(imported) {
@ -293,6 +294,10 @@ fn start_phase<'a>(
.union(import_store.closure_from_imported(exposed_symbols));
}
}
if let Some(params) = state.module_cache.module_params.get(imported) {
imported_module_params.insert(*imported, params.clone());
}
}
let skip_constraint_gen = {
@ -311,6 +316,7 @@ fn start_phase<'a>(
skip_constraint_gen,
exposed_module_ids: state.exposed_modules,
exec_mode: state.exec_mode,
imported_module_params,
}
}
@ -891,6 +897,7 @@ enum BuildTask<'a> {
exposed_module_ids: &'a [ModuleId],
skip_constraint_gen: bool,
exec_mode: ExecutionMode,
imported_module_params: VecMap<ModuleId, ModuleParams>,
},
Solve {
module: Module,
@ -5006,6 +5013,7 @@ fn canonicalize_and_constrain<'a>(
skip_constraint_gen: bool,
exposed_module_ids: &[ModuleId],
exec_mode: ExecutionMode,
imported_module_params: VecMap<ModuleId, ModuleParams>,
) -> CanAndCon {
let canonicalize_start = Instant::now();
@ -5097,14 +5105,17 @@ fn canonicalize_and_constrain<'a>(
// If we did, we'd have to update the language server to exclude the extra arguments
}
ExecutionMode::Executable | ExecutionMode::ExecutableIfCheck | ExecutionMode::Test => {
// lower module params
roc_lower_params::lower::lower(
module_id,
&module_output.module_params,
&mut module_output.declarations,
&mut module_output.scope.locals.ident_ids,
&mut var_store,
);
// We need to lower params only if the current module has any or imports at least one with params
if module_output.module_params.is_some() || !imported_module_params.is_empty() {
roc_lower_params::lower::lower(
module_id,
&module_output.module_params,
imported_module_params,
&mut module_output.declarations,
&mut module_output.scope.locals.ident_ids,
&mut var_store,
);
}
}
}
@ -6227,6 +6238,7 @@ fn run_task<'a>(
skip_constraint_gen,
exposed_module_ids,
exec_mode,
imported_module_params,
} => {
let can_and_con = canonicalize_and_constrain(
arena,
@ -6239,6 +6251,7 @@ fn run_task<'a>(
skip_constraint_gen,
exposed_module_ids,
exec_mode,
imported_module_params,
);
Ok(Msg::CanonicalizedAndConstrained(can_and_con))

View file

@ -8,6 +8,7 @@ use roc_can::{
module::ModuleParams,
pattern::Pattern,
};
use roc_collections::VecMap;
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_region::all::Loc;
use roc_types::subs::{VarStore, Variable};
@ -16,6 +17,7 @@ use roc_types::types::Type;
struct LowerParams<'a> {
home_id: ModuleId,
home_params: &'a Option<ModuleParams>,
imported_params: VecMap<ModuleId, ModuleParams>,
var_store: &'a mut VarStore,
ident_ids: &'a mut IdentIds,
}
@ -23,6 +25,7 @@ struct LowerParams<'a> {
pub fn lower(
home_id: ModuleId,
home_params: &Option<ModuleParams>,
imported_params: VecMap<ModuleId, ModuleParams>,
decls: &mut Declarations,
ident_ids: &mut IdentIds,
var_store: &mut VarStore,
@ -30,6 +33,7 @@ pub fn lower(
let mut env = LowerParams {
home_id,
home_params,
imported_params,
ident_ids,
var_store,
};
@ -92,14 +96,19 @@ impl<'a> LowerParams<'a> {
params_symbol,
params_var,
} => {
*expr = self.lower_naked_params_var(
// todo: get arity of imported symbol
0,
*symbol,
*var,
*params_symbol,
*params_var,
);
// The module was imported with params, but it might not actually expect them.
// We should only lower if it does to prevent confusing type errors.
if let Some(params) = self.imported_params.get(&symbol.module_id()) {
let arity = params.arity_by_name.get(&symbol.ident_id()).unwrap();
*expr = self.lower_naked_params_var(
*arity,
*symbol,
*var,
*params_symbol,
*params_var,
);
}
}
Var(symbol, var) => {
if let Some(arity) = self.params_extended_home_symbol(symbol) {
@ -125,7 +134,15 @@ impl<'a> LowerParams<'a> {
params_symbol,
} => {
// Calling an imported function with params
args.push((params_var, Loc::at_zero(Var(params_symbol, params_var))));
// Extend arguments only if the imported module actually expects params
if self.imported_params.contains_key(&symbol.module_id()) {
args.push((
params_var,
Loc::at_zero(Var(params_symbol, params_var)),
));
}
fun.1.value = Var(symbol, var);
}
Var(symbol, _var) => {
@ -415,12 +432,19 @@ impl<'a> LowerParams<'a> {
roc_module::called_via::CalledVia::Space,
);
let captured_symbols = if symbol.module_id() == self.home_id {
vec![(params_symbol, params_var)]
} else {
// todo: capture if import is not top-level
vec![]
};
Closure(ClosureData {
function_type: self.var_store.fresh(),
closure_type: self.var_store.fresh(),
return_type: self.var_store.fresh(),
name: self.unique_symbol(),
captured_symbols: vec![(params_symbol, params_var)],
captured_symbols,
recursive: roc_can::expr::Recursive::NotRecursive,
arguments,
loc_body: Box::new(Loc::at_zero(body)),