diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 5d054ad831..dab48890e3 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -1381,6 +1381,13 @@ pub fn types() -> MutMap { Box::new(bool_type()), ); + // isErr : Result * * -> bool + add_top_level_function_type!( + Symbol::RESULT_IS_ERR, + vec![result_type(flex(TVAR1), flex(TVAR3))], + Box::new(bool_type()), + ); + types } diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index ddabf11685..c718f22b5f 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -193,6 +193,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option RESULT_AFTER => result_after, RESULT_WITH_DEFAULT => result_with_default, RESULT_IS_OK => result_is_ok, + RESULT_IS_ERR => result_is_err, } } @@ -3992,6 +3993,83 @@ fn result_with_default(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } +fn result_is_err(symbol: Symbol, var_store: &mut VarStore) -> Def { + let ret_var = var_store.fresh(); + let result_var = var_store.fresh(); + + let mut branches = vec![]; + + { + // ok branch + let tag_name = TagName::Global("Ok".into()); + + let pattern = Pattern::AppliedTag { + whole_var: result_var, + ext_var: var_store.fresh(), + tag_name, + arguments: vec![(var_store.fresh(), no_region(Pattern::Underscore))], + }; + + let false_expr = Tag { + variant_var: var_store.fresh(), + ext_var: var_store.fresh(), + name: TagName::Global("False".into()), + arguments: vec![], + }; + + let branch = WhenBranch { + patterns: vec![no_region(pattern)], + value: no_region(false_expr), + guard: None, + }; + + branches.push(branch); + } + + { + // err branch + let tag_name = TagName::Global("Err".into()); + + let pattern = Pattern::AppliedTag { + whole_var: result_var, + ext_var: var_store.fresh(), + tag_name, + arguments: vec![(var_store.fresh(), no_region(Pattern::Underscore))], + }; + + let true_expr = Tag { + variant_var: var_store.fresh(), + ext_var: var_store.fresh(), + name: TagName::Global("True".into()), + arguments: vec![], + }; + + let branch = WhenBranch { + patterns: vec![no_region(pattern)], + value: no_region(true_expr), + guard: None, + }; + + branches.push(branch); + } + + let body = When { + cond_var: result_var, + expr_var: ret_var, + region: Region::zero(), + loc_cond: Box::new(no_region(Var(Symbol::ARG_1))), + branches, + }; + + defn( + symbol, + vec![(result_var, Symbol::ARG_1)], + var_store, + body, + ret_var, + ) +} + fn result_is_ok(symbol: Symbol, var_store: &mut VarStore) -> Def { let ret_var = var_store.fresh(); let result_var = var_store.fresh(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 92345fbdf0..2233003ca0 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1079,6 +1079,7 @@ define_builtins! { 3 RESULT_WITH_DEFAULT: "withDefault" 4 RESULT_AFTER: "after" 5 RESULT_IS_OK: "isOk" + 6 RESULT_IS_ERR: "isErr" } 6 DICT: "Dict" => { 0 DICT_DICT: "Dict" imported // the Dict.Dict type alias diff --git a/compiler/test_gen/src/gen_result.rs b/compiler/test_gen/src/gen_result.rs index bfb0634326..4b86af9e83 100644 --- a/compiler/test_gen/src/gen_result.rs +++ b/compiler/test_gen/src/gen_result.rs @@ -189,3 +189,33 @@ fn is_ok() { bool ); } + +#[test] +#[cfg(any(feature = "gen-llvm"))] +fn is_err() { + assert_evals_to!( + indoc!( + r#" + result : Result I64 {} + result = Ok 2 + + Result.isErr result + "# + ), + false, + bool + ); + + assert_evals_to!( + indoc!( + r#" + result : Result I64 {} + result = Err {} + + Result.isErr result + "# + ), + true, + bool + ); +}