mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 07:49:17 +03:00
Merge pull request #4768 from roc-lang/expects-store-specialized-variable
Support using dbg/expect in polymorphic functions
This commit is contained in:
commit
f550f049db
@ -568,7 +568,7 @@ mod cli_run {
|
||||
r#"
|
||||
This expectation failed:
|
||||
|
||||
14│ expect x != x
|
||||
18│ expect x != x
|
||||
^^^^^^
|
||||
|
||||
When it failed, these variables had these values:
|
||||
@ -576,8 +576,11 @@ mod cli_run {
|
||||
x : Num *
|
||||
x = 42
|
||||
|
||||
[<ignored for tests> 15:9] 42
|
||||
[<ignored for tests> 16:9] "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||
[<ignored for tests> 19:9] 42
|
||||
[<ignored for tests> 20:9] "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||
[<ignored for tests> 13:9] "abc"
|
||||
[<ignored for tests> 13:9] 10
|
||||
[<ignored for tests> 13:9] A (B C)
|
||||
Program finished!
|
||||
"#
|
||||
),
|
||||
|
1
crates/cli_testing_examples/.gitignore
vendored
1
crates/cli_testing_examples/.gitignore
vendored
@ -4,3 +4,4 @@ libapp.so
|
||||
dynhost
|
||||
preprocessedhost
|
||||
metadata
|
||||
expects
|
||||
|
@ -9,9 +9,17 @@ expect
|
||||
|
||||
a == b
|
||||
|
||||
polyDbg = \x ->
|
||||
dbg x
|
||||
x
|
||||
|
||||
main =
|
||||
x = 42
|
||||
expect x != x
|
||||
dbg x
|
||||
dbg "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||
"Program finished!\n"
|
||||
|
||||
r = {x : polyDbg "abc", y: polyDbg 10u8, z : polyDbg (A (B C))}
|
||||
|
||||
when r is
|
||||
_ -> "Program finished!\n"
|
||||
|
@ -1287,6 +1287,14 @@ fn lowlevel_spec<'a>(
|
||||
|
||||
builder.add_make_tuple(block, &[byte_index, string, is_ok, problem_code])
|
||||
}
|
||||
Dbg => {
|
||||
let arguments = [env.symbols[&arguments[0]]];
|
||||
|
||||
let result_type =
|
||||
layout_spec(env, builder, interner, layout, &WhenRecursive::Unreachable)?;
|
||||
|
||||
builder.add_unknown_with(block, &arguments, result_type)
|
||||
}
|
||||
_other => {
|
||||
// println!("missing {:?}", _other);
|
||||
// TODO overly pessimstic
|
||||
|
@ -705,7 +705,7 @@ pub fn constrain_expr(
|
||||
expected,
|
||||
);
|
||||
|
||||
constraints.exists_many([], [cond_con, continuation_con])
|
||||
constraints.exists_many([*variable], [cond_con, continuation_con])
|
||||
}
|
||||
|
||||
If {
|
||||
|
@ -2585,6 +2585,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
condition: cond_symbol,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let bd = env.builder;
|
||||
@ -2619,6 +2620,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
*cond_symbol,
|
||||
*region,
|
||||
lookups,
|
||||
variables,
|
||||
);
|
||||
|
||||
if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
@ -2653,6 +2655,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
condition: cond_symbol,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let bd = env.builder;
|
||||
@ -2687,6 +2690,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
*cond_symbol,
|
||||
*region,
|
||||
lookups,
|
||||
variables,
|
||||
);
|
||||
|
||||
bd.build_unconditional_branch(then_block);
|
||||
|
@ -10,6 +10,7 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::ir::LookupType;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_region::all::Region;
|
||||
|
||||
@ -143,6 +144,21 @@ pub(crate) fn notify_parent_dbg(env: &Env, shared_memory: &SharedMemoryPointer)
|
||||
);
|
||||
}
|
||||
|
||||
// Shape of expect frame:
|
||||
//
|
||||
// ===
|
||||
// Fixed-size header
|
||||
// ===
|
||||
// /-- ptr_lookup_1 (ptr_size)
|
||||
// | var_lookup_1 (u32)
|
||||
// | ..
|
||||
// | ptr_lookup_n (ptr_size)
|
||||
// | var_lookup_n (u32)
|
||||
// \-> lookup_val_1 (varsize)
|
||||
// ..
|
||||
// lookup_val_n (varsize)
|
||||
//
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
@ -151,6 +167,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
condition: Symbol,
|
||||
region: Region,
|
||||
lookups: &[Symbol],
|
||||
lookup_variables: &[LookupType],
|
||||
) {
|
||||
let original_ptr = shared_memory.0;
|
||||
|
||||
@ -160,9 +177,11 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
|
||||
let after_header = offset;
|
||||
|
||||
let space_for_offsets = env
|
||||
.ptr_int()
|
||||
.const_int((lookups.len() * env.target_info.ptr_size()) as _, false);
|
||||
let space_for_offsets = env.ptr_int().const_int(
|
||||
(lookups.len() * env.target_info.ptr_size() + lookups.len() * std::mem::size_of::<u32>())
|
||||
as _,
|
||||
false,
|
||||
);
|
||||
|
||||
let mut lookup_starts = bumpalo::collections::Vec::with_capacity_in(lookups.len(), env.arena);
|
||||
|
||||
@ -203,14 +222,43 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
{
|
||||
let mut offset = after_header;
|
||||
|
||||
for lookup_start in lookup_starts {
|
||||
build_copy(env, original_ptr, offset, lookup_start.into());
|
||||
for (lookup_start, lookup_var) in lookup_starts.into_iter().zip(lookup_variables) {
|
||||
// Store the pointer to the value
|
||||
{
|
||||
build_copy(env, original_ptr, offset, lookup_start.into());
|
||||
|
||||
let ptr_width = env
|
||||
.ptr_int()
|
||||
.const_int(env.target_info.ptr_size() as _, false);
|
||||
let ptr_width = env
|
||||
.ptr_int()
|
||||
.const_int(env.target_info.ptr_size() as _, false);
|
||||
|
||||
offset = env.builder.build_int_add(offset, ptr_width, "offset")
|
||||
offset = env.builder.build_int_add(offset, ptr_width, "offset");
|
||||
}
|
||||
|
||||
// Store the specialized variable of the value
|
||||
{
|
||||
let ptr = unsafe {
|
||||
env.builder
|
||||
.build_in_bounds_gep(original_ptr, &[offset], "at_current_offset")
|
||||
};
|
||||
|
||||
let u32_ptr = env.context.i32_type().ptr_type(AddressSpace::Generic);
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_pointer_cast(ptr, u32_ptr, "cast_ptr_type");
|
||||
|
||||
let var_value = env
|
||||
.context
|
||||
.i32_type()
|
||||
.const_int(lookup_var.index() as _, false);
|
||||
|
||||
env.builder.build_store(ptr, var_value);
|
||||
|
||||
let var_size = env
|
||||
.ptr_int()
|
||||
.const_int(std::mem::size_of::<u32>() as _, false);
|
||||
|
||||
offset = env.builder.build_int_add(offset, var_size, "offset");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::{low_level::LowLevel, symbol::Symbol};
|
||||
use roc_mono::{
|
||||
ir::HigherOrderLowLevel,
|
||||
ir::{HigherOrderLowLevel, LookupType},
|
||||
layout::{Builtin, LambdaSet, Layout, LayoutIds},
|
||||
};
|
||||
use roc_target::PtrWidth;
|
||||
@ -1120,14 +1120,19 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||
}
|
||||
},
|
||||
Dbg => {
|
||||
// now what
|
||||
arguments!(condition);
|
||||
assert_eq!(args.len(), 2);
|
||||
let condition = load_symbol(scope, &args[0]);
|
||||
let dbg_spec_var_symbol = args[1];
|
||||
|
||||
if env.mode.runs_expects() {
|
||||
let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(args[0]) };
|
||||
|
||||
let shared_memory = crate::llvm::expect::SharedMemoryPointer::get(env);
|
||||
|
||||
// HACK(dbg-spec-var): the specialized type variable is passed along as a fake symbol
|
||||
let specialized_var =
|
||||
unsafe { LookupType::from_index(dbg_spec_var_symbol.ident_id().index() as _) };
|
||||
|
||||
crate::llvm::expect::clone_to_shared_memory(
|
||||
env,
|
||||
scope,
|
||||
@ -1136,6 +1141,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||
args[0],
|
||||
region,
|
||||
&[args[0]],
|
||||
&[specialized_var],
|
||||
);
|
||||
|
||||
crate::llvm::expect::notify_parent_dbg(env, &shared_memory);
|
||||
|
@ -138,7 +138,6 @@ struct ModuleCache<'a> {
|
||||
found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
||||
late_specializations: MutMap<ModuleId, LateSpecializationsModule<'a>>,
|
||||
external_specializations_requested: MutMap<ModuleId, Vec<ExternalSpecializations<'a>>>,
|
||||
expectations: VecMap<ModuleId, Expectations>,
|
||||
|
||||
/// Various information
|
||||
imports: MutMap<ModuleId, MutSet<ModuleId>>,
|
||||
@ -215,7 +214,6 @@ impl Default for ModuleCache<'_> {
|
||||
can_problems: Default::default(),
|
||||
type_problems: Default::default(),
|
||||
sources: Default::default(),
|
||||
expectations: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -435,6 +433,7 @@ fn start_phase<'a>(
|
||||
decls,
|
||||
ident_ids,
|
||||
abilities_store,
|
||||
expectations,
|
||||
} = typechecked;
|
||||
|
||||
let mut imported_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
||||
@ -451,8 +450,8 @@ fn start_phase<'a>(
|
||||
|
||||
let derived_module = SharedDerivedModule::clone(&state.derived_module);
|
||||
|
||||
let build_expects = matches!(state.exec_mode, ExecutionMode::Test)
|
||||
&& state.module_cache.expectations.contains_key(&module_id);
|
||||
let build_expects =
|
||||
matches!(state.exec_mode, ExecutionMode::Test) && expectations.is_some();
|
||||
|
||||
BuildTask::BuildPendingSpecializations {
|
||||
layout_cache,
|
||||
@ -467,6 +466,7 @@ fn start_phase<'a>(
|
||||
// TODO: awful, how can we get rid of the clone?
|
||||
exposed_by_module: state.exposed_types.clone(),
|
||||
derived_module,
|
||||
expectations,
|
||||
build_expects,
|
||||
}
|
||||
}
|
||||
@ -488,67 +488,90 @@ fn start_phase<'a>(
|
||||
specializations_we_must_make.extend(derived_synth_specializations)
|
||||
}
|
||||
|
||||
let (mut ident_ids, mut subs, mut procs_base, layout_cache, mut module_timing) =
|
||||
if state.make_specializations_pass.current_pass() == 1
|
||||
&& module_id == ModuleId::DERIVED_GEN
|
||||
{
|
||||
// This is the first time the derived module is introduced into the load
|
||||
// graph. It has no abilities of its own or anything, just generate fresh
|
||||
// information for it.
|
||||
(
|
||||
IdentIds::default(),
|
||||
Subs::default(),
|
||||
ProcsBase::default(),
|
||||
LayoutCache::new(state.layout_interner.fork(), state.target_info),
|
||||
ModuleTiming::new(Instant::now()),
|
||||
)
|
||||
} else if state.make_specializations_pass.current_pass() == 1 {
|
||||
let found_specializations = state
|
||||
.module_cache
|
||||
.found_specializations
|
||||
.remove(&module_id)
|
||||
.unwrap();
|
||||
let (
|
||||
mut ident_ids,
|
||||
mut subs,
|
||||
expectations,
|
||||
mut procs_base,
|
||||
layout_cache,
|
||||
mut module_timing,
|
||||
) = if state.make_specializations_pass.current_pass() == 1
|
||||
&& module_id == ModuleId::DERIVED_GEN
|
||||
{
|
||||
// This is the first time the derived module is introduced into the load
|
||||
// graph. It has no abilities of its own or anything, just generate fresh
|
||||
// information for it.
|
||||
(
|
||||
IdentIds::default(),
|
||||
Subs::default(),
|
||||
None, // no expectations for derived module
|
||||
ProcsBase::default(),
|
||||
LayoutCache::new(state.layout_interner.fork(), state.target_info),
|
||||
ModuleTiming::new(Instant::now()),
|
||||
)
|
||||
} else if state.make_specializations_pass.current_pass() == 1 {
|
||||
let found_specializations = state
|
||||
.module_cache
|
||||
.found_specializations
|
||||
.remove(&module_id)
|
||||
.unwrap();
|
||||
|
||||
let FoundSpecializationsModule {
|
||||
ident_ids,
|
||||
subs,
|
||||
procs_base,
|
||||
layout_cache,
|
||||
module_timing,
|
||||
abilities_store,
|
||||
} = found_specializations;
|
||||
let FoundSpecializationsModule {
|
||||
ident_ids,
|
||||
subs,
|
||||
procs_base,
|
||||
layout_cache,
|
||||
module_timing,
|
||||
abilities_store,
|
||||
expectations,
|
||||
} = found_specializations;
|
||||
|
||||
let our_exposed_types = state
|
||||
.exposed_types
|
||||
.get(&module_id)
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!("Exposed types for {:?} missing", module_id)
|
||||
})
|
||||
.clone();
|
||||
let our_exposed_types = state
|
||||
.exposed_types
|
||||
.get(&module_id)
|
||||
.unwrap_or_else(|| {
|
||||
internal_error!("Exposed types for {:?} missing", module_id)
|
||||
})
|
||||
.clone();
|
||||
|
||||
// Add our abilities to the world.
|
||||
state.world_abilities.insert(
|
||||
module_id,
|
||||
abilities_store,
|
||||
our_exposed_types.exposed_types_storage_subs,
|
||||
);
|
||||
// Add our abilities to the world.
|
||||
state.world_abilities.insert(
|
||||
module_id,
|
||||
abilities_store,
|
||||
our_exposed_types.exposed_types_storage_subs,
|
||||
);
|
||||
|
||||
(ident_ids, subs, procs_base, layout_cache, module_timing)
|
||||
} else {
|
||||
let LateSpecializationsModule {
|
||||
ident_ids,
|
||||
subs,
|
||||
module_timing,
|
||||
layout_cache,
|
||||
procs_base,
|
||||
} = state
|
||||
.module_cache
|
||||
.late_specializations
|
||||
.remove(&module_id)
|
||||
.unwrap();
|
||||
(
|
||||
ident_ids,
|
||||
subs,
|
||||
expectations,
|
||||
procs_base,
|
||||
layout_cache,
|
||||
module_timing,
|
||||
)
|
||||
} else {
|
||||
let LateSpecializationsModule {
|
||||
ident_ids,
|
||||
subs,
|
||||
expectations,
|
||||
module_timing,
|
||||
layout_cache,
|
||||
procs_base,
|
||||
} = state
|
||||
.module_cache
|
||||
.late_specializations
|
||||
.remove(&module_id)
|
||||
.unwrap();
|
||||
|
||||
(ident_ids, subs, procs_base, layout_cache, module_timing)
|
||||
};
|
||||
(
|
||||
ident_ids,
|
||||
subs,
|
||||
expectations,
|
||||
procs_base,
|
||||
layout_cache,
|
||||
module_timing,
|
||||
)
|
||||
};
|
||||
|
||||
if module_id == ModuleId::DERIVED_GEN {
|
||||
load_derived_partial_procs(
|
||||
@ -579,6 +602,7 @@ fn start_phase<'a>(
|
||||
// TODO: awful, how can we get rid of the clone?
|
||||
exposed_by_module: state.exposed_types.clone(),
|
||||
derived_module,
|
||||
expectations,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -679,6 +703,7 @@ pub struct TypeCheckedModule<'a> {
|
||||
pub decls: Declarations,
|
||||
pub ident_ids: IdentIds,
|
||||
pub abilities_store: AbilitiesStore,
|
||||
pub expectations: Option<Expectations>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -689,6 +714,7 @@ struct FoundSpecializationsModule<'a> {
|
||||
subs: Subs,
|
||||
module_timing: ModuleTiming,
|
||||
abilities_store: AbilitiesStore,
|
||||
expectations: Option<Expectations>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -698,6 +724,7 @@ struct LateSpecializationsModule<'a> {
|
||||
module_timing: ModuleTiming,
|
||||
layout_cache: LayoutCache<'a>,
|
||||
procs_base: ProcsBase<'a>,
|
||||
expectations: Option<Expectations>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -831,6 +858,7 @@ enum Msg<'a> {
|
||||
module_timing: ModuleTiming,
|
||||
abilities_store: AbilitiesStore,
|
||||
toplevel_expects: ToplevelExpects,
|
||||
expectations: Option<Expectations>,
|
||||
},
|
||||
MadeSpecializations {
|
||||
module_id: ModuleId,
|
||||
@ -842,6 +870,7 @@ enum Msg<'a> {
|
||||
update_mode_ids: UpdateModeIds,
|
||||
module_timing: ModuleTiming,
|
||||
subs: Subs,
|
||||
expectations: Option<Expectations>,
|
||||
},
|
||||
|
||||
/// The task is to only typecheck AND monomorphize modules
|
||||
@ -852,6 +881,7 @@ enum Msg<'a> {
|
||||
/// DO NOT use the one on state; that is left in an empty state after specialization is complete!
|
||||
layout_interner: STLayoutInterner<'a>,
|
||||
exposed_to_host: ExposedToHost,
|
||||
module_expectations: VecMap<ModuleId, Expectations>,
|
||||
},
|
||||
|
||||
FailedToParse(FileError<'a, SyntaxError<'a>>),
|
||||
@ -1147,6 +1177,7 @@ enum BuildTask<'a> {
|
||||
exposed_by_module: ExposedByModule,
|
||||
abilities_store: AbilitiesStore,
|
||||
derived_module: SharedDerivedModule,
|
||||
expectations: Option<Expectations>,
|
||||
build_expects: bool,
|
||||
},
|
||||
MakeSpecializations {
|
||||
@ -1160,6 +1191,7 @@ enum BuildTask<'a> {
|
||||
exposed_by_module: ExposedByModule,
|
||||
world_abilities: WorldAbilities,
|
||||
derived_module: SharedDerivedModule,
|
||||
expectations: Option<Expectations>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -1717,6 +1749,7 @@ fn state_thread_step<'a>(
|
||||
subs,
|
||||
layout_interner,
|
||||
exposed_to_host,
|
||||
module_expectations,
|
||||
} => {
|
||||
// We're done! There should be no more messages pending.
|
||||
debug_assert!(msg_rx.is_empty());
|
||||
@ -1727,6 +1760,7 @@ fn state_thread_step<'a>(
|
||||
subs,
|
||||
layout_interner,
|
||||
exposed_to_host,
|
||||
module_expectations,
|
||||
)?;
|
||||
|
||||
Ok(ControlFlow::Break(LoadResult::Monomorphized(monomorphized)))
|
||||
@ -2608,22 +2642,19 @@ fn update<'a>(
|
||||
.expect("root or this module is not yet known - that's a bug!")
|
||||
};
|
||||
|
||||
if should_include_expects {
|
||||
let opt_expectations = if should_include_expects {
|
||||
let (path, _) = state.module_cache.sources.get(&module_id).unwrap();
|
||||
|
||||
let expectations = Expectations {
|
||||
Some(Expectations {
|
||||
expectations: loc_expects,
|
||||
dbgs: loc_dbgs,
|
||||
subs: solved_subs.clone().into_inner(),
|
||||
path: path.to_owned(),
|
||||
ident_ids: ident_ids.clone(),
|
||||
};
|
||||
|
||||
state
|
||||
.module_cache
|
||||
.expectations
|
||||
.insert(module_id, expectations);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let work = state.dependencies.notify(module_id, Phase::SolveTypes);
|
||||
|
||||
@ -2736,6 +2767,7 @@ fn update<'a>(
|
||||
decls,
|
||||
ident_ids,
|
||||
abilities_store,
|
||||
expectations: opt_expectations,
|
||||
};
|
||||
|
||||
state
|
||||
@ -2775,6 +2807,7 @@ fn update<'a>(
|
||||
module_timing,
|
||||
abilities_store,
|
||||
toplevel_expects,
|
||||
expectations,
|
||||
} => {
|
||||
log!("found specializations for {:?}", module_id);
|
||||
|
||||
@ -2797,6 +2830,7 @@ fn update<'a>(
|
||||
subs,
|
||||
module_timing,
|
||||
abilities_store,
|
||||
expectations,
|
||||
};
|
||||
|
||||
state
|
||||
@ -2822,6 +2856,7 @@ fn update<'a>(
|
||||
external_specializations_requested,
|
||||
module_timing,
|
||||
layout_cache,
|
||||
expectations,
|
||||
..
|
||||
} => {
|
||||
debug_assert!(
|
||||
@ -2843,6 +2878,7 @@ fn update<'a>(
|
||||
subs,
|
||||
layout_cache,
|
||||
procs_base,
|
||||
expectations,
|
||||
},
|
||||
);
|
||||
|
||||
@ -2900,6 +2936,9 @@ fn update<'a>(
|
||||
);
|
||||
}
|
||||
|
||||
let mut module_expectations =
|
||||
VecMap::with_capacity(state.module_cache.module_names.len());
|
||||
|
||||
// Flush late-specialization module information to the top-level of the state
|
||||
// where it will be visible to others, since we don't need late specialization
|
||||
// anymore.
|
||||
@ -2911,6 +2950,7 @@ fn update<'a>(
|
||||
module_timing,
|
||||
layout_cache: _layout_cache,
|
||||
procs_base: _,
|
||||
expectations,
|
||||
},
|
||||
) in state.module_cache.late_specializations.drain()
|
||||
{
|
||||
@ -2919,6 +2959,9 @@ fn update<'a>(
|
||||
state.root_subs = Some(subs);
|
||||
}
|
||||
state.timings.insert(module_id, module_timing);
|
||||
if let Some(expectations) = expectations {
|
||||
module_expectations.insert(module_id, expectations);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
@ -2981,6 +3024,7 @@ fn update<'a>(
|
||||
subs,
|
||||
layout_interner,
|
||||
exposed_to_host: state.exposed_to_host.clone(),
|
||||
module_expectations,
|
||||
})
|
||||
.map_err(|_| LoadingProblem::MsgChannelDied)?;
|
||||
|
||||
@ -3114,6 +3158,7 @@ fn finish_specialization<'a>(
|
||||
subs: Subs,
|
||||
layout_interner: STLayoutInterner<'a>,
|
||||
exposed_to_host: ExposedToHost,
|
||||
module_expectations: VecMap<ModuleId, Expectations>,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||
if false {
|
||||
println!(
|
||||
@ -3154,7 +3199,6 @@ fn finish_specialization<'a>(
|
||||
} = state;
|
||||
|
||||
let ModuleCache {
|
||||
expectations,
|
||||
type_problems,
|
||||
can_problems,
|
||||
sources,
|
||||
@ -3245,7 +3289,7 @@ fn finish_specialization<'a>(
|
||||
can_problems,
|
||||
type_problems,
|
||||
output_path,
|
||||
expectations,
|
||||
expectations: module_expectations,
|
||||
exposed_to_host,
|
||||
module_id: state.root_id,
|
||||
subs,
|
||||
@ -5230,6 +5274,7 @@ fn make_specializations<'a>(
|
||||
world_abilities: WorldAbilities,
|
||||
exposed_by_module: &ExposedByModule,
|
||||
derived_module: SharedDerivedModule,
|
||||
mut expectations: Option<Expectations>,
|
||||
) -> Msg<'a> {
|
||||
let make_specializations_start = Instant::now();
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
@ -5237,6 +5282,7 @@ fn make_specializations<'a>(
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena,
|
||||
subs: &mut subs,
|
||||
expectation_subs: expectations.as_mut().map(|e| &mut e.subs),
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
target_info,
|
||||
@ -5288,6 +5334,7 @@ fn make_specializations<'a>(
|
||||
procedures,
|
||||
update_mode_ids,
|
||||
subs,
|
||||
expectations,
|
||||
external_specializations_requested,
|
||||
module_timing,
|
||||
}
|
||||
@ -5307,6 +5354,7 @@ fn build_pending_specializations<'a>(
|
||||
exposed_by_module: &ExposedByModule,
|
||||
abilities_store: AbilitiesStore,
|
||||
derived_module: SharedDerivedModule,
|
||||
mut expectations: Option<Expectations>,
|
||||
build_expects: bool,
|
||||
) -> Msg<'a> {
|
||||
let find_specializations_start = Instant::now();
|
||||
@ -5327,6 +5375,7 @@ fn build_pending_specializations<'a>(
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena,
|
||||
subs: &mut subs,
|
||||
expectation_subs: expectations.as_mut().map(|e| &mut e.subs),
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
target_info,
|
||||
@ -5716,6 +5765,7 @@ fn build_pending_specializations<'a>(
|
||||
module_timing,
|
||||
abilities_store,
|
||||
toplevel_expects,
|
||||
expectations,
|
||||
}
|
||||
}
|
||||
|
||||
@ -5757,6 +5807,8 @@ fn load_derived_partial_procs<'a>(
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena,
|
||||
subs,
|
||||
// There are no derived expectations.
|
||||
expectation_subs: None,
|
||||
home,
|
||||
ident_ids,
|
||||
target_info,
|
||||
@ -5916,6 +5968,7 @@ fn run_task<'a>(
|
||||
abilities_store,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
expectations,
|
||||
build_expects,
|
||||
} => Ok(build_pending_specializations(
|
||||
arena,
|
||||
@ -5931,6 +5984,7 @@ fn run_task<'a>(
|
||||
&exposed_by_module,
|
||||
abilities_store,
|
||||
derived_module,
|
||||
expectations,
|
||||
build_expects,
|
||||
)),
|
||||
MakeSpecializations {
|
||||
@ -5944,6 +5998,7 @@ fn run_task<'a>(
|
||||
world_abilities,
|
||||
exposed_by_module,
|
||||
derived_module,
|
||||
expectations,
|
||||
} => Ok(make_specializations(
|
||||
arena,
|
||||
module_id,
|
||||
@ -5957,6 +6012,7 @@ fn run_task<'a>(
|
||||
world_abilities,
|
||||
&exposed_by_module,
|
||||
derived_module,
|
||||
expectations,
|
||||
)),
|
||||
}?;
|
||||
|
||||
|
@ -594,6 +594,13 @@ impl IdentId {
|
||||
pub const fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// The index is not guaranteed to know to exist.
|
||||
pub unsafe fn from_index(index: u32) -> Self {
|
||||
Self(index)
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a mapping between Ident and IdentId.
|
||||
|
@ -948,7 +948,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||
|
||||
ListIsUnique => arena.alloc_slice_copy(&[borrowed]),
|
||||
|
||||
Dbg => arena.alloc_slice_copy(&[borrowed]),
|
||||
Dbg => arena.alloc_slice_copy(&[borrowed, /* dbg-spec-var */ irrelevant]),
|
||||
|
||||
BoxExpr | UnboxExpr => {
|
||||
unreachable!("These lowlevel operations are turned into mono Expr's")
|
||||
|
@ -309,12 +309,14 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
||||
condition,
|
||||
region: _,
|
||||
lookups,
|
||||
variables: _,
|
||||
remainder,
|
||||
}
|
||||
| &Stmt::ExpectFx {
|
||||
condition,
|
||||
region: _,
|
||||
lookups,
|
||||
variables: _,
|
||||
remainder,
|
||||
} => {
|
||||
self.check_sym_layout(
|
||||
|
@ -555,7 +555,13 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||
match &call_type {
|
||||
LowLevel { op, .. } => {
|
||||
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
||||
let b = match op {
|
||||
roc_module::low_level::LowLevel::Dbg => {
|
||||
// NB(dbg-spec-var) second var is the Variable
|
||||
self.add_dec_after_lowlevel(&arguments[..1], ps, b, b_live_vars)
|
||||
}
|
||||
_ => self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars),
|
||||
};
|
||||
|
||||
let v = Expr::Call(crate::ir::Call {
|
||||
call_type,
|
||||
@ -1199,6 +1205,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
} => {
|
||||
let (b, mut b_live_vars) = self.visit_stmt(codegen, remainder);
|
||||
|
||||
@ -1206,6 +1213,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
});
|
||||
|
||||
@ -1221,6 +1229,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
} => {
|
||||
let (b, mut b_live_vars) = self.visit_stmt(codegen, remainder);
|
||||
|
||||
@ -1228,6 +1237,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
});
|
||||
|
||||
|
@ -27,14 +27,14 @@ use roc_late_solve::storage::{ExternalModuleStorage, ExternalModuleStorageSnapsh
|
||||
use roc_late_solve::{resolve_ability_specialization, AbilitiesView, Resolved, UnificationFailed};
|
||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_module::symbol::{IdentId, IdentIds, ModuleId, Symbol};
|
||||
use roc_problem::can::{RuntimeError, ShadowKind};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_std::RocDec;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{
|
||||
instantiate_rigids, Content, ExhaustiveMark, FlatType, RedundantMark, StorageSubs, Subs,
|
||||
Variable, VariableSubsSlice,
|
||||
instantiate_rigids, storage_copy_var_to, Content, ExhaustiveMark, FlatType, RedundantMark,
|
||||
StorageSubs, Subs, Variable, VariableSubsSlice,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||
@ -1465,6 +1465,9 @@ impl<'a> Specializations<'a> {
|
||||
pub struct Env<'a, 'i> {
|
||||
pub arena: &'a Bump,
|
||||
pub subs: &'i mut Subs,
|
||||
/// [Subs] to write specialized variables of lookups in expects.
|
||||
/// [None] if this module doesn't produce any expects.
|
||||
pub expectation_subs: Option<&'i mut Subs>,
|
||||
pub home: ModuleId,
|
||||
pub ident_ids: &'i mut IdentIds,
|
||||
pub target_info: TargetInfo,
|
||||
@ -1601,6 +1604,9 @@ pub fn cond<'a>(
|
||||
|
||||
pub type Stores<'a> = &'a [(Symbol, Layout<'a>, Expr<'a>)];
|
||||
|
||||
/// The specialized type of a lookup. Represented as a type-variable.
|
||||
pub type LookupType = Variable;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Stmt<'a> {
|
||||
Let(Symbol, Expr<'a>, Layout<'a>, &'a Stmt<'a>),
|
||||
@ -1622,6 +1628,7 @@ pub enum Stmt<'a> {
|
||||
condition: Symbol,
|
||||
region: Region,
|
||||
lookups: &'a [Symbol],
|
||||
variables: &'a [LookupType],
|
||||
/// what happens after the expect
|
||||
remainder: &'a Stmt<'a>,
|
||||
},
|
||||
@ -1629,6 +1636,7 @@ pub enum Stmt<'a> {
|
||||
condition: Symbol,
|
||||
region: Region,
|
||||
lookups: &'a [Symbol],
|
||||
variables: &'a [LookupType],
|
||||
/// what happens after the expect
|
||||
remainder: &'a Stmt<'a>,
|
||||
},
|
||||
@ -6568,12 +6576,14 @@ pub fn from_can<'a>(
|
||||
let cond_symbol = env.unique_symbol();
|
||||
|
||||
let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||
let mut lookup_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||
let mut specialized_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||
|
||||
for ExpectLookup {
|
||||
symbol,
|
||||
var,
|
||||
ability_info,
|
||||
} in lookups_in_cond
|
||||
} in lookups_in_cond.iter().copied()
|
||||
{
|
||||
let symbol = match ability_info {
|
||||
Some(specialization_id) => late_resolve_ability_specialization(
|
||||
@ -6584,16 +6594,28 @@ pub fn from_can<'a>(
|
||||
),
|
||||
None => symbol,
|
||||
};
|
||||
|
||||
let expectation_subs = env
|
||||
.expectation_subs
|
||||
.as_deref_mut()
|
||||
.expect("if expects are compiled, their subs should be available");
|
||||
let spec_var = expectation_subs.fresh_unnamed_flex_var();
|
||||
|
||||
if !env.subs.is_function(var) {
|
||||
// Exclude functions from lookups
|
||||
lookups.push(symbol);
|
||||
lookup_variables.push(var);
|
||||
specialized_variables.push(spec_var);
|
||||
}
|
||||
}
|
||||
|
||||
let specialized_variables = specialized_variables.into_bump_slice();
|
||||
|
||||
let mut stmt = Stmt::Expect {
|
||||
condition: cond_symbol,
|
||||
region: loc_condition.region,
|
||||
lookups: lookups.into_bump_slice(),
|
||||
variables: specialized_variables,
|
||||
remainder: env.arena.alloc(rest),
|
||||
};
|
||||
|
||||
@ -6607,6 +6629,10 @@ pub fn from_can<'a>(
|
||||
env.arena.alloc(stmt),
|
||||
);
|
||||
|
||||
// Now that the condition has been specialized, export the specialized types of our
|
||||
// lookups into the expectation subs.
|
||||
store_specialized_expectation_lookups(env, lookup_variables, specialized_variables);
|
||||
|
||||
stmt
|
||||
}
|
||||
|
||||
@ -6619,12 +6645,14 @@ pub fn from_can<'a>(
|
||||
let cond_symbol = env.unique_symbol();
|
||||
|
||||
let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||
let mut lookup_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||
let mut specialized_variables = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
|
||||
|
||||
for ExpectLookup {
|
||||
symbol,
|
||||
var,
|
||||
ability_info,
|
||||
} in lookups_in_cond
|
||||
} in lookups_in_cond.iter().copied()
|
||||
{
|
||||
let symbol = match ability_info {
|
||||
Some(specialization_id) => late_resolve_ability_specialization(
|
||||
@ -6635,16 +6663,28 @@ pub fn from_can<'a>(
|
||||
),
|
||||
None => symbol,
|
||||
};
|
||||
|
||||
let expectation_subs = env
|
||||
.expectation_subs
|
||||
.as_deref_mut()
|
||||
.expect("if expects are compiled, their subs should be available");
|
||||
let spec_var = expectation_subs.fresh_unnamed_flex_var();
|
||||
|
||||
if !env.subs.is_function(var) {
|
||||
// Exclude functions from lookups
|
||||
lookups.push(symbol);
|
||||
lookup_variables.push(var);
|
||||
specialized_variables.push(spec_var);
|
||||
}
|
||||
}
|
||||
|
||||
let specialized_variables = specialized_variables.into_bump_slice();
|
||||
|
||||
let mut stmt = Stmt::ExpectFx {
|
||||
condition: cond_symbol,
|
||||
region: loc_condition.region,
|
||||
lookups: lookups.into_bump_slice(),
|
||||
variables: specialized_variables,
|
||||
remainder: env.arena.alloc(rest),
|
||||
};
|
||||
|
||||
@ -6658,6 +6698,8 @@ pub fn from_can<'a>(
|
||||
env.arena.alloc(stmt),
|
||||
);
|
||||
|
||||
store_specialized_expectation_lookups(env, lookup_variables, specialized_variables);
|
||||
|
||||
stmt
|
||||
}
|
||||
|
||||
@ -6669,12 +6711,23 @@ pub fn from_can<'a>(
|
||||
} => {
|
||||
let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache);
|
||||
|
||||
let spec_var = env
|
||||
.expectation_subs
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.fresh_unnamed_flex_var();
|
||||
// HACK(dbg-spec-var): pass the specialized type variable along injected into a fake symbol
|
||||
let dbg_spec_var_symbol = Symbol::new(ModuleId::ATTR, unsafe {
|
||||
IdentId::from_index(spec_var.index())
|
||||
});
|
||||
|
||||
// TODO: need to store the specialized variable of this dbg in the expectation_subs
|
||||
let call = crate::ir::Call {
|
||||
call_type: CallType::LowLevel {
|
||||
op: LowLevel::Dbg,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: env.arena.alloc([dbg_symbol]),
|
||||
arguments: env.arena.alloc([dbg_symbol, dbg_spec_var_symbol]),
|
||||
};
|
||||
|
||||
let dbg_layout = layout_cache
|
||||
@ -6702,6 +6755,10 @@ pub fn from_can<'a>(
|
||||
);
|
||||
}
|
||||
|
||||
// Now that the dbg value has been specialized, export its specialized type into the
|
||||
// expectations subs.
|
||||
store_specialized_expectation_lookups(env, [variable], &[spec_var]);
|
||||
|
||||
stmt
|
||||
}
|
||||
|
||||
@ -6740,6 +6797,21 @@ pub fn from_can<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
fn store_specialized_expectation_lookups(
|
||||
env: &mut Env,
|
||||
lookup_variables: impl IntoIterator<Item = Variable>,
|
||||
specialized_variables: &[Variable],
|
||||
) {
|
||||
let subs = &env.subs;
|
||||
let expectation_subs = env.expectation_subs.as_deref_mut().unwrap();
|
||||
for (lookup_var, stored_var) in lookup_variables.into_iter().zip(specialized_variables) {
|
||||
let stored_specialized_var =
|
||||
storage_copy_var_to(&mut Default::default(), subs, expectation_subs, lookup_var);
|
||||
let stored_specialized_desc = expectation_subs.get(stored_specialized_var);
|
||||
expectation_subs.union(*stored_var, stored_specialized_var, stored_specialized_desc);
|
||||
}
|
||||
}
|
||||
|
||||
fn to_opt_branches<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
@ -7070,6 +7142,7 @@ fn substitute_in_stmt_help<'a>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let new_remainder =
|
||||
@ -7084,6 +7157,7 @@ fn substitute_in_stmt_help<'a>(
|
||||
condition: substitute(subs, *condition).unwrap_or(*condition),
|
||||
region: *region,
|
||||
lookups: new_lookups.into_bump_slice(),
|
||||
variables,
|
||||
remainder: new_remainder,
|
||||
};
|
||||
|
||||
@ -7094,6 +7168,7 @@ fn substitute_in_stmt_help<'a>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let new_remainder =
|
||||
@ -7108,6 +7183,7 @@ fn substitute_in_stmt_help<'a>(
|
||||
condition: substitute(subs, *condition).unwrap_or(*condition),
|
||||
region: *region,
|
||||
lookups: new_lookups.into_bump_slice(),
|
||||
variables,
|
||||
remainder: new_remainder,
|
||||
};
|
||||
|
||||
|
@ -195,6 +195,7 @@ fn function_s<'a, 'i>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let continuation: &Stmt = remainder;
|
||||
@ -207,6 +208,7 @@ fn function_s<'a, 'i>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: new_continuation,
|
||||
};
|
||||
|
||||
@ -218,6 +220,7 @@ fn function_s<'a, 'i>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let continuation: &Stmt = remainder;
|
||||
@ -230,6 +233,7 @@ fn function_s<'a, 'i>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: new_continuation,
|
||||
};
|
||||
|
||||
@ -438,6 +442,7 @@ fn function_d_main<'a, 'i>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let (b, found) = function_d_main(env, x, c, remainder);
|
||||
@ -447,6 +452,7 @@ fn function_d_main<'a, 'i>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
};
|
||||
|
||||
@ -458,6 +464,7 @@ fn function_d_main<'a, 'i>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
};
|
||||
|
||||
@ -468,6 +475,7 @@ fn function_d_main<'a, 'i>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let (b, found) = function_d_main(env, x, c, remainder);
|
||||
@ -477,6 +485,7 @@ fn function_d_main<'a, 'i>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
};
|
||||
|
||||
@ -488,6 +497,7 @@ fn function_d_main<'a, 'i>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
};
|
||||
|
||||
@ -650,6 +660,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let b = function_r(env, remainder);
|
||||
@ -658,6 +669,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
};
|
||||
|
||||
@ -668,6 +680,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => {
|
||||
let b = function_r(env, remainder);
|
||||
@ -676,6 +689,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: b,
|
||||
};
|
||||
|
||||
|
@ -253,6 +253,7 @@ fn insert_jumps<'a>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => match insert_jumps(
|
||||
arena,
|
||||
@ -266,6 +267,7 @@ fn insert_jumps<'a>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: cont,
|
||||
})),
|
||||
None => None,
|
||||
@ -275,6 +277,7 @@ fn insert_jumps<'a>(
|
||||
condition,
|
||||
region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder,
|
||||
} => match insert_jumps(
|
||||
arena,
|
||||
@ -288,6 +291,7 @@ fn insert_jumps<'a>(
|
||||
condition: *condition,
|
||||
region: *region,
|
||||
lookups,
|
||||
variables,
|
||||
remainder: cont,
|
||||
})),
|
||||
None => None,
|
||||
|
@ -8529,4 +8529,23 @@ mod solve_expr {
|
||||
print_can_decls: true
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constrain_dbg_flex_var() {
|
||||
infer_queries!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
polyDbg = \x ->
|
||||
#^^^^^^^{-1}
|
||||
dbg x
|
||||
x
|
||||
|
||||
main = polyDbg ""
|
||||
"#
|
||||
),
|
||||
@"polyDbg : a -[[polyDbg(1)]]-> a"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,10 @@ pub fn get_values<'a>(
|
||||
layout_interner: &Arc<GlobalInterner<'a, Layout<'a>>>,
|
||||
start: *const u8,
|
||||
start_offset: usize,
|
||||
variables: &[Variable],
|
||||
) -> (usize, Vec<Expr<'a>>) {
|
||||
let mut result = Vec::with_capacity(variables.len());
|
||||
number_of_lookups: usize,
|
||||
) -> (usize, Vec<Expr<'a>>, Vec<Variable>) {
|
||||
let mut result = Vec::with_capacity(number_of_lookups);
|
||||
let mut result_vars = Vec::with_capacity(number_of_lookups);
|
||||
|
||||
let memory = ExpectMemory { start };
|
||||
|
||||
@ -45,13 +46,20 @@ pub fn get_values<'a>(
|
||||
|
||||
let app = arena.alloc(app);
|
||||
|
||||
for (i, variable) in variables.iter().enumerate() {
|
||||
let start = app.memory.deref_usize(start_offset + i * 8);
|
||||
for i in 0..number_of_lookups {
|
||||
let size_of_lookup_header = 8 /* pointer to value */ + 4 /* type variable */;
|
||||
|
||||
let start = app
|
||||
.memory
|
||||
.deref_usize(start_offset + i * size_of_lookup_header);
|
||||
let variable = app.memory.deref_u32(
|
||||
start_offset + i * size_of_lookup_header + 8, /* skip the pointer */
|
||||
);
|
||||
let variable = unsafe { Variable::from_index(variable) };
|
||||
|
||||
app.offset = start;
|
||||
|
||||
let expr = {
|
||||
let variable = *variable;
|
||||
|
||||
// TODO: pass layout_cache to jit_to_ast directly
|
||||
let mut layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
|
||||
let layout = layout_cache.from_var(arena, variable, subs).unwrap();
|
||||
@ -76,9 +84,10 @@ pub fn get_values<'a>(
|
||||
};
|
||||
|
||||
result.push(expr);
|
||||
result_vars.push(variable);
|
||||
}
|
||||
|
||||
(app.offset, result)
|
||||
(app.offset, result, result_vars)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
@ -25,7 +25,7 @@ use roc_mono::{ir::OptLevel, layout::Layout};
|
||||
use roc_region::all::Region;
|
||||
use roc_reporting::{error::expect::Renderer, report::RenderTarget};
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{Subs, Variable};
|
||||
use roc_types::subs::Subs;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
pub struct ExpectMemory<'a> {
|
||||
@ -471,7 +471,7 @@ pub fn render_dbgs_in_memory<'a>(
|
||||
)
|
||||
}
|
||||
|
||||
fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> (Vec<Symbol>, Vec<Variable>) {
|
||||
fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> Vec<Symbol> {
|
||||
lookups
|
||||
.iter()
|
||||
.filter_map(
|
||||
@ -485,11 +485,11 @@ fn split_expect_lookups(subs: &Subs, lookups: &[ExpectLookup]) -> (Vec<Symbol>,
|
||||
if subs.is_function(*var) {
|
||||
None
|
||||
} else {
|
||||
Some((*symbol, *var))
|
||||
Some(*symbol)
|
||||
}
|
||||
},
|
||||
)
|
||||
.unzip()
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@ -523,15 +523,7 @@ fn render_dbg_failure<'a>(
|
||||
|
||||
let subs = arena.alloc(&mut data.subs);
|
||||
|
||||
let current = ExpectLookup {
|
||||
symbol: current.symbol,
|
||||
var: current.var,
|
||||
ability_info: current.ability_info,
|
||||
};
|
||||
|
||||
let (_symbols, variables) = split_expect_lookups(subs, &[current]);
|
||||
|
||||
let (offset, expressions) = crate::get_values(
|
||||
let (offset, expressions, _variables) = crate::get_values(
|
||||
target_info,
|
||||
arena,
|
||||
subs,
|
||||
@ -539,7 +531,7 @@ fn render_dbg_failure<'a>(
|
||||
layout_interner,
|
||||
start,
|
||||
frame.start_offset,
|
||||
&variables,
|
||||
1,
|
||||
);
|
||||
|
||||
renderer.render_dbg(writer, &expressions, expect_region, failure_region)?;
|
||||
@ -574,24 +566,23 @@ fn render_expect_failure<'a>(
|
||||
None => panic!("region {failure_region:?} not in list of expects"),
|
||||
Some(current) => current,
|
||||
};
|
||||
let subs = arena.alloc(&mut data.subs);
|
||||
|
||||
let (symbols, variables) = split_expect_lookups(subs, current);
|
||||
let symbols = split_expect_lookups(&data.subs, current);
|
||||
|
||||
let (offset, expressions) = crate::get_values(
|
||||
let (offset, expressions, variables) = crate::get_values(
|
||||
target_info,
|
||||
arena,
|
||||
subs,
|
||||
&data.subs,
|
||||
interns,
|
||||
layout_interner,
|
||||
start,
|
||||
frame.start_offset,
|
||||
&variables,
|
||||
symbols.len(),
|
||||
);
|
||||
|
||||
renderer.render_failure(
|
||||
writer,
|
||||
subs,
|
||||
&mut data.subs,
|
||||
&symbols,
|
||||
&variables,
|
||||
&expressions,
|
||||
|
Loading…
Reference in New Issue
Block a user