mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Issue 7089: ?? operator
This commit is contained in:
parent
57cab7f69a
commit
c70ceb4f98
7 changed files with 367 additions and 16 deletions
|
@ -0,0 +1,180 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-85,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 1 },
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-69 Apply(
|
||||
@11-69 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@11-69 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-69,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
AnnotatedBody {
|
||||
ann_pattern: @11-69 Identifier {
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
ann_type: @11-69 Apply(
|
||||
"",
|
||||
"Task",
|
||||
[
|
||||
@11-69 Record {
|
||||
fields: [],
|
||||
ext: None,
|
||||
},
|
||||
@11-69 Inferred,
|
||||
],
|
||||
),
|
||||
lines_between: [],
|
||||
body_pattern: @11-69 Identifier {
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
body_expr: @11-69 Apply(
|
||||
@11-69 Var {
|
||||
module_name: "",
|
||||
ident: "line",
|
||||
},
|
||||
[
|
||||
@11-56 Apply(
|
||||
@47-56 Var {
|
||||
module_name: "Num",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@11-39 Apply(
|
||||
@24-39 When(
|
||||
@24-32 Var {
|
||||
module_name: "Str",
|
||||
ident: "toU8",
|
||||
},
|
||||
[
|
||||
WhenBranch {
|
||||
patterns: [
|
||||
@24-32 Apply(
|
||||
@24-32 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@24-32 Identifier {
|
||||
ident: "success_BRANCH1_24_32",
|
||||
},
|
||||
],
|
||||
),
|
||||
],
|
||||
value: @24-32 Var {
|
||||
module_name: "",
|
||||
ident: "success_BRANCH1_24_32",
|
||||
},
|
||||
guard: None,
|
||||
},
|
||||
WhenBranch {
|
||||
patterns: [
|
||||
@36-39 Apply(
|
||||
@24-32 Tag(
|
||||
"Err",
|
||||
),
|
||||
[
|
||||
@36-39 Underscore(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
value: @36-39 Num(
|
||||
"255",
|
||||
),
|
||||
guard: None,
|
||||
},
|
||||
],
|
||||
),
|
||||
[
|
||||
@11-16 Str(
|
||||
PlainLine(
|
||||
"123",
|
||||
),
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Pizza,
|
||||
),
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Pizza,
|
||||
),
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Pizza,
|
||||
),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
@11-69 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
),
|
||||
@11-69 Closure(
|
||||
[
|
||||
@11-69 Underscore(
|
||||
"#!stmt",
|
||||
),
|
||||
],
|
||||
@75-85 Apply(
|
||||
@75-82 Var {
|
||||
module_name: "Task",
|
||||
ident: "ok",
|
||||
},
|
||||
[
|
||||
@83-85 Record(
|
||||
[],
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
BangSuffix,
|
||||
),
|
||||
),
|
||||
],
|
||||
}
|
|
@ -22,7 +22,7 @@ mod test_can {
|
|||
use roc_problem::can::{CycleEntry, FloatErrorKind, IntErrorKind, Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
use roc_types::subs::Variable;
|
||||
use std::{f64, i64};
|
||||
use std::{assert_eq, f64, i64};
|
||||
|
||||
fn assert_can_runtime_error(input: &str, expected: RuntimeError) {
|
||||
let arena = Bump::new();
|
||||
|
@ -971,6 +971,47 @@ mod test_can {
|
|||
assert_str_value(&cond_args[0].1.value, "123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_desugar_double_question_suffix() {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
Str.toU64 "123" ?? Num.maxU64
|
||||
"#
|
||||
);
|
||||
let arena = Bump::new();
|
||||
let out = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(out.problems, Vec::new());
|
||||
|
||||
// Assert that we desugar to:
|
||||
//
|
||||
// when Str.toU64 "123"
|
||||
// Ok success_BRANCH1_0_9 -> success_BRANCH1_0_9
|
||||
// Err _ -> Num.maxU64
|
||||
|
||||
let (cond_expr, branches) = assert_when(&out.loc_expr.value);
|
||||
let cond_args = assert_func_call(cond_expr, "toU64", CalledVia::Space, &out.interns);
|
||||
|
||||
assert_eq!(cond_args.len(), 1);
|
||||
assert_str_value(&cond_args[0].1.value, "123");
|
||||
assert_eq!(branches.len(), 2);
|
||||
assert_eq!(branches[0].patterns.len(), 1);
|
||||
assert_eq!(branches[1].patterns.len(), 1);
|
||||
assert_pattern_tag_apply_with_ident(
|
||||
&branches[0].patterns[0].pattern.value,
|
||||
"Ok",
|
||||
"success_BRANCH1_0_15",
|
||||
&out.interns,
|
||||
);
|
||||
assert_var_usage(
|
||||
&branches[0].value.value,
|
||||
"success_BRANCH1_0_15",
|
||||
&out.interns,
|
||||
);
|
||||
assert_pattern_tag_apply_with_underscore(&branches[1].patterns[0].pattern.value, "Err");
|
||||
assert_var_usage(&branches[1].value.value, "maxU64", &out.interns);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_desugar_works_elsewhere() {
|
||||
let src = indoc!(
|
||||
|
@ -1090,6 +1131,51 @@ mod test_can {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_pattern_tag_apply_with_ident(
|
||||
pattern: &Pattern,
|
||||
name: &str,
|
||||
ident: &str,
|
||||
interns: &roc_module::symbol::Interns,
|
||||
) {
|
||||
match pattern {
|
||||
Pattern::AppliedTag {
|
||||
tag_name,
|
||||
arguments,
|
||||
..
|
||||
} if arguments.len() == 1 => {
|
||||
assert_eq!(tag_name.as_ident_str().as_str(), name);
|
||||
match arguments[0].1.value {
|
||||
Pattern::Identifier(sym) => assert_eq!(sym.as_str(interns), ident),
|
||||
_ => panic!(
|
||||
"The tag was expected to be applied with {:?} but we instead found {:?}",
|
||||
ident, arguments[0].1.value
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => panic!("Pattern was not an applied tag: {:?}", pattern),
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_pattern_tag_apply_with_underscore(pattern: &Pattern, name: &str) {
|
||||
match pattern {
|
||||
Pattern::AppliedTag {
|
||||
tag_name,
|
||||
arguments,
|
||||
..
|
||||
} if arguments.len() == 1 => {
|
||||
assert_eq!(tag_name.as_ident_str().as_str(), name);
|
||||
match arguments[0].1.value {
|
||||
Pattern::Underscore => {},
|
||||
_ => panic!(
|
||||
"The tag was expected to be applied with an underscore but we instead found {:?}",
|
||||
arguments[0].1.value
|
||||
),
|
||||
}
|
||||
}
|
||||
_ => panic!("Pattern was not an applied tag: {:?}", pattern),
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_when(expr: &Expr) -> (&Expr, &Vec<WhenBranch>) {
|
||||
match expr {
|
||||
Expr::When {
|
||||
|
|
|
@ -150,6 +150,28 @@ mod suffixed_tests {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example of unwrapping a Result with ?? operator
|
||||
*
|
||||
* Note that ?? is desugared into a when expression,
|
||||
* however this also tests the parser.
|
||||
*
|
||||
*/
|
||||
#[test]
|
||||
fn simple_double_question() {
|
||||
run_test!(
|
||||
r#"
|
||||
main =
|
||||
"123"
|
||||
|> Str.toU8 ?? 255
|
||||
|> Num.toStr
|
||||
|> line!
|
||||
|
||||
Task.ok {}
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example with a parens suffixed sub-expression
|
||||
* in the function part of an Apply.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue