mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
commit
fbcde5dd9e
10 changed files with 340 additions and 209 deletions
|
@ -149,7 +149,8 @@ pub fn gen_from_mono_module(
|
||||||
// env.module.print_to_stderr();
|
// env.module.print_to_stderr();
|
||||||
// NOTE: If this fails, uncomment the above println to debug.
|
// NOTE: If this fails, uncomment the above println to debug.
|
||||||
panic!(
|
panic!(
|
||||||
"Non-main function failed LLVM verification. Uncomment the above println to debug!"
|
r"Non-main function {:?} failed LLVM verification. Uncomment the above println to debug!",
|
||||||
|
fn_val.get_name(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub enum ExposedModuleTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConstrainedModule {
|
pub struct ConstrainedModule {
|
||||||
pub unused_imports: MutSet<ModuleId>,
|
pub unused_imports: MutMap<ModuleId, Region>,
|
||||||
pub constraint: Constraint,
|
pub constraint: Constraint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ pub fn constrain_imports(
|
||||||
pub struct ConstrainableImports {
|
pub struct ConstrainableImports {
|
||||||
pub imported_symbols: Vec<Import>,
|
pub imported_symbols: Vec<Import>,
|
||||||
pub imported_aliases: MutMap<Symbol, Alias>,
|
pub imported_aliases: MutMap<Symbol, Alias>,
|
||||||
pub unused_imports: MutSet<ModuleId>,
|
pub unused_imports: MutMap<ModuleId, Region>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run this before constraining imports.
|
/// Run this before constraining imports.
|
||||||
|
@ -143,7 +143,7 @@ pub struct ConstrainableImports {
|
||||||
pub fn pre_constrain_imports(
|
pub fn pre_constrain_imports(
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
references: &MutSet<Symbol>,
|
references: &MutSet<Symbol>,
|
||||||
imported_modules: MutSet<ModuleId>,
|
imported_modules: MutMap<ModuleId, Region>,
|
||||||
exposed_types: &mut SubsByModule,
|
exposed_types: &mut SubsByModule,
|
||||||
stdlib: &StdLib,
|
stdlib: &StdLib,
|
||||||
) -> ConstrainableImports {
|
) -> ConstrainableImports {
|
||||||
|
|
|
@ -2249,12 +2249,10 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||||
let mut argument_types = Vec::with_capacity_in(arguments.len() + 3, env.arena);
|
let mut argument_types = Vec::with_capacity_in(arguments.len() + 3, env.arena);
|
||||||
|
|
||||||
for layout in arguments {
|
for layout in arguments {
|
||||||
argument_types.push(basic_type_from_layout(
|
let arg_type = basic_type_from_layout(arena, context, layout, env.ptr_bytes);
|
||||||
arena,
|
let arg_ptr_type = arg_type.ptr_type(AddressSpace::Generic);
|
||||||
context,
|
|
||||||
layout,
|
argument_types.push(arg_ptr_type.into());
|
||||||
env.ptr_bytes,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_pointer_type = {
|
let function_pointer_type = {
|
||||||
|
@ -2310,6 +2308,12 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
|
||||||
let closure_data = builder.build_load(closure_data_ptr, "load_closure_data");
|
let closure_data = builder.build_load(closure_data_ptr, "load_closure_data");
|
||||||
|
|
||||||
let mut parameters = parameters;
|
let mut parameters = parameters;
|
||||||
|
|
||||||
|
for param in parameters.iter_mut() {
|
||||||
|
debug_assert!(param.is_pointer_value());
|
||||||
|
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
||||||
|
}
|
||||||
|
|
||||||
parameters.push(closure_data);
|
parameters.push(closure_data);
|
||||||
|
|
||||||
let call_result = invoke_and_catch(env, function_value, function_ptr, ¶meters, result_type);
|
let call_result = invoke_and_catch(env, function_value, function_ptr, ¶meters, result_type);
|
||||||
|
@ -2357,12 +2361,10 @@ pub fn build_function_caller<'a, 'ctx, 'env>(
|
||||||
let mut argument_types = Vec::with_capacity_in(arguments.len() + 3, env.arena);
|
let mut argument_types = Vec::with_capacity_in(arguments.len() + 3, env.arena);
|
||||||
|
|
||||||
for layout in arguments {
|
for layout in arguments {
|
||||||
argument_types.push(basic_type_from_layout(
|
let arg_type = basic_type_from_layout(arena, context, layout, env.ptr_bytes);
|
||||||
arena,
|
let arg_ptr_type = arg_type.ptr_type(AddressSpace::Generic);
|
||||||
context,
|
|
||||||
layout,
|
argument_types.push(arg_ptr_type.into());
|
||||||
env.ptr_bytes,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_pointer_type = {
|
let function_pointer_type = {
|
||||||
|
@ -2429,6 +2431,13 @@ pub fn build_function_caller<'a, 'ctx, 'env>(
|
||||||
.build_bitcast(function_ptr, actual_function_type, "cast")
|
.build_bitcast(function_ptr, actual_function_type, "cast")
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
|
let mut parameters = parameters;
|
||||||
|
|
||||||
|
for param in parameters.iter_mut() {
|
||||||
|
debug_assert!(param.is_pointer_value());
|
||||||
|
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
||||||
|
}
|
||||||
|
|
||||||
let call_result = invoke_and_catch(env, function_value, function_ptr, ¶meters, result_type);
|
let call_result = invoke_and_catch(env, function_value, function_ptr, ¶meters, result_type);
|
||||||
|
|
||||||
builder.build_store(output, call_result);
|
builder.build_store(output, call_result);
|
||||||
|
|
|
@ -106,12 +106,12 @@ impl Dependencies {
|
||||||
&mut self,
|
&mut self,
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
opt_effect_module: Option<ModuleId>,
|
opt_effect_module: Option<ModuleId>,
|
||||||
dependencies: &MutSet<ModuleId>,
|
dependencies: &MutMap<ModuleId, Region>,
|
||||||
goal_phase: Phase,
|
goal_phase: Phase,
|
||||||
) -> MutSet<(ModuleId, Phase)> {
|
) -> MutSet<(ModuleId, Phase)> {
|
||||||
use Phase::*;
|
use Phase::*;
|
||||||
|
|
||||||
for dep in dependencies.iter().copied() {
|
for dep in dependencies.keys().copied() {
|
||||||
// to parse and generate constraints, the headers of all dependencies must be loaded!
|
// to parse and generate constraints, the headers of all dependencies must be loaded!
|
||||||
// otherwise, we don't know whether an imported symbol is actually exposed
|
// otherwise, we don't know whether an imported symbol is actually exposed
|
||||||
self.add_dependency_help(module_id, dep, Phase::Parse, Phase::LoadHeader);
|
self.add_dependency_help(module_id, dep, Phase::Parse, Phase::LoadHeader);
|
||||||
|
@ -146,7 +146,7 @@ impl Dependencies {
|
||||||
let mut output = MutSet::default();
|
let mut output = MutSet::default();
|
||||||
|
|
||||||
// all the dependencies can be loaded
|
// all the dependencies can be loaded
|
||||||
for dep in dependencies {
|
for dep in dependencies.keys() {
|
||||||
// TODO figure out how to "load" (because it doesn't exist on the file system) the Effect module
|
// TODO figure out how to "load" (because it doesn't exist on the file system) the Effect module
|
||||||
|
|
||||||
if Some(*dep) != opt_effect_module {
|
if Some(*dep) != opt_effect_module {
|
||||||
|
@ -420,7 +420,7 @@ fn start_phase<'a>(module_id: ModuleId, phase: Phase, state: &mut State<'a>) ->
|
||||||
|
|
||||||
let mut aliases = MutMap::default();
|
let mut aliases = MutMap::default();
|
||||||
|
|
||||||
for imported in parsed.imported_modules.iter() {
|
for imported in parsed.imported_modules.keys() {
|
||||||
match state.module_cache.aliases.get(imported) {
|
match state.module_cache.aliases.get(imported) {
|
||||||
None => unreachable!(
|
None => unreachable!(
|
||||||
r"imported module {:?} did not register its aliases, so {:?} cannot use them",
|
r"imported module {:?} did not register its aliases, so {:?} cannot use them",
|
||||||
|
@ -556,7 +556,7 @@ struct ModuleHeader<'a> {
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
||||||
packages: MutMap<&'a str, PackageOrPath<'a>>,
|
packages: MutMap<&'a str, PackageOrPath<'a>>,
|
||||||
imported_modules: MutSet<ModuleId>,
|
imported_modules: MutMap<ModuleId, Region>,
|
||||||
exposes: Vec<Symbol>,
|
exposes: Vec<Symbol>,
|
||||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||||
src: &'a [u8],
|
src: &'a [u8],
|
||||||
|
@ -574,7 +574,7 @@ enum HeaderFor<'a> {
|
||||||
struct ConstrainedModule {
|
struct ConstrainedModule {
|
||||||
module: Module,
|
module: Module,
|
||||||
declarations: Vec<Declaration>,
|
declarations: Vec<Declaration>,
|
||||||
imported_modules: MutSet<ModuleId>,
|
imported_modules: MutMap<ModuleId, Region>,
|
||||||
constraint: Constraint,
|
constraint: Constraint,
|
||||||
ident_ids: IdentIds,
|
ident_ids: IdentIds,
|
||||||
var_store: VarStore,
|
var_store: VarStore,
|
||||||
|
@ -631,7 +631,7 @@ struct ParsedModule<'a> {
|
||||||
src: &'a str,
|
src: &'a str,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
|
||||||
imported_modules: MutSet<ModuleId>,
|
imported_modules: MutMap<ModuleId, Region>,
|
||||||
exposed_ident_ids: IdentIds,
|
exposed_ident_ids: IdentIds,
|
||||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||||
parsed_defs: &'a [Located<roc_parse::ast::Def<'a>>],
|
parsed_defs: &'a [Located<roc_parse::ast::Def<'a>>],
|
||||||
|
@ -659,6 +659,7 @@ enum Msg<'a> {
|
||||||
solved_subs: Solved<Subs>,
|
solved_subs: Solved<Subs>,
|
||||||
decls: Vec<Declaration>,
|
decls: Vec<Declaration>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
unused_imports: MutMap<ModuleId, Region>,
|
||||||
},
|
},
|
||||||
FinishedAllTypeChecking {
|
FinishedAllTypeChecking {
|
||||||
solved_subs: Solved<Subs>,
|
solved_subs: Solved<Subs>,
|
||||||
|
@ -870,6 +871,7 @@ enum BuildTask<'a> {
|
||||||
constraint: Constraint,
|
constraint: Constraint,
|
||||||
var_store: VarStore,
|
var_store: VarStore,
|
||||||
declarations: Vec<Declaration>,
|
declarations: Vec<Declaration>,
|
||||||
|
unused_imports: MutMap<ModuleId, Region>,
|
||||||
},
|
},
|
||||||
BuildPendingSpecializations {
|
BuildPendingSpecializations {
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
@ -1607,6 +1609,7 @@ fn update<'a>(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
decls,
|
decls,
|
||||||
mut module_timing,
|
mut module_timing,
|
||||||
|
mut unused_imports,
|
||||||
} => {
|
} => {
|
||||||
log!("solved types for {:?}", module_id);
|
log!("solved types for {:?}", module_id);
|
||||||
module_timing.end_time = SystemTime::now();
|
module_timing.end_time = SystemTime::now();
|
||||||
|
@ -1616,6 +1619,15 @@ fn update<'a>(
|
||||||
.type_problems
|
.type_problems
|
||||||
.insert(module_id, solved_module.problems);
|
.insert(module_id, solved_module.problems);
|
||||||
|
|
||||||
|
let existing = match state.module_cache.can_problems.entry(module_id) {
|
||||||
|
Vacant(entry) => entry.insert(std::vec::Vec::new()),
|
||||||
|
Occupied(entry) => entry.into_mut(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (unused, region) in unused_imports.drain() {
|
||||||
|
existing.push(roc_problem::can::Problem::UnusedImport(unused, region));
|
||||||
|
}
|
||||||
|
|
||||||
let work = state.dependencies.notify(module_id, Phase::SolveTypes);
|
let work = state.dependencies.notify(module_id, Phase::SolveTypes);
|
||||||
|
|
||||||
// if there is a platform, the Pkg-Config module provides host-exposed,
|
// if there is a platform, the Pkg-Config module provides host-exposed,
|
||||||
|
@ -2350,7 +2362,7 @@ fn send_header<'a>(
|
||||||
|
|
||||||
let mut imported: Vec<(QualifiedModuleName, Vec<Ident>, Region)> =
|
let mut imported: Vec<(QualifiedModuleName, Vec<Ident>, Region)> =
|
||||||
Vec::with_capacity(imports.len());
|
Vec::with_capacity(imports.len());
|
||||||
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
let mut imported_modules: MutMap<ModuleId, Region> = MutMap::default();
|
||||||
let mut scope_size = 0;
|
let mut scope_size = 0;
|
||||||
|
|
||||||
for loc_entry in imports {
|
for loc_entry in imports {
|
||||||
|
@ -2410,7 +2422,7 @@ fn send_header<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let module_id = module_ids.get_or_insert(&pq_module_name);
|
let module_id = module_ids.get_or_insert(&pq_module_name);
|
||||||
imported_modules.insert(module_id);
|
imported_modules.insert(module_id, region);
|
||||||
|
|
||||||
deps_by_name.insert(pq_module_name, module_id);
|
deps_by_name.insert(pq_module_name, module_id);
|
||||||
|
|
||||||
|
@ -2534,7 +2546,7 @@ fn send_header_two<'a>(
|
||||||
|
|
||||||
let mut imported: Vec<(QualifiedModuleName, Vec<Ident>, Region)> =
|
let mut imported: Vec<(QualifiedModuleName, Vec<Ident>, Region)> =
|
||||||
Vec::with_capacity(imports.len());
|
Vec::with_capacity(imports.len());
|
||||||
let mut imported_modules: MutSet<ModuleId> = MutSet::default();
|
let mut imported_modules: MutMap<ModuleId, Region> = MutMap::default();
|
||||||
|
|
||||||
let num_exposes = provides.len();
|
let num_exposes = provides.len();
|
||||||
let mut deps_by_name: MutMap<PQModuleName, ModuleId> =
|
let mut deps_by_name: MutMap<PQModuleName, ModuleId> =
|
||||||
|
@ -2542,7 +2554,7 @@ fn send_header_two<'a>(
|
||||||
|
|
||||||
// add standard imports
|
// add standard imports
|
||||||
// TODO add Effect by default
|
// TODO add Effect by default
|
||||||
imported_modules.insert(app_module_id);
|
imported_modules.insert(app_module_id, Region::zero());
|
||||||
deps_by_name.insert(
|
deps_by_name.insert(
|
||||||
PQModuleName::Unqualified(ModuleName::APP.into()),
|
PQModuleName::Unqualified(ModuleName::APP.into()),
|
||||||
app_module_id,
|
app_module_id,
|
||||||
|
@ -2594,7 +2606,7 @@ fn send_header_two<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let module_id = module_ids.get_or_insert(&pq_module_name);
|
let module_id = module_ids.get_or_insert(&pq_module_name);
|
||||||
imported_modules.insert(module_id);
|
imported_modules.insert(module_id, region);
|
||||||
|
|
||||||
deps_by_name.insert(pq_module_name, module_id);
|
deps_by_name.insert(pq_module_name, module_id);
|
||||||
|
|
||||||
|
@ -2720,7 +2732,7 @@ impl<'a> BuildTask<'a> {
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
constraint: Constraint,
|
constraint: Constraint,
|
||||||
var_store: VarStore,
|
var_store: VarStore,
|
||||||
imported_modules: MutSet<ModuleId>,
|
imported_modules: MutMap<ModuleId, Region>,
|
||||||
exposed_types: &mut SubsByModule,
|
exposed_types: &mut SubsByModule,
|
||||||
stdlib: &StdLib,
|
stdlib: &StdLib,
|
||||||
declarations: Vec<Declaration>,
|
declarations: Vec<Declaration>,
|
||||||
|
@ -2742,14 +2754,6 @@ impl<'a> BuildTask<'a> {
|
||||||
stdlib,
|
stdlib,
|
||||||
);
|
);
|
||||||
|
|
||||||
if !unused_imports.is_empty() {
|
|
||||||
todo!(
|
|
||||||
"TODO gracefully handle unused import {:?} from module {:?}",
|
|
||||||
&unused_imports,
|
|
||||||
home,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, solve this module in the background.
|
// Next, solve this module in the background.
|
||||||
Self::Solve {
|
Self::Solve {
|
||||||
module,
|
module,
|
||||||
|
@ -2759,6 +2763,7 @@ impl<'a> BuildTask<'a> {
|
||||||
var_store,
|
var_store,
|
||||||
declarations,
|
declarations,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
unused_imports,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2772,6 +2777,7 @@ fn run_solve<'a>(
|
||||||
constraint: Constraint,
|
constraint: Constraint,
|
||||||
mut var_store: VarStore,
|
mut var_store: VarStore,
|
||||||
decls: Vec<Declaration>,
|
decls: Vec<Declaration>,
|
||||||
|
unused_imports: MutMap<ModuleId, Region>,
|
||||||
) -> Msg<'a> {
|
) -> Msg<'a> {
|
||||||
// We have more constraining work to do now, so we'll add it to our timings.
|
// We have more constraining work to do now, so we'll add it to our timings.
|
||||||
let constrain_start = SystemTime::now();
|
let constrain_start = SystemTime::now();
|
||||||
|
@ -2819,6 +2825,7 @@ fn run_solve<'a>(
|
||||||
decls,
|
decls,
|
||||||
solved_module,
|
solved_module,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
unused_imports,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3071,7 +3078,7 @@ fn fabricate_effects_module<'a>(
|
||||||
rigid_variables: module_output.rigid_variables,
|
rigid_variables: module_output.rigid_variables,
|
||||||
};
|
};
|
||||||
|
|
||||||
let imported_modules = MutSet::default();
|
let imported_modules = MutMap::default();
|
||||||
|
|
||||||
// Should a effect module ever have a ModuleDocumentation?
|
// Should a effect module ever have a ModuleDocumentation?
|
||||||
let module_docs = ModuleDocumentation {
|
let module_docs = ModuleDocumentation {
|
||||||
|
@ -3615,6 +3622,7 @@ fn run_task<'a>(
|
||||||
var_store,
|
var_store,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
declarations,
|
declarations,
|
||||||
|
unused_imports,
|
||||||
} => Ok(run_solve(
|
} => Ok(run_solve(
|
||||||
module,
|
module,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
|
@ -3623,6 +3631,7 @@ fn run_task<'a>(
|
||||||
constraint,
|
constraint,
|
||||||
var_store,
|
var_store,
|
||||||
declarations,
|
declarations,
|
||||||
|
unused_imports,
|
||||||
)),
|
)),
|
||||||
BuildPendingSpecializations {
|
BuildPendingSpecializations {
|
||||||
module_id,
|
module_id,
|
||||||
|
|
|
@ -64,7 +64,7 @@ impl TagName {
|
||||||
impl ModuleName {
|
impl ModuleName {
|
||||||
// NOTE: After adding one of these, go to `impl ModuleId` and
|
// NOTE: After adding one of these, go to `impl ModuleId` and
|
||||||
// add a corresponding ModuleId to there!
|
// add a corresponding ModuleId to there!
|
||||||
pub const APP: &'static str = ""; // app modules have no module name
|
pub const APP: &'static str = "#UserApp"; // app modules have this hardcoded name
|
||||||
pub const BOOL: &'static str = "Bool";
|
pub const BOOL: &'static str = "Bool";
|
||||||
pub const STR: &'static str = "Str";
|
pub const STR: &'static str = "Str";
|
||||||
pub const NUM: &'static str = "Num";
|
pub const NUM: &'static str = "Num";
|
||||||
|
|
|
@ -571,6 +571,12 @@ impl<'a> Procs<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is an imported symbol, let its home module make this specialization
|
||||||
|
if env.is_imported_symbol(name) {
|
||||||
|
add_needed_external(self, env, fn_var, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We're done with that tuple, so move layout back out to avoid cloning it.
|
// We're done with that tuple, so move layout back out to avoid cloning it.
|
||||||
let (name, layout) = tuple;
|
let (name, layout) = tuple;
|
||||||
|
|
||||||
|
@ -589,7 +595,7 @@ impl<'a> Procs<'a> {
|
||||||
// TODO should pending_procs hold a Rc<Proc>?
|
// TODO should pending_procs hold a Rc<Proc>?
|
||||||
let partial_proc = match self.partial_procs.get(&symbol) {
|
let partial_proc = match self.partial_procs.get(&symbol) {
|
||||||
Some(p) => p.clone(),
|
Some(p) => p.clone(),
|
||||||
None => panic!("no partial_proc for {:?}", symbol),
|
None => panic!("no partial_proc for {:?} in module {:?}", symbol, env.home),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mark this proc as in-progress, so if we're dealing with
|
// Mark this proc as in-progress, so if we're dealing with
|
||||||
|
@ -695,6 +701,10 @@ impl<'a, 'i> Env<'a, 'i> {
|
||||||
|
|
||||||
Symbol::new(self.home, ident_id)
|
Symbol::new(self.home, ident_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_imported_symbol(&self, symbol: Symbol) -> bool {
|
||||||
|
symbol.module_id() != self.home && !symbol.is_builtin()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Copy, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Copy, Eq, Hash)]
|
||||||
|
@ -904,13 +914,16 @@ where
|
||||||
D::Doc: Clone,
|
D::Doc: Clone,
|
||||||
A: Clone,
|
A: Clone,
|
||||||
{
|
{
|
||||||
|
use roc_module::ident::ModuleName;
|
||||||
|
|
||||||
if PRETTY_PRINT_IR_SYMBOLS {
|
if PRETTY_PRINT_IR_SYMBOLS {
|
||||||
alloc.text(format!("{:?}", symbol))
|
alloc.text(format!("{:?}", symbol))
|
||||||
} else {
|
} else {
|
||||||
let text = format!("{}", symbol);
|
let text = format!("{}", symbol);
|
||||||
|
|
||||||
if text.starts_with('.') {
|
if text.starts_with(ModuleName::APP) {
|
||||||
alloc.text("Test").append(text)
|
let name: String = text.trim_start_matches(ModuleName::APP).into();
|
||||||
|
alloc.text("Test").append(name)
|
||||||
} else {
|
} else {
|
||||||
alloc.text(text)
|
alloc.text(text)
|
||||||
}
|
}
|
||||||
|
@ -2129,6 +2142,96 @@ impl<'a> FunctionLayouts<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn specialize_naked_symbol<'a>(
|
||||||
|
env: &mut Env<'a, '_>,
|
||||||
|
variable: Variable,
|
||||||
|
procs: &mut Procs<'a>,
|
||||||
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
|
assigned: Symbol,
|
||||||
|
hole: &'a Stmt<'a>,
|
||||||
|
symbol: Symbol,
|
||||||
|
) -> Stmt<'a> {
|
||||||
|
if procs.module_thunks.contains(&symbol) {
|
||||||
|
let partial_proc = procs.partial_procs.get(&symbol).unwrap();
|
||||||
|
let fn_var = partial_proc.annotation;
|
||||||
|
|
||||||
|
// This is a top-level declaration, which will code gen to a 0-arity thunk.
|
||||||
|
let result = call_by_name(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
fn_var,
|
||||||
|
symbol,
|
||||||
|
std::vec::Vec::new(),
|
||||||
|
layout_cache,
|
||||||
|
assigned,
|
||||||
|
env.arena.alloc(Stmt::Ret(assigned)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else if env.is_imported_symbol(symbol) {
|
||||||
|
match layout_cache.from_var(env.arena, variable, env.subs) {
|
||||||
|
Err(e) => panic!("invalid layout {:?}", e),
|
||||||
|
Ok(layout @ Layout::FunctionPointer(_, _)) => {
|
||||||
|
add_needed_external(procs, env, variable, symbol);
|
||||||
|
|
||||||
|
match hole {
|
||||||
|
Stmt::Jump(_, _) => todo!("not sure what to do in this case yet"),
|
||||||
|
_ => {
|
||||||
|
let expr = Expr::FunctionPointer(symbol, layout.clone());
|
||||||
|
let new_symbol = env.unique_symbol();
|
||||||
|
return Stmt::Let(
|
||||||
|
new_symbol,
|
||||||
|
expr,
|
||||||
|
layout,
|
||||||
|
env.arena.alloc(Stmt::Ret(new_symbol)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => {
|
||||||
|
// this is a 0-arity thunk
|
||||||
|
let result = call_by_name(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
variable,
|
||||||
|
symbol,
|
||||||
|
std::vec::Vec::new(),
|
||||||
|
layout_cache,
|
||||||
|
assigned,
|
||||||
|
env.arena.alloc(Stmt::Ret(assigned)),
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A bit ugly, but it does the job
|
||||||
|
match hole {
|
||||||
|
Stmt::Jump(id, _) => Stmt::Jump(*id, env.arena.alloc([symbol])),
|
||||||
|
_ => {
|
||||||
|
let result = Stmt::Ret(symbol);
|
||||||
|
let original = symbol;
|
||||||
|
|
||||||
|
// we don't have a more accurate variable available, which means the variable
|
||||||
|
// from the partial_proc will be used. So far that has given the correct
|
||||||
|
// result, but I'm not sure this will continue to be the case in more complex
|
||||||
|
// examples.
|
||||||
|
let opt_fn_var = None;
|
||||||
|
|
||||||
|
// if this is a function symbol, ensure that it's properly specialized!
|
||||||
|
reuse_function_symbol(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
opt_fn_var,
|
||||||
|
symbol,
|
||||||
|
result,
|
||||||
|
original,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_hole<'a>(
|
pub fn with_hole<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
can_expr: roc_can::expr::Expr,
|
can_expr: roc_can::expr::Expr,
|
||||||
|
@ -2387,85 +2490,7 @@ pub fn with_hole<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Var(symbol) => {
|
Var(symbol) => {
|
||||||
if procs.module_thunks.contains(&symbol) {
|
specialize_naked_symbol(env, variable, procs, layout_cache, assigned, hole, symbol)
|
||||||
let partial_proc = procs.partial_procs.get(&symbol).unwrap();
|
|
||||||
let fn_var = partial_proc.annotation;
|
|
||||||
|
|
||||||
// This is a top-level declaration, which will code gen to a 0-arity thunk.
|
|
||||||
let result = call_by_name(
|
|
||||||
env,
|
|
||||||
procs,
|
|
||||||
fn_var,
|
|
||||||
symbol,
|
|
||||||
std::vec::Vec::new(),
|
|
||||||
layout_cache,
|
|
||||||
assigned,
|
|
||||||
env.arena.alloc(Stmt::Ret(assigned)),
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} else if symbol.module_id() != env.home && symbol.module_id() != ModuleId::ATTR {
|
|
||||||
match layout_cache.from_var(env.arena, variable, env.subs) {
|
|
||||||
Err(e) => panic!("invalid layout {:?}", e),
|
|
||||||
Ok(layout @ Layout::FunctionPointer(_, _)) => {
|
|
||||||
add_needed_external(procs, env, variable, symbol);
|
|
||||||
|
|
||||||
match hole {
|
|
||||||
Stmt::Jump(_, _) => todo!("not sure what to do in this case yet"),
|
|
||||||
_ => {
|
|
||||||
let expr = Expr::FunctionPointer(symbol, layout.clone());
|
|
||||||
let new_symbol = env.unique_symbol();
|
|
||||||
return Stmt::Let(
|
|
||||||
new_symbol,
|
|
||||||
expr,
|
|
||||||
layout,
|
|
||||||
env.arena.alloc(Stmt::Ret(new_symbol)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(_) => {
|
|
||||||
// this is a 0-arity thunk
|
|
||||||
let result = call_by_name(
|
|
||||||
env,
|
|
||||||
procs,
|
|
||||||
variable,
|
|
||||||
symbol,
|
|
||||||
std::vec::Vec::new(),
|
|
||||||
layout_cache,
|
|
||||||
assigned,
|
|
||||||
env.arena.alloc(Stmt::Ret(assigned)),
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A bit ugly, but it does the job
|
|
||||||
match hole {
|
|
||||||
Stmt::Jump(id, _) => Stmt::Jump(*id, env.arena.alloc([symbol])),
|
|
||||||
_ => {
|
|
||||||
let result = Stmt::Ret(symbol);
|
|
||||||
let original = symbol;
|
|
||||||
|
|
||||||
// we don't have a more accurate variable available, which means the variable
|
|
||||||
// from the partial_proc will be used. So far that has given the correct
|
|
||||||
// result, but I'm not sure this will continue to be the case in more complex
|
|
||||||
// examples.
|
|
||||||
let opt_fn_var = None;
|
|
||||||
|
|
||||||
// if this is a function symbol, ensure that it's properly specialized!
|
|
||||||
reuse_function_symbol(
|
|
||||||
env,
|
|
||||||
procs,
|
|
||||||
layout_cache,
|
|
||||||
opt_fn_var,
|
|
||||||
symbol,
|
|
||||||
result,
|
|
||||||
original,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Tag {
|
Tag {
|
||||||
variant_var,
|
variant_var,
|
||||||
|
@ -2636,17 +2661,28 @@ pub fn with_hole<'a>(
|
||||||
let mut field_symbols = Vec::with_capacity_in(fields.len(), env.arena);
|
let mut field_symbols = Vec::with_capacity_in(fields.len(), env.arena);
|
||||||
let mut can_fields = Vec::with_capacity_in(fields.len(), env.arena);
|
let mut can_fields = Vec::with_capacity_in(fields.len(), env.arena);
|
||||||
|
|
||||||
for (label, _, _) in sorted_fields.into_iter() {
|
enum Field {
|
||||||
// TODO how should function pointers be handled here?
|
Function(Symbol, Variable),
|
||||||
match fields.remove(&label) {
|
ValueSymbol,
|
||||||
Some(field) => match can_reuse_symbol(procs, &field.loc_expr.value) {
|
Field(roc_can::expr::Field),
|
||||||
Some(reusable) => {
|
|
||||||
field_symbols.push(reusable);
|
|
||||||
can_fields.push(None);
|
|
||||||
}
|
}
|
||||||
None => {
|
|
||||||
|
for (label, variable, _) in sorted_fields.into_iter() {
|
||||||
|
// TODO how should function pointers be handled here?
|
||||||
|
use ReuseSymbol::*;
|
||||||
|
match fields.remove(&label) {
|
||||||
|
Some(field) => match can_reuse_symbol(env, procs, &field.loc_expr.value) {
|
||||||
|
Imported(symbol) | LocalFunction(symbol) => {
|
||||||
|
field_symbols.push(symbol);
|
||||||
|
can_fields.push(Field::Function(symbol, variable));
|
||||||
|
}
|
||||||
|
Value(reusable) => {
|
||||||
|
field_symbols.push(reusable);
|
||||||
|
can_fields.push(Field::ValueSymbol);
|
||||||
|
}
|
||||||
|
NotASymbol => {
|
||||||
field_symbols.push(env.unique_symbol());
|
field_symbols.push(env.unique_symbol());
|
||||||
can_fields.push(Some(field));
|
can_fields.push(Field::Field(field));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
@ -2666,7 +2702,22 @@ pub fn with_hole<'a>(
|
||||||
|
|
||||||
for (opt_field, symbol) in can_fields.into_iter().rev().zip(field_symbols.iter().rev())
|
for (opt_field, symbol) in can_fields.into_iter().rev().zip(field_symbols.iter().rev())
|
||||||
{
|
{
|
||||||
if let Some(field) = opt_field {
|
match opt_field {
|
||||||
|
Field::ValueSymbol => {
|
||||||
|
// this symbol is already defined; nothing to do
|
||||||
|
}
|
||||||
|
Field::Function(symbol, variable) => {
|
||||||
|
stmt = reuse_function_symbol(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
Some(variable),
|
||||||
|
symbol,
|
||||||
|
stmt,
|
||||||
|
symbol,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Field::Field(field) => {
|
||||||
stmt = with_hole(
|
stmt = with_hole(
|
||||||
env,
|
env,
|
||||||
field.loc_expr.value,
|
field.loc_expr.value,
|
||||||
|
@ -2678,6 +2729,7 @@ pub fn with_hole<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
@ -3342,8 +3394,15 @@ pub fn with_hole<'a>(
|
||||||
// if the function expression (loc_expr) is already a symbol,
|
// if the function expression (loc_expr) is already a symbol,
|
||||||
// re-use that symbol, and don't define its value again
|
// re-use that symbol, and don't define its value again
|
||||||
let mut result;
|
let mut result;
|
||||||
match can_reuse_symbol(procs, &loc_expr.value) {
|
use ReuseSymbol::*;
|
||||||
Some(function_symbol) => {
|
match can_reuse_symbol(env, procs, &loc_expr.value) {
|
||||||
|
LocalFunction(_) => {
|
||||||
|
unreachable!("if this was known to be a function, we would not be here")
|
||||||
|
}
|
||||||
|
Imported(_) => {
|
||||||
|
unreachable!("an imported value is never an anonymous function")
|
||||||
|
}
|
||||||
|
Value(function_symbol) => {
|
||||||
if let Layout::Closure(_, closure_fields, _) = full_layout {
|
if let Layout::Closure(_, closure_fields, _) = full_layout {
|
||||||
// we're invoking a closure
|
// we're invoking a closure
|
||||||
let closure_record_symbol = env.unique_symbol();
|
let closure_record_symbol = env.unique_symbol();
|
||||||
|
@ -3436,7 +3495,7 @@ pub fn with_hole<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
NotASymbol => {
|
||||||
let function_symbol = env.unique_symbol();
|
let function_symbol = env.unique_symbol();
|
||||||
|
|
||||||
result = Stmt::Let(
|
result = Stmt::Let(
|
||||||
|
@ -4677,15 +4736,33 @@ fn store_record_destruct<'a>(
|
||||||
/// We want to re-use symbols that are not function symbols
|
/// We want to re-use symbols that are not function symbols
|
||||||
/// for any other expression, we create a new symbol, and will
|
/// for any other expression, we create a new symbol, and will
|
||||||
/// later make sure it gets assigned the correct value.
|
/// later make sure it gets assigned the correct value.
|
||||||
fn can_reuse_symbol<'a>(procs: &Procs<'a>, expr: &roc_can::expr::Expr) -> Option<Symbol> {
|
|
||||||
|
enum ReuseSymbol {
|
||||||
|
Imported(Symbol),
|
||||||
|
LocalFunction(Symbol),
|
||||||
|
Value(Symbol),
|
||||||
|
NotASymbol,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_reuse_symbol<'a>(
|
||||||
|
env: &mut Env<'a, '_>,
|
||||||
|
procs: &Procs<'a>,
|
||||||
|
expr: &roc_can::expr::Expr,
|
||||||
|
) -> ReuseSymbol {
|
||||||
|
use ReuseSymbol::*;
|
||||||
|
|
||||||
if let roc_can::expr::Expr::Var(symbol) = expr {
|
if let roc_can::expr::Expr::Var(symbol) = expr {
|
||||||
if procs.partial_procs.contains_key(&symbol) {
|
let symbol = *symbol;
|
||||||
None
|
|
||||||
|
if env.is_imported_symbol(symbol) {
|
||||||
|
Imported(symbol)
|
||||||
|
} else if procs.partial_procs.contains_key(&symbol) {
|
||||||
|
LocalFunction(symbol)
|
||||||
} else {
|
} else {
|
||||||
Some(*symbol)
|
Value(symbol)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
NotASymbol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4694,9 +4771,9 @@ fn possible_reuse_symbol<'a>(
|
||||||
procs: &Procs<'a>,
|
procs: &Procs<'a>,
|
||||||
expr: &roc_can::expr::Expr,
|
expr: &roc_can::expr::Expr,
|
||||||
) -> Symbol {
|
) -> Symbol {
|
||||||
match can_reuse_symbol(procs, expr) {
|
match can_reuse_symbol(env, procs, expr) {
|
||||||
Some(s) => s,
|
ReuseSymbol::Value(s) => s,
|
||||||
None => env.unique_symbol(),
|
_ => env.unique_symbol(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4752,8 +4829,7 @@ fn reuse_function_symbol<'a>(
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
match procs.partial_procs.get(&original) {
|
match procs.partial_procs.get(&original) {
|
||||||
None => {
|
None => {
|
||||||
let is_imported =
|
let is_imported = env.is_imported_symbol(original);
|
||||||
!(env.home == original.module_id() || original.module_id() == ModuleId::ATTR);
|
|
||||||
|
|
||||||
match arg_var {
|
match arg_var {
|
||||||
Some(arg_var) if is_imported => {
|
Some(arg_var) if is_imported => {
|
||||||
|
@ -4761,8 +4837,6 @@ fn reuse_function_symbol<'a>(
|
||||||
.from_var(env.arena, arg_var, env.subs)
|
.from_var(env.arena, arg_var, env.subs)
|
||||||
.expect("creating layout does not fail");
|
.expect("creating layout does not fail");
|
||||||
|
|
||||||
add_needed_external(procs, env, arg_var, original);
|
|
||||||
|
|
||||||
procs.insert_passed_by_name(
|
procs.insert_passed_by_name(
|
||||||
env,
|
env,
|
||||||
arg_var,
|
arg_var,
|
||||||
|
@ -4774,7 +4848,7 @@ fn reuse_function_symbol<'a>(
|
||||||
// an imported symbol is always a function pointer:
|
// an imported symbol is always a function pointer:
|
||||||
// either it's a function, or a top-level 0-argument thunk
|
// either it's a function, or a top-level 0-argument thunk
|
||||||
let expr = Expr::FunctionPointer(original, layout.clone());
|
let expr = Expr::FunctionPointer(original, layout.clone());
|
||||||
return Stmt::Let(original, expr, layout, env.arena.alloc(result));
|
return Stmt::Let(symbol, expr, layout, env.arena.alloc(result));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// danger: a foreign symbol may not be specialized!
|
// danger: a foreign symbol may not be specialized!
|
||||||
|
@ -4914,8 +4988,10 @@ fn assign_to_symbol<'a>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
result: Stmt<'a>,
|
result: Stmt<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
// if this argument is already a symbol, we don't need to re-define it
|
use ReuseSymbol::*;
|
||||||
if let roc_can::expr::Expr::Var(original) = loc_arg.value {
|
match can_reuse_symbol(env, procs, &loc_arg.value) {
|
||||||
|
Imported(original) | LocalFunction(original) => {
|
||||||
|
// for functions we must make sure they are specialized correctly
|
||||||
reuse_function_symbol(
|
reuse_function_symbol(
|
||||||
env,
|
env,
|
||||||
procs,
|
procs,
|
||||||
|
@ -4925,8 +5001,12 @@ fn assign_to_symbol<'a>(
|
||||||
result,
|
result,
|
||||||
original,
|
original,
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
with_hole(
|
Value(_) => {
|
||||||
|
// symbol is already defined; nothing else to do here
|
||||||
|
result
|
||||||
|
}
|
||||||
|
NotASymbol => with_hole(
|
||||||
env,
|
env,
|
||||||
loc_arg.value,
|
loc_arg.value,
|
||||||
arg_var,
|
arg_var,
|
||||||
|
@ -4934,7 +5014,7 @@ fn assign_to_symbol<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
symbol,
|
symbol,
|
||||||
env.arena.alloc(result),
|
env.arena.alloc(result),
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,15 +28,22 @@ pub fn can_problem<'b>(
|
||||||
.append(alloc.reflow(line)),
|
.append(alloc.reflow(line)),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
Problem::UnusedImport(module_id, region) => alloc.concat(vec![
|
Problem::UnusedImport(module_id, region) => {
|
||||||
|
alloc.stack(vec![
|
||||||
|
alloc.concat(vec![
|
||||||
alloc.reflow("Nothing from "),
|
alloc.reflow("Nothing from "),
|
||||||
alloc.module(module_id),
|
alloc.module(module_id),
|
||||||
alloc.reflow(" is used in this module."),
|
alloc.reflow(" is used in this module."),
|
||||||
|
]),
|
||||||
alloc.region(region),
|
alloc.region(region),
|
||||||
|
alloc.concat(vec![
|
||||||
alloc.reflow("Since "),
|
alloc.reflow("Since "),
|
||||||
alloc.module(module_id),
|
alloc.module(module_id),
|
||||||
alloc.reflow(" isn't used, you don't need to import it."),
|
alloc.reflow(" isn't used, you don't need to import it."),
|
||||||
]),
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
}
|
||||||
Problem::ExposedButNotDefined(symbol) => {
|
Problem::ExposedButNotDefined(symbol) => {
|
||||||
alloc.stack(vec![
|
alloc.stack(vec![
|
||||||
alloc
|
alloc
|
||||||
|
|
|
@ -3,5 +3,29 @@ app "effect-example"
|
||||||
imports [base.Cmd]
|
imports [base.Cmd]
|
||||||
provides [ main ] to base
|
provides [ main ] to base
|
||||||
|
|
||||||
main : I64
|
Model : I64
|
||||||
main = 42
|
|
||||||
|
Msg : [ Line Str ]
|
||||||
|
|
||||||
|
main = { init, update }
|
||||||
|
|
||||||
|
init : {} -> { model : Model, cmd : Cmd.Cmd Msg }
|
||||||
|
init = \{} ->
|
||||||
|
cmd =
|
||||||
|
Cmd.after (Cmd.putLine "Type a thing, and I'll say it back") \{} ->
|
||||||
|
Cmd.getLine (\l -> Line l)
|
||||||
|
|
||||||
|
{ model: 42, cmd }
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg, Model -> { model : Model, cmd : Cmd.Cmd Msg }
|
||||||
|
update = \msg, model ->
|
||||||
|
when msg is
|
||||||
|
Line line ->
|
||||||
|
cmd =
|
||||||
|
Cmd.after (Cmd.putLine "You said:") \{} ->
|
||||||
|
Cmd.after (Cmd.putLine line) \{} ->
|
||||||
|
Cmd.after (Cmd.putLine "Type another thing, and I'll say it back") \{} ->
|
||||||
|
Cmd.getLine (\l -> Line l)
|
||||||
|
|
||||||
|
{ model: model + 1, cmd }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
platform folkertdev/foo
|
platform folkertdev/foo
|
||||||
requires { main : Effect {} }
|
requires { main : {} }
|
||||||
exposes []
|
exposes []
|
||||||
packages {}
|
packages {}
|
||||||
imports [Cmd]
|
imports [Cmd]
|
||||||
|
@ -11,31 +11,9 @@ platform folkertdev/foo
|
||||||
getLine : Effect Str
|
getLine : Effect Str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mainForHost :
|
mainForHost :
|
||||||
{
|
{
|
||||||
init : ({} -> { model: I64, cmd : (Cmd.Cmd [ Line Str ]) as Fx }) as Init,
|
init : ({} -> { model: I64, cmd : (Cmd.Cmd [ Line Str ]) as Fx }) as Init,
|
||||||
update : ([ Line Str ], I64 -> { model: I64, cmd : Cmd.Cmd [ Line Str ] } ) as Update
|
update : ([ Line Str ], I64 -> { model: I64, cmd : Cmd.Cmd [ Line Str ] } ) as Update
|
||||||
}
|
}
|
||||||
mainForHost =
|
mainForHost = main
|
||||||
{
|
|
||||||
init : \{} ->
|
|
||||||
{
|
|
||||||
model: 42,
|
|
||||||
cmd:
|
|
||||||
Cmd.after (Cmd.putLine "Type a thing, and I'll say it back") \{} ->
|
|
||||||
Cmd.getLine (\l -> Line l)
|
|
||||||
},
|
|
||||||
update : \msg, model ->
|
|
||||||
when msg is
|
|
||||||
Line line ->
|
|
||||||
cmd =
|
|
||||||
Cmd.after (Cmd.putLine "You said:") \{} ->
|
|
||||||
Cmd.after (Cmd.putLine line) \{} ->
|
|
||||||
Cmd.after (Cmd.putLine "Type another thing, and I'll say it back") \{} ->
|
|
||||||
Cmd.getLine (\l -> Line l)
|
|
||||||
|
|
||||||
{ model: model + 1, cmd }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,12 @@ extern "C" {
|
||||||
fn roc_main_size() -> i64;
|
fn roc_main_size() -> i64;
|
||||||
|
|
||||||
#[link_name = "roc__mainForHost_1_Init_caller"]
|
#[link_name = "roc__mainForHost_1_Init_caller"]
|
||||||
fn call_Init(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> ();
|
fn _call_Init(
|
||||||
|
flags: &(),
|
||||||
|
function_pointer: *const u8,
|
||||||
|
closure_data: *const u8,
|
||||||
|
output: *mut u8,
|
||||||
|
) -> ();
|
||||||
|
|
||||||
#[link_name = "roc__mainForHost_1_Init_size"]
|
#[link_name = "roc__mainForHost_1_Init_size"]
|
||||||
fn size_Init() -> i64;
|
fn size_Init() -> i64;
|
||||||
|
@ -27,8 +32,8 @@ extern "C" {
|
||||||
|
|
||||||
#[link_name = "roc__mainForHost_1_Update_caller"]
|
#[link_name = "roc__mainForHost_1_Update_caller"]
|
||||||
fn call_Update(
|
fn call_Update(
|
||||||
msg: Msg,
|
msg: &Msg,
|
||||||
model: Model,
|
model: &Model,
|
||||||
function_pointer: *const u8,
|
function_pointer: *const u8,
|
||||||
closure_data: *const u8,
|
closure_data: *const u8,
|
||||||
output: *mut u8,
|
output: *mut u8,
|
||||||
|
@ -41,7 +46,12 @@ extern "C" {
|
||||||
fn size_Update_result() -> i64;
|
fn size_Update_result() -> i64;
|
||||||
|
|
||||||
#[link_name = "roc__mainForHost_1_Fx_caller"]
|
#[link_name = "roc__mainForHost_1_Fx_caller"]
|
||||||
fn call_Fx(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> ();
|
fn _call_Fx(
|
||||||
|
unit: &(),
|
||||||
|
function_pointer: *const u8,
|
||||||
|
closure_data: *const u8,
|
||||||
|
output: *mut u8,
|
||||||
|
) -> ();
|
||||||
|
|
||||||
#[link_name = "roc__mainForHost_1_Fx_size"]
|
#[link_name = "roc__mainForHost_1_Fx_size"]
|
||||||
fn size_Fx() -> i64;
|
fn size_Fx() -> i64;
|
||||||
|
@ -53,6 +63,17 @@ extern "C" {
|
||||||
fn size_Model() -> i64;
|
fn size_Model() -> i64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn call_Fx(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> () {
|
||||||
|
// Fx (or Cmd on the roc side) is a thunk, so we know its first argument is a (pointer to) unit
|
||||||
|
_call_Fx(&(), function_pointer, closure_data, output)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn call_Init(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> () {
|
||||||
|
// for now, we hardcode flags to be `()` (or `{}` on the roc side)
|
||||||
|
let flags = ();
|
||||||
|
_call_Init(&flags, function_pointer, closure_data, output)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn roc_fx_putChar(foo: i64) -> () {
|
pub fn roc_fx_putChar(foo: i64) -> () {
|
||||||
let character = foo as u8 as char;
|
let character = foo as u8 as char;
|
||||||
|
@ -152,9 +173,11 @@ unsafe fn run_update(
|
||||||
let buffer: *mut std::ffi::c_void = buffer;
|
let buffer: *mut std::ffi::c_void = buffer;
|
||||||
let buffer: *mut u8 = buffer as *mut u8;
|
let buffer: *mut u8 = buffer as *mut u8;
|
||||||
|
|
||||||
|
println!("let's try update!");
|
||||||
|
|
||||||
call_Update(
|
call_Update(
|
||||||
msg,
|
&msg,
|
||||||
model,
|
&model,
|
||||||
function_pointer,
|
function_pointer,
|
||||||
closure_data_ptr,
|
closure_data_ptr,
|
||||||
buffer as *mut u8,
|
buffer as *mut u8,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue