Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper try keyword #7296

Merged
merged 2 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,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