Pattern guards for functions and switch statements #830

Merged
ghallak merged 23 commits from ghallak/232 into master 2021-10-20 17:04:01 +09:00
2 changed files with 36 additions and 8 deletions
Showing only changes of commit f437ee564e - Show all commits

View File

@ -1616,8 +1616,16 @@ infer_expr(Env, {'if', Attrs, Cond, Then, Else}) ->
infer_expr(Env, {switch, Attrs, Expr, Cases}) ->
NewExpr = {typed, _, _, ExprType} = infer_expr(Env, Expr),
SwitchType = fresh_uvar(Attrs),
NewCases = [infer_case(Env, As, Pattern, ExprType, Branch, SwitchType)
|| {'case', As, Pattern, Branch} <- Cases],
ApplyInferCase =
fun(Case) ->
case Case of
{'case', As, Pattern, Branch} ->
infer_case(Env, As, Pattern, ExprType, Branch, SwitchType);
{'case', As, Pattern, Guard, Branch} ->
infer_case(Env, As, Pattern, Guard, ExprType, Branch, SwitchType)
end
end,
NewCases = lists:map(ApplyInferCase, Cases),
{typed, Attrs, {switch, Attrs, NewExpr, NewCases}, SwitchType};
infer_expr(Env, {record, Attrs, Fields}) ->
RecordType = fresh_uvar(Attrs),
@ -1837,10 +1845,19 @@ infer_pattern(Env, Pattern) ->
{NewEnv#env{ in_pattern = Env#env.in_pattern }, NewPattern}.
infer_case(Env, Attrs, Pattern, ExprType, Branch, SwitchType) ->
infer_case(Env, Attrs, Pattern, none, ExprType, Branch, SwitchType).
infer_case(Env, Attrs, Pattern, Guard, ExprType, Branch, SwitchType) ->
{NewEnv, NewPattern = {typed, _, _, PatType}} = infer_pattern(Env, Pattern),
NewBranch = check_expr(NewEnv#env{ in_pattern = false }, Branch, SwitchType),
unify(Env, PatType, ExprType, {case_pat, Pattern, PatType, ExprType}),
{'case', Attrs, NewPattern, NewBranch}.
case Guard of
none ->
{'case', Attrs, NewPattern, NewBranch};
_ ->
NewGuard = check_expr(NewEnv, Guard, {id, Attrs, "bool"}),
{'case', Attrs, NewPattern, NewGuard, NewBranch}
end.
%% NewStmts = infer_block(Env, Attrs, Stmts, BlockType)
infer_block(_Env, Attrs, [], BlockType) ->

View File

@ -683,9 +683,9 @@ expr_to_fcode(Env, _Type, {'if', _, Cond, Then, Else}) ->
expr_to_fcode(Env, Else));
%% Switch
expr_to_fcode(Env, _, {switch, _, Expr = {typed, _, E, Type}, Alts}) ->
expr_to_fcode(Env, _, S = {switch, _, Expr = {typed, _, E, Type}, Alts}) ->
Switch = fun(X) ->
{switch, alts_to_fcode(Env, type_to_fcode(Env, Type), X, Alts)}
{switch, alts_to_fcode(Env, type_to_fcode(Env, Type), X, Alts, S)}
end,
case E of
{id, _, X} -> Switch(X);
@ -863,9 +863,9 @@ is_first_order(_) -> true.
%% -- Pattern matching --
-spec alts_to_fcode(env(), ftype(), var_name(), [aeso_syntax:alt()]) -> fsplit().
alts_to_fcode(Env, Type, X, Alts) ->
FAlts = [alt_to_fcode(Env, Alt) || Alt <- Alts],
-spec alts_to_fcode(env(), ftype(), var_name(), [aeso_syntax:alt()], aeso_syntax:expr()) -> fsplit().
alts_to_fcode(Env, Type, X, Alts, Switch) ->
FAlts = remove_guards(Env, Alts, Switch),
split_tree(Env, [{X, Type}], FAlts).
%% Intermediate format before case trees (fcase() and fsplit()).
@ -879,6 +879,17 @@ alts_to_fcode(Env, Type, X, Alts) ->
| {con, arities(), tag(), [fpat()]}
| {assign, fpat(), fpat()}.
remove_guards(_Env, [], _Switch) ->
[];
remove_guards(Env, [Alt = {'case', _, _, _} | Rest], Switch) ->
[alt_to_fcode(Env, Alt) | remove_guards(Env, Rest, Switch)];
remove_guards(Env, [{'case', _, Pat, Guard, Body} | Rest], {switch, Ann, Expr, _}) ->
FPat = pat_to_fcode(Env, Pat),
FSwitch = expr_to_fcode(Env, {switch, Ann, Expr, Rest}),
FGuard = expr_to_fcode(bind_vars(Env, pat_vars(FPat)), Guard),
FBody = expr_to_fcode(bind_vars(Env, pat_vars(FPat)), Body),
[{'case', [FPat], make_if(FGuard, FBody, FSwitch)}].
%% %% Invariant: the number of variables matches the number of patterns in each falt.
-spec split_tree(env(), [{var_name(), ftype()}], [falt()]) -> fsplit().
split_tree(_Env, _Vars, []) ->