mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Eliminate Stmt::RuntimeError in favor of crash
This commit is contained in:
parent
a2f2a18a76
commit
803d7e30e3
14 changed files with 115 additions and 130 deletions
|
@ -640,11 +640,6 @@ fn stmt_spec<'a>(
|
|||
let jpid = env.join_points[id];
|
||||
builder.add_jump(block, jpid, argument, ret_type_id)
|
||||
}
|
||||
RuntimeError(_) => {
|
||||
let type_id = layout_spec(env, builder, interner, layout, &WhenRecursive::Unreachable)?;
|
||||
|
||||
builder.add_terminate(block, type_id)
|
||||
}
|
||||
Crash(msg, _) => {
|
||||
// Model this as a foreign call rather than TERMINATE because
|
||||
// we want ownership of the message.
|
||||
|
|
|
@ -1110,7 +1110,6 @@ trait Backend<'a> {
|
|||
Stmt::Expect { .. } => todo!("expect is not implemented in the dev backend"),
|
||||
Stmt::ExpectFx { .. } => todo!("expect-fx is not implemented in the dev backend"),
|
||||
|
||||
Stmt::RuntimeError(..) => todo!("runtime-error is not implemented in the dev backend"),
|
||||
Stmt::Crash(..) => todo!("crash is not implemented in the dev backend"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ use roc_debug_flags::dbg_do;
|
|||
use roc_debug_flags::ROC_PRINT_LLVM_FN_VERIFICATION;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, CallType, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc, OptLevel,
|
||||
ProcLayout,
|
||||
BranchInfo, CallType, CrashTag, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc,
|
||||
OptLevel, ProcLayout,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, CapturesNiche, LambdaName, LambdaSet, Layout, LayoutIds, RawFunctionLayout,
|
||||
|
@ -183,24 +183,6 @@ pub struct Env<'a, 'ctx, 'env> {
|
|||
pub exposed_to_host: MutSet<Symbol>,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum PanicTagId {
|
||||
RocPanic = 0,
|
||||
UserPanic = 1,
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<u32> for PanicTagId {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(PanicTagId::RocPanic),
|
||||
1 => Ok(PanicTagId::UserPanic),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||
/// The integer type representing a pointer
|
||||
///
|
||||
|
@ -350,13 +332,10 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
|||
&self,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
message: BasicValueEnum<'ctx>,
|
||||
tag_id: PanicTagId,
|
||||
tag: CrashTag,
|
||||
) {
|
||||
let function = self.module.get_function("roc_panic").unwrap();
|
||||
let tag_id = self
|
||||
.context
|
||||
.i32_type()
|
||||
.const_int(tag_id as u32 as u64, false);
|
||||
let tag_id = self.context.i32_type().const_int(tag as u32 as u64, false);
|
||||
|
||||
let msg = match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes4 => {
|
||||
|
@ -2648,7 +2627,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
}
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
// temporary WASM implementation
|
||||
throw_exception(env, parent, "An expectation failed!");
|
||||
throw_internal_exception(env, parent, "An expectation failed!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2710,7 +2689,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
}
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
// temporary WASM implementation
|
||||
throw_exception(env, parent, "An expectation failed!");
|
||||
throw_internal_exception(env, parent, "An expectation failed!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2730,15 +2709,8 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
RuntimeError(error_msg) => {
|
||||
throw_exception(env, parent, error_msg);
|
||||
|
||||
// unused value (must return a BasicValue)
|
||||
let zero = env.context.i64_type().const_zero();
|
||||
zero.into()
|
||||
}
|
||||
Crash(sym, _) => {
|
||||
throw_user_exception(env, scope, sym);
|
||||
Crash(sym, tag) => {
|
||||
throw_exception(env, scope, sym, *tag);
|
||||
|
||||
// unused value (must return a BasicValue)
|
||||
let zero = env.context.i64_type().const_zero();
|
||||
|
@ -5566,7 +5538,7 @@ fn define_global_str_literal<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn throw_exception<'a, 'ctx, 'env>(
|
||||
pub(crate) fn throw_internal_exception<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
message: &str,
|
||||
|
@ -5575,19 +5547,20 @@ pub(crate) fn throw_exception<'a, 'ctx, 'env>(
|
|||
|
||||
let str = build_string_literal(env, parent, message);
|
||||
|
||||
env.call_panic(env, str, PanicTagId::RocPanic);
|
||||
env.call_panic(env, str, CrashTag::Roc);
|
||||
|
||||
builder.build_unreachable();
|
||||
}
|
||||
|
||||
pub(crate) fn throw_user_exception<'a, 'ctx, 'env>(
|
||||
pub(crate) fn throw_exception<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &mut Scope<'a, 'ctx>,
|
||||
message: &Symbol,
|
||||
tag: CrashTag,
|
||||
) {
|
||||
let msg_val = load_symbol(scope, message);
|
||||
|
||||
env.call_panic(env, msg_val, PanicTagId::UserPanic);
|
||||
env.call_panic(env, msg_val, tag);
|
||||
|
||||
env.builder.build_unreachable();
|
||||
}
|
||||
|
|
|
@ -41,9 +41,9 @@ use crate::llvm::{
|
|||
},
|
||||
};
|
||||
|
||||
use super::convert::zig_with_overflow_roc_dec;
|
||||
use super::{build::throw_internal_exception, convert::zig_with_overflow_roc_dec};
|
||||
use super::{
|
||||
build::{load_symbol, load_symbol_and_layout, throw_exception, Env, Scope},
|
||||
build::{load_symbol, load_symbol_and_layout, Env, Scope},
|
||||
convert::zig_dec_type,
|
||||
};
|
||||
|
||||
|
@ -1557,7 +1557,7 @@ fn throw_on_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
bd.position_at_end(throw_block);
|
||||
|
||||
throw_exception(env, parent, message);
|
||||
throw_internal_exception(env, parent, message);
|
||||
|
||||
bd.position_at_end(then_block);
|
||||
|
||||
|
@ -2003,7 +2003,7 @@ fn int_neg_raise_on_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(then_block);
|
||||
|
||||
throw_exception(
|
||||
throw_internal_exception(
|
||||
env,
|
||||
parent,
|
||||
"integer negation overflowed because its argument is the minimum value",
|
||||
|
@ -2034,7 +2034,7 @@ fn int_abs_raise_on_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(then_block);
|
||||
|
||||
throw_exception(
|
||||
throw_internal_exception(
|
||||
env,
|
||||
parent,
|
||||
"integer absolute overflowed because its argument is the minimum value",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::mem::MaybeUninit;
|
||||
|
||||
use roc_mono::ir::CrashTag;
|
||||
use roc_std::RocStr;
|
||||
|
||||
/// This must have the same size as the repr() of RocCallResult!
|
||||
|
@ -32,13 +33,18 @@ impl<T: Default> Default for RocCallResult<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Sized> From<RocCallResult<T>> for Result<T, (String, u32)> {
|
||||
impl<T: Sized> From<RocCallResult<T>> for Result<T, (String, CrashTag)> {
|
||||
fn from(call_result: RocCallResult<T>) -> Self {
|
||||
match call_result.tag {
|
||||
0 => Ok(unsafe { call_result.value.assume_init() }),
|
||||
n => Err({
|
||||
let msg: &RocStr = unsafe { &*call_result.error_msg };
|
||||
(msg.as_str().to_owned(), (n - 1) as _)
|
||||
let tag = (n - 1) as u32;
|
||||
let tag = tag
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| panic!("received illegal tag: {tag}"));
|
||||
|
||||
(msg.as_str().to_owned(), tag)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ use roc_module::low_level::{LowLevel, LowLevelWrapperType};
|
|||
use roc_module::symbol::{Interns, Symbol};
|
||||
use roc_mono::code_gen_help::{CodeGenHelp, HelperOp, REFCOUNT_MAX};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, CallType, Expr, JoinPointId, ListLiteralElement, Literal, ModifyRc, Param, Proc,
|
||||
ProcLayout, Stmt,
|
||||
BranchInfo, CallType, CrashTag, Expr, JoinPointId, ListLiteralElement, Literal, ModifyRc,
|
||||
Param, Proc, ProcLayout, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
||||
use roc_std::RocDec;
|
||||
|
@ -717,8 +717,7 @@ impl<'a> WasmBackend<'a> {
|
|||
Stmt::Expect { .. } => todo!("expect is not implemented in the wasm backend"),
|
||||
Stmt::ExpectFx { .. } => todo!("expect-fx is not implemented in the wasm backend"),
|
||||
|
||||
Stmt::RuntimeError(msg) => self.stmt_runtime_error(msg),
|
||||
Stmt::Crash(sym, _) => self.stmt_crash(*sym),
|
||||
Stmt::Crash(sym, tag) => self.stmt_crash(*sym, *tag),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1016,11 +1015,10 @@ impl<'a> WasmBackend<'a> {
|
|||
self.code_builder.unreachable_();
|
||||
}
|
||||
|
||||
pub fn stmt_crash(&mut self, msg: Symbol) {
|
||||
let tag_id = 1;
|
||||
pub fn stmt_crash(&mut self, msg: Symbol, tag: CrashTag) {
|
||||
// load the pointer
|
||||
self.storage.load_symbols(&mut self.code_builder, &[msg]);
|
||||
self.code_builder.i32_const(tag_id);
|
||||
self.code_builder.i32_const(tag as _);
|
||||
self.call_host_fn_after_loading_args("roc_panic", 2, false);
|
||||
|
||||
self.code_builder.unreachable_();
|
||||
|
|
|
@ -321,7 +321,7 @@ impl<'a> ParamMap<'a> {
|
|||
}
|
||||
Refcounting(_, _) => unreachable!("these have not been introduced yet"),
|
||||
|
||||
Ret(_) | Jump(_, _) | RuntimeError(_) | Crash(..) => {
|
||||
Ret(_) | Jump(_, _) | Crash(..) => {
|
||||
// these are terminal, do nothing
|
||||
}
|
||||
}
|
||||
|
@ -832,7 +832,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
self.own_var(*msg);
|
||||
}
|
||||
|
||||
Ret(_) | RuntimeError(_) => {
|
||||
Ret(_) => {
|
||||
// these are terminal, do nothing
|
||||
}
|
||||
}
|
||||
|
@ -1006,7 +1006,7 @@ fn call_info_stmt<'a>(arena: &'a Bump, stmt: &Stmt<'a>, info: &mut CallInfo<'a>)
|
|||
|
||||
Refcounting(_, _) => unreachable!("these have not been introduced yet"),
|
||||
|
||||
Ret(_) | Jump(_, _) | RuntimeError(_) | Crash(..) => {
|
||||
Ret(_) | Jump(_, _) | Crash(..) => {
|
||||
// these are terminal, do nothing
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,8 +161,6 @@ pub fn occurring_variables(stmt: &Stmt<'_>) -> (MutSet<Symbol>, MutSet<Symbol>)
|
|||
Crash(sym, _) => {
|
||||
result.insert(*sym);
|
||||
}
|
||||
|
||||
RuntimeError(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1257,7 +1255,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
}
|
||||
}
|
||||
|
||||
RuntimeError(_) | Refcounting(_, _) => (stmt, MutSet::default()),
|
||||
Refcounting(_, _) => (stmt, MutSet::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1432,8 +1430,6 @@ pub fn collect_stmt(
|
|||
vars.insert(*m);
|
||||
vars
|
||||
}
|
||||
|
||||
RuntimeError(_) => vars,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1668,14 +1668,29 @@ pub enum Stmt<'a> {
|
|||
remainder: &'a Stmt<'a>,
|
||||
},
|
||||
Jump(JoinPointId, &'a [Symbol]),
|
||||
RuntimeError(&'a str),
|
||||
Crash(Symbol, CrashTag),
|
||||
}
|
||||
|
||||
/// Source of crash, and its runtime representation to roc_panic.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
pub enum CrashTag {
|
||||
Roc,
|
||||
User,
|
||||
/// The crash is due to Roc, either via a builtin or type error.
|
||||
Roc = 0,
|
||||
/// The crash is user-defined.
|
||||
User = 1,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for CrashTag {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(Self::Roc),
|
||||
1 => Ok(Self::User),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// in the block below, symbol `scrutinee` is assumed be be of shape `tag_id`
|
||||
|
@ -2323,7 +2338,6 @@ impl<'a> Stmt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
RuntimeError(s) => alloc.text(format!("Error {}", s)),
|
||||
Crash(s, _src) => alloc.text(format!("Crash {:?}", s)),
|
||||
|
||||
Join {
|
||||
|
@ -3173,7 +3187,7 @@ fn generate_runtime_error_function<'a>(
|
|||
);
|
||||
});
|
||||
|
||||
let runtime_error = Stmt::RuntimeError(msg.into_bump_str());
|
||||
let runtime_error = runtime_error(env, msg.into_bump_str());
|
||||
|
||||
let (args, ret_layout) = match layout {
|
||||
RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout) => {
|
||||
|
@ -4321,7 +4335,7 @@ pub fn with_hole<'a>(
|
|||
};
|
||||
let sorted_fields = match sorted_fields_result {
|
||||
Ok(fields) => fields,
|
||||
Err(_) => return Stmt::RuntimeError("Can't create record with improper layout"),
|
||||
Err(_) => return runtime_error(env, "Can't create record with improper layout"),
|
||||
};
|
||||
|
||||
let mut field_symbols = Vec::with_capacity_in(fields.len(), env.arena);
|
||||
|
@ -4373,7 +4387,7 @@ pub fn with_hole<'a>(
|
|||
// creating a record from the var will unpack it if it's just a single field.
|
||||
let layout = match layout_cache.from_var(env.arena, record_var, env.subs) {
|
||||
Ok(layout) => layout,
|
||||
Err(_) => return Stmt::RuntimeError("Can't create record with improper layout"),
|
||||
Err(_) => return runtime_error(env, "Can't create record with improper layout"),
|
||||
};
|
||||
|
||||
let field_symbols = field_symbols.into_bump_slice();
|
||||
|
@ -4552,8 +4566,8 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
(Err(_), _) => Stmt::RuntimeError("invalid ret_layout"),
|
||||
(_, Err(_)) => Stmt::RuntimeError("invalid cond_layout"),
|
||||
(Err(_), _) => runtime_error(env, "invalid ret_layout"),
|
||||
(_, Err(_)) => runtime_error(env, "invalid cond_layout"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4719,7 +4733,7 @@ pub fn with_hole<'a>(
|
|||
};
|
||||
let sorted_fields = match sorted_fields_result {
|
||||
Ok(fields) => fields,
|
||||
Err(_) => return Stmt::RuntimeError("Can't access record with improper layout"),
|
||||
Err(_) => return runtime_error(env, "Can't access record with improper layout"),
|
||||
};
|
||||
|
||||
let mut index = None;
|
||||
|
@ -4837,7 +4851,8 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
Err(_error) => Stmt::RuntimeError(
|
||||
Err(_error) => runtime_error(
|
||||
env,
|
||||
"TODO convert anonymous function error to a RuntimeError string",
|
||||
),
|
||||
}
|
||||
|
@ -4893,7 +4908,8 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
Err(_error) => Stmt::RuntimeError(
|
||||
Err(_error) => runtime_error(
|
||||
env,
|
||||
"TODO convert anonymous function error to a RuntimeError string",
|
||||
),
|
||||
}
|
||||
|
@ -4928,7 +4944,7 @@ pub fn with_hole<'a>(
|
|||
|
||||
let sorted_fields = match sorted_fields_result {
|
||||
Ok(fields) => fields,
|
||||
Err(_) => return Stmt::RuntimeError("Can't update record with improper layout"),
|
||||
Err(_) => return runtime_error(env, "Can't update record with improper layout"),
|
||||
};
|
||||
|
||||
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
||||
|
@ -5114,10 +5130,10 @@ pub fn with_hole<'a>(
|
|||
layout_cache,
|
||||
);
|
||||
|
||||
if let Err(runtime_error) = inserted {
|
||||
return Stmt::RuntimeError(
|
||||
env.arena
|
||||
.alloc(format!("RuntimeError: {:?}", runtime_error,)),
|
||||
if let Err(e) = inserted {
|
||||
return runtime_error(
|
||||
env,
|
||||
env.arena.alloc(format!("RuntimeError: {:?}", e,)),
|
||||
);
|
||||
} else {
|
||||
drop(inserted);
|
||||
|
@ -5581,8 +5597,8 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
TypedHole(_) => Stmt::RuntimeError("Hit a blank"),
|
||||
RuntimeError(e) => Stmt::RuntimeError(env.arena.alloc(e.runtime_message())),
|
||||
TypedHole(_) => runtime_error(env, "Hit a blank"),
|
||||
RuntimeError(e) => runtime_error(env, env.arena.alloc(e.runtime_message())),
|
||||
Crash { msg, ret_var: _ } => {
|
||||
let msg_sym = possible_reuse_symbol_or_specialize(
|
||||
env,
|
||||
|
@ -5853,16 +5869,22 @@ fn convert_tag_union<'a>(
|
|||
let variant = match res_variant {
|
||||
Ok(cached) => cached,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"Unresolved type variable for tag {}",
|
||||
tag_name.0.as_str()
|
||||
)))
|
||||
return runtime_error(
|
||||
env,
|
||||
env.arena.alloc(format!(
|
||||
"Unresolved type variable for tag {}",
|
||||
tag_name.0.as_str()
|
||||
)),
|
||||
)
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"Tag {} was part of a type error!",
|
||||
tag_name.0.as_str()
|
||||
)));
|
||||
return runtime_error(
|
||||
env,
|
||||
env.arena.alloc(format!(
|
||||
"Tag {} was part of a type error!",
|
||||
tag_name.0.as_str()
|
||||
)),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5890,7 +5912,7 @@ fn convert_tag_union<'a>(
|
|||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
hole,
|
||||
),
|
||||
None => Stmt::RuntimeError("tag must be in its own type"),
|
||||
None => runtime_error(env, "tag must be in its own type"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5930,7 +5952,7 @@ fn convert_tag_union<'a>(
|
|||
|
||||
if dataful_tag != tag_name {
|
||||
// this tag is not represented, and hence will never be reached, at runtime.
|
||||
Stmt::RuntimeError("voided tag constructor is unreachable")
|
||||
runtime_error(env, "voided tag constructor is unreachable")
|
||||
} else {
|
||||
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
|
||||
|
||||
|
@ -6194,10 +6216,13 @@ fn tag_union_to_function<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
Err(runtime_error) => Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"Could not produce tag function due to a runtime error: {:?}",
|
||||
runtime_error,
|
||||
))),
|
||||
Err(e) => runtime_error(
|
||||
env,
|
||||
env.arena.alloc(format!(
|
||||
"Could not produce tag function due to a runtime error: {:?}",
|
||||
e,
|
||||
)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6747,7 +6772,7 @@ fn from_can_when<'a>(
|
|||
if branches.is_empty() {
|
||||
// A when-expression with no branches is a runtime error.
|
||||
// We can't know what to return!
|
||||
return Stmt::RuntimeError("Hit a 0-branch when expression");
|
||||
return runtime_error(env, "Hit a 0-branch when expression");
|
||||
}
|
||||
let opt_branches = to_opt_branches(env, procs, branches, exhaustive_mark, layout_cache);
|
||||
|
||||
|
@ -7050,8 +7075,6 @@ fn substitute_in_stmt_help<'a>(
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
RuntimeError(_) => None,
|
||||
Crash(msg, tag) => substitute(subs, *msg).map(|new| &*arena.alloc(Crash(new, *tag))),
|
||||
}
|
||||
}
|
||||
|
@ -8435,7 +8458,7 @@ fn evaluate_arguments_then_runtime_error<'a>(
|
|||
let arena = env.arena;
|
||||
|
||||
// eventually we will throw this runtime error
|
||||
let result = Stmt::RuntimeError(env.arena.alloc(msg));
|
||||
let result = runtime_error(env, env.arena.alloc(msg));
|
||||
|
||||
// but, we also still evaluate and specialize the arguments to give better error messages
|
||||
let arg_symbols = Vec::from_iter_in(
|
||||
|
@ -8660,7 +8683,7 @@ fn call_by_name_help<'a>(
|
|||
Err(_) => {
|
||||
// One of this function's arguments code gens to a runtime error,
|
||||
// so attempting to call it will immediately crash.
|
||||
return Stmt::RuntimeError("TODO runtime error for invalid layout");
|
||||
return runtime_error(env, "TODO runtime error for invalid layout");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10159,7 +10182,7 @@ where
|
|||
ToLowLevelCall: Fn(ToLowLevelCallArguments<'a>) -> Call<'a> + Copy,
|
||||
{
|
||||
match lambda_set.call_by_name_options(&layout_cache.interner) {
|
||||
ClosureCallOptions::Void => empty_lambda_set_error(),
|
||||
ClosureCallOptions::Void => empty_lambda_set_error(env),
|
||||
ClosureCallOptions::Union(union_layout) => {
|
||||
let closure_tag_id_symbol = env.unique_symbol();
|
||||
|
||||
|
@ -10338,9 +10361,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn empty_lambda_set_error() -> Stmt<'static> {
|
||||
fn empty_lambda_set_error<'a>(env: &mut Env<'a, '_>) -> Stmt<'a> {
|
||||
let msg = "a Lambda Set is empty. Most likely there is a type error in your program.";
|
||||
Stmt::RuntimeError(msg)
|
||||
runtime_error(env, msg)
|
||||
}
|
||||
|
||||
/// Use the lambda set to figure out how to make a call-by-name
|
||||
|
@ -10358,7 +10381,7 @@ fn match_on_lambda_set<'a>(
|
|||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
match lambda_set.call_by_name_options(&layout_cache.interner) {
|
||||
ClosureCallOptions::Void => empty_lambda_set_error(),
|
||||
ClosureCallOptions::Void => empty_lambda_set_error(env),
|
||||
ClosureCallOptions::Union(union_layout) => {
|
||||
let closure_tag_id_symbol = env.unique_symbol();
|
||||
|
||||
|
@ -10512,7 +10535,7 @@ fn union_lambda_set_to_switch<'a>(
|
|||
// there is really nothing we can do here. We generate a runtime error here which allows
|
||||
// code gen to proceed. We then assume that we hit another (more descriptive) error before
|
||||
// hitting this one
|
||||
return empty_lambda_set_error();
|
||||
return empty_lambda_set_error(env);
|
||||
}
|
||||
|
||||
let join_point_id = JoinPointId(env.unique_symbol());
|
||||
|
|
|
@ -241,7 +241,7 @@ fn function_s<'a, 'i>(
|
|||
}
|
||||
}
|
||||
|
||||
Ret(_) | Jump(_, _) | RuntimeError(_) | Crash(..) => stmt,
|
||||
Ret(_) | Jump(_, _) | Crash(..) => stmt,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,9 +535,7 @@ fn function_d_main<'a, 'i>(
|
|||
|
||||
(arena.alloc(new_join), found)
|
||||
}
|
||||
Ret(_) | Jump(_, _) | RuntimeError(_) | Crash(..) => {
|
||||
(stmt, has_live_var(&env.jp_live_vars, stmt, x))
|
||||
}
|
||||
Ret(_) | Jump(_, _) | Crash(..) => (stmt, has_live_var(&env.jp_live_vars, stmt, x)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -698,7 +696,7 @@ fn function_r<'a, 'i>(env: &mut Env<'a, 'i>, stmt: &'a Stmt<'a>) -> &'a Stmt<'a>
|
|||
arena.alloc(expect)
|
||||
}
|
||||
|
||||
Ret(_) | Jump(_, _) | RuntimeError(_) | Crash(..) => {
|
||||
Ret(_) | Jump(_, _) | Crash(..) => {
|
||||
// terminals
|
||||
stmt
|
||||
}
|
||||
|
@ -764,7 +762,6 @@ fn has_live_var<'a>(jp_live_vars: &JPLiveVarMap, stmt: &'a Stmt<'a>, needle: Sym
|
|||
arguments.iter().any(|s| *s == needle) || jp_live_vars[id].contains(&needle)
|
||||
}
|
||||
Crash(m, _) => *m == needle,
|
||||
RuntimeError(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -299,7 +299,6 @@ fn insert_jumps<'a>(
|
|||
|
||||
Ret(_) => None,
|
||||
Jump(_, _) => None,
|
||||
RuntimeError(_) => None,
|
||||
Crash(..) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use roc_collections::all::MutSet;
|
|||
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
||||
use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult};
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_mono::ir::{CrashTag, OptLevel};
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
|
||||
use roc_utils::zig;
|
||||
|
@ -547,7 +547,7 @@ macro_rules! assert_wasm_evals_to {
|
|||
pub fn try_run_lib_function<T>(
|
||||
main_fn_name: &str,
|
||||
lib: &libloading::Library,
|
||||
) -> Result<T, (String, u32)> {
|
||||
) -> Result<T, (String, CrashTag)> {
|
||||
unsafe {
|
||||
let main: libloading::Symbol<unsafe extern "C" fn(*mut RocCallResult<T>)> = lib
|
||||
.get(main_fn_name.as_bytes())
|
||||
|
@ -568,6 +568,7 @@ macro_rules! assert_llvm_evals_to {
|
|||
use bumpalo::Bump;
|
||||
use inkwell::context::Context;
|
||||
use roc_gen_llvm::llvm::build::LlvmBackendMode;
|
||||
use roc_mono::ir::CrashTag;
|
||||
|
||||
let arena = Bump::new();
|
||||
let context = Context::create();
|
||||
|
@ -598,9 +599,8 @@ macro_rules! assert_llvm_evals_to {
|
|||
std::mem::forget(given);
|
||||
}
|
||||
Err((msg, tag)) => match tag {
|
||||
0 => panic!(r#"Roc failed with message: "{}""#, msg),
|
||||
1 => panic!(r#"User crash with message: "{}""#, msg),
|
||||
_ => panic!(r#"Got an invalid panic tag: "{}""#, tag),
|
||||
CrashTag::Roc => panic!(r#"Roc failed with message: "{}""#, msg),
|
||||
CrashTag::User => panic!(r#"User crash with message: "{}""#, msg),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use core::ffi::c_void;
|
||||
|
||||
use roc_mono::ir::CrashTag;
|
||||
use roc_std::RocStr;
|
||||
|
||||
/// # Safety
|
||||
|
@ -39,14 +40,12 @@ pub unsafe fn roc_dealloc(c_ptr: *mut c_void, _alignment: u32) {
|
|||
/// The Roc application needs this.
|
||||
#[no_mangle]
|
||||
pub unsafe fn roc_panic(msg: &RocStr, tag_id: u32) {
|
||||
use roc_gen_llvm::llvm::build::PanicTagId;
|
||||
|
||||
match PanicTagId::try_from(tag_id) {
|
||||
Ok(PanicTagId::RocPanic) => {
|
||||
match CrashTag::try_from(tag_id) {
|
||||
Ok(CrashTag::Roc) => {
|
||||
eprintln!("Roc hit a panic: {}", msg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(PanicTagId::UserPanic) => {
|
||||
Ok(CrashTag::User) => {
|
||||
eprintln!("User panic: {}", msg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue