mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
Constrain + solve crash
This commit is contained in:
parent
9dc489c2b0
commit
e2b30e5301
13 changed files with 194 additions and 60 deletions
|
@ -376,7 +376,10 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
||||||
*called_via,
|
*called_via,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Crash => Crash,
|
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 {
|
RunLowLevel { op, args, ret_var } => RunLowLevel {
|
||||||
op: *op,
|
op: *op,
|
||||||
args: args
|
args: args
|
||||||
|
|
|
@ -167,7 +167,10 @@ pub enum Expr {
|
||||||
EmptyRecord,
|
EmptyRecord,
|
||||||
|
|
||||||
/// The "crash" keyword
|
/// The "crash" keyword
|
||||||
Crash,
|
Crash {
|
||||||
|
msg: Box<Loc<Expr>>,
|
||||||
|
ret_var: Variable,
|
||||||
|
},
|
||||||
|
|
||||||
/// Look up exactly one field on a record, e.g. (expr).foo.
|
/// Look up exactly one field on a record, e.g. (expr).foo.
|
||||||
Access {
|
Access {
|
||||||
|
@ -312,7 +315,7 @@ impl Expr {
|
||||||
}
|
}
|
||||||
Self::Expect { .. } => Category::Expect,
|
Self::Expect { .. } => Category::Expect,
|
||||||
Self::ExpectFx { .. } => Category::Expect,
|
Self::ExpectFx { .. } => Category::Expect,
|
||||||
Self::Crash => Category::Crash,
|
Self::Crash { .. } => Category::Crash,
|
||||||
|
|
||||||
Self::Dbg { .. } => Category::Expect,
|
Self::Dbg { .. } => Category::Expect,
|
||||||
|
|
||||||
|
@ -788,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 {
|
} else {
|
||||||
// Canonicalize the function expression and its arguments
|
// Canonicalize the function expression and its arguments
|
||||||
let (fn_expr, fn_expr_output) =
|
let (fn_expr, fn_expr_output) =
|
||||||
|
@ -878,7 +922,22 @@ pub fn canonicalize_expr<'a>(
|
||||||
|
|
||||||
(RuntimeError(problem), Output::default())
|
(RuntimeError(problem), Output::default())
|
||||||
}
|
}
|
||||||
ast::Expr::Crash => (Crash, 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) => {
|
ast::Expr::Defs(loc_defs, loc_ret) => {
|
||||||
// The body expression gets a new scope for canonicalization,
|
// The body expression gets a new scope for canonicalization,
|
||||||
scope.inner_scope(|inner_scope| {
|
scope.inner_scope(|inner_scope| {
|
||||||
|
@ -1726,7 +1785,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
||||||
| other @ TypedHole { .. }
|
| other @ TypedHole { .. }
|
||||||
| other @ ForeignCall { .. }
|
| other @ ForeignCall { .. }
|
||||||
| other @ OpaqueWrapFunction(_)
|
| other @ OpaqueWrapFunction(_)
|
||||||
| other @ Crash => other,
|
| other @ Crash { .. } => other,
|
||||||
|
|
||||||
List {
|
List {
|
||||||
elem_var,
|
elem_var,
|
||||||
|
@ -2834,8 +2893,7 @@ fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
||||||
| Expr::EmptyRecord
|
| Expr::EmptyRecord
|
||||||
| Expr::TypedHole(_)
|
| Expr::TypedHole(_)
|
||||||
| Expr::RuntimeError(_)
|
| Expr::RuntimeError(_)
|
||||||
| Expr::OpaqueWrapFunction(_)
|
| Expr::OpaqueWrapFunction(_) => {}
|
||||||
| Expr::Crash => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
Closure(ClosureData {
|
||||||
captured_symbols,
|
captured_symbols,
|
||||||
name,
|
name,
|
||||||
|
@ -1056,8 +1064,7 @@ fn fix_values_captured_in_closure_expr(
|
||||||
| TypedHole { .. }
|
| TypedHole { .. }
|
||||||
| RuntimeError(_)
|
| RuntimeError(_)
|
||||||
| ZeroArgumentTag { .. }
|
| ZeroArgumentTag { .. }
|
||||||
| Accessor { .. }
|
| Accessor { .. } => {}
|
||||||
| Crash => {}
|
|
||||||
|
|
||||||
List { loc_elems, .. } => {
|
List { loc_elems, .. } => {
|
||||||
for elem in loc_elems.iter_mut() {
|
for elem in loc_elems.iter_mut() {
|
||||||
|
|
|
@ -185,7 +185,6 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr, var: Variable) {
|
||||||
}
|
}
|
||||||
Expr::Var(..) => { /* terminal */ }
|
Expr::Var(..) => { /* terminal */ }
|
||||||
Expr::AbilityMember(..) => { /* terminal */ }
|
Expr::AbilityMember(..) => { /* terminal */ }
|
||||||
Expr::Crash => { /* terminal */ }
|
|
||||||
Expr::If {
|
Expr::If {
|
||||||
cond_var,
|
cond_var,
|
||||||
branches,
|
branches,
|
||||||
|
@ -204,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;
|
let (fn_var, loc_fn, _closure_var, _ret_var) = &**f;
|
||||||
walk_call(visitor, *fn_var, loc_fn, args);
|
walk_call(visitor, *fn_var, loc_fn, args);
|
||||||
}
|
}
|
||||||
|
Expr::Crash { msg, .. } => {
|
||||||
|
visitor.visit_expr(&msg.value, msg.region, Variable::STR);
|
||||||
|
}
|
||||||
Expr::RunLowLevel {
|
Expr::RunLowLevel {
|
||||||
op: _,
|
op: _,
|
||||||
args,
|
args,
|
||||||
|
|
|
@ -482,11 +482,17 @@ pub fn constrain_expr(
|
||||||
let and_constraint = constraints.and_constraint(and_cons);
|
let and_constraint = constraints.and_constraint(and_cons);
|
||||||
constraints.exists(vars, and_constraint)
|
constraints.exists(vars, and_constraint)
|
||||||
}
|
}
|
||||||
Expr::Crash => {
|
Expr::Crash { msg, ret_var } => {
|
||||||
let crash_type_index = constraints.push_type(Type::Crash);
|
let expected_msg = Expected::ForReason(Reason::CrashArg, str_type(), msg.region);
|
||||||
let expected_index = constraints.push_expected_type(expected);
|
let expected_ret = constraints.push_expected_type(expected);
|
||||||
|
|
||||||
constraints.equal_types(crash_type_index, expected_index, Category::Crash, region)
|
let msg_is_str = constrain_expr(constraints, env, msg.region, &msg.value, expected_msg);
|
||||||
|
let magic =
|
||||||
|
constraints.equal_types_var(*ret_var, expected_ret, Category::Crash, region);
|
||||||
|
|
||||||
|
let and = constraints.and_constraint([msg_is_str, magic]);
|
||||||
|
|
||||||
|
constraints.exists([*ret_var], and)
|
||||||
}
|
}
|
||||||
Var(symbol, variable) => {
|
Var(symbol, variable) => {
|
||||||
// Save the expectation in the variable, then lookup the symbol's type in the environment
|
// Save the expectation in the variable, then lookup the symbol's type in the environment
|
||||||
|
|
|
@ -5562,7 +5562,7 @@ pub fn with_hole<'a>(
|
||||||
}
|
}
|
||||||
TypedHole(_) => Stmt::RuntimeError("Hit a blank"),
|
TypedHole(_) => Stmt::RuntimeError("Hit a blank"),
|
||||||
RuntimeError(e) => Stmt::RuntimeError(env.arena.alloc(e.runtime_message())),
|
RuntimeError(e) => Stmt::RuntimeError(env.arena.alloc(e.runtime_message())),
|
||||||
Crash => todo!(),
|
Crash { .. } => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,12 @@ pub enum Problem {
|
||||||
type_got: u8,
|
type_got: u8,
|
||||||
alias_kind: AliasKind,
|
alias_kind: AliasKind,
|
||||||
},
|
},
|
||||||
|
UnappliedCrash {
|
||||||
|
region: Region,
|
||||||
|
},
|
||||||
|
OverAppliedCrash {
|
||||||
|
region: Region,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Problem {
|
impl Problem {
|
||||||
|
@ -325,7 +331,9 @@ impl Problem {
|
||||||
}
|
}
|
||||||
| Problem::MultipleListRestPattern { region }
|
| Problem::MultipleListRestPattern { region }
|
||||||
| Problem::BadTypeArguments { region, .. }
|
| Problem::BadTypeArguments { region, .. }
|
||||||
| Problem::UnnecessaryOutputWildcard { region } => Some(*region),
|
| Problem::UnnecessaryOutputWildcard { region }
|
||||||
|
| Problem::OverAppliedCrash { region }
|
||||||
|
| Problem::UnappliedCrash { region } => Some(*region),
|
||||||
Problem::RuntimeError(RuntimeError::CircularDef(cycle_entries))
|
Problem::RuntimeError(RuntimeError::CircularDef(cycle_entries))
|
||||||
| Problem::BadRecursion(cycle_entries) => {
|
| Problem::BadRecursion(cycle_entries) => {
|
||||||
cycle_entries.first().map(|entry| entry.expr_region)
|
cycle_entries.first().map(|entry| entry.expr_region)
|
||||||
|
|
|
@ -2961,27 +2961,6 @@ fn type_to_variable<'a>(
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
register_with_known_var(subs, destination, rank, pools, content)
|
||||||
}
|
}
|
||||||
Crash => {
|
|
||||||
let magic_return = subs.fresh(Descriptor {
|
|
||||||
content: Content::FlexVar(None),
|
|
||||||
rank,
|
|
||||||
mark: Mark::NONE,
|
|
||||||
copy: OptVariable::NONE,
|
|
||||||
});
|
|
||||||
let magic_lambda_set = subs.fresh(Descriptor {
|
|
||||||
content: Content::FlexVar(None),
|
|
||||||
rank,
|
|
||||||
mark: Mark::NONE,
|
|
||||||
copy: OptVariable::NONE,
|
|
||||||
});
|
|
||||||
let magic_crash = Content::Structure(FlatType::Func(
|
|
||||||
Subs::STR_SLICE,
|
|
||||||
magic_lambda_set,
|
|
||||||
magic_return,
|
|
||||||
));
|
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, magic_crash)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
||||||
)
|
)
|
||||||
.group()
|
.group()
|
||||||
),
|
),
|
||||||
Crash => f.text("crash"),
|
Crash { .. } => todo!(),
|
||||||
ZeroArgumentTag { .. } => todo!(),
|
ZeroArgumentTag { .. } => todo!(),
|
||||||
OpaqueRef { .. } => todo!(),
|
OpaqueRef { .. } => todo!(),
|
||||||
Dbg { .. } => todo!(),
|
Dbg { .. } => todo!(),
|
||||||
|
|
|
@ -994,7 +994,6 @@ impl Types {
|
||||||
self.set_type_tag(index, TypeTag::RangedNumber(*range), Slice::default())
|
self.set_type_tag(index, TypeTag::RangedNumber(*range), Slice::default())
|
||||||
}
|
}
|
||||||
Type::Error => self.set_type_tag(index, TypeTag::Error, Slice::default()),
|
Type::Error => self.set_type_tag(index, TypeTag::Error, Slice::default()),
|
||||||
Type::Crash => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1669,7 +1668,6 @@ pub enum Type {
|
||||||
Apply(Symbol, Vec<Loc<Type>>, Region),
|
Apply(Symbol, Vec<Loc<Type>>, Region),
|
||||||
Variable(Variable),
|
Variable(Variable),
|
||||||
RangedNumber(NumericRange),
|
RangedNumber(NumericRange),
|
||||||
Crash, // Str -> a
|
|
||||||
/// A type error, which will code gen to a runtime error
|
/// A type error, which will code gen to a runtime error
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
@ -1712,7 +1710,6 @@ impl Clone for Type {
|
||||||
match self {
|
match self {
|
||||||
Self::EmptyRec => Self::EmptyRec,
|
Self::EmptyRec => Self::EmptyRec,
|
||||||
Self::EmptyTagUnion => Self::EmptyTagUnion,
|
Self::EmptyTagUnion => Self::EmptyTagUnion,
|
||||||
Self::Crash => Self::Crash,
|
|
||||||
Self::Function(arg0, arg1, arg2) => {
|
Self::Function(arg0, arg1, arg2) => {
|
||||||
Self::Function(arg0.clone(), arg1.clone(), arg2.clone())
|
Self::Function(arg0.clone(), arg1.clone(), arg2.clone())
|
||||||
}
|
}
|
||||||
|
@ -2081,7 +2078,6 @@ impl fmt::Debug for Type {
|
||||||
Type::RangedNumber(range_vars) => {
|
Type::RangedNumber(range_vars) => {
|
||||||
write!(f, "Ranged({:?})", range_vars)
|
write!(f, "Ranged({:?})", range_vars)
|
||||||
}
|
}
|
||||||
Type::Crash => write!(f, "Crash"),
|
|
||||||
Type::UnspecializedLambdaSet { unspecialized } => {
|
Type::UnspecializedLambdaSet { unspecialized } => {
|
||||||
write!(f, "{:?}", unspecialized)
|
write!(f, "{:?}", unspecialized)
|
||||||
}
|
}
|
||||||
|
@ -2245,7 +2241,7 @@ impl Type {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmptyRec | EmptyTagUnion | Crash | Error => {}
|
EmptyRec | EmptyTagUnion | Error => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2375,7 +2371,7 @@ impl Type {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmptyRec | EmptyTagUnion | Crash | Error => {}
|
EmptyRec | EmptyTagUnion | Error => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2478,7 +2474,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
RangedNumber(_) => Ok(()),
|
RangedNumber(_) => Ok(()),
|
||||||
UnspecializedLambdaSet { .. } => Ok(()),
|
UnspecializedLambdaSet { .. } => Ok(()),
|
||||||
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) | Crash => Ok(()),
|
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2540,7 +2536,7 @@ impl Type {
|
||||||
UnspecializedLambdaSet {
|
UnspecializedLambdaSet {
|
||||||
unspecialized: Uls(_, sym, _),
|
unspecialized: Uls(_, sym, _),
|
||||||
} => *sym == rep_symbol,
|
} => *sym == rep_symbol,
|
||||||
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) | Crash => false,
|
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2596,7 +2592,7 @@ impl Type {
|
||||||
.iter()
|
.iter()
|
||||||
.any(|arg| arg.value.contains_variable(rep_variable)),
|
.any(|arg| arg.value.contains_variable(rep_variable)),
|
||||||
RangedNumber(_) => false,
|
RangedNumber(_) => false,
|
||||||
EmptyRec | EmptyTagUnion | Error | Crash => false,
|
EmptyRec | EmptyTagUnion | Error => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2970,7 +2966,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
RangedNumber(_) => {}
|
RangedNumber(_) => {}
|
||||||
UnspecializedLambdaSet { .. } => {}
|
UnspecializedLambdaSet { .. } => {}
|
||||||
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) | Crash => {}
|
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3106,7 +3102,7 @@ fn symbols_help(initial: &Type) -> Vec<Symbol> {
|
||||||
} => {
|
} => {
|
||||||
// ignore the member symbol because unspecialized lambda sets are internal-only
|
// ignore the member symbol because unspecialized lambda sets are internal-only
|
||||||
}
|
}
|
||||||
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) | Crash => {}
|
EmptyRec | EmptyTagUnion | ClosureTag { .. } | Error | Variable(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3222,7 +3218,7 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
|
||||||
}
|
}
|
||||||
variables_help(actual, accum);
|
variables_help(actual, accum);
|
||||||
}
|
}
|
||||||
RangedNumber(_) | Crash => {}
|
RangedNumber(_) => {}
|
||||||
Apply(_, args, _) => {
|
Apply(_, args, _) => {
|
||||||
for x in args {
|
for x in args {
|
||||||
variables_help(&x.value, accum);
|
variables_help(&x.value, accum);
|
||||||
|
@ -3250,7 +3246,7 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
|
||||||
match tipe {
|
match tipe {
|
||||||
EmptyRec | EmptyTagUnion | Error | Crash => (),
|
EmptyRec | EmptyTagUnion | Error => (),
|
||||||
|
|
||||||
Variable(v) => {
|
Variable(v) => {
|
||||||
accum.type_variables.insert(*v);
|
accum.type_variables.insert(*v);
|
||||||
|
@ -3490,6 +3486,7 @@ pub enum Reason {
|
||||||
member_name: Symbol,
|
member_name: Symbol,
|
||||||
def_region: Region,
|
def_region: Region,
|
||||||
},
|
},
|
||||||
|
CrashArg,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
|
@ -4377,7 +4374,6 @@ fn instantiate_lambda_sets_as_unspecialized(
|
||||||
match typ {
|
match typ {
|
||||||
Type::EmptyRec => {}
|
Type::EmptyRec => {}
|
||||||
Type::EmptyTagUnion => {}
|
Type::EmptyTagUnion => {}
|
||||||
Type::Crash => {}
|
|
||||||
Type::Function(args, lambda_set, ret) => {
|
Type::Function(args, lambda_set, ret) => {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
matches!(**lambda_set, Type::Variable(..)),
|
matches!(**lambda_set, Type::Variable(..)),
|
||||||
|
|
|
@ -1086,7 +1086,36 @@ pub fn can_problem<'b>(
|
||||||
} else {
|
} else {
|
||||||
"TOO FEW TYPE ARGUMENTS".to_string()
|
"TOO FEW TYPE ARGUMENTS".to_string()
|
||||||
};
|
};
|
||||||
|
severity = Severity::RuntimeError;
|
||||||
|
}
|
||||||
|
Problem::UnappliedCrash { region } => {
|
||||||
|
doc = alloc.stack([
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow("This "), alloc.keyword("crash"), alloc.reflow(" doesn't have a message given to it:")
|
||||||
|
]),
|
||||||
|
alloc.region(lines.convert_region(region)),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.keyword("crash"), alloc.reflow(" must be passed a message to crash with at the exact place it's used. "),
|
||||||
|
alloc.keyword("crash"), alloc.reflow(" can't be used as a value that's passed around, like functions can be - it must be applied immediately!"),
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
title = "UNAPPLIED CRASH".to_string();
|
||||||
|
severity = Severity::RuntimeError;
|
||||||
|
}
|
||||||
|
Problem::OverAppliedCrash { region } => {
|
||||||
|
doc = alloc.stack([
|
||||||
|
alloc.concat([
|
||||||
|
alloc.reflow("This "),
|
||||||
|
alloc.keyword("crash"),
|
||||||
|
alloc.reflow(" has too many values given to it:"),
|
||||||
|
]),
|
||||||
|
alloc.region(lines.convert_region(region)),
|
||||||
|
alloc.concat([
|
||||||
|
alloc.keyword("crash"),
|
||||||
|
alloc.reflow(" must be given exacly one message to crash with."),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
title = "OVERAPPLIED CRASH".to_string();
|
||||||
severity = Severity::RuntimeError;
|
severity = Severity::RuntimeError;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1375,6 +1375,42 @@ fn to_expr_report<'b>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reason::CrashArg => {
|
||||||
|
let this_is = alloc.reflow("The value is");
|
||||||
|
|
||||||
|
let wanted = alloc.concat([
|
||||||
|
alloc.reflow("But I can only "),
|
||||||
|
alloc.keyword("crash"),
|
||||||
|
alloc.reflow(" with messages of type"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let details = None;
|
||||||
|
|
||||||
|
let lines = [
|
||||||
|
alloc
|
||||||
|
.reflow("This value passed to ")
|
||||||
|
.append(alloc.keyword("crash"))
|
||||||
|
.append(alloc.reflow(" is not a string:")),
|
||||||
|
alloc.region(lines.convert_region(region)),
|
||||||
|
type_comparison(
|
||||||
|
alloc,
|
||||||
|
found,
|
||||||
|
expected_type,
|
||||||
|
ExpectationContext::WhenCondition,
|
||||||
|
add_category(alloc, this_is, &category),
|
||||||
|
wanted,
|
||||||
|
details,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
title: "TYPE MISMATCH".to_string(),
|
||||||
|
doc: alloc.stack(lines),
|
||||||
|
severity: Severity::RuntimeError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reason::LowLevelOpArg { op, arg_index } => {
|
Reason::LowLevelOpArg { op, arg_index } => {
|
||||||
panic!(
|
panic!(
|
||||||
"Compiler bug: argument #{} to low-level operation {:?} was the wrong type!",
|
"Compiler bug: argument #{} to low-level operation {:?} was the wrong type!",
|
||||||
|
|
|
@ -12431,16 +12431,16 @@ All branches in an `if` must have the same type!
|
||||||
@r###"
|
@r###"
|
||||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
This 1st argument to this function has an unexpected type:
|
This value passed to `crash` is not a string:
|
||||||
|
|
||||||
4│ crash {}
|
4│ crash {}
|
||||||
^^
|
^^
|
||||||
|
|
||||||
The argument is a record of type:
|
The value is a record of type:
|
||||||
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
But this function needs its 1st argument to be:
|
But I can only `crash` with messages of type
|
||||||
|
|
||||||
Str
|
Str
|
||||||
"###
|
"###
|
||||||
|
@ -12454,6 +12454,16 @@ All branches in an `if` must have the same type!
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r###"
|
@r###"
|
||||||
|
── UNAPPLIED CRASH ─────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
This `crash` doesn't have a message given to it:
|
||||||
|
|
||||||
|
4│ crash
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
`crash` must be passed a message to crash with at the exact place it's
|
||||||
|
used. `crash` can't be used as a value that's passed around, like
|
||||||
|
functions can be - it must be applied immediately!
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -12465,14 +12475,14 @@ All branches in an `if` must have the same type!
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
@r###"
|
@r###"
|
||||||
── TOO MANY ARGS ───────────────────────────────────────── /code/proj/Main.roc ─
|
── OVERAPPLIED CRASH ───────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
This function expects 1 argument, but it got 2 instead:
|
This `crash` has too many values given to it:
|
||||||
|
|
||||||
4│ crash "" ""
|
4│ crash "" ""
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
Are there any missing commas? Or missing parentheses?
|
`crash` must be given exacly one message to crash with.
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue