Skip to content

Commit

Permalink
Merge pull request #7296 from smores56/proper-try-keyword
Browse files Browse the repository at this point in the history
Proper `try` keyword
  • Loading branch information
smores56 authored Dec 5, 2024
2 parents 54e78e8 + 4c1f434 commit 193c23b
Show file tree
Hide file tree
Showing 33 changed files with 1,036 additions and 521 deletions.
2 changes: 2 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ fn main() -> io::Result<()> {
) {
Ok((problems, total_time)) => {
problems.print_error_warning_count(total_time);
println!(".\n");

exit_code = problems.exit_code();
}

Expand Down
2 changes: 1 addition & 1 deletion crates/cli/tests/cli_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ mod cli_tests {
);

let expected_out =
"0 error and 0 warning found in <ignored for test> ms\n0 error and 0 warning found in <ignored for test> ms\n";
"0 errors and 0 warnings found in <ignored for test> ms.\n\n0 errors and 0 warnings found in <ignored for test> ms.\n\n";

cli_build.run().assert_clean_stdout(expected_out);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
source: crates/cli/tests/cli_tests.rs
assertion_line: 429
expression: cli_dev_out.normalize_stdout_and_stderr()
snapshot_kind: text
---

── TOO MANY ARGS in tests/test-projects/module_params/arity_mismatch.roc ───────
Expand Down Expand Up @@ -36,8 +36,6 @@ make partial application explicit.

────────────────────────────────────────────────────────────────────────────────

3 error and 0 warning found in <ignored for test> ms
.
3 errors and 0 warnings found in <ignored for test> ms.

You can run <ignored for tests>

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
source: crates/cli/tests/cli_tests.rs
assertion_line: 445
expression: cli_dev_out.normalize_stdout_and_stderr()
snapshot_kind: text
---

── TYPE MISMATCH in tests/test-projects/module_params/BadAnn.roc ───────────────
Expand Down Expand Up @@ -41,8 +41,6 @@ Tip: It looks like it takes too many arguments. I'm seeing 1 extra.

────────────────────────────────────────────────────────────────────────────────

2 error and 1 warning found in <ignored for test> ms
.
2 errors and 1 warning found in <ignored for test> ms.

You can run <ignored for tests>

Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
---
source: crates/cli/tests/cli_tests.rs
assertion_line: 476
expression: cli_dev_out.normalize_stdout_and_stderr()
snapshot_kind: text
---

── TYPE MISMATCH in tests/test-projects/module_params/unexpected_fn.roc ────────

This argument to this string interpolation has an unexpected type:

11$(Api.getPost)
^^^^^^^^^^^
10"""
11│> $(Api.getPost)
12"""
The argument is an anonymous function of type:

Expand All @@ -21,8 +22,6 @@ But this string interpolation needs its argument to be:

────────────────────────────────────────────────────────────────────────────────

1 error and 0 warning found in <ignored for test> ms
.
1 error and 0 warnings found in <ignored for test> ms.

You can run <ignored for tests>

37 changes: 36 additions & 1 deletion crates/compiler/can/src/constraint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct Constraints {
pub cycles: Vec<Cycle>,
pub fx_call_constraints: Vec<FxCallConstraint>,
pub fx_suffix_constraints: Vec<FxSuffixConstraint>,
pub try_target_constraints: Vec<TryTargetConstraint>,
}

impl std::fmt::Debug for Constraints {
Expand Down Expand Up @@ -87,6 +88,7 @@ impl Constraints {
let cycles = Vec::new();
let fx_call_constraints = Vec::with_capacity(16);
let fx_suffix_constraints = Vec::new();
let result_type_constraints = Vec::new();

categories.extend([
Category::Record,
Expand All @@ -103,7 +105,6 @@ impl Constraints {
Category::List,
Category::Str,
Category::Character,
Category::Return,
]);

pattern_categories.extend([
Expand Down Expand Up @@ -138,6 +139,7 @@ impl Constraints {
cycles,
fx_call_constraints,
fx_suffix_constraints,
try_target_constraints: result_type_constraints,
}
}

Expand Down Expand Up @@ -635,6 +637,25 @@ impl Constraints {
Constraint::FlexToPure(fx_var)
}

pub fn try_target(
&mut self,
result_type_index: TypeOrVar,
ok_payload_var: Variable,
err_payload_var: Variable,
region: Region,
) -> Constraint {
let constraint = TryTargetConstraint {
target_type_index: result_type_index,
ok_payload_var,
err_payload_var,
region,
};

let constraint_index = index_push_new(&mut self.try_target_constraints, constraint);

Constraint::TryTarget(constraint_index)
}

pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool {
match constraint {
Constraint::SaveTheEnvironment => true,
Expand All @@ -660,6 +681,7 @@ impl Constraints {
| Constraint::Lookup(..)
| Constraint::Pattern(..)
| Constraint::ExpectEffectful(..)
| Constraint::TryTarget(_)
| Constraint::FxCall(_)
| Constraint::FxSuffix(_)
| Constraint::FlexToPure(_)
Expand Down Expand Up @@ -843,6 +865,8 @@ pub enum Constraint {
FlexToPure(Variable),
/// Expect statement or ignored def to be effectful
ExpectEffectful(Variable, ExpectEffectfulReason, Region),
/// Expect value to be some kind of Result
TryTarget(Index<TryTargetConstraint>),
/// Used for things that always unify, e.g. blanks and runtime errors
True,
SaveTheEnvironment,
Expand Down Expand Up @@ -909,6 +933,14 @@ pub struct IncludesTag {
pub region: Region,
}

#[derive(Debug, Clone)]
pub struct TryTargetConstraint {
pub target_type_index: TypeOrVar,
pub ok_payload_var: Variable,
pub err_payload_var: Variable,
pub region: Region,
}

#[derive(Debug, Clone, Copy)]
pub struct Cycle {
pub def_names: Slice<(Symbol, Region)>,
Expand Down Expand Up @@ -1000,6 +1032,9 @@ impl std::fmt::Debug for Constraint {
Self::FlexToPure(arg0) => {
write!(f, "FlexToPure({arg0:?})")
}
Self::TryTarget(arg0) => {
write!(f, "ExpectResultType({arg0:?})")
}
Self::True => write!(f, "True"),
Self::SaveTheEnvironment => write!(f, "SaveTheEnvironment"),
Self::Let(arg0, arg1) => f.debug_tuple("Let").field(arg0).field(arg1).finish(),
Expand Down
18 changes: 17 additions & 1 deletion crates/compiler/can/src/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
fx_type: sub!(*fx_type),
early_returns: early_returns
.iter()
.map(|(var, region)| (sub!(*var), *region))
.map(|(var, region, type_)| (sub!(*var), *region, *type_))
.collect(),
name: *name,
captured_symbols: captured_symbols
Expand Down Expand Up @@ -718,6 +718,22 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
symbol: *symbol,
},

Try {
result_expr,
result_var,
return_var,
ok_payload_var,
err_payload_var,
err_ext_var,
} => Try {
result_expr: Box::new(result_expr.map(|e| go_help!(e))),
result_var: sub!(*result_var),
return_var: sub!(*return_var),
ok_payload_var: sub!(*ok_payload_var),
err_payload_var: sub!(*err_payload_var),
err_ext_var: sub!(*err_ext_var),
},

RuntimeError(err) => RuntimeError(err.clone()),
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/compiler/can/src/debug/pretty_print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
),
Dbg { .. } => todo!(),
Expect { .. } => todo!(),
Try { .. } => todo!(),
Return { .. } => todo!(),
RuntimeError(_) => todo!(),
}
Expand Down
91 changes: 14 additions & 77 deletions crates/compiler/can/src/desugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn new_op_call_expr<'a>(
match right_without_spaces {
Try => {
let desugared_left = desugar_expr(env, scope, left);
return desugar_try_expr(env, scope, desugared_left);
return Loc::at(region, Expr::LowLevelTry(desugared_left));
}
Apply(&Loc { value: Try, .. }, arguments, _called_via) => {
let try_fn = desugar_expr(env, scope, arguments.first().unwrap());
Expand All @@ -58,13 +58,12 @@ fn new_op_call_expr<'a>(
.map(|a| desugar_expr(env, scope, a)),
);

return desugar_try_expr(
env,
scope,
env.arena.alloc(Loc::at(
right.region,
return Loc::at(
region,
Expr::LowLevelTry(env.arena.alloc(Loc::at(
region,
Expr::Apply(try_fn, args.into_bump_slice(), CalledVia::Try),
)),
))),
);
}
_ => {}
Expand Down Expand Up @@ -957,13 +956,17 @@ pub fn desugar_expr<'a>(
desugared_args.push(desugar_expr(env, scope, loc_arg));
}

let args_region =
Region::span_across(&loc_args[0].region, &loc_args[loc_args.len() - 1].region);

env.arena.alloc(Loc::at(
loc_expr.region,
args_region,
Expr::Apply(function, desugared_args.into_bump_slice(), CalledVia::Try),
))
};

env.arena.alloc(desugar_try_expr(env, scope, result_expr))
env.arena
.alloc(Loc::at(loc_expr.region, Expr::LowLevelTry(result_expr)))
}
Apply(loc_fn, loc_args, called_via) => {
let mut desugared_args = Vec::with_capacity_in(loc_args.len(), env.arena);
Expand Down Expand Up @@ -1134,77 +1137,11 @@ pub fn desugar_expr<'a>(
})
}

// note this only exists after desugaring
LowLevelDbg(_, _, _) => loc_expr,
// note these only exist after desugaring
LowLevelDbg(_, _, _) | LowLevelTry(_) => loc_expr,
}
}

pub fn desugar_try_expr<'a>(
env: &mut Env<'a>,
scope: &mut Scope,
result_expr: &'a Loc<Expr<'a>>,
) -> Loc<Expr<'a>> {
let region = result_expr.region;
let ok_symbol = env.arena.alloc(scope.gen_unique_symbol_name().to_string());
let err_symbol = env.arena.alloc(scope.gen_unique_symbol_name().to_string());

let ok_branch = env.arena.alloc(WhenBranch {
patterns: env.arena.alloc([Loc::at(
region,
Pattern::Apply(
env.arena.alloc(Loc::at(region, Pattern::Tag("Ok"))),
env.arena
.alloc([Loc::at(region, Pattern::Identifier { ident: ok_symbol })]),
),
)]),
value: Loc::at(
region,
Expr::Var {
module_name: "",
ident: ok_symbol,
},
),
guard: None,
});

let err_branch = env.arena.alloc(WhenBranch {
patterns: env.arena.alloc([Loc::at(
region,
Pattern::Apply(
env.arena.alloc(Loc::at(region, Pattern::Tag("Err"))),
env.arena
.alloc([Loc::at(region, Pattern::Identifier { ident: err_symbol })]),
),
)]),
value: Loc::at(
region,
Expr::Return(
env.arena.alloc(Loc::at(
region,
Expr::Apply(
env.arena.alloc(Loc::at(region, Expr::Tag("Err"))),
&*env.arena.alloc([&*env.arena.alloc(Loc::at(
region,
Expr::Var {
module_name: "",
ident: err_symbol,
},
))]),
CalledVia::Try,
),
)),
None,
),
),
guard: None,
});

Loc::at(
region,
Expr::When(result_expr, &*env.arena.alloc([&*ok_branch, &*err_branch])),
)
}

fn desugar_str_segments<'a>(
env: &mut Env<'a>,
scope: &mut Scope,
Expand Down
Loading

0 comments on commit 193c23b

Please sign in to comment.