correct codegen for calling the extern

This commit is contained in:
Folkert 2023-01-20 15:07:49 +01:00
parent 1ac2c2bb80
commit c622cebea6
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
4 changed files with 204 additions and 165 deletions

View file

@ -637,7 +637,6 @@ fn add_tag_union(
types: &Types, types: &Types,
impls: &mut Impls, impls: &mut Impls,
) { ) {
dbg!("adding", name);
let name = escape_kw(name.to_string()); let name = escape_kw(name.to_string());
// We should never be attempting to generate glue for empty tag unions; // We should never be attempting to generate glue for empty tag unions;
@ -1844,26 +1843,35 @@ fn add_function(
buf.push('\n'); buf.push('\n');
buf.push('\n'); buf.push('\n');
let arguments = "";
let argument_types = "";
let argument_names = "";
let extern_name = &roc_fn.extern_name; let extern_name = &roc_fn.extern_name;
let return_type_str = type_name(roc_fn.ret, types); let return_type_str = type_name(roc_fn.ret, types);
writeln!(buf, "impl {name} {{").unwrap(); writeln!(buf, "impl {name} {{").unwrap();
writeln!(
write!(buf, "{INDENT}pub fn force_thunk(self").unwrap();
for (i, argument_type) in roc_fn.args.iter().enumerate() {
write!(buf, ", arg_{i}: {}", type_name(*argument_type, types)).unwrap();
}
writeln!(buf, ") -> {return_type_str} {{").unwrap();
writeln!(buf, "{INDENT}{INDENT}extern \"C\" {{").unwrap();
// fn extern_name(output: *mut return_type, arg1: arg1_type, ..., closure_data: *mut u8);
write!(
buf, buf,
"{INDENT}pub fn force_thunk(self, {arguments}) -> {return_type_str} {{" "{INDENT}{INDENT}{INDENT} fn {extern_name}(output: *mut {return_type_str}, "
) )
.unwrap(); .unwrap();
writeln!(buf, "{INDENT}{INDENT}extern \"C\" {{").unwrap(); for (i, argument_type) in roc_fn.args.iter().enumerate() {
writeln!( write!(buf, "arg_{i}: {}, ", type_name(*argument_type, types)).unwrap();
buf, }
"{INDENT}{INDENT}{INDENT} fn {extern_name}(output: *mut {return_type_str}, {argument_types}, closure_data: *mut u8);"
) writeln!(buf, "closure_data: *mut u8);").unwrap();
.unwrap();
// {argument_types} "
writeln!(buf, "{INDENT}{INDENT}}}").unwrap(); writeln!(buf, "{INDENT}{INDENT}}}").unwrap();
writeln!(buf).unwrap(); writeln!(buf).unwrap();
@ -1874,12 +1882,18 @@ fn add_function(
) )
.unwrap(); .unwrap();
writeln!( write!(
buf, buf,
"{INDENT}{INDENT}unsafe {{ {extern_name}(output.as_mut_ptr(), {argument_names}, self.closure_data) }};" "{INDENT}{INDENT}unsafe {{ {extern_name}(output.as_mut_ptr(), "
) )
.unwrap(); .unwrap();
for (i, _) in roc_fn.args.iter().enumerate() {
write!(buf, "arg_{i}, ").unwrap();
}
writeln!(buf, "self.closure_data) }};").unwrap();
writeln!(buf, "{INDENT}{INDENT}unsafe {{ output.assume_init() }}").unwrap(); writeln!(buf, "{INDENT}{INDENT}unsafe {{ output.assume_init() }}").unwrap();
writeln!(buf, "{INDENT}}}").unwrap(); writeln!(buf, "{INDENT}}}").unwrap();

View file

@ -1005,16 +1005,12 @@ fn add_type_help<'a>(
let extern_name = String::from("roc__mainForHost_1__Fx2_caller"); let extern_name = String::from("roc__mainForHost_1__Fx2_caller");
// let extern_name = env.extern_names.get(&lambda_set).cloned().unwrap(); // let extern_name = env.extern_names.get(&lambda_set).cloned().unwrap();
dbg!(&extern_name, &name);
for arg_var in args { for arg_var in args {
let arg_layout = env let arg_layout = env
.layout_cache .layout_cache
.from_var(env.arena, *arg_var, env.subs) .from_var(env.arena, *arg_var, env.subs)
.expect("Something weird ended up in the content"); .expect("Something weird ended up in the content");
dbg!(&arg_layout);
arg_type_ids.push(add_type_help(env, arg_layout, *arg_var, None, types)); arg_type_ids.push(add_type_help(env, arg_layout, *arg_var, None, types));
} }
@ -1027,8 +1023,6 @@ fn add_type_help<'a>(
.from_var(env.arena, *ret_var, env.subs) .from_var(env.arena, *ret_var, env.subs)
.expect("Something weird ended up in the content"); .expect("Something weird ended up in the content");
dbg!(ret_layout);
add_type_help(env, ret_layout, *ret_var, None, types) add_type_help(env, ret_layout, *ret_var, None, types)
}; };
@ -1202,7 +1196,7 @@ fn add_type_help<'a>(
if tags.is_empty() { if tags.is_empty() {
// this function does not capture anything. Represent that at runtime as a unit value // this function does not capture anything. Represent that at runtime as a unit value
types.add_anonymous(&env.layout_cache.interner, RocType::Unit, layout) types.add_anonymous(&env.layout_cache.interner, RocType::Unsized, layout)
} else { } else {
add_tag_union(env, opt_name, &tags, var, types, layout, None) add_tag_union(env, opt_name, &tags, var, types, layout, None)
} }

View file

@ -59,6 +59,7 @@ pub struct Op {
pointer: *mut union_Op, pointer: *mut union_Op,
} }
#[cfg(any( #[cfg(any(
target_arch = "arm", target_arch = "arm",
target_arch = "aarch64", target_arch = "aarch64",
@ -86,6 +87,7 @@ union union_Op {
target_arch = "x86_64" target_arch = "x86_64"
))] ))]
//TODO HAS CLOSURE 2 //TODO HAS CLOSURE 2
#[cfg(any( #[cfg(any(
target_arch = "arm", target_arch = "arm",
target_arch = "aarch64", target_arch = "aarch64",
@ -93,20 +95,20 @@ union union_Op {
target_arch = "x86", target_arch = "x86",
target_arch = "x86_64" target_arch = "x86_64"
))] ))]
#[repr(C)] #[repr(C)]
pub struct RocFunction_65<'a> { pub struct RocFunction_65 {
closure_data: *const u8, pub closure_data: *mut u8,
_marker: std::marker::PhantomData<&'a ()>,
} }
impl<'a> RocFunction_65<'a> { impl RocFunction_65 {
pub fn force_thunk(self) -> Op { pub fn force_thunk(self, arg_0: ()) -> Op {
extern "C" { extern "C" {
fn roc__mainForHost_1__Fx2_caller(output: *mut Op, input: *const u8); fn roc__mainForHost_1__Fx2_caller(output: *mut Op, arg_0: (), closure_data: *mut u8);
} }
let mut output = std::mem::MaybeUninit::uninit(); let mut output = std::mem::MaybeUninit::uninit();
unsafe { roc__mainForHost_1__Fx2_caller(output.as_mut_ptr(), self.closure_data) }; unsafe { roc__mainForHost_1__Fx2_caller(output.as_mut_ptr(), arg_0, self.closure_data) };
unsafe { output.assume_init() } unsafe { output.assume_init() }
} }
} }
@ -118,19 +120,20 @@ impl<'a> RocFunction_65<'a> {
target_arch = "x86", target_arch = "x86",
target_arch = "x86_64" target_arch = "x86_64"
))] ))]
#[repr(C)] #[repr(C)]
pub struct RocFunction_67 { pub struct RocFunction_67 {
pub closure_data: (), pub closure_data: *mut u8,
} }
impl RocFunction_67 { impl RocFunction_67 {
pub fn force_thunk(self) -> Op { pub fn force_thunk(self, arg_0: ()) -> Op {
extern "C" { extern "C" {
fn roc__mainForHost_1__Fx2_caller(output: *mut Op); fn roc__mainForHost_1__Fx2_caller(output: *mut Op, arg_0: (), closure_data: *mut u8);
} }
let mut output = std::mem::MaybeUninit::uninit(); let mut output = std::mem::MaybeUninit::uninit();
unsafe { roc__mainForHost_1__Fx2_caller(output.as_mut_ptr()) }; unsafe { roc__mainForHost_1__Fx2_caller(output.as_mut_ptr(), arg_0, self.closure_data) };
unsafe { output.assume_init() } unsafe { output.assume_init() }
} }
} }
@ -158,18 +161,28 @@ impl Op {
if untagged.is_null() { if untagged.is_null() {
None None
} else { } else {
unsafe { Some(&*untagged.sub(1)) } unsafe {
Some(&*untagged.sub(1))
}
} }
} }
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] #[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
/// Returns which variant this tag union holds. Note that this never includes a payload! /// Returns which variant this tag union holds. Note that this never includes a payload!
pub fn discriminant(&self) -> discriminant_Op { pub fn discriminant(&self) -> discriminant_Op {
// The discriminant is stored in the unused bytes at the end of the recursive pointer // The discriminant is stored in the unused bytes at the end of the recursive pointer
unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b11) } unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b11) }
} }
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] #[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
/// Internal helper /// Internal helper
fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op { fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer // The discriminant is stored in the unused bytes at the end of the union pointer
@ -179,7 +192,11 @@ impl Op {
tagged as *mut union_Op tagged as *mut union_Op
} }
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] #[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
/// Internal helper /// Internal helper
fn union_pointer(&self) -> *mut union_Op { fn union_pointer(&self) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer // The discriminant is stored in the unused bytes at the end of the union pointer
@ -257,28 +274,32 @@ impl Op {
))] ))]
/// Construct a tag named `StderrWrite`, with the appropriate payload /// Construct a tag named `StderrWrite`, with the appropriate payload
pub fn StderrWrite(arg: Op_StderrWrite) -> Self { pub fn StderrWrite(arg: Op_StderrWrite) -> Self {
let size = core::mem::size_of::<union_Op>(); let size = core::mem::size_of::<union_Op>();
let align = core::mem::align_of::<union_Op>() as u32; let align = core::mem::align_of::<union_Op>() as u32;
unsafe { unsafe {
let ptr = roc_std::roc_alloc_refcounted::<union_Op>(); let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
*ptr = union_Op { *ptr = union_Op {
StderrWrite: core::mem::ManuallyDrop::new(arg), StderrWrite: core::mem::ManuallyDrop::new(arg)
}; };
Self { Self {
pointer: Self::tag_discriminant(ptr, discriminant_Op::StderrWrite), pointer: Self::tag_discriminant(ptr, discriminant_Op::StderrWrite),
}
} }
}
} }
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] #[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite { pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op; let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit(); let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -297,12 +318,16 @@ impl Op {
payload payload
} }
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] #[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite { pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op; let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
@ -352,16 +377,14 @@ impl Op {
extern "C" { extern "C" {
#[link_name = "roc__getter__3"] #[link_name = "roc__getter__3"]
fn getter(_: *const Op) -> *const u8; fn getter(_: *mut RocFunction_65, _: *const Op);
// fn getter(_: *mut RocFunction_65, _: *const Op);
} }
let ptr = getter(self); let mut ret = core::mem::MaybeUninit::uninit();
RocFunction_65 { getter(ret.as_mut_ptr(), self);
closure_data: ptr,
_marker: Default::default(), ret.assume_init()
}
} }
#[cfg(any( #[cfg(any(
@ -373,28 +396,32 @@ impl Op {
))] ))]
/// Construct a tag named `StdoutWrite`, with the appropriate payload /// Construct a tag named `StdoutWrite`, with the appropriate payload
pub fn StdoutWrite(arg: Op_StdoutWrite) -> Self { pub fn StdoutWrite(arg: Op_StdoutWrite) -> Self {
let size = core::mem::size_of::<union_Op>(); let size = core::mem::size_of::<union_Op>();
let align = core::mem::align_of::<union_Op>() as u32; let align = core::mem::align_of::<union_Op>() as u32;
unsafe { unsafe {
let ptr = roc_std::roc_alloc_refcounted::<union_Op>(); let ptr = roc_std::roc_alloc_refcounted::<union_Op>();
*ptr = union_Op { *ptr = union_Op {
StdoutWrite: core::mem::ManuallyDrop::new(arg), StdoutWrite: core::mem::ManuallyDrop::new(arg)
}; };
Self { Self {
pointer: Self::tag_discriminant(ptr, discriminant_Op::StdoutWrite), pointer: Self::tag_discriminant(ptr, discriminant_Op::StdoutWrite),
}
} }
}
} }
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] #[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite { pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op; let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit(); let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -413,12 +440,16 @@ impl Op {
payload payload
} }
#[cfg(any(target_arch = "arm", target_arch = "wasm32", target_arch = "x86"))] #[cfg(any(
target_arch = "arm",
target_arch = "wasm32",
target_arch = "x86"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite { pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b11) as *mut union_Op; let ptr = (self.pointer as usize & !0b11) as *mut union_Op;
@ -428,14 +459,20 @@ impl Op {
&payload &payload
} }
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] #[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
/// Returns which variant this tag union holds. Note that this never includes a payload! /// Returns which variant this tag union holds. Note that this never includes a payload!
pub fn discriminant(&self) -> discriminant_Op { pub fn discriminant(&self) -> discriminant_Op {
// The discriminant is stored in the unused bytes at the end of the recursive pointer // The discriminant is stored in the unused bytes at the end of the recursive pointer
unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b111) } unsafe { core::mem::transmute::<u8, discriminant_Op>((self.pointer as u8) & 0b111) }
} }
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] #[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
/// Internal helper /// Internal helper
fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op { fn tag_discriminant(pointer: *mut union_Op, discriminant: discriminant_Op) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer // The discriminant is stored in the unused bytes at the end of the union pointer
@ -445,19 +482,25 @@ impl Op {
tagged as *mut union_Op tagged as *mut union_Op
} }
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] #[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
/// Internal helper /// Internal helper
fn union_pointer(&self) -> *mut union_Op { fn union_pointer(&self) -> *mut union_Op {
// The discriminant is stored in the unused bytes at the end of the union pointer // The discriminant is stored in the unused bytes at the end of the union pointer
((self.pointer as usize) & (!0b111 as usize)) as *mut union_Op ((self.pointer as usize) & (!0b111 as usize)) as *mut union_Op
} }
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] #[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and convert it to `StderrWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite { pub unsafe fn into_StderrWrite(mut self) -> Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op; let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit(); let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -476,12 +519,15 @@ impl Op {
payload payload
} }
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] #[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StderrWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StderrWrite`.
pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite { pub unsafe fn as_StderrWrite(&self) -> &Op_StderrWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StderrWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op; let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
@ -491,12 +537,15 @@ impl Op {
&payload &payload
} }
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] #[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and convert it to `StdoutWrite`'s payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite { pub unsafe fn into_StdoutWrite(mut self) -> Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op; let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
let mut uninitialized = core::mem::MaybeUninit::uninit(); let mut uninitialized = core::mem::MaybeUninit::uninit();
@ -515,12 +564,15 @@ impl Op {
payload payload
} }
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] #[cfg(any(
target_arch = "aarch64",
target_arch = "x86_64"
))]
/// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload. /// Unsafely assume this `Op` has a `.discriminant()` of `StdoutWrite` and return its payload.
/// (Always examine `.discriminant()` first to make sure this is the correct variant!) /// (Always examine `.discriminant()` first to make sure this is the correct variant!)
/// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`. /// Panics in debug builds if the `.discriminant()` doesn't return `StdoutWrite`.
pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite { pub unsafe fn as_StdoutWrite(&self) -> &Op_StdoutWrite {
debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite); debug_assert_eq!(self.discriminant(), discriminant_Op::StdoutWrite);
let payload = { let payload = {
let ptr = (self.pointer as usize & !0b111) as *mut union_Op; let ptr = (self.pointer as usize & !0b111) as *mut union_Op;
@ -549,23 +601,17 @@ impl Drop for Op {
if needs_dealloc { if needs_dealloc {
// Drop the payload first. // Drop the payload first.
match self.discriminant() { match self.discriminant() {
discriminant_Op::Done => {} discriminant_Op::Done => {}
discriminant_Op::StderrWrite => unsafe { discriminant_Op::StderrWrite => unsafe { core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StderrWrite) },
core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StderrWrite) discriminant_Op::StdoutWrite => unsafe { core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StdoutWrite) },
}, }
discriminant_Op::StdoutWrite => unsafe {
core::mem::ManuallyDrop::drop(&mut (&mut *self.union_pointer()).StdoutWrite)
},
}
// Dealloc the pointer // Dealloc the pointer
let alignment = let alignment = core::mem::align_of::<Self>().max(core::mem::align_of::<roc_std::Storage>());
core::mem::align_of::<Self>().max(core::mem::align_of::<roc_std::Storage>());
unsafe { unsafe { crate::roc_dealloc(storage.as_ptr().cast(), alignment as u32); }
crate::roc_dealloc(storage.as_ptr().cast(), alignment as u32);
}
} else { } else {
// Write the storage back. // Write the storage back.
storage.set(new_storage); storage.set(new_storage);
@ -585,19 +631,15 @@ impl PartialEq for Op {
target_arch = "x86_64" target_arch = "x86_64"
))] ))]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if self.discriminant() != other.discriminant() { if self.discriminant() != other.discriminant() {
return false; return false;
} }
unsafe { unsafe {
match self.discriminant() { match self.discriminant() {
discriminant_Op::Done => true, discriminant_Op::Done => true,
discriminant_Op::StderrWrite => { discriminant_Op::StderrWrite => (&*self.union_pointer()).StderrWrite == (&*other.union_pointer()).StderrWrite,
(&*self.union_pointer()).StderrWrite == (&*other.union_pointer()).StderrWrite discriminant_Op::StdoutWrite => (&*self.union_pointer()).StdoutWrite == (&*other.union_pointer()).StdoutWrite,
}
discriminant_Op::StdoutWrite => {
(&*self.union_pointer()).StdoutWrite == (&*other.union_pointer()).StdoutWrite
}
} }
} }
} }
@ -620,12 +662,8 @@ impl PartialOrd for Op {
unsafe { unsafe {
match self.discriminant() { match self.discriminant() {
discriminant_Op::Done => Some(core::cmp::Ordering::Equal), discriminant_Op::Done => Some(core::cmp::Ordering::Equal),
discriminant_Op::StderrWrite => (&*self.union_pointer()) discriminant_Op::StderrWrite => (&*self.union_pointer()).StderrWrite.partial_cmp(&(&*other.union_pointer()).StderrWrite),
.StderrWrite discriminant_Op::StdoutWrite => (&*self.union_pointer()).StdoutWrite.partial_cmp(&(&*other.union_pointer()).StdoutWrite),
.partial_cmp(&(&*other.union_pointer()).StderrWrite),
discriminant_Op::StdoutWrite => (&*self.union_pointer())
.StdoutWrite
.partial_cmp(&(&*other.union_pointer()).StdoutWrite),
} }
} }
} }
@ -640,20 +678,16 @@ impl Ord for Op {
target_arch = "x86_64" target_arch = "x86_64"
))] ))]
fn cmp(&self, other: &Self) -> core::cmp::Ordering { fn cmp(&self, other: &Self) -> core::cmp::Ordering {
match self.discriminant().cmp(&other.discriminant()) { match self.discriminant().cmp(&other.discriminant()) {
core::cmp::Ordering::Equal => {} core::cmp::Ordering::Equal => {}
not_eq => return not_eq, not_eq => return not_eq,
} }
unsafe { unsafe {
match self.discriminant() { match self.discriminant() {
discriminant_Op::Done => core::cmp::Ordering::Equal, discriminant_Op::Done => core::cmp::Ordering::Equal,
discriminant_Op::StderrWrite => (&*self.union_pointer()) discriminant_Op::StderrWrite => (&*self.union_pointer()).StderrWrite.cmp(&(&*other.union_pointer()).StderrWrite),
.StderrWrite discriminant_Op::StdoutWrite => (&*self.union_pointer()).StdoutWrite.cmp(&(&*other.union_pointer()).StdoutWrite),
.cmp(&(&*other.union_pointer()).StderrWrite),
discriminant_Op::StdoutWrite => (&*self.union_pointer())
.StdoutWrite
.cmp(&(&*other.union_pointer()).StdoutWrite),
} }
} }
} }
@ -677,7 +711,7 @@ impl Clone for Op {
} }
Self { Self {
pointer: self.pointer, pointer: self.pointer
} }
} }
} }
@ -690,17 +724,16 @@ impl core::hash::Hash for Op {
target_arch = "x86", target_arch = "x86",
target_arch = "x86_64" target_arch = "x86_64"
))] ))]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) { fn hash<H: core::hash::Hasher>(&self, state: &mut H) { match self.discriminant() {
match self.discriminant() {
discriminant_Op::Done => discriminant_Op::Done.hash(state), discriminant_Op::Done => discriminant_Op::Done.hash(state),
discriminant_Op::StderrWrite => unsafe { discriminant_Op::StderrWrite => unsafe {
discriminant_Op::StderrWrite.hash(state); discriminant_Op::StderrWrite.hash(state);
(&*self.union_pointer()).StderrWrite.hash(state); (&*self.union_pointer()).StderrWrite.hash(state);
}, },
discriminant_Op::StdoutWrite => unsafe { discriminant_Op::StdoutWrite => unsafe {
discriminant_Op::StdoutWrite.hash(state); discriminant_Op::StdoutWrite.hash(state);
(&*self.union_pointer()).StdoutWrite.hash(state); (&*self.union_pointer()).StdoutWrite.hash(state);
}, },
} }
} }
} }
@ -719,14 +752,12 @@ impl core::fmt::Debug for Op {
unsafe { unsafe {
match self.discriminant() { match self.discriminant() {
discriminant_Op::Done => f.write_str("Done"), discriminant_Op::Done => f.write_str("Done"),
discriminant_Op::StderrWrite => f discriminant_Op::StderrWrite => f.debug_tuple("StderrWrite")
.debug_tuple("StderrWrite") // TODO HAS CLOSURE
// TODO HAS CLOSURE .finish(),
.finish(), discriminant_Op::StdoutWrite => f.debug_tuple("StdoutWrite")
discriminant_Op::StdoutWrite => f // TODO HAS CLOSURE
.debug_tuple("StdoutWrite") .finish(),
// TODO HAS CLOSURE
.finish(),
} }
} }
} }

View file

@ -105,7 +105,7 @@ pub extern "C" fn rust_main() -> i32 {
match dbg!(op.discriminant()) { match dbg!(op.discriminant()) {
StdoutWrite => { StdoutWrite => {
let output: RocStr = unsafe { op.get_StdoutWrite_0() }; let output: RocStr = unsafe { op.get_StdoutWrite_0() };
op = unsafe { op.get_StdoutWrite_1().force_thunk() }; op = unsafe { op.get_StdoutWrite_1().force_thunk(()) };
dbg!(&output); dbg!(&output);