make after work

This commit is contained in:
Folkert 2020-11-06 21:48:54 +01:00
parent f3ed367d97
commit 7e6724262d
7 changed files with 449 additions and 135 deletions

View file

@ -162,15 +162,20 @@ mod cli_run {
); );
} }
#[test]
#[serial(effect)]
fn run_effect_unoptimized() {
check_output(
&example_file("effect", "Main.roc"),
&[],
"I am Dep2.str2\n",
true,
);
}
#[test] #[test]
#[serial(multi_dep_str)] #[serial(multi_dep_str)]
fn run_multi_dep_str_unoptimized() { fn run_multi_dep_str_unoptimized() {
// if true {
// todo!(
// "fix this test so it no longer deadlocks and hangs during monomorphization! The test never shows the error; to see the panic error, run this: cargo run run cli/tests/fixtures/multi-dep-str/Main.roc"
// );
// }
check_output( check_output(
&fixture_file("multi-dep-str", "Main.roc"), &fixture_file("multi-dep-str", "Main.roc"),
&[], &[],

View file

@ -1134,9 +1134,10 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
env.arena.alloc(format!("closure_field_access_{}_", index)), env.arena.alloc(format!("closure_field_access_{}_", index)),
) )
.unwrap(), .unwrap(),
(other, layout) => { (other, layout) => unreachable!(
unreachable!("can only index into struct layout {:?} {:?}", other, layout) "can only index into struct layout\nValue: {:?}\nLayout: {:?}\nIndex: {:?}",
} other, layout, index
),
} }
} }

View file

@ -279,7 +279,7 @@ fn start_phase<'a>(module_id: ModuleId, phase: Phase, state: &mut State<'a>) ->
let deps_by_name = &parsed.deps_by_name; let deps_by_name = &parsed.deps_by_name;
let num_deps = deps_by_name.len(); let num_deps = deps_by_name.len();
let mut dep_idents: IdentIdsByModule = IdentIds::exposed_builtins(num_deps); let mut dep_idents: MutMap<ModuleId, IdentIds> = IdentIds::exposed_builtins(num_deps);
let State { let State {
ident_ids_by_module, ident_ids_by_module,
@ -596,7 +596,7 @@ struct State<'a> {
/// From now on, these will be used by multiple threads; time to make an Arc<Mutex<_>>! /// From now on, these will be used by multiple threads; time to make an Arc<Mutex<_>>!
pub arc_modules: Arc<Mutex<ModuleIds>>, pub arc_modules: Arc<Mutex<ModuleIds>>,
pub ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, pub ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
/// All the dependent modules we've already begun loading - /// All the dependent modules we've already begun loading -
/// meaning we should never kick off another load_module on them! /// meaning we should never kick off another load_module on them!
@ -714,7 +714,7 @@ enum BuildTask<'a> {
LoadModule { LoadModule {
module_name: ModuleName, module_name: ModuleName,
module_ids: Arc<Mutex<ModuleIds>>, module_ids: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
}, },
Parse { Parse {
header: ModuleHeader<'a>, header: ModuleHeader<'a>,
@ -722,7 +722,7 @@ enum BuildTask<'a> {
CanonicalizeAndConstrain { CanonicalizeAndConstrain {
parsed: ParsedModule<'a>, parsed: ParsedModule<'a>,
module_ids: ModuleIds, module_ids: ModuleIds,
dep_idents: IdentIdsByModule, dep_idents: MutMap<ModuleId, IdentIds>,
mode: Mode, mode: Mode,
exposed_symbols: MutSet<Symbol>, exposed_symbols: MutSet<Symbol>,
aliases: MutMap<Symbol, Alias>, aliases: MutMap<Symbol, Alias>,
@ -782,7 +782,6 @@ pub enum Phases {
Monomorphize, Monomorphize,
} }
type IdentIdsByModule = MutMap<ModuleId, IdentIds>;
type MsgSender<'a> = Sender<Msg<'a>>; type MsgSender<'a> = Sender<Msg<'a>>;
/// Add a task to the queue, and notify all the listeners. /// Add a task to the queue, and notify all the listeners.
@ -877,7 +876,7 @@ pub fn load_and_monomorphize_from_str<'a>(
struct LoadStart<'a> { struct LoadStart<'a> {
pub arc_modules: Arc<Mutex<ModuleIds>>, pub arc_modules: Arc<Mutex<ModuleIds>>,
pub ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, pub ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
pub root_id: ModuleId, pub root_id: ModuleId,
pub root_msg: Msg<'a>, pub root_msg: Msg<'a>,
} }
@ -1701,7 +1700,7 @@ fn load_module<'a>(
src_dir: &Path, src_dir: &Path,
module_name: ModuleName, module_name: ModuleName,
module_ids: Arc<Mutex<ModuleIds>>, module_ids: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
let module_start_time = SystemTime::now(); let module_start_time = SystemTime::now();
let mut filename = PathBuf::new(); let mut filename = PathBuf::new();
@ -1756,7 +1755,7 @@ fn parse_header<'a>(
read_file_duration: Duration, read_file_duration: Duration,
filename: PathBuf, filename: PathBuf,
module_ids: Arc<Mutex<ModuleIds>>, module_ids: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
src_bytes: &'a [u8], src_bytes: &'a [u8],
start_time: SystemTime, start_time: SystemTime,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
@ -1814,7 +1813,7 @@ fn load_filename<'a>(
arena: &'a Bump, arena: &'a Bump,
filename: PathBuf, filename: PathBuf,
module_ids: Arc<Mutex<ModuleIds>>, module_ids: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
module_start_time: SystemTime, module_start_time: SystemTime,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
let file_io_start = SystemTime::now(); let file_io_start = SystemTime::now();
@ -1845,7 +1844,7 @@ fn load_from_str<'a>(
filename: PathBuf, filename: PathBuf,
src: &'a str, src: &'a str,
module_ids: Arc<Mutex<ModuleIds>>, module_ids: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
module_start_time: SystemTime, module_start_time: SystemTime,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> {
let file_io_start = SystemTime::now(); let file_io_start = SystemTime::now();
@ -1870,7 +1869,7 @@ fn send_header<'a>(
imports: &'a [Located<ImportsEntry<'a>>], imports: &'a [Located<ImportsEntry<'a>>],
parse_state: parser::State<'a>, parse_state: parser::State<'a>,
module_ids: Arc<Mutex<ModuleIds>>, module_ids: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
module_timing: ModuleTiming, module_timing: ModuleTiming,
) -> (ModuleId, Msg<'a>) { ) -> (ModuleId, Msg<'a>) {
let declared_name: ModuleName = name.value.as_str().into(); let declared_name: ModuleName = name.value.as_str().into();
@ -2109,9 +2108,185 @@ fn run_solve<'a>(
} }
} }
fn fabricate_host_exposed_def<'a>( fn fabricate_effect_after<'a>(
env: &mut roc_can::env::Env,
scope: &mut roc_can::scope::Scope,
module_id: ModuleId,
effect_symbol: Symbol,
effect_tag_name: TagName,
var_store: &mut VarStore,
) -> (Symbol, roc_can::def::Def) {
use roc_can::expr::Expr;
use roc_can::expr::Recursive;
use roc_module::operator::CalledVia;
let thunk_symbol = {
scope
.introduce(
"thunk".into(),
&env.exposed_ident_ids,
&mut env.ident_ids,
Region::zero(),
)
.unwrap()
};
let to_effect_symbol = {
scope
.introduce(
"toEffect".into(),
&env.exposed_ident_ids,
&mut env.ident_ids,
Region::zero(),
)
.unwrap()
};
let after_symbol = {
scope
.introduce(
"after".into(),
&env.exposed_ident_ids,
&mut env.ident_ids,
Region::zero(),
)
.unwrap()
};
// `thunk {}`
let force_thunk_call = {
let boxed = (
var_store.fresh(),
Located::at_zero(Expr::Var(thunk_symbol)),
var_store.fresh(),
var_store.fresh(),
);
let arguments = vec![(var_store.fresh(), Located::at_zero(Expr::EmptyRecord))];
Expr::Call(Box::new(boxed), arguments, CalledVia::Space)
};
// `toEffect (thunk {})`
let to_effect_call = {
let boxed = (
var_store.fresh(),
Located::at_zero(Expr::Var(to_effect_symbol)),
var_store.fresh(),
var_store.fresh(),
);
let arguments = vec![(var_store.fresh(), Located::at_zero(force_thunk_call))];
Expr::Call(Box::new(boxed), arguments, CalledVia::Space)
};
use roc_can::pattern::Pattern;
let arguments = vec![
(
var_store.fresh(),
Located::at_zero(Pattern::AppliedTag {
whole_var: var_store.fresh(),
ext_var: var_store.fresh(),
tag_name: effect_tag_name.clone(),
arguments: vec![(
var_store.fresh(),
Located::at_zero(Pattern::Identifier(thunk_symbol)),
)],
}),
),
(
var_store.fresh(),
Located::at_zero(Pattern::Identifier(to_effect_symbol)),
),
];
let function_var = var_store.fresh();
let after_closure = Expr::Closure {
function_type: function_var,
closure_type: var_store.fresh(),
closure_ext_var: var_store.fresh(),
return_type: var_store.fresh(),
name: after_symbol,
captured_symbols: Vec::new(),
recursive: Recursive::NotRecursive,
arguments,
loc_body: Box::new(Located::at_zero(to_effect_call)),
};
use roc_can::annotation::IntroducedVariables;
let mut introduced_variables = IntroducedVariables::default();
let signature = {
let var_a = var_store.fresh();
let var_b = var_store.fresh();
introduced_variables.insert_named("a".into(), var_a);
introduced_variables.insert_named("b".into(), var_b);
let effect_a = {
let actual =
build_effect_actual(effect_tag_name.clone(), Type::Variable(var_a), var_store);
Type::Alias(
effect_symbol,
vec![("a".into(), Type::Variable(var_a))],
Box::new(actual),
)
};
let effect_b = {
let actual =
build_effect_actual(effect_tag_name.clone(), Type::Variable(var_b), var_store);
Type::Alias(
effect_symbol,
vec![("b".into(), Type::Variable(var_b))],
Box::new(actual),
)
};
let closure_var = var_store.fresh();
introduced_variables.insert_wildcard(closure_var);
let a_to_effect_b = Type::Function(
vec![Type::Variable(var_a)],
Box::new(Type::Variable(closure_var)),
Box::new(effect_b.clone()),
);
let closure_var = var_store.fresh();
introduced_variables.insert_wildcard(closure_var);
Type::Function(
vec![effect_a, a_to_effect_b],
Box::new(Type::Variable(closure_var)),
Box::new(effect_b),
)
};
let def_annotation = roc_can::def::Annotation {
signature,
introduced_variables,
aliases: SendMap::default(),
region: Region::zero(),
};
let pattern = Pattern::Identifier(after_symbol);
let mut pattern_vars = SendMap::default();
pattern_vars.insert(after_symbol, function_var);
let def = roc_can::def::Def {
loc_pattern: Located::at_zero(pattern),
loc_expr: Located::at_zero(after_closure),
expr_var: function_var,
pattern_vars,
annotation: Some(def_annotation),
};
(after_symbol, def)
}
fn fabricate_host_exposed_def<'a>(
env: &mut roc_can::env::Env,
scope: &mut roc_can::scope::Scope,
module_id: ModuleId, module_id: ModuleId,
ident_ids: &mut IdentIds,
symbol: Symbol, symbol: Symbol,
effect_tag_name: TagName, effect_tag_name: TagName,
var_store: &mut VarStore, var_store: &mut VarStore,
@ -2132,11 +2307,21 @@ fn fabricate_host_exposed_def<'a>(
match annotation.typ.shallow_dealias() { match annotation.typ.shallow_dealias() {
Type::Function(args, _, _) => { Type::Function(args, _, _) => {
for _ in 0..args.len() { for i in 0..args.len() {
// let ident_id = ident_ids.gen_unique(); let name = format!("closure_arg_{}", i);
let ident_id = ident_ids.get_or_insert(&"mything".into());
module_id.register_debug_idents(&ident_ids); let arg_symbol = {
let arg_symbol = Symbol::new(module_id, ident_id); let ident = name.clone().into();
scope
.introduce(
ident,
&env.exposed_ident_ids,
&mut env.ident_ids,
Region::zero(),
)
.unwrap()
};
let arg_var = var_store.fresh(); let arg_var = var_store.fresh();
arguments.push((arg_var, Located::at_zero(Pattern::Identifier(arg_symbol)))); arguments.push((arg_var, Located::at_zero(Pattern::Identifier(arg_symbol))));
@ -2156,9 +2341,17 @@ fn fabricate_host_exposed_def<'a>(
}; };
let effect_closure_symbol = { let effect_closure_symbol = {
let ident_id = ident_ids.gen_unique(); let name = "effect_closure";
module_id.register_debug_idents(&ident_ids);
Symbol::new(module_id, ident_id) let ident = name.clone().into();
scope
.introduce(
ident,
&env.exposed_ident_ids,
&mut env.ident_ids,
Region::zero(),
)
.unwrap()
}; };
let empty_record_pattern = Pattern::RecordDestructure { let empty_record_pattern = Pattern::RecordDestructure {
@ -2214,10 +2407,60 @@ fn fabricate_host_exposed_def<'a>(
} }
} }
fn build_effect_actual(effect_tag_name: TagName, a_type: Type, var_store: &mut VarStore) -> Type {
let closure_var = var_store.fresh();
Type::TagUnion(
vec![(
effect_tag_name,
vec![Type::Function(
vec![Type::EmptyRec],
Box::new(Type::Variable(closure_var)),
Box::new(a_type),
)],
)],
Box::new(Type::EmptyTagUnion),
)
}
fn unpack_exposes_entries<'a>(
arena: &'a Bump,
entries: &'a [Located<roc_parse::ast::EffectsEntry<'a>>],
) -> bumpalo::collections::Vec<
'a,
(
&'a Located<&'a str>,
&'a Located<roc_parse::ast::TypeAnnotation<'a>>,
),
> {
use bumpalo::collections::Vec;
use roc_parse::ast::EffectsEntry;
let mut stack: Vec<&EffectsEntry> = Vec::with_capacity_in(entries.len(), arena);
let mut output = Vec::with_capacity_in(entries.len(), arena);
for entry in entries.iter() {
stack.push(&entry.value);
}
while let Some(effects_entry) = stack.pop() {
match effects_entry {
EffectsEntry::Effect { ident, ann } => {
output.push((ident, ann));
}
EffectsEntry::SpaceAfter(nested, _) | EffectsEntry::SpaceBefore(nested, _) => {
stack.push(nested);
}
}
}
output
}
fn fabricate_effects_module<'a>( fn fabricate_effects_module<'a>(
arena: &'a Bump, arena: &'a Bump,
module_ids: Arc<Mutex<ModuleIds>>, module_ids: Arc<Mutex<ModuleIds>>,
ident_ids_by_module: Arc<Mutex<IdentIdsByModule>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
mode: Mode, mode: Mode,
header: PlatformHeader<'a>, header: PlatformHeader<'a>,
module_timing: ModuleTiming, module_timing: ModuleTiming,
@ -2230,48 +2473,112 @@ fn fabricate_effects_module<'a>(
// exposed_symbols: MutSet<Symbol>, // exposed_symbols: MutSet<Symbol>,
// aliases: MutMap<Symbol, Alias>, // aliases: MutMap<Symbol, Alias>,
let mut var_store = VarStore::default();
let num_exposes = header.provides.len() + 1;
let mut exposed: Vec<Symbol> = Vec::with_capacity(num_exposes);
let module_id: ModuleId;
let name = "Effect";
let declared_name: ModuleName = name.into();
let PlatformHeader { effects, .. } = header; let PlatformHeader { effects, .. } = header;
let effect_entries = unpack_exposes_entries(arena, &effects);
let declared_name = "Effect".into(); let hardcoded_exposed_functions = vec![name, "after"];
let module_id = {
let exposed_ident_ids = {
// Lock just long enough to perform the minimal operations necessary. // Lock just long enough to perform the minimal operations necessary.
let mut module_ids = (*module_ids).lock(); let mut module_ids = (*module_ids).lock();
module_ids.get_or_insert(&declared_name)
};
let mut scope = roc_can::scope::Scope::new(module_id, &mut var_store);
let effect_symbol = {
let mut ident_ids_by_module = (*ident_ids_by_module).lock(); let mut ident_ids_by_module = (*ident_ids_by_module).lock();
let ident_ids: &mut IdentIds = ident_ids_by_module.get_mut(&module_id).unwrap(); module_id = module_ids.get_or_insert(&declared_name.as_inline_str());
//let ident_id = ident_ids.get_or_insert(&declared_name);
//Symbol::new(module_id, ident_id)
let ident = declared_name.clone().into(); // Ensure this module has an entry in the exposed_ident_ids map.
ident_ids_by_module
.entry(module_id)
.or_insert_with(IdentIds::default);
let ident_ids = ident_ids_by_module.get_mut(&module_id).unwrap();
// Generate IdentIds entries for all values this module exposes.
// This way, when we encounter them in Defs later, they already
// have an IdentIds entry.
//
// We must *not* add them to scope yet, or else the Defs will
// incorrectly think they're shadowing them!
for (loc_exposed, _) in effect_entries.iter() {
// Use get_or_insert here because the ident_ids may already
// created an IdentId for this, when it was imported exposed
// in a dependent module.
//
// For example, if module A has [ B.{ foo } ], then
// when we get here for B, `foo` will already have
// an IdentId. We must reuse that!
let ident_id = ident_ids.get_or_insert(&loc_exposed.value.into());
let symbol = Symbol::new(module_id, ident_id);
exposed.push(symbol);
}
for hardcoded in hardcoded_exposed_functions {
// Use get_or_insert here because the ident_ids may already
// created an IdentId for this, when it was imported exposed
// in a dependent module.
//
// For example, if module A has [ B.{ foo } ], then
// when we get here for B, `foo` will already have
// an IdentId. We must reuse that!
let ident_id = ident_ids.get_or_insert(&hardcoded.into());
let symbol = Symbol::new(module_id, ident_id);
exposed.push(symbol);
}
if cfg!(debug_assertions) {
module_id.register_debug_idents(&ident_ids);
}
ident_ids.clone()
};
// a platform module has no dependencies, hence empty
let dep_idents: MutMap<ModuleId, IdentIds> = IdentIds::exposed_builtins(0);
let mut var_store = VarStore::default();
let module_ids = { (*module_ids).lock().clone() };
let mut scope = roc_can::scope::Scope::new(module_id, &mut var_store);
let mut can_env = roc_can::env::Env::new(module_id, dep_idents, &module_ids, exposed_ident_ids);
let mut ident_ids_by_module = (*ident_ids_by_module).lock();
let ident_ids: &mut IdentIds = ident_ids_by_module.get_mut(&module_id).unwrap();
let effect_symbol = {
let ident = name.clone().into();
scope scope
.introduce(ident, &(ident_ids.clone()), ident_ids, Region::zero()) .introduce(
ident,
&can_env.exposed_ident_ids,
&mut can_env.ident_ids,
Region::zero(),
)
.unwrap() .unwrap()
}; };
let effect_tag_name = TagName::Private(effect_symbol);
let mut aliases = MutMap::default(); let mut aliases = MutMap::default();
let alias = { let alias = {
let a_var = var_store.fresh(); let a_var = var_store.fresh();
let closure_var = var_store.fresh();
let actual = Type::TagUnion( let actual = build_effect_actual(
vec![( effect_tag_name.clone(),
TagName::Private(effect_symbol), Type::Variable(a_var),
vec![Type::Function( &mut var_store,
vec![Type::EmptyRec],
Box::new(Type::Variable(closure_var)),
Box::new(Type::Variable(a_var)),
)],
)],
Box::new(Type::EmptyTagUnion),
); );
scope.add_alias( scope.add_alias(
effect_symbol, effect_symbol,
Region::zero(), Region::zero(),
@ -2287,69 +2594,56 @@ fn fabricate_effects_module<'a>(
let mut declarations = Vec::new(); let mut declarations = Vec::new();
let exposed_vars_by_symbol = { let exposed_vars_by_symbol = {
let module_ids = (*module_ids).lock();
let mut ident_ids_by_module = (*ident_ids_by_module).lock();
let ident_ids: &mut IdentIds = ident_ids_by_module.get_mut(&module_id).unwrap();
let ident_id = ident_ids.get_or_insert(&declared_name);
let effect_symbol = Symbol::new(module_id, ident_id);
let mut exposed_vars_by_symbol = Vec::new(); let mut exposed_vars_by_symbol = Vec::new();
{ {
use bumpalo::collections::Vec; for (ident, ann) in effect_entries {
let symbol = {
let mut stack: Vec<&EffectsEntry> = Vec::with_capacity_in(effects.len(), arena); scope
.introduce(
for entry in &effects { ident.value.into(),
stack.push(&entry.value); &can_env.exposed_ident_ids,
} &mut can_env.ident_ids,
use roc_parse::ast::EffectsEntry;
// TODO this clone is almost certainly wrong
let exposed_ident_ids = ident_ids.clone();
let dep_idents: MutMap<ModuleId, IdentIds> = MutMap::default();
let mut can_env =
roc_can::env::Env::new(module_id, dep_idents, &module_ids, exposed_ident_ids);
while let Some(effects_entry) = stack.pop() {
match effects_entry {
EffectsEntry::Effect { ident, ann } => {
let as_inlinable_string: inlinable_string::InlinableString =
ident.value.into();
let ident_id = ident_ids.get_or_insert(&as_inlinable_string);
let symbol = Symbol::new(module_id, ident_id);
let annotation = roc_can::annotation::canonicalize_annotation(
&mut can_env,
&mut scope,
&ann.value,
Region::zero(), Region::zero(),
&mut var_store, )
); .unwrap()
};
let def = fabricate_host_exposed_def( let annotation = roc_can::annotation::canonicalize_annotation(
module_id, &mut can_env,
ident_ids, &mut scope,
symbol, &ann.value,
TagName::Private(effect_symbol), Region::zero(),
&mut var_store, &mut var_store,
annotation, );
);
exposed_vars_by_symbol.push((symbol, def.expr_var)); let def = fabricate_host_exposed_def(
&mut can_env,
&mut scope,
module_id,
symbol,
TagName::Private(effect_symbol),
&mut var_store,
annotation,
);
declarations.push(Declaration::Declare(def)); exposed_vars_by_symbol.push((symbol, def.expr_var));
}
EffectsEntry::SpaceAfter(nested, _) | EffectsEntry::SpaceBefore(nested, _) => { declarations.push(Declaration::Declare(def));
stack.push(nested);
}
}
} }
} }
let (effect_after_symbol, def) = fabricate_effect_after(
&mut can_env,
&mut scope,
module_id,
effect_symbol,
effect_tag_name,
&mut var_store,
);
exposed_vars_by_symbol.push((effect_after_symbol, def.expr_var));
declarations.push(Declaration::Declare(def));
exposed_vars_by_symbol exposed_vars_by_symbol
}; };
@ -2360,8 +2654,8 @@ fn fabricate_effects_module<'a>(
declarations, declarations,
exposed_imports: MutMap::default(), exposed_imports: MutMap::default(),
lookups: Vec::new(), lookups: Vec::new(),
problems: Vec::new(), problems: can_env.problems,
ident_ids: IdentIds::default(), ident_ids: can_env.ident_ids,
exposed_vars_by_symbol, exposed_vars_by_symbol,
references: MutSet::default(), references: MutSet::default(),
}; };
@ -2377,6 +2671,7 @@ fn fabricate_effects_module<'a>(
// } // }
let constraint = constrain_module(&module_output, module_id, mode, &mut var_store); let constraint = constrain_module(&module_output, module_id, mode, &mut var_store);
dbg!(&module_output.aliases);
let module = Module { let module = Module {
module_id, module_id,
@ -2431,7 +2726,7 @@ fn fabricate_effects_module<'a>(
fn canonicalize_and_constrain<'a>( fn canonicalize_and_constrain<'a>(
arena: &'a Bump, arena: &'a Bump,
module_ids: &ModuleIds, module_ids: &ModuleIds,
dep_idents: IdentIdsByModule, dep_idents: MutMap<ModuleId, IdentIds>,
exposed_symbols: MutSet<Symbol>, exposed_symbols: MutSet<Symbol>,
aliases: MutMap<Symbol, Alias>, aliases: MutMap<Symbol, Alias>,
mode: Mode, mode: Mode,
@ -2742,6 +3037,8 @@ fn add_def_to_module<'a>(
// this is a top-level definition, it should not capture anything // this is a top-level definition, it should not capture anything
debug_assert!(captured_symbols.is_empty()); debug_assert!(captured_symbols.is_empty());
dbg!(symbol, &loc_body.value);
// If this is an exposed symbol, we need to // If this is an exposed symbol, we need to
// register it as such. Otherwise, since it // register it as such. Otherwise, since it
// never gets called by Roc code, it will never // never gets called by Roc code, it will never

View file

@ -15,7 +15,7 @@ pub struct Symbol(u64);
// Set it to false if you want to see the raw ModuleId and IdentId ints, // Set it to false if you want to see the raw ModuleId and IdentId ints,
// but please set it back to true before checking in the result! // but please set it back to true before checking in the result!
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
const PRETTY_PRINT_DEBUG_SYMBOLS: bool = true; const PRETTY_PRINT_DEBUG_SYMBOLS: bool = false;
/// In Debug builds only, Symbol has a name() method that lets /// In Debug builds only, Symbol has a name() method that lets
/// you look up its name in a global intern table. This table is /// you look up its name in a global intern table. This table is

View file

@ -3,7 +3,7 @@ use crate::exhaustive::{Ctor, Guard, RenderAs, TagId};
use crate::layout::{Builtin, ClosureLayout, Layout, LayoutCache, LayoutProblem}; use crate::layout::{Builtin, ClosureLayout, Layout, LayoutCache, LayoutProblem};
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_collections::all::{default_hasher, MutMap, MutSet, SendMap}; use roc_collections::all::{default_hasher, MutMap, MutSet};
use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName}; use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName};
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_module::symbol::{IdentIds, ModuleId, Symbol};
@ -419,6 +419,7 @@ impl<'a> Procs<'a> {
match patterns_to_when(env, layout_cache, loc_args, ret_var, loc_body) { match patterns_to_when(env, layout_cache, loc_args, ret_var, loc_body) {
Ok((_, pattern_symbols, body)) => { Ok((_, pattern_symbols, body)) => {
dbg!(symbol, &pattern_symbols, &body);
// an anonymous closure. These will always be specialized already // an anonymous closure. These will always be specialized already
// by the surrounding context, so we can add pending specializations // by the surrounding context, so we can add pending specializations
// for them immediately. // for them immediately.
@ -587,12 +588,12 @@ impl<'a> Procs<'a> {
self.specialized self.specialized
.insert((symbol, layout.clone()), InProgress); .insert((symbol, layout.clone()), InProgress);
dbg!(symbol, &pending);
match specialize(env, self, symbol, layout_cache, pending, partial_proc) { match specialize(env, self, symbol, layout_cache, pending, partial_proc) {
Ok((proc, _ignore_layout)) => { Ok((proc, _ignore_layout)) => {
// the `layout` is a function pointer, while `_ignore_layout` can be a // the `layout` is a function pointer, while `_ignore_layout` can be a
// closure. We only specialize functions, storing this value with a closure // closure. We only specialize functions, storing this value with a closure
// layout will give trouble. // layout will give trouble.
dbg!(symbol, &layout);
self.specialized.insert((symbol, layout), Done(proc)); self.specialized.insert((symbol, layout), Done(proc));
} }
Err(error) => { Err(error) => {
@ -614,6 +615,7 @@ fn add_pending<'a>(
layout: Layout<'a>, layout: Layout<'a>,
pending: PendingSpecialization, pending: PendingSpecialization,
) { ) {
// dbg!(symbol, &layout, &pending);
let all_pending = pending_specializations let all_pending = pending_specializations
.entry(symbol) .entry(symbol)
.or_insert_with(|| HashMap::with_capacity_and_hasher(1, default_hasher())); .or_insert_with(|| HashMap::with_capacity_and_hasher(1, default_hasher()));
@ -1337,6 +1339,7 @@ pub fn specialize_all<'a>(
mut procs: Procs<'a>, mut procs: Procs<'a>,
layout_cache: &mut LayoutCache<'a>, layout_cache: &mut LayoutCache<'a>,
) -> Procs<'a> { ) -> Procs<'a> {
dbg!(&procs.externals_others_need);
let it = procs.externals_others_need.specs.clone(); let it = procs.externals_others_need.specs.clone();
let it = it let it = it
.into_iter() .into_iter()
@ -1360,7 +1363,6 @@ pub fn specialize_all<'a>(
partial_proc, partial_proc,
) { ) {
Ok((proc, layout)) => { Ok((proc, layout)) => {
dbg!(name, &layout);
procs.specialized.insert((name, layout), Done(proc)); procs.specialized.insert((name, layout), Done(proc));
} }
Err(error) => { Err(error) => {
@ -1406,7 +1408,7 @@ pub fn specialize_all<'a>(
procs procs
.specialized .specialized
.insert((name, outside_layout.clone()), InProgress); .insert((name, outside_layout.clone()), InProgress);
dbg!(name);
match specialize( match specialize(
env, env,
&mut procs, &mut procs,
@ -1417,9 +1419,6 @@ pub fn specialize_all<'a>(
) { ) {
Ok((proc, layout)) => { Ok((proc, layout)) => {
debug_assert_eq!(outside_layout, layout); debug_assert_eq!(outside_layout, layout);
// procs.specialized.remove(&(name, outside_layout));
// dbg!(name, &layout);
// procs.specialized.insert((name, layout), Done(proc));
if let Layout::Closure(args, closure, ret) = layout { if let Layout::Closure(args, closure, ret) = layout {
procs.specialized.remove(&(name, outside_layout)); procs.specialized.remove(&(name, outside_layout));
@ -1457,6 +1456,8 @@ fn specialize_external<'a>(
host_exposed_variables: &[(Symbol, Variable)], host_exposed_variables: &[(Symbol, Variable)],
partial_proc: PartialProc<'a>, partial_proc: PartialProc<'a>,
) -> Result<Proc<'a>, LayoutProblem> { ) -> Result<Proc<'a>, LayoutProblem> {
println!("------- SPECIALIZE EXTERNAL {:?}", proc_name);
let PartialProc { let PartialProc {
annotation, annotation,
pattern_symbols, pattern_symbols,
@ -1465,6 +1466,8 @@ fn specialize_external<'a>(
is_self_recursive, is_self_recursive,
} = partial_proc; } = partial_proc;
dbg!(&body);
// unify the called function with the specialized signature, then specialize the function body // unify the called function with the specialized signature, then specialize the function body
let snapshot = env.subs.snapshot(); let snapshot = env.subs.snapshot();
let cache_snapshot = layout_cache.snapshot(); let cache_snapshot = layout_cache.snapshot();
@ -1472,7 +1475,7 @@ fn specialize_external<'a>(
let unified = roc_unify::unify::unify(env.subs, annotation, fn_var); let unified = roc_unify::unify::unify(env.subs, annotation, fn_var);
let is_valid = matches!(unified, roc_unify::unify::Unified::Success(_)); let is_valid = matches!(unified, roc_unify::unify::Unified::Success(_));
debug_assert!(is_valid); debug_assert!(is_valid, "unificaton failure for {:?}", proc_name);
// if this is a closure, add the closure record argument // if this is a closure, add the closure record argument
let pattern_symbols = if let CapturedSymbols::Captured(_) = captured_symbols { let pattern_symbols = if let CapturedSymbols::Captured(_) = captured_symbols {
@ -1558,7 +1561,8 @@ fn specialize_external<'a>(
None => None, None => None,
}; };
dbg!(proc_name, &proc_args, &ret_layout); println!("Done for {:?}\n\n", proc_name);
let proc = Proc { let proc = Proc {
name: proc_name, name: proc_name,
args: proc_args, args: proc_args,
@ -2977,16 +2981,19 @@ pub fn with_hole<'a>(
}; };
match loc_expr.value { match loc_expr.value {
roc_can::expr::Expr::Var(proc_name) if is_known(&proc_name) => call_by_name( roc_can::expr::Expr::Var(proc_name) if is_known(&proc_name) => {
env, // a call by a known name
procs, call_by_name(
fn_var, env,
proc_name, procs,
loc_args, fn_var,
layout_cache, proc_name,
assigned, loc_args,
hole, layout_cache,
), assigned,
hole,
)
}
_ => { _ => {
// Call by pointer - the closure was anonymous, e.g. // Call by pointer - the closure was anonymous, e.g.
// //
@ -3184,6 +3191,7 @@ pub fn with_hole<'a>(
hole, hole,
); );
let (var, _) = args[0];
let iter = args let iter = args
.into_iter() .into_iter()
.rev() .rev()
@ -4699,7 +4707,6 @@ fn call_by_name<'a>(
procs.specialized.remove(&(proc_name, full_layout)); procs.specialized.remove(&(proc_name, full_layout));
dbg!(proc_name, &function_layout.full);
procs.specialized.insert( procs.specialized.insert(
(proc_name, function_layout.full.clone()), (proc_name, function_layout.full.clone()),
Done(proc), Done(proc),

View file

@ -1,5 +1,9 @@
app Main provides [ main ] imports [ Effect ] app Main provides [ main ] imports [ Effect ]
main : Effect.Effect {} as Fx main : Effect.Effect {} as Fx
main = main =
Effect.putChar 68 e = Effect.putChar 68
e |> Effect.after \{} -> e

View file

@ -20,7 +20,7 @@ extern "C" {
#[no_mangle] #[no_mangle]
pub fn roc_fx_put_char(foo: i64) -> () { pub fn roc_fx_put_char(foo: i64) -> () {
let character = foo as u8 as char; let character = foo as u8 as char;
println!("{}", character); print!("{}", character);
() ()
} }