Use new try impl for ? operator

This commit is contained in:
Sam Mohr 2024-12-05 02:13:08 -08:00
parent 193c23bac8
commit de626102c8
No known key found for this signature in database
GPG key ID: EA41D161A3C1BC99
20 changed files with 429 additions and 110 deletions

View file

@ -5,6 +5,7 @@ use std::sync::Arc;
use crate::abilities::SpecializationId;
use crate::exhaustive::{ExhaustiveContext, SketchedRows};
use crate::expected::{Expected, PExpected};
use crate::expr::TryKind;
use roc_collections::soa::{index_push_new, slice_extend_new};
use roc_module::ident::{IdentSuffix, TagName};
use roc_module::symbol::{ModuleId, Symbol};
@ -643,12 +644,14 @@ impl Constraints {
ok_payload_var: Variable,
err_payload_var: Variable,
region: Region,
kind: TryKind,
) -> Constraint {
let constraint = TryTargetConstraint {
target_type_index: result_type_index,
ok_payload_var,
err_payload_var,
region,
kind,
};
let constraint_index = index_push_new(&mut self.try_target_constraints, constraint);
@ -939,6 +942,7 @@ pub struct TryTargetConstraint {
pub ok_payload_var: Variable,
pub err_payload_var: Variable,
pub region: Region,
pub kind: TryKind,
}
#[derive(Debug, Clone, Copy)]

View file

@ -725,6 +725,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
ok_payload_var,
err_payload_var,
err_ext_var,
kind,
} => Try {
result_expr: Box::new(result_expr.map(|e| go_help!(e))),
result_var: sub!(*result_var),
@ -732,6 +733,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
ok_payload_var: sub!(*ok_payload_var),
err_payload_var: sub!(*err_payload_var),
err_ext_var: sub!(*err_ext_var),
kind: *kind,
},
RuntimeError(err) => RuntimeError(err.clone()),

View file

@ -11,8 +11,8 @@ use roc_module::called_via::{BinOp, CalledVia};
use roc_module::ident::ModuleName;
use roc_parse::ast::Expr::{self, *};
use roc_parse::ast::{
is_expr_suffixed, AssignedField, Collection, Defs, ModuleImportParams, Pattern, StrLiteral,
StrSegment, TypeAnnotation, ValueDef, WhenBranch,
is_expr_suffixed, AssignedField, Collection, Defs, ModuleImportParams, Pattern, ResultTryKind,
StrLiteral, StrSegment, TryTarget, TypeAnnotation, ValueDef, WhenBranch,
};
use roc_problem::can::Problem;
use roc_region::all::{Loc, Region};
@ -44,7 +44,10 @@ fn new_op_call_expr<'a>(
match right_without_spaces {
Try => {
let desugared_left = desugar_expr(env, scope, left);
return Loc::at(region, Expr::LowLevelTry(desugared_left));
return Loc::at(
region,
Expr::LowLevelTry(desugared_left, ResultTryKind::KeywordPrefix),
);
}
Apply(&Loc { value: Try, .. }, arguments, _called_via) => {
let try_fn = desugar_expr(env, scope, arguments.first().unwrap());
@ -60,10 +63,71 @@ fn new_op_call_expr<'a>(
return Loc::at(
region,
Expr::LowLevelTry(env.arena.alloc(Loc::at(
region,
Expr::Apply(try_fn, args.into_bump_slice(), CalledVia::Try),
))),
Expr::LowLevelTry(
env.arena.alloc(Loc::at(
region,
Expr::Apply(try_fn, args.into_bump_slice(), CalledVia::Try),
)),
ResultTryKind::KeywordPrefix,
),
);
}
TrySuffix {
target: TryTarget::Result,
expr: fn_expr,
} => {
let loc_fn = env.arena.alloc(Loc::at(right.region, **fn_expr));
let function = desugar_expr(env, scope, loc_fn);
return Loc::at(
region,
LowLevelTry(
env.arena.alloc(Loc::at(
region,
Expr::Apply(
function,
env.arena.alloc([desugar_expr(env, scope, left)]),
CalledVia::Try,
),
)),
ResultTryKind::OperatorSuffix,
),
);
}
Apply(
&Loc {
value:
TrySuffix {
target: TryTarget::Result,
expr: fn_expr,
},
region: fn_region,
},
loc_args,
_called_via,
) => {
let loc_fn = env.arena.alloc(Loc::at(fn_region, *fn_expr));
let function = desugar_expr(env, scope, loc_fn);
let mut desugared_args = Vec::with_capacity_in(loc_args.len() + 1, env.arena);
desugared_args.push(desugar_expr(env, scope, left));
for loc_arg in &loc_args[..] {
desugared_args.push(desugar_expr(env, scope, loc_arg));
}
return Loc::at(
region,
LowLevelTry(
env.arena.alloc(Loc::at(
region,
Expr::Apply(
function,
desugared_args.into_bump_slice(),
CalledVia::Try,
),
)),
ResultTryKind::OperatorSuffix,
),
);
}
_ => {}
@ -456,23 +520,32 @@ pub fn desugar_expr<'a>(
env.arena.alloc(Loc { region, value })
}
// desugar the sub_expression, but leave the TrySuffix as this will
// be unwrapped later in desugar_value_def_suffixed
TrySuffix {
expr: sub_expr,
target,
} => {
let intermediate = env.arena.alloc(Loc::at(loc_expr.region, **sub_expr));
let new_sub_loc_expr = desugar_expr(env, scope, intermediate);
let new_sub_expr = env.arena.alloc(new_sub_loc_expr.value);
env.arena.alloc(Loc::at(
loc_expr.region,
TrySuffix {
expr: new_sub_expr,
target: *target,
},
))
match target {
TryTarget::Result => env.arena.alloc(Loc::at(
loc_expr.region,
LowLevelTry(new_sub_loc_expr, ResultTryKind::OperatorSuffix),
)),
TryTarget::Task => {
let new_sub_expr = env.arena.alloc(new_sub_loc_expr.value);
// desugar the sub_expression, but leave the TrySuffix as this will
// be unwrapped later in desugar_value_def_suffixed
env.arena.alloc(Loc::at(
loc_expr.region,
TrySuffix {
expr: new_sub_expr,
target: *target,
},
))
}
}
}
RecordAccess(sub_expr, paths) => {
let region = loc_expr.region;
@ -965,8 +1038,43 @@ pub fn desugar_expr<'a>(
))
};
env.arena
.alloc(Loc::at(loc_expr.region, Expr::LowLevelTry(result_expr)))
env.arena.alloc(Loc::at(
loc_expr.region,
Expr::LowLevelTry(result_expr, ResultTryKind::KeywordPrefix),
))
}
Apply(
Loc {
value:
TrySuffix {
target: TryTarget::Result,
expr: fn_expr,
},
region: fn_region,
},
loc_args,
_called_via,
) => {
let loc_fn = env.arena.alloc(Loc::at(*fn_region, **fn_expr));
let function = desugar_expr(env, scope, loc_fn);
let mut desugared_args = Vec::with_capacity_in(loc_args.len(), env.arena);
for loc_arg in &loc_args[..] {
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);
let result_expr = env.arena.alloc(Loc::at(
args_region,
Expr::Apply(function, desugared_args.into_bump_slice(), CalledVia::Try),
));
env.arena.alloc(Loc::at(
loc_expr.region,
Expr::LowLevelTry(result_expr, ResultTryKind::OperatorSuffix),
))
}
Apply(loc_fn, loc_args, called_via) => {
let mut desugared_args = Vec::with_capacity_in(loc_args.len(), env.arena);
@ -1138,7 +1246,7 @@ pub fn desugar_expr<'a>(
}
// note these only exist after desugaring
LowLevelDbg(_, _, _) | LowLevelTry(_) => loc_expr,
LowLevelDbg(_, _, _) | LowLevelTry(_, _) => loc_expr,
}
}

View file

@ -19,7 +19,7 @@ use roc_module::called_via::CalledVia;
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
use roc_module::low_level::LowLevel;
use roc_module::symbol::{IdentId, ModuleId, Symbol};
use roc_parse::ast::{self, Defs, PrecedenceConflict, StrLiteral};
use roc_parse::ast::{self, Defs, PrecedenceConflict, ResultTryKind, StrLiteral};
use roc_parse::ident::Accessor;
use roc_parse::pattern::PatternType::*;
use roc_problem::can::{PrecedenceProblem, Problem, RuntimeError};
@ -337,6 +337,7 @@ pub enum Expr {
ok_payload_var: Variable,
err_payload_var: Variable,
err_ext_var: Variable,
kind: TryKind,
},
Return {
@ -348,6 +349,12 @@ pub enum Expr {
RuntimeError(RuntimeError),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum TryKind {
KeywordPrefix,
OperatorSuffix,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ExpectLookup {
pub symbol: Symbol,
@ -1397,7 +1404,7 @@ pub fn canonicalize_expr<'a>(
output,
)
}
ast::Expr::LowLevelTry(loc_expr) => {
ast::Expr::LowLevelTry(loc_expr, kind) => {
let (loc_result_expr, output) =
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
@ -1415,6 +1422,10 @@ pub fn canonicalize_expr<'a>(
ok_payload_var: var_store.fresh(),
err_payload_var: var_store.fresh(),
err_ext_var: var_store.fresh(),
kind: match kind {
ResultTryKind::KeywordPrefix => TryKind::KeywordPrefix,
ResultTryKind::OperatorSuffix => TryKind::OperatorSuffix,
},
},
output,
)
@ -2394,6 +2405,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
ok_payload_var,
err_payload_var,
err_ext_var,
kind,
} => {
let loc_result_expr = Loc {
region: result_expr.region,
@ -2407,6 +2419,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
ok_payload_var,
err_payload_var,
err_ext_var,
kind,
}
}
@ -2704,7 +2717,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::Expr::MalformedIdent(_, _)
| ast::Expr::Tag(_)
| ast::Expr::OpaqueRef(_) => true,
ast::Expr::LowLevelTry(loc_expr) => is_valid_interpolation(&loc_expr.value),
ast::Expr::LowLevelTry(loc_expr, _) => is_valid_interpolation(&loc_expr.value),
// Newlines are disallowed inside interpolation, and these all require newlines
ast::Expr::DbgStmt { .. }
| ast::Expr::LowLevelDbg(_, _, _)

View file

@ -407,6 +407,7 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr, var: Variable) {
ok_payload_var: _,
err_payload_var: _,
err_ext_var: _,
kind: _,
} => {
visitor.visit_expr(&result_expr.value, result_expr.region, *result_var);
}