mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Merge branch 'trunk' into store-dec-as-str
This commit is contained in:
commit
ffeaa1ac08
30 changed files with 555 additions and 142 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -3918,9 +3918,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.10.0"
|
version = "0.12.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
|
checksum = "d9bffcddbc2458fa3e6058414599e3c838a022abae82e5c67b4f7f80298d5bff"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
|
|
|
@ -67,7 +67,7 @@ libc = "0.2"
|
||||||
libloading = "0.6"
|
libloading = "0.6"
|
||||||
|
|
||||||
inkwell = { path = "../vendor/inkwell", optional = true }
|
inkwell = { path = "../vendor/inkwell", optional = true }
|
||||||
target-lexicon = "0.10"
|
target-lexicon = "0.12.2"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -222,7 +222,8 @@ fn jit_to_ast_help<'a>(
|
||||||
let tags_map: roc_collections::all::MutMap<_, _> =
|
let tags_map: roc_collections::all::MutMap<_, _> =
|
||||||
tags_vec.iter().cloned().collect();
|
tags_vec.iter().cloned().collect();
|
||||||
|
|
||||||
let union_variant = union_sorted_tags_help(env.arena, tags_vec, None, env.subs);
|
let union_variant =
|
||||||
|
union_sorted_tags_help(env.arena, tags_vec, None, env.subs, env.ptr_bytes);
|
||||||
|
|
||||||
let size = layout.stack_size(env.ptr_bytes);
|
let size = layout.stack_size(env.ptr_bytes);
|
||||||
use roc_mono::layout::WrappedVariant::*;
|
use roc_mono::layout::WrappedVariant::*;
|
||||||
|
@ -886,7 +887,8 @@ fn byte_to_ast<'a>(env: &Env<'a, '_>, value: u8, content: &Content) -> Expr<'a>
|
||||||
.map(|(a, b)| (a.clone(), b.to_vec()))
|
.map(|(a, b)| (a.clone(), b.to_vec()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let union_variant = union_sorted_tags_help(env.arena, tags_vec, None, env.subs);
|
let union_variant =
|
||||||
|
union_sorted_tags_help(env.arena, tags_vec, None, env.subs, env.ptr_bytes);
|
||||||
|
|
||||||
match union_variant {
|
match union_variant {
|
||||||
UnionVariant::ByteUnion(tagnames) => {
|
UnionVariant::ByteUnion(tagnames) => {
|
||||||
|
|
|
@ -223,13 +223,13 @@ mod cli_run {
|
||||||
// expected_ending: "",
|
// expected_ending: "",
|
||||||
// use_valgrind: true,
|
// use_valgrind: true,
|
||||||
// },
|
// },
|
||||||
// cli:"cli" => Example {
|
cli:"cli" => Example {
|
||||||
// filename: "Echo.roc",
|
filename: "Echo.roc",
|
||||||
// executable_filename: "echo",
|
executable_filename: "echo",
|
||||||
// stdin: &["Giovanni\n", "Giorgio\n"],
|
stdin: &["Giovanni\n", "Giorgio\n"],
|
||||||
// expected_ending: "Giovanni Giorgio!\n",
|
expected_ending: "Hi, Giovanni Giorgio!\n",
|
||||||
// use_valgrind: true,
|
use_valgrind: true,
|
||||||
// },
|
},
|
||||||
// custom_malloc:"custom-malloc" => Example {
|
// custom_malloc:"custom-malloc" => Example {
|
||||||
// filename: "Main.roc",
|
// filename: "Main.roc",
|
||||||
// executable_filename: "custom-malloc-example",
|
// executable_filename: "custom-malloc-example",
|
||||||
|
|
|
@ -30,7 +30,7 @@ libloading = "0.6"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
inkwell = { path = "../../vendor/inkwell", optional = true }
|
inkwell = { path = "../../vendor/inkwell", optional = true }
|
||||||
target-lexicon = "0.10"
|
target-lexicon = "0.12.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "0.5.1"
|
pretty_assertions = "0.5.1"
|
||||||
|
|
|
@ -21,7 +21,7 @@ roc_mono = { path = "../mono" }
|
||||||
im = "14" # im and im-rc should always have the same version!
|
im = "14" # im and im-rc should always have the same version!
|
||||||
im-rc = "14" # im and im-rc should always have the same version!
|
im-rc = "14" # im and im-rc should always have the same version!
|
||||||
bumpalo = { version = "3.6.1", features = ["collections"] }
|
bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||||
target-lexicon = "0.10"
|
target-lexicon = "0.12.2"
|
||||||
libloading = "0.6"
|
libloading = "0.6"
|
||||||
object = { version = "0.24", features = ["write"] }
|
object = { version = "0.24", features = ["write"] }
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ im = "14" # im and im-rc should always have the same version!
|
||||||
im-rc = "14" # im and im-rc should always have the same version!
|
im-rc = "14" # im and im-rc should always have the same version!
|
||||||
bumpalo = { version = "3.6.1", features = ["collections"] }
|
bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||||
inkwell = { path = "../../vendor/inkwell" }
|
inkwell = { path = "../../vendor/inkwell" }
|
||||||
target-lexicon = "0.10"
|
target-lexicon = "0.12.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
roc_can = { path = "../can" }
|
roc_can = { path = "../can" }
|
||||||
|
|
|
@ -3935,6 +3935,8 @@ pub fn get_call_conventions(cc: target_lexicon::CallingConvention) -> u32 {
|
||||||
SystemV => C_CALL_CONV,
|
SystemV => C_CALL_CONV,
|
||||||
WasmBasicCAbi => C_CALL_CONV,
|
WasmBasicCAbi => C_CALL_CONV,
|
||||||
WindowsFastcall => C_CALL_CONV,
|
WindowsFastcall => C_CALL_CONV,
|
||||||
|
AppleAarch64 => C_CALL_CONV,
|
||||||
|
_ => C_CALL_CONV,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5174,89 +5176,171 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_foreign_symbol_return_result<'a, 'ctx, 'env>(
|
/// A type that is valid according to the C ABI
|
||||||
|
///
|
||||||
|
/// As an example, structs that fit inside an integer type should
|
||||||
|
/// (this does not currently happen here) be coerced to that integer type.
|
||||||
|
fn to_cc_type<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &mut Scope<'a, 'ctx>,
|
layout: &Layout<'a>,
|
||||||
foreign: &roc_module::ident::ForeignSymbol,
|
) -> BasicTypeEnum<'ctx> {
|
||||||
arguments: &[Symbol],
|
match layout {
|
||||||
return_type: BasicTypeEnum<'ctx>,
|
Layout::Builtin(builtin) => to_cc_type_builtin(env, builtin),
|
||||||
) -> (FunctionValue<'ctx>, &'a [BasicValueEnum<'ctx>]) {
|
_ => {
|
||||||
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(arguments.len(), env.arena);
|
// TODO this is almost certainly incorrect for bigger structs
|
||||||
let mut arg_types = Vec::with_capacity_in(arguments.len() + 1, env.arena);
|
basic_type_from_layout(env, layout)
|
||||||
|
}
|
||||||
for arg in arguments.iter() {
|
}
|
||||||
let (value, layout) = load_symbol_and_layout(scope, arg);
|
|
||||||
arg_vals.push(value);
|
|
||||||
let arg_type = basic_type_from_layout(env, layout);
|
|
||||||
debug_assert_eq!(arg_type, value.get_type());
|
|
||||||
arg_types.push(arg_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_type = return_type.fn_type(&arg_types, false);
|
fn to_cc_type_builtin<'a, 'ctx, 'env>(
|
||||||
let function = get_foreign_symbol(env, foreign.clone(), function_type);
|
|
||||||
|
|
||||||
(function, arg_vals.into_bump_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_foreign_symbol_write_result_into_ptr<'a, 'ctx, 'env>(
|
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &mut Scope<'a, 'ctx>,
|
builtin: &Builtin<'a>,
|
||||||
foreign: &roc_module::ident::ForeignSymbol,
|
) -> BasicTypeEnum<'ctx> {
|
||||||
arguments: &[Symbol],
|
match builtin {
|
||||||
return_pointer: PointerValue<'ctx>,
|
Builtin::Int128
|
||||||
) -> (FunctionValue<'ctx>, &'a [BasicValueEnum<'ctx>]) {
|
| Builtin::Int64
|
||||||
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(arguments.len(), env.arena);
|
| Builtin::Int32
|
||||||
let mut arg_types = Vec::with_capacity_in(arguments.len() + 1, env.arena);
|
| Builtin::Int16
|
||||||
|
| Builtin::Int8
|
||||||
arg_vals.push(return_pointer.into());
|
| Builtin::Int1
|
||||||
arg_types.push(return_pointer.get_type().into());
|
| Builtin::Usize
|
||||||
|
| Builtin::Decimal
|
||||||
for arg in arguments.iter() {
|
| Builtin::Float128
|
||||||
let (value, layout) = load_symbol_and_layout(scope, arg);
|
| Builtin::Float64
|
||||||
arg_vals.push(value);
|
| Builtin::Float32
|
||||||
let arg_type = basic_type_from_layout(env, layout);
|
| Builtin::Float16 => basic_type_from_builtin(env, builtin),
|
||||||
debug_assert_eq!(arg_type, value.get_type());
|
Builtin::Str | Builtin::EmptyStr | Builtin::List(_) | Builtin::EmptyList => {
|
||||||
arg_types.push(arg_type);
|
env.str_list_c_abi().into()
|
||||||
|
}
|
||||||
|
Builtin::Dict(_, _) | Builtin::Set(_) | Builtin::EmptyDict | Builtin::EmptySet => {
|
||||||
|
// TODO verify this is what actually happens
|
||||||
|
basic_type_from_builtin(env, builtin)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_type = env.context.void_type().fn_type(&arg_types, false);
|
enum CCReturn {
|
||||||
let function = get_foreign_symbol(env, foreign.clone(), function_type);
|
/// Return as normal
|
||||||
|
Return,
|
||||||
(function, arg_vals.into_bump_slice())
|
/// require an extra argument, a pointer
|
||||||
|
/// where the result is written into
|
||||||
|
/// returns void
|
||||||
|
ByPointer,
|
||||||
|
/// The return type is zero-sized
|
||||||
|
Void,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// According to the C ABI, how should we return a value with the given layout?
|
||||||
|
fn to_cc_return<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> CCReturn {
|
||||||
|
let return_size = layout.stack_size(env.ptr_bytes);
|
||||||
|
let pass_result_by_pointer = return_size > 2 * env.ptr_bytes;
|
||||||
|
|
||||||
|
if return_size == 0 {
|
||||||
|
CCReturn::Void
|
||||||
|
} else if pass_result_by_pointer {
|
||||||
|
CCReturn::ByPointer
|
||||||
|
} else {
|
||||||
|
CCReturn::Return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
fn build_foreign_symbol<'a, 'ctx, 'env>(
|
fn build_foreign_symbol<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
scope: &mut Scope<'a, 'ctx>,
|
scope: &mut Scope<'a, 'ctx>,
|
||||||
foreign: &roc_module::ident::ForeignSymbol,
|
foreign: &roc_module::ident::ForeignSymbol,
|
||||||
arguments: &[Symbol],
|
argument_symbols: &[Symbol],
|
||||||
ret_layout: &Layout<'a>,
|
ret_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let ret_type = basic_type_from_layout(env, ret_layout);
|
let builder = env.builder;
|
||||||
let return_pointer = env.builder.build_alloca(ret_type, "return_value");
|
let context = env.context;
|
||||||
|
|
||||||
// crude approximation of the C calling convention
|
// Here we build two functions:
|
||||||
let pass_result_by_pointer = ret_layout.stack_size(env.ptr_bytes) > 2 * env.ptr_bytes;
|
//
|
||||||
|
// - an C_CALL_CONV extern that will be provided by the host, e.g. `roc_fx_putLine`
|
||||||
|
// This is just a type signature that we make available to the linker,
|
||||||
|
// and can use in the wrapper
|
||||||
|
// - a FAST_CALL_CONV wrapper that we make here, e.g. `roc_fx_putLine_fastcc_wrapper`
|
||||||
|
|
||||||
let (function, arguments) = if pass_result_by_pointer {
|
let return_type = basic_type_from_layout(env, ret_layout);
|
||||||
build_foreign_symbol_write_result_into_ptr(env, scope, foreign, arguments, return_pointer)
|
let cc_return = to_cc_return(env, ret_layout);
|
||||||
} else {
|
|
||||||
build_foreign_symbol_return_result(env, scope, foreign, arguments, ret_type)
|
let mut cc_argument_types = Vec::with_capacity_in(argument_symbols.len() + 1, env.arena);
|
||||||
|
let mut fastcc_argument_types = Vec::with_capacity_in(argument_symbols.len(), env.arena);
|
||||||
|
let mut arguments = Vec::with_capacity_in(argument_symbols.len(), env.arena);
|
||||||
|
|
||||||
|
for symbol in argument_symbols {
|
||||||
|
let (value, layout) = load_symbol_and_layout(scope, symbol);
|
||||||
|
|
||||||
|
cc_argument_types.push(to_cc_type(env, layout));
|
||||||
|
|
||||||
|
let basic_type = basic_type_from_layout(env, layout);
|
||||||
|
fastcc_argument_types.push(basic_type);
|
||||||
|
|
||||||
|
arguments.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cc_type = match cc_return {
|
||||||
|
CCReturn::Void => env.context.void_type().fn_type(&cc_argument_types, false),
|
||||||
|
CCReturn::ByPointer => {
|
||||||
|
cc_argument_types.push(return_type.ptr_type(AddressSpace::Generic).into());
|
||||||
|
env.context.void_type().fn_type(&cc_argument_types, false)
|
||||||
|
}
|
||||||
|
CCReturn::Return => return_type.fn_type(&cc_argument_types, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let call = env.builder.build_call(function, arguments, "tmp");
|
let cc_function = get_foreign_symbol(env, foreign.clone(), cc_type);
|
||||||
|
|
||||||
// this is a foreign function, use c calling convention
|
let fastcc_type = return_type.fn_type(&fastcc_argument_types, false);
|
||||||
|
|
||||||
|
let fastcc_function = add_func(
|
||||||
|
env.module,
|
||||||
|
&format!("{}_fastcc_wrapper", foreign.as_str()),
|
||||||
|
fastcc_type,
|
||||||
|
Linkage::Private,
|
||||||
|
FAST_CALL_CONV,
|
||||||
|
);
|
||||||
|
|
||||||
|
let old = builder.get_insert_block().unwrap();
|
||||||
|
|
||||||
|
let entry = context.append_basic_block(fastcc_function, "entry");
|
||||||
|
{
|
||||||
|
builder.position_at_end(entry);
|
||||||
|
let return_pointer = env.builder.build_alloca(return_type, "return_value");
|
||||||
|
|
||||||
|
let fastcc_parameters = fastcc_function.get_params();
|
||||||
|
let mut cc_arguments = Vec::with_capacity_in(fastcc_parameters.len() + 1, env.arena);
|
||||||
|
|
||||||
|
for (param, cc_type) in fastcc_parameters.into_iter().zip(cc_argument_types.iter()) {
|
||||||
|
if param.get_type() == *cc_type {
|
||||||
|
cc_arguments.push(param);
|
||||||
|
} else {
|
||||||
|
let as_cc_type = complex_bitcast(env.builder, param, *cc_type, "to_cc_type");
|
||||||
|
cc_arguments.push(as_cc_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let CCReturn::ByPointer = cc_return {
|
||||||
|
cc_arguments.push(return_pointer.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let call = env.builder.build_call(cc_function, &cc_arguments, "tmp");
|
||||||
call.set_call_convention(C_CALL_CONV);
|
call.set_call_convention(C_CALL_CONV);
|
||||||
|
|
||||||
call.try_as_basic_value();
|
let return_value = match cc_return {
|
||||||
|
CCReturn::Return => call.try_as_basic_value().left().unwrap(),
|
||||||
|
|
||||||
if pass_result_by_pointer {
|
CCReturn::ByPointer => env.builder.build_load(return_pointer, "read_result"),
|
||||||
env.builder.build_load(return_pointer, "read_result")
|
CCReturn::Void => return_type.const_zero(),
|
||||||
} else {
|
};
|
||||||
call.try_as_basic_value().left().unwrap()
|
|
||||||
|
builder.build_return(Some(&return_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.position_at_end(old);
|
||||||
|
let call = env.builder.build_call(fastcc_function, &arguments, "tmp");
|
||||||
|
call.set_call_convention(FAST_CALL_CONV);
|
||||||
|
return call.try_as_basic_value().left().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn throw_on_overflow<'a, 'ctx, 'env>(
|
fn throw_on_overflow<'a, 'ctx, 'env>(
|
||||||
|
|
|
@ -832,6 +832,7 @@ struct State<'a> {
|
||||||
pub exposed_types: SubsByModule,
|
pub exposed_types: SubsByModule,
|
||||||
pub output_path: Option<&'a str>,
|
pub output_path: Option<&'a str>,
|
||||||
pub platform_path: PlatformPath<'a>,
|
pub platform_path: PlatformPath<'a>,
|
||||||
|
pub ptr_bytes: u32,
|
||||||
|
|
||||||
pub headers_parsed: MutSet<ModuleId>,
|
pub headers_parsed: MutSet<ModuleId>,
|
||||||
|
|
||||||
|
@ -1467,6 +1468,7 @@ where
|
||||||
|
|
||||||
let mut state = State {
|
let mut state = State {
|
||||||
root_id,
|
root_id,
|
||||||
|
ptr_bytes,
|
||||||
platform_data: None,
|
platform_data: None,
|
||||||
goal_phase,
|
goal_phase,
|
||||||
stdlib,
|
stdlib,
|
||||||
|
@ -1978,7 +1980,10 @@ fn update<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
if state.goal_phase > Phase::SolveTypes {
|
if state.goal_phase > Phase::SolveTypes {
|
||||||
let layout_cache = state.layout_caches.pop().unwrap_or_default();
|
let layout_cache = state
|
||||||
|
.layout_caches
|
||||||
|
.pop()
|
||||||
|
.unwrap_or_else(|| LayoutCache::new(state.ptr_bytes));
|
||||||
|
|
||||||
let typechecked = TypeCheckedModule {
|
let typechecked = TypeCheckedModule {
|
||||||
module_id,
|
module_id,
|
||||||
|
|
|
@ -3124,7 +3124,8 @@ pub fn with_hole<'a>(
|
||||||
mut fields,
|
mut fields,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let sorted_fields = crate::layout::sort_record_fields(env.arena, record_var, env.subs);
|
let sorted_fields =
|
||||||
|
crate::layout::sort_record_fields(env.arena, record_var, env.subs, env.ptr_bytes);
|
||||||
|
|
||||||
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);
|
||||||
|
@ -3459,7 +3460,8 @@ pub fn with_hole<'a>(
|
||||||
loc_expr,
|
loc_expr,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let sorted_fields = crate::layout::sort_record_fields(env.arena, record_var, env.subs);
|
let sorted_fields =
|
||||||
|
crate::layout::sort_record_fields(env.arena, record_var, env.subs, env.ptr_bytes);
|
||||||
|
|
||||||
let mut index = None;
|
let mut index = None;
|
||||||
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
||||||
|
@ -3601,7 +3603,8 @@ pub fn with_hole<'a>(
|
||||||
// This has the benefit that we don't need to do anything special for reference
|
// This has the benefit that we don't need to do anything special for reference
|
||||||
// counting
|
// counting
|
||||||
|
|
||||||
let sorted_fields = crate::layout::sort_record_fields(env.arena, record_var, env.subs);
|
let sorted_fields =
|
||||||
|
crate::layout::sort_record_fields(env.arena, record_var, env.subs, env.ptr_bytes);
|
||||||
|
|
||||||
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
||||||
|
|
||||||
|
@ -4205,7 +4208,8 @@ fn convert_tag_union<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
use crate::layout::UnionVariant::*;
|
use crate::layout::UnionVariant::*;
|
||||||
let res_variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
|
let res_variant =
|
||||||
|
crate::layout::union_sorted_tags(env.arena, variant_var, env.subs, env.ptr_bytes);
|
||||||
let variant = match res_variant {
|
let variant = match res_variant {
|
||||||
Ok(cached) => cached,
|
Ok(cached) => cached,
|
||||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||||
|
@ -4541,7 +4545,7 @@ fn sorted_field_symbols<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let alignment = layout.alignment_bytes(8);
|
let alignment = layout.alignment_bytes(env.ptr_bytes);
|
||||||
|
|
||||||
let symbol = possible_reuse_symbol(env, procs, &arg.value);
|
let symbol = possible_reuse_symbol(env, procs, &arg.value);
|
||||||
field_symbols_temp.push((alignment, symbol, ((var, arg), &*env.arena.alloc(symbol))));
|
field_symbols_temp.push((alignment, symbol, ((var, arg), &*env.arena.alloc(symbol))));
|
||||||
|
@ -6978,7 +6982,8 @@ fn from_can_pattern_help<'a>(
|
||||||
use crate::exhaustive::Union;
|
use crate::exhaustive::Union;
|
||||||
use crate::layout::UnionVariant::*;
|
use crate::layout::UnionVariant::*;
|
||||||
|
|
||||||
let res_variant = crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs);
|
let res_variant =
|
||||||
|
crate::layout::union_sorted_tags(env.arena, *whole_var, env.subs, env.ptr_bytes);
|
||||||
|
|
||||||
let variant = match res_variant {
|
let variant = match res_variant {
|
||||||
Ok(cached) => cached,
|
Ok(cached) => cached,
|
||||||
|
@ -7397,7 +7402,8 @@ fn from_can_pattern_help<'a>(
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// sorted fields based on the type
|
// sorted fields based on the type
|
||||||
let sorted_fields = crate::layout::sort_record_fields(env.arena, *whole_var, env.subs);
|
let sorted_fields =
|
||||||
|
crate::layout::sort_record_fields(env.arena, *whole_var, env.subs, env.ptr_bytes);
|
||||||
|
|
||||||
// sorted fields based on the destruct
|
// sorted fields based on the destruct
|
||||||
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
|
let mut mono_destructs = Vec::with_capacity_in(destructs.len(), env.arena);
|
||||||
|
|
|
@ -138,7 +138,8 @@ impl<'a> RawFunctionLayout<'a> {
|
||||||
let fn_args = fn_args.into_bump_slice();
|
let fn_args = fn_args.into_bump_slice();
|
||||||
let ret = arena.alloc(ret);
|
let ret = arena.alloc(ret);
|
||||||
|
|
||||||
let lambda_set = LambdaSet::from_var(env.arena, env.subs, closure_var)?;
|
let lambda_set =
|
||||||
|
LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes)?;
|
||||||
|
|
||||||
Ok(Self::Function(fn_args, lambda_set, ret))
|
Ok(Self::Function(fn_args, lambda_set, ret))
|
||||||
}
|
}
|
||||||
|
@ -516,6 +517,7 @@ impl<'a> LambdaSet<'a> {
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
closure_var: Variable,
|
closure_var: Variable,
|
||||||
|
ptr_bytes: u32,
|
||||||
) -> Result<Self, LayoutProblem> {
|
) -> Result<Self, LayoutProblem> {
|
||||||
let mut tags = std::vec::Vec::new();
|
let mut tags = std::vec::Vec::new();
|
||||||
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
|
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
|
||||||
|
@ -529,6 +531,7 @@ impl<'a> LambdaSet<'a> {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (tag_name, variables) in tags.iter() {
|
for (tag_name, variables) in tags.iter() {
|
||||||
|
@ -545,7 +548,8 @@ impl<'a> LambdaSet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let representation = arena.alloc(Self::make_representation(arena, subs, tags));
|
let representation =
|
||||||
|
arena.alloc(Self::make_representation(arena, subs, tags, ptr_bytes));
|
||||||
|
|
||||||
Ok(LambdaSet {
|
Ok(LambdaSet {
|
||||||
set: set.into_bump_slice(),
|
set: set.into_bump_slice(),
|
||||||
|
@ -568,9 +572,10 @@ impl<'a> LambdaSet<'a> {
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
tags: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
|
tags: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
|
||||||
|
ptr_bytes: u32,
|
||||||
) -> Layout<'a> {
|
) -> Layout<'a> {
|
||||||
// otherwise, this is a closure with a payload
|
// otherwise, this is a closure with a payload
|
||||||
let variant = union_sorted_tags_help(arena, tags, None, subs);
|
let variant = union_sorted_tags_help(arena, tags, None, subs, ptr_bytes);
|
||||||
|
|
||||||
use UnionVariant::*;
|
use UnionVariant::*;
|
||||||
match variant {
|
match variant {
|
||||||
|
@ -648,6 +653,7 @@ pub enum Builtin<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Env<'a, 'b> {
|
pub struct Env<'a, 'b> {
|
||||||
|
ptr_bytes: u32,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
seen: Vec<'a, Variable>,
|
seen: Vec<'a, Variable>,
|
||||||
subs: &'b Subs,
|
subs: &'b Subs,
|
||||||
|
@ -972,8 +978,9 @@ impl<'a> Layout<'a> {
|
||||||
/// e.g. `identity : a -> a` could be specialized to `Bool -> Bool` or `Str -> Str`.
|
/// e.g. `identity : a -> a` could be specialized to `Bool -> Bool` or `Str -> Str`.
|
||||||
/// Therefore in general it's invalid to store a map from variables to layouts
|
/// Therefore in general it's invalid to store a map from variables to layouts
|
||||||
/// But if we're careful when to invalidate certain keys, we still get some benefit
|
/// But if we're careful when to invalidate certain keys, we still get some benefit
|
||||||
#[derive(Default, Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LayoutCache<'a> {
|
pub struct LayoutCache<'a> {
|
||||||
|
ptr_bytes: u32,
|
||||||
_marker: std::marker::PhantomData<&'a u8>,
|
_marker: std::marker::PhantomData<&'a u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,6 +992,13 @@ pub enum CachedLayout<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LayoutCache<'a> {
|
impl<'a> LayoutCache<'a> {
|
||||||
|
pub fn new(ptr_bytes: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
ptr_bytes,
|
||||||
|
_marker: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_var(
|
pub fn from_var(
|
||||||
&mut self,
|
&mut self,
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -998,6 +1012,7 @@ impl<'a> LayoutCache<'a> {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
|
ptr_bytes: self.ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
Layout::from_var(&mut env, var)
|
Layout::from_var(&mut env, var)
|
||||||
|
@ -1016,6 +1031,7 @@ impl<'a> LayoutCache<'a> {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
|
ptr_bytes: self.ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
RawFunctionLayout::from_var(&mut env, var)
|
RawFunctionLayout::from_var(&mut env, var)
|
||||||
|
@ -1182,6 +1198,7 @@ fn layout_from_flat_type<'a>(
|
||||||
|
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
let subs = env.subs;
|
let subs = env.subs;
|
||||||
|
let ptr_bytes = env.ptr_bytes;
|
||||||
|
|
||||||
match flat_type {
|
match flat_type {
|
||||||
Apply(symbol, args) => {
|
Apply(symbol, args) => {
|
||||||
|
@ -1273,7 +1290,7 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Func(_, closure_var, _) => {
|
Func(_, closure_var, _) => {
|
||||||
let lambda_set = LambdaSet::from_var(env.arena, env.subs, closure_var)?;
|
let lambda_set = LambdaSet::from_var(env.arena, env.subs, closure_var, env.ptr_bytes)?;
|
||||||
|
|
||||||
Ok(lambda_set.runtime_representation())
|
Ok(lambda_set.runtime_representation())
|
||||||
}
|
}
|
||||||
|
@ -1299,8 +1316,6 @@ fn layout_from_flat_type<'a>(
|
||||||
let mut pairs = Vec::from_iter_in(pairs_it, arena);
|
let mut pairs = Vec::from_iter_in(pairs_it, arena);
|
||||||
|
|
||||||
pairs.sort_by(|(label1, layout1), (label2, layout2)| {
|
pairs.sort_by(|(label1, layout1), (label2, layout2)| {
|
||||||
let ptr_bytes = 8;
|
|
||||||
|
|
||||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||||
|
|
||||||
|
@ -1320,14 +1335,14 @@ fn layout_from_flat_type<'a>(
|
||||||
TagUnion(tags, ext_var) => {
|
TagUnion(tags, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
|
||||||
Ok(layout_from_tag_union(arena, tags, subs))
|
Ok(layout_from_tag_union(arena, tags, subs, env.ptr_bytes))
|
||||||
}
|
}
|
||||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
|
||||||
let tags = UnionTags::from_tag_name_index(tag_name);
|
let tags = UnionTags::from_tag_name_index(tag_name);
|
||||||
|
|
||||||
Ok(layout_from_tag_union(arena, tags, subs))
|
Ok(layout_from_tag_union(arena, tags, subs, env.ptr_bytes))
|
||||||
}
|
}
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
@ -1377,8 +1392,6 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_layout.sort_by(|layout1, layout2| {
|
tag_layout.sort_by(|layout1, layout2| {
|
||||||
let ptr_bytes = 8;
|
|
||||||
|
|
||||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||||
|
|
||||||
|
@ -1425,11 +1438,13 @@ pub fn sort_record_fields<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
var: Variable,
|
var: Variable,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
|
ptr_bytes: u32,
|
||||||
) -> Vec<'a, (Lowercase, Variable, Result<Layout<'a>, Layout<'a>>)> {
|
) -> Vec<'a, (Lowercase, Variable, Result<Layout<'a>, Layout<'a>>)> {
|
||||||
let mut env = Env {
|
let mut env = Env {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (it, _) = gather_fields_unsorted_iter(subs, RecordFields::empty(), var);
|
let (it, _) = gather_fields_unsorted_iter(subs, RecordFields::empty(), var);
|
||||||
|
@ -1445,6 +1460,8 @@ fn sort_record_fields_help<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
fields_map: impl Iterator<Item = (Lowercase, RecordField<Variable>)>,
|
fields_map: impl Iterator<Item = (Lowercase, RecordField<Variable>)>,
|
||||||
) -> Vec<'a, (Lowercase, Variable, Result<Layout<'a>, Layout<'a>>)> {
|
) -> Vec<'a, (Lowercase, Variable, Result<Layout<'a>, Layout<'a>>)> {
|
||||||
|
let ptr_bytes = env.ptr_bytes;
|
||||||
|
|
||||||
// Sort the fields by label
|
// Sort the fields by label
|
||||||
let mut sorted_fields = Vec::with_capacity_in(fields_map.size_hint().0, env.arena);
|
let mut sorted_fields = Vec::with_capacity_in(fields_map.size_hint().0, env.arena);
|
||||||
|
|
||||||
|
@ -1468,8 +1485,6 @@ fn sort_record_fields_help<'a>(
|
||||||
|(label1, _, res_layout1), (label2, _, res_layout2)| match res_layout1 {
|
|(label1, _, res_layout1), (label2, _, res_layout2)| match res_layout1 {
|
||||||
Ok(layout1) | Err(layout1) => match res_layout2 {
|
Ok(layout1) | Err(layout1) => match res_layout2 {
|
||||||
Ok(layout2) | Err(layout2) => {
|
Ok(layout2) | Err(layout2) => {
|
||||||
let ptr_bytes = 8;
|
|
||||||
|
|
||||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||||
|
|
||||||
|
@ -1605,6 +1620,7 @@ pub fn union_sorted_tags<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
var: Variable,
|
var: Variable,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
|
ptr_bytes: u32,
|
||||||
) -> Result<UnionVariant<'a>, LayoutProblem> {
|
) -> Result<UnionVariant<'a>, LayoutProblem> {
|
||||||
let var =
|
let var =
|
||||||
if let Content::RecursionVar { structure, .. } = subs.get_content_without_compacting(var) {
|
if let Content::RecursionVar { structure, .. } = subs.get_content_without_compacting(var) {
|
||||||
|
@ -1617,7 +1633,7 @@ pub fn union_sorted_tags<'a>(
|
||||||
let result = match roc_types::pretty_print::chase_ext_tag_union(subs, var, &mut tags_vec) {
|
let result = match roc_types::pretty_print::chase_ext_tag_union(subs, var, &mut tags_vec) {
|
||||||
Ok(()) | Err((_, Content::FlexVar(_))) | Err((_, Content::RecursionVar { .. })) => {
|
Ok(()) | Err((_, Content::FlexVar(_))) | Err((_, Content::RecursionVar { .. })) => {
|
||||||
let opt_rec_var = get_recursion_var(subs, var);
|
let opt_rec_var = get_recursion_var(subs, var);
|
||||||
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs)
|
union_sorted_tags_help(arena, tags_vec, opt_rec_var, subs, ptr_bytes)
|
||||||
}
|
}
|
||||||
Err((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
|
Err((_, Content::Error)) => return Err(LayoutProblem::Erroneous),
|
||||||
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
|
Err(other) => panic!("invalid content in tag union variable: {:?}", other),
|
||||||
|
@ -1651,6 +1667,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
mut tags_vec: Vec<(&'_ TagName, VariableSubsSlice)>,
|
mut tags_vec: Vec<(&'_ TagName, VariableSubsSlice)>,
|
||||||
opt_rec_var: Option<Variable>,
|
opt_rec_var: Option<Variable>,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
|
ptr_bytes: u32,
|
||||||
) -> UnionVariant<'a> {
|
) -> UnionVariant<'a> {
|
||||||
// sort up front; make sure the ordering stays intact!
|
// sort up front; make sure the ordering stays intact!
|
||||||
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
@ -1659,6 +1676,7 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
match tags_vec.len() {
|
match tags_vec.len() {
|
||||||
|
@ -1708,8 +1726,6 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
layouts.sort_by(|layout1, layout2| {
|
layouts.sort_by(|layout1, layout2| {
|
||||||
let ptr_bytes = 8;
|
|
||||||
|
|
||||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||||
|
|
||||||
|
@ -1793,8 +1809,6 @@ fn union_sorted_tags_help_new<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_layouts.sort_by(|layout1, layout2| {
|
arg_layouts.sort_by(|layout1, layout2| {
|
||||||
let ptr_bytes = 8;
|
|
||||||
|
|
||||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||||
|
|
||||||
|
@ -1867,6 +1881,7 @@ pub fn union_sorted_tags_help<'a>(
|
||||||
mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
|
mut tags_vec: std::vec::Vec<(TagName, std::vec::Vec<Variable>)>,
|
||||||
opt_rec_var: Option<Variable>,
|
opt_rec_var: Option<Variable>,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
|
ptr_bytes: u32,
|
||||||
) -> UnionVariant<'a> {
|
) -> UnionVariant<'a> {
|
||||||
// sort up front; make sure the ordering stays intact!
|
// sort up front; make sure the ordering stays intact!
|
||||||
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
tags_vec.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
@ -1875,6 +1890,7 @@ pub fn union_sorted_tags_help<'a>(
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
match tags_vec.len() {
|
match tags_vec.len() {
|
||||||
|
@ -1921,8 +1937,6 @@ pub fn union_sorted_tags_help<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
layouts.sort_by(|layout1, layout2| {
|
layouts.sort_by(|layout1, layout2| {
|
||||||
let ptr_bytes = 8;
|
|
||||||
|
|
||||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||||
|
|
||||||
|
@ -2005,8 +2019,6 @@ pub fn union_sorted_tags_help<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_layouts.sort_by(|layout1, layout2| {
|
arg_layouts.sort_by(|layout1, layout2| {
|
||||||
let ptr_bytes = 8;
|
|
||||||
|
|
||||||
let size1 = layout1.alignment_bytes(ptr_bytes);
|
let size1 = layout1.alignment_bytes(ptr_bytes);
|
||||||
let size2 = layout2.alignment_bytes(ptr_bytes);
|
let size2 = layout2.alignment_bytes(ptr_bytes);
|
||||||
|
|
||||||
|
@ -2091,7 +2103,12 @@ fn cheap_sort_tags<'a, 'b>(
|
||||||
tags_vec
|
tags_vec
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_from_newtype<'a>(arena: &'a Bump, tags: UnionTags, subs: &Subs) -> Layout<'a> {
|
fn layout_from_newtype<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
tags: UnionTags,
|
||||||
|
subs: &Subs,
|
||||||
|
ptr_bytes: u32,
|
||||||
|
) -> Layout<'a> {
|
||||||
debug_assert!(tags.is_newtype_wrapper(subs));
|
debug_assert!(tags.is_newtype_wrapper(subs));
|
||||||
|
|
||||||
let slice_index = tags.variables().into_iter().next().unwrap();
|
let slice_index = tags.variables().into_iter().next().unwrap();
|
||||||
|
@ -2109,6 +2126,7 @@ fn layout_from_newtype<'a>(arena: &'a Bump, tags: UnionTags, subs: &Subs) -> Lay
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
seen: Vec::new_in(arena),
|
seen: Vec::new_in(arena),
|
||||||
|
ptr_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
match Layout::from_var(&mut env, var) {
|
match Layout::from_var(&mut env, var) {
|
||||||
|
@ -2128,11 +2146,16 @@ fn layout_from_newtype<'a>(arena: &'a Bump, tags: UnionTags, subs: &Subs) -> Lay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_from_tag_union<'a>(arena: &'a Bump, tags: UnionTags, subs: &Subs) -> Layout<'a> {
|
fn layout_from_tag_union<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
tags: UnionTags,
|
||||||
|
subs: &Subs,
|
||||||
|
ptr_bytes: u32,
|
||||||
|
) -> Layout<'a> {
|
||||||
use UnionVariant::*;
|
use UnionVariant::*;
|
||||||
|
|
||||||
if tags.is_newtype_wrapper(subs) {
|
if tags.is_newtype_wrapper(subs) {
|
||||||
return layout_from_newtype(arena, tags, subs);
|
return layout_from_newtype(arena, tags, subs, ptr_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tags_vec = cheap_sort_tags(arena, tags, subs);
|
let tags_vec = cheap_sort_tags(arena, tags, subs);
|
||||||
|
@ -2148,7 +2171,7 @@ fn layout_from_tag_union<'a>(arena: &'a Bump, tags: UnionTags, subs: &Subs) -> L
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let opt_rec_var = None;
|
let opt_rec_var = None;
|
||||||
let variant = union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs);
|
let variant = union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs, ptr_bytes);
|
||||||
|
|
||||||
match variant {
|
match variant {
|
||||||
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
|
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
|
||||||
|
|
|
@ -92,14 +92,15 @@ mod test_reporting {
|
||||||
let mut ident_ids = interns.all_ident_ids.remove(&home).unwrap();
|
let mut ident_ids = interns.all_ident_ids.remove(&home).unwrap();
|
||||||
|
|
||||||
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
||||||
let mut layout_cache = LayoutCache::default();
|
let ptr_bytes = 8;
|
||||||
|
let mut layout_cache = LayoutCache::new(ptr_bytes);
|
||||||
let mut mono_env = roc_mono::ir::Env {
|
let mut mono_env = roc_mono::ir::Env {
|
||||||
arena: &arena,
|
arena: &arena,
|
||||||
subs: &mut subs,
|
subs: &mut subs,
|
||||||
problems: &mut mono_problems,
|
problems: &mut mono_problems,
|
||||||
home,
|
home,
|
||||||
ident_ids: &mut ident_ids,
|
ident_ids: &mut ident_ids,
|
||||||
ptr_bytes: 8,
|
ptr_bytes,
|
||||||
update_mode_counter: 0,
|
update_mode_counter: 0,
|
||||||
// call_specialization_counter=0 is reserved
|
// call_specialization_counter=0 is reserved
|
||||||
call_specialization_counter: 1,
|
call_specialization_counter: 1,
|
||||||
|
|
|
@ -30,7 +30,7 @@ either = "1.6.1"
|
||||||
indoc = "0.3.3"
|
indoc = "0.3.3"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
inkwell = { path = "../../vendor/inkwell" }
|
inkwell = { path = "../../vendor/inkwell" }
|
||||||
target-lexicon = "0.10"
|
target-lexicon = "0.12.2"
|
||||||
libloading = "0.6"
|
libloading = "0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -28,7 +28,7 @@ bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||||
either = "1.6.1"
|
either = "1.6.1"
|
||||||
indoc = "0.3.3"
|
indoc = "0.3.3"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
target-lexicon = "0.10"
|
target-lexicon = "0.12.2"
|
||||||
libloading = "0.6"
|
libloading = "0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
1
examples/.gitignore
vendored
1
examples/.gitignore
vendored
|
@ -4,4 +4,3 @@ app
|
||||||
libhost.a
|
libhost.a
|
||||||
roc_app.ll
|
roc_app.ll
|
||||||
roc_app.bc
|
roc_app.bc
|
||||||
effect-example
|
|
||||||
|
|
|
@ -29,23 +29,33 @@ extern fn roc__mainForHost_1_Fx_caller(*const u8, [*]u8, [*]u8) void;
|
||||||
extern fn roc__mainForHost_1_Fx_size() i64;
|
extern fn roc__mainForHost_1_Fx_size() i64;
|
||||||
extern fn roc__mainForHost_1_Fx_result_size() i64;
|
extern fn roc__mainForHost_1_Fx_result_size() i64;
|
||||||
|
|
||||||
extern fn malloc(size: usize) callconv(.C) ?*c_void;
|
const Align = extern struct { a: usize, b: usize };
|
||||||
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
|
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
|
||||||
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void;
|
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void;
|
||||||
|
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void;
|
||||||
|
|
||||||
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
|
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
|
||||||
|
_ = alignment;
|
||||||
|
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void {
|
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void {
|
||||||
return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size);
|
_ = old_size;
|
||||||
|
_ = alignment;
|
||||||
|
|
||||||
|
return realloc(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)), new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
_ = alignment;
|
||||||
|
|
||||||
|
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
||||||
|
_ = tag_id;
|
||||||
|
|
||||||
const stderr = std.io.getStdErr().writer();
|
const stderr = std.io.getStdErr().writer();
|
||||||
const msg = @ptrCast([*:0]const u8, c_ptr);
|
const msg = @ptrCast([*:0]const u8, c_ptr);
|
||||||
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
||||||
|
@ -54,12 +64,9 @@ export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
||||||
|
|
||||||
const Unit = extern struct {};
|
const Unit = extern struct {};
|
||||||
|
|
||||||
pub export fn main() u8 {
|
pub fn main() u8 {
|
||||||
const stdout = std.io.getStdOut().writer();
|
|
||||||
const stderr = std.io.getStdErr().writer();
|
|
||||||
|
|
||||||
const size = @intCast(usize, roc__mainForHost_size());
|
const size = @intCast(usize, roc__mainForHost_size());
|
||||||
const raw_output = std.heap.c_allocator.alloc(u8, size) catch unreachable;
|
const raw_output = std.heap.c_allocator.allocAdvanced(u8, @alignOf(u64), @intCast(usize, size), .at_least) catch unreachable;
|
||||||
var output = @ptrCast([*]u8, raw_output);
|
var output = @ptrCast([*]u8, raw_output);
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
|
@ -71,17 +78,17 @@ pub export fn main() u8 {
|
||||||
|
|
||||||
roc__mainForHost_1_exposed(output);
|
roc__mainForHost_1_exposed(output);
|
||||||
|
|
||||||
const elements = @ptrCast([*]u64, @alignCast(8, output));
|
const flag = @ptrCast(*u64, @alignCast(@alignOf(u64), output)).*;
|
||||||
|
|
||||||
var flag = elements[0];
|
|
||||||
|
|
||||||
if (flag == 0) {
|
if (flag == 0) {
|
||||||
// all is well
|
// all is well
|
||||||
const closure_data_pointer = @ptrCast([*]u8, output[8..size]);
|
const closure_data_pointer = @ptrCast([*]u8, output[@sizeOf(u64)..size]);
|
||||||
|
|
||||||
call_the_closure(closure_data_pointer);
|
call_the_closure(closure_data_pointer);
|
||||||
} else {
|
} else {
|
||||||
const msg = @intToPtr([*:0]const u8, elements[1]);
|
const ptr = @ptrCast(*u32, output + @sizeOf(u64));
|
||||||
|
const msg = @intToPtr([*:0]const u8, ptr.*);
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -92,6 +99,7 @@ pub export fn main() u8 {
|
||||||
|
|
||||||
const delta = to_seconds(ts2) - to_seconds(ts1);
|
const delta = to_seconds(ts2) - to_seconds(ts1);
|
||||||
|
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
stderr.print("runtime: {d:.3}ms\n", .{delta * 1000}) catch unreachable;
|
stderr.print("runtime: {d:.3}ms\n", .{delta * 1000}) catch unreachable;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -103,7 +111,7 @@ fn to_seconds(tms: std.os.timespec) f64 {
|
||||||
|
|
||||||
fn call_the_closure(closure_data_pointer: [*]u8) void {
|
fn call_the_closure(closure_data_pointer: [*]u8) void {
|
||||||
const size = roc__mainForHost_1_Fx_result_size();
|
const size = roc__mainForHost_1_Fx_result_size();
|
||||||
const raw_output = std.heap.c_allocator.alloc(u8, @intCast(usize, size)) catch unreachable;
|
const raw_output = std.heap.c_allocator.allocAdvanced(u8, @alignOf(u64), @intCast(usize, size), .at_least) catch unreachable;
|
||||||
var output = @ptrCast([*]u8, raw_output);
|
var output = @ptrCast([*]u8, raw_output);
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
|
@ -135,7 +143,7 @@ pub export fn roc_fx_putInt(int: i64) i64 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn roc_fx_putLine(rocPath: str.RocStr) i64 {
|
export fn roc_fx_putLine(rocPath: str.RocStr) callconv(.C) void {
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
for (rocPath.asSlice()) |char| {
|
for (rocPath.asSlice()) |char| {
|
||||||
|
@ -143,8 +151,6 @@ pub export fn roc_fx_putLine(rocPath: str.RocStr) i64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout.print("\n", .{}) catch unreachable;
|
stdout.print("\n", .{}) catch unreachable;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetInt = extern struct {
|
const GetInt = extern struct {
|
||||||
|
|
1
examples/cli/.gitignore
vendored
Normal file
1
examples/cli/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
echo
|
18
examples/cli/Echo.roc
Normal file
18
examples/cli/Echo.roc
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env roc
|
||||||
|
|
||||||
|
app "echo"
|
||||||
|
packages { base: "platform" }
|
||||||
|
imports [ base.Task.{ Task, await }, base.Stdout, base.Stdin ]
|
||||||
|
provides [ main ] to base
|
||||||
|
|
||||||
|
main : Task {} *
|
||||||
|
main =
|
||||||
|
{} <- await (Stdout.line "What's your first name?")
|
||||||
|
|
||||||
|
firstName <- await Stdin.line
|
||||||
|
|
||||||
|
{} <- await (Stdout.line "What's your last name?")
|
||||||
|
|
||||||
|
lastName <- await Stdin.line
|
||||||
|
|
||||||
|
Stdout.line "Hi, \(firstName) \(lastName)!"
|
BIN
examples/cli/cli-example
Executable file
BIN
examples/cli/cli-example
Executable file
Binary file not shown.
BIN
examples/cli/hello-world
Executable file
BIN
examples/cli/hello-world
Executable file
Binary file not shown.
21
examples/cli/platform/Cargo.lock
generated
Normal file
21
examples/cli/platform/Cargo.lock
generated
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "host"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"roc_std",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_std"
|
||||||
|
version = "0.1.0"
|
15
examples/cli/platform/Cargo.toml
Normal file
15
examples/cli/platform/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "host"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The Roc Contributors"]
|
||||||
|
license = "UPL-1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
roc_std = { path = "../../../roc_std" }
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
|
[workspace]
|
14
examples/cli/platform/Package-Config.roc
Normal file
14
examples/cli/platform/Package-Config.roc
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
platform examples/cli
|
||||||
|
requires {}{ main : Task {} [] } # TODO FIXME
|
||||||
|
exposes []
|
||||||
|
packages {}
|
||||||
|
imports [ Task.{ Task } ]
|
||||||
|
provides [ mainForHost ]
|
||||||
|
effects fx.Effect
|
||||||
|
{
|
||||||
|
putLine : Str -> Effect {},
|
||||||
|
getLine : Effect Str
|
||||||
|
}
|
||||||
|
|
||||||
|
mainForHost : Task {} [] as Fx
|
||||||
|
mainForHost = main
|
6
examples/cli/platform/Stdin.roc
Normal file
6
examples/cli/platform/Stdin.roc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
interface Stdin
|
||||||
|
exposes [ line ]
|
||||||
|
imports [ fx.Effect, Task ]
|
||||||
|
|
||||||
|
line : Task.Task Str *
|
||||||
|
line = Effect.after Effect.getLine Task.succeed # TODO FIXME Effect.getLine should suffice
|
9
examples/cli/platform/Stdout.roc
Normal file
9
examples/cli/platform/Stdout.roc
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
interface Stdout
|
||||||
|
exposes [ line ]
|
||||||
|
imports [ fx.Effect, Task.{ Task } ]
|
||||||
|
|
||||||
|
# line : Str -> Task.Task {} *
|
||||||
|
# line = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
||||||
|
|
||||||
|
line : Str -> Task {} *
|
||||||
|
line = \str -> Effect.map (Effect.putLine str) (\_ -> Ok {})
|
44
examples/cli/platform/Task.roc
Normal file
44
examples/cli/platform/Task.roc
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
interface Task
|
||||||
|
exposes [ Task, succeed, fail, await, map, onFail, attempt ]
|
||||||
|
imports [ fx.Effect ]
|
||||||
|
|
||||||
|
|
||||||
|
Task ok err : Effect.Effect (Result ok err)
|
||||||
|
|
||||||
|
|
||||||
|
succeed : val -> Task val *
|
||||||
|
succeed = \val ->
|
||||||
|
Effect.always (Ok val)
|
||||||
|
|
||||||
|
|
||||||
|
fail : err -> Task * err
|
||||||
|
fail = \val ->
|
||||||
|
Effect.always (Err val)
|
||||||
|
|
||||||
|
attempt : Task a b, (Result a b -> Task c d) -> Task c d
|
||||||
|
attempt = \effect, transform ->
|
||||||
|
Effect.after effect \result ->
|
||||||
|
when result is
|
||||||
|
Ok ok -> transform (Ok ok)
|
||||||
|
Err err -> transform (Err err)
|
||||||
|
|
||||||
|
await : Task a err, (a -> Task b err) -> Task b err
|
||||||
|
await = \effect, transform ->
|
||||||
|
Effect.after effect \result ->
|
||||||
|
when result is
|
||||||
|
Ok a -> transform a
|
||||||
|
Err err -> Task.fail err
|
||||||
|
|
||||||
|
onFail : Task ok a, (a -> Task ok b) -> Task ok b
|
||||||
|
onFail = \effect, transform ->
|
||||||
|
Effect.after effect \result ->
|
||||||
|
when result is
|
||||||
|
Ok a -> Task.succeed a
|
||||||
|
Err err -> transform err
|
||||||
|
|
||||||
|
map : Task a err, (a -> b) -> Task b err
|
||||||
|
map = \effect, transform ->
|
||||||
|
Effect.after effect \result ->
|
||||||
|
when result is
|
||||||
|
Ok a -> Task.succeed (transform a)
|
||||||
|
Err err -> Task.fail err
|
7
examples/cli/platform/host.c
Normal file
7
examples/cli/platform/host.c
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int rust_main();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return rust_main();
|
||||||
|
}
|
139
examples/cli/platform/src/lib.rs
Normal file
139
examples/cli/platform/src/lib.rs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::ffi::c_void;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use libc;
|
||||||
|
use roc_std::{RocCallResult, RocStr};
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#[link_name = "roc__mainForHost_1_exposed"]
|
||||||
|
fn roc_main(output: *mut u8) -> ();
|
||||||
|
|
||||||
|
#[link_name = "roc__mainForHost_size"]
|
||||||
|
fn roc_main_size() -> i64;
|
||||||
|
|
||||||
|
#[link_name = "roc__mainForHost_1_Fx_caller"]
|
||||||
|
fn call_Fx(flags: *const u8, closure_data: *const u8, output: *mut u8) -> ();
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[link_name = "roc__mainForHost_1_Fx_size"]
|
||||||
|
fn size_Fx() -> i64;
|
||||||
|
|
||||||
|
#[link_name = "roc__mainForHost_1_Fx_result_size"]
|
||||||
|
fn size_Fx_result() -> i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_alloc(size: usize, _alignment: u32) -> *mut c_void {
|
||||||
|
libc::malloc(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_realloc(
|
||||||
|
c_ptr: *mut c_void,
|
||||||
|
new_size: usize,
|
||||||
|
_old_size: usize,
|
||||||
|
_alignment: u32,
|
||||||
|
) -> *mut c_void {
|
||||||
|
libc::realloc(c_ptr, new_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
||||||
|
libc::free(c_ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn roc_panic(c_ptr: *mut c_void, tag_id: u32) {
|
||||||
|
match tag_id {
|
||||||
|
0 => {
|
||||||
|
let slice = CStr::from_ptr(c_ptr as *const c_char);
|
||||||
|
let string = slice.to_str().unwrap();
|
||||||
|
eprintln!("Roc hit a panic: {}", string);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn rust_main() -> isize {
|
||||||
|
let size = unsafe { roc_main_size() } as usize;
|
||||||
|
let layout = Layout::array::<u8>(size).unwrap();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// TODO allocate on the stack if it's under a certain size
|
||||||
|
let buffer = std::alloc::alloc(layout);
|
||||||
|
|
||||||
|
roc_main(buffer);
|
||||||
|
|
||||||
|
let output = buffer as *mut RocCallResult<()>;
|
||||||
|
|
||||||
|
match (&*output).into() {
|
||||||
|
Ok(()) => {
|
||||||
|
let closure_data_ptr = buffer.offset(8);
|
||||||
|
let result = call_the_closure(closure_data_ptr as *const u8);
|
||||||
|
|
||||||
|
std::alloc::dealloc(buffer, layout);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
Err(msg) => {
|
||||||
|
std::alloc::dealloc(buffer, layout);
|
||||||
|
|
||||||
|
panic!("Roc failed with message: {}", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exit code
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn call_the_closure(closure_data_ptr: *const u8) -> i64 {
|
||||||
|
let size = size_Fx_result() as usize;
|
||||||
|
let layout = Layout::array::<u8>(size).unwrap();
|
||||||
|
let buffer = std::alloc::alloc(layout) as *mut u8;
|
||||||
|
|
||||||
|
call_Fx(
|
||||||
|
// This flags pointer will never get dereferenced
|
||||||
|
MaybeUninit::uninit().as_ptr(),
|
||||||
|
closure_data_ptr as *const u8,
|
||||||
|
buffer as *mut u8,
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = &*(buffer as *mut RocCallResult<()>);
|
||||||
|
|
||||||
|
match output.into() {
|
||||||
|
Ok(_) => {
|
||||||
|
std::alloc::dealloc(buffer, layout);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
Err(e) => panic!("failed with {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn roc_fx_getLine() -> RocStr {
|
||||||
|
use std::io::{self, BufRead};
|
||||||
|
|
||||||
|
let stdin = io::stdin();
|
||||||
|
let line1 = stdin.lock().lines().next().unwrap().unwrap();
|
||||||
|
|
||||||
|
RocStr::from_slice(line1.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn roc_fx_putLine(line: RocStr) -> () {
|
||||||
|
let bytes = line.as_slice();
|
||||||
|
let string = unsafe { std::str::from_utf8_unchecked(bytes) };
|
||||||
|
println!("{}", string);
|
||||||
|
|
||||||
|
// don't mess with the refcount!
|
||||||
|
core::mem::forget(line);
|
||||||
|
|
||||||
|
()
|
||||||
|
}
|
|
@ -19,23 +19,32 @@ comptime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern fn malloc(size: usize) callconv(.C) ?*c_void;
|
const Align = extern struct { a: usize, b: usize };
|
||||||
extern fn realloc(c_ptr: [*]align(@alignOf(u128)) u8, size: usize) callconv(.C) ?*c_void;
|
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
|
||||||
extern fn free(c_ptr: [*]align(@alignOf(u128)) u8) callconv(.C) void;
|
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void;
|
||||||
|
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void;
|
||||||
|
|
||||||
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
|
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*c_void {
|
||||||
|
_ = alignment;
|
||||||
|
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_realloc(c_ptr: *c_void, old_size: usize, new_size: usize, alignment: u32) callconv(.C) ?*c_void {
|
export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*c_void {
|
||||||
return realloc(@alignCast(16, @ptrCast([*]u8, c_ptr)), new_size);
|
_ = old_size;
|
||||||
|
_ = alignment;
|
||||||
|
|
||||||
|
return realloc(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)), new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
|
||||||
free(@alignCast(16, @ptrCast([*]u8, c_ptr)));
|
_ = alignment;
|
||||||
|
|
||||||
|
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
|
||||||
|
_ = tag_id;
|
||||||
const stderr = std.io.getStdErr().writer();
|
const stderr = std.io.getStdErr().writer();
|
||||||
const msg = @ptrCast([*:0]const u8, c_ptr);
|
const msg = @ptrCast([*:0]const u8, c_ptr);
|
||||||
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
||||||
|
@ -47,11 +56,11 @@ const Allocator = mem.Allocator;
|
||||||
|
|
||||||
extern fn roc__mainForHost_1_exposed(*RocCallResult) void;
|
extern fn roc__mainForHost_1_exposed(*RocCallResult) void;
|
||||||
|
|
||||||
const RocCallResult = extern struct { flag: usize, content: RocStr };
|
const RocCallResult = extern struct { flag: u64, content: RocStr };
|
||||||
|
|
||||||
const Unit = extern struct {};
|
const Unit = extern struct {};
|
||||||
|
|
||||||
pub export fn main() i32 {
|
pub fn main() u8 {
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
const stderr = std.io.getStdErr().writer();
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
|
||||||
|
|
|
@ -584,6 +584,10 @@ impl RocStr {
|
||||||
|
|
||||||
let raw_ptr = Self::get_element_ptr(raw_ptr as *mut u8);
|
let raw_ptr = Self::get_element_ptr(raw_ptr as *mut u8);
|
||||||
|
|
||||||
|
// write the refcount
|
||||||
|
let refcount_ptr = raw_ptr as *mut isize;
|
||||||
|
*(refcount_ptr.offset(-1)) = isize::MIN;
|
||||||
|
|
||||||
{
|
{
|
||||||
// NOTE: using a memcpy here causes weird issues
|
// NOTE: using a memcpy here causes weird issues
|
||||||
let target_ptr = raw_ptr as *mut u8;
|
let target_ptr = raw_ptr as *mut u8;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue