mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
commit
58fad36f9d
62 changed files with 1247 additions and 455 deletions
|
@ -376,6 +376,10 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
*called_via,
|
||||
)
|
||||
}
|
||||
Crash { msg, ret_var } => Crash {
|
||||
msg: Box::new(msg.map(|m| go_help!(m))),
|
||||
ret_var: sub!(*ret_var),
|
||||
},
|
||||
RunLowLevel { op, args, ret_var } => RunLowLevel {
|
||||
op: *op,
|
||||
args: args
|
||||
|
|
|
@ -166,6 +166,12 @@ pub enum Expr {
|
|||
/// Empty record constant
|
||||
EmptyRecord,
|
||||
|
||||
/// The "crash" keyword
|
||||
Crash {
|
||||
msg: Box<Loc<Expr>>,
|
||||
ret_var: Variable,
|
||||
},
|
||||
|
||||
/// Look up exactly one field on a record, e.g. (expr).foo.
|
||||
Access {
|
||||
record_var: Variable,
|
||||
|
@ -309,6 +315,7 @@ impl Expr {
|
|||
}
|
||||
Self::Expect { .. } => Category::Expect,
|
||||
Self::ExpectFx { .. } => Category::Expect,
|
||||
Self::Crash { .. } => Category::Crash,
|
||||
|
||||
Self::Dbg { .. } => Category::Expect,
|
||||
|
||||
|
@ -784,6 +791,47 @@ pub fn canonicalize_expr<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if let ast::Expr::Crash = loc_fn.value {
|
||||
// We treat crash specially, since crashing must be applied with one argument.
|
||||
|
||||
debug_assert!(!args.is_empty());
|
||||
|
||||
let mut args = Vec::new();
|
||||
let mut output = Output::default();
|
||||
|
||||
for loc_arg in loc_args.iter() {
|
||||
let (arg_expr, arg_out) =
|
||||
canonicalize_expr(env, var_store, scope, loc_arg.region, &loc_arg.value);
|
||||
|
||||
args.push(arg_expr);
|
||||
output.references.union_mut(&arg_out.references);
|
||||
}
|
||||
|
||||
let crash = if args.len() > 1 {
|
||||
let args_region = Region::span_across(
|
||||
&loc_args.first().unwrap().region,
|
||||
&loc_args.last().unwrap().region,
|
||||
);
|
||||
env.problem(Problem::OverAppliedCrash {
|
||||
region: args_region,
|
||||
});
|
||||
// Still crash, just with our own message, and drop the references.
|
||||
Crash {
|
||||
msg: Box::new(Loc::at(
|
||||
region,
|
||||
Expr::Str(String::from("hit a crash!").into_boxed_str()),
|
||||
)),
|
||||
ret_var: var_store.fresh(),
|
||||
}
|
||||
} else {
|
||||
let msg = args.pop().unwrap();
|
||||
Crash {
|
||||
msg: Box::new(msg),
|
||||
ret_var: var_store.fresh(),
|
||||
}
|
||||
};
|
||||
|
||||
(crash, output)
|
||||
} else {
|
||||
// Canonicalize the function expression and its arguments
|
||||
let (fn_expr, fn_expr_output) =
|
||||
|
@ -874,6 +922,22 @@ pub fn canonicalize_expr<'a>(
|
|||
|
||||
(RuntimeError(problem), Output::default())
|
||||
}
|
||||
ast::Expr::Crash => {
|
||||
// Naked crashes aren't allowed; we'll admit this with our own message, but yield an
|
||||
// error.
|
||||
env.problem(Problem::UnappliedCrash { region });
|
||||
|
||||
(
|
||||
Crash {
|
||||
msg: Box::new(Loc::at(
|
||||
region,
|
||||
Expr::Str(String::from("hit a crash!").into_boxed_str()),
|
||||
)),
|
||||
ret_var: var_store.fresh(),
|
||||
},
|
||||
Output::default(),
|
||||
)
|
||||
}
|
||||
ast::Expr::Defs(loc_defs, loc_ret) => {
|
||||
// The body expression gets a new scope for canonicalization,
|
||||
scope.inner_scope(|inner_scope| {
|
||||
|
@ -1728,7 +1792,8 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
| other @ RunLowLevel { .. }
|
||||
| other @ TypedHole { .. }
|
||||
| other @ ForeignCall { .. }
|
||||
| other @ OpaqueWrapFunction(_) => other,
|
||||
| other @ OpaqueWrapFunction(_)
|
||||
| other @ Crash { .. } => other,
|
||||
|
||||
List {
|
||||
elem_var,
|
||||
|
@ -2826,6 +2891,7 @@ fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
|||
// Intentionally ignore the lookups in the nested `expect` condition itself,
|
||||
// because they couldn't possibly influence the outcome of this `expect`!
|
||||
}
|
||||
Expr::Crash { msg, .. } => stack.push(&msg.value),
|
||||
Expr::Num(_, _, _, _)
|
||||
| Expr::Float(_, _, _, _, _)
|
||||
| Expr::Int(_, _, _, _, _)
|
||||
|
|
|
@ -981,6 +981,14 @@ fn fix_values_captured_in_closure_expr(
|
|||
);
|
||||
}
|
||||
|
||||
Crash { msg, ret_var: _ } => {
|
||||
fix_values_captured_in_closure_expr(
|
||||
&mut msg.value,
|
||||
no_capture_symbols,
|
||||
closure_captures,
|
||||
);
|
||||
}
|
||||
|
||||
Closure(ClosureData {
|
||||
captured_symbols,
|
||||
name,
|
||||
|
|
|
@ -138,7 +138,8 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Loc<Expr<'a>>) -> &'a Loc
|
|||
| MalformedClosure
|
||||
| PrecedenceConflict { .. }
|
||||
| Tag(_)
|
||||
| OpaqueRef(_) => loc_expr,
|
||||
| OpaqueRef(_)
|
||||
| Crash => loc_expr,
|
||||
|
||||
TupleAccess(_sub_expr, _paths) => todo!("Handle TupleAccess"),
|
||||
RecordAccess(sub_expr, paths) => {
|
||||
|
|
|
@ -203,6 +203,9 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr, var: Variable) {
|
|||
let (fn_var, loc_fn, _closure_var, _ret_var) = &**f;
|
||||
walk_call(visitor, *fn_var, loc_fn, args);
|
||||
}
|
||||
Expr::Crash { msg, .. } => {
|
||||
visitor.visit_expr(&msg.value, msg.region, Variable::STR);
|
||||
}
|
||||
Expr::RunLowLevel {
|
||||
op: _,
|
||||
args,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue