1#[derive(Debug, PartialEq, Eq)]
3pub enum Yield {
4 Done(*mut u8),
6 Request {
9 tag: u64,
10 request: *mut u8,
11 continuation: *mut u8,
12 },
13 Error(YieldError),
15}
16
17impl std::fmt::Display for Yield {
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 match self {
20 Yield::Done(ptr) => write!(f, "Done({:p})", ptr),
21 Yield::Request {
22 tag,
23 request,
24 continuation,
25 } => {
26 write!(
27 f,
28 "Request(tag={}, req={:p}, cont={:p})",
29 tag, request, continuation
30 )
31 }
32 Yield::Error(e) => write!(f, "Error({})", e),
33 }
34 }
35}
36
37#[derive(Debug, PartialEq, Eq, Clone)]
38pub enum YieldError {
39 UnexpectedTag(u8),
41 UnexpectedConTag(u64),
43 BadValFields(u16),
45 BadEFields(u16),
47 BadUnionFields(u16),
49 NullPointer,
51 DivisionByZero,
53 Overflow,
55 UserError,
57 UserErrorMsg(String),
59 Undefined,
61 TypeMetadata,
63 UnresolvedVar(u64),
65 NullFunPtr,
67 BadFunPtrTag(u8),
69 HeapOverflow,
71 StackOverflow,
73 Signal(i32),
75 BlackHole,
77 BadThunkState(u8),
79}
80
81impl std::fmt::Display for YieldError {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 YieldError::UnexpectedTag(tag) => write!(f, "unexpected heap tag: {}", tag),
85 YieldError::UnexpectedConTag(tag) => write!(f, "unexpected constructor tag: {}", tag),
86 YieldError::BadValFields(n) => {
87 write!(f, "Val constructor has {} fields, expected >= 1", n)
88 }
89 YieldError::BadEFields(n) => write!(f, "E constructor has {} fields, expected 2", n),
90 YieldError::BadUnionFields(n) => {
91 write!(f, "Union constructor has {} fields, expected 2", n)
92 }
93 YieldError::NullPointer => write!(f, "null pointer in effect result"),
94 YieldError::DivisionByZero => write!(f, "division by zero"),
95 YieldError::Overflow => write!(f, "arithmetic overflow"),
96 YieldError::UserError => write!(f, "Haskell error called"),
97 YieldError::UserErrorMsg(msg) => write!(f, "Haskell error: {}", msg),
98 YieldError::Undefined => write!(f, "Haskell undefined forced"),
99 YieldError::TypeMetadata => write!(f, "forced type metadata (should be dead code)"),
100 YieldError::UnresolvedVar(id) => {
101 let tag_char = (*id >> 56) as u8 as char;
102 let key = *id & ((1u64 << 56) - 1);
103 write!(
104 f,
105 "unresolved variable VarId({:#x}) [tag='{}', key={}]",
106 id, tag_char, key
107 )
108 }
109 YieldError::NullFunPtr => write!(f, "application of null function pointer"),
110 YieldError::BadFunPtrTag(tag) => write!(f, "application of non-closure (tag={})", tag),
111 YieldError::HeapOverflow => write!(f, "heap overflow (nursery exhausted after GC)"),
112 YieldError::StackOverflow => write!(f, "stack overflow (likely infinite list or unbounded recursion — use zipWithIndex/imap/enumFromTo instead of [0..])"),
113 YieldError::BlackHole => write!(f, "blackhole detected (infinite loop: thunk forced itself)"),
114 YieldError::BadThunkState(state) => write!(f, "thunk has invalid evaluation state: {}", state),
115 YieldError::Signal(sig) => {
116 let ctx = crate::host_fns::get_exec_context();
117 #[cfg(unix)]
118 {
119 let name = match *sig {
120 libc::SIGILL => {
121 "SIGILL (illegal instruction — likely exhausted case branch)"
122 }
123 libc::SIGSEGV => {
124 "SIGSEGV (segmentation fault — likely invalid memory access)"
125 }
126 libc::SIGBUS => "SIGBUS (bus error)",
127 libc::SIGTRAP => "SIGTRAP (trap — likely Cranelift trap instruction)",
128 _ => {
129 if !ctx.is_empty() {
130 return write!(
131 f,
132 "JIT signal: signal {} (unknown, context: {})",
133 sig, ctx
134 );
135 } else {
136 return write!(f, "JIT signal: signal {} (unknown)", sig);
137 }
138 }
139 };
140 if !ctx.is_empty() {
141 write!(f, "JIT signal: {} (context: {})", name, ctx)
142 } else {
143 write!(f, "JIT signal: {}", name)
144 }
145 }
146 #[cfg(not(unix))]
147 if !ctx.is_empty() {
148 write!(f, "JIT signal: signal {} (context: {})", sig, ctx)
149 } else {
150 write!(f, "JIT signal: signal {}", sig)
151 }
152 }
153 }
154 }
155}
156
157impl std::error::Error for YieldError {}
158
159impl From<crate::host_fns::RuntimeError> for YieldError {
160 fn from(err: crate::host_fns::RuntimeError) -> Self {
161 use crate::host_fns::RuntimeError;
162 match err {
163 RuntimeError::DivisionByZero => YieldError::DivisionByZero,
164 RuntimeError::Overflow => YieldError::Overflow,
165 RuntimeError::UserError => YieldError::UserError,
166 RuntimeError::UserErrorMsg(msg) => YieldError::UserErrorMsg(msg),
167 RuntimeError::Undefined => YieldError::Undefined,
168 RuntimeError::TypeMetadata => YieldError::TypeMetadata,
169 RuntimeError::UnresolvedVar(id) => YieldError::UnresolvedVar(id),
170 RuntimeError::NullFunPtr => YieldError::NullFunPtr,
171 RuntimeError::BadFunPtrTag(tag) => YieldError::BadFunPtrTag(tag),
172 RuntimeError::HeapOverflow => YieldError::HeapOverflow,
173 RuntimeError::StackOverflow => YieldError::StackOverflow,
174 RuntimeError::BlackHole => YieldError::BlackHole,
175 RuntimeError::BadThunkState(state) => YieldError::BadThunkState(state),
176 }
177 }
178}