Skip to content

Commit 47c8b58

Browse files
authored
Merge pull request #489 from ferd/maybe_expr_unsupported
Add known problem for unsupported maybe expression
2 parents 7773a04 + da382b5 commit 47c8b58

16 files changed

+84
-32
lines changed

.github/workflows/build-and-test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ on:
99

1010
jobs:
1111
test:
12-
runs-on: ubuntu-latest
12+
runs-on: ubuntu-20.04
1313
name: Erlang ${{matrix.otp}}
1414
strategy:
1515
matrix:
16-
otp: ['22.3.4.20', '23.3.4.7', '24.3.4.4']
16+
otp: ['23.3.4.7', '24.3.4.4', '25.1.2']
1717
steps:
1818
- uses: actions/checkout@v2
1919
- uses: erlef/setup-beam@v1

.github/workflows/proptests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99

1010
jobs:
1111
test:
12-
runs-on: ubuntu-latest
12+
runs-on: ubuntu-20.04
1313
name: Erlang ${{matrix.otp}}
1414
strategy:
1515
matrix:

.github/workflows/publish-to-hex.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55

66
jobs:
77
publish:
8-
runs-on: ubuntu-latest
8+
runs-on: ubuntu-20.04
99

1010
steps:
1111
- name: Check Out

.github/workflows/self-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99

1010
jobs:
1111
test:
12-
runs-on: ubuntu-latest
12+
runs-on: ubuntu-20.04
1313
name: Erlang ${{matrix.otp}}
1414
strategy:
1515
matrix:

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
.PHONY: all
3333
all: app escript
3434

35+
ERL_OPTS = -enable-feature maybe_expr
36+
3537
# Compilation
3638

3739
erls = $(wildcard src/*.erl)
@@ -143,7 +145,7 @@ end
143145
endef
144146

145147
eunit: compile-tests
146-
erl -noinput -pa ebin -pa test -eval \
148+
erl $(ERL_OPTS) -noinput -pa ebin -pa test -eval \
147149
'$(erl_run_eunit), halt().'
148150

149151
cli-tests: bin/gradualizer test/arg.beam

rebar.config

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
{deps,
55
[
66
{proper, {git, "https://github.com/proper-testing/proper.git", {branch, "master"}}}
7-
]}
7+
]},
8+
%% see the maybe expression fail;
9+
%% the VM also needs to be configured to load the module
10+
{erl_opts, [{feature,maybe_expr,enable}]}
811
]}
912
]}.
1013

src/gradualizer_fmt.erl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,12 @@ format_type_error({form_check_timeout, Form}, Opts) ->
362362
[form_info(Form),
363363
format_location(Form, verbose, Opts)])
364364
end]);
365+
format_type_error({unsupported_expression, Anno, Expr}, Opts) ->
366+
io_lib:format(
367+
"~sThe ~s expression~s is not supported yet~n",
368+
[format_location(Anno, brief, Opts),
369+
atom_to_list(element(1, Expr)),
370+
format_location(Anno, verbose, Opts)]);
365371
format_type_error({Location, Module, ErrorDescription}, Opts)
366372
when is_integer(Location) orelse is_tuple(Location),
367373
is_atom(Module) ->

src/typechecker.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1903,7 +1903,12 @@ do_type_check_expr(Env, {'try', _, Block, CaseCs, CatchCs, AfterBlock}) ->
19031903
end,
19041904
{normalize({type, erl_anno:new(0), union, [Ty, TyC, TyS]}, Env)
19051905
,VB
1906-
,constraints:combine([Cs1,Cs2,Cs3,Cs4])}.
1906+
,constraints:combine([Cs1,Cs2,Cs3,Cs4])};
1907+
1908+
%% Maybe - value-based error handling expression
1909+
%% See https://www.erlang.org/eeps/eep-0049
1910+
do_type_check_expr(Env, {'maybe', Anno, [{maybe_match, _, _LHS, _RHS}]} = MaybeExpr) ->
1911+
erlang:throw({unsupported_expression, Anno, MaybeExpr}).
19071912

19081913
%% Helper for type_check_expr for funs
19091914
-spec type_check_fun(env(), _) -> {type(), env(), constraints:constraints()}.

test/known_problems/should_pass/any_doesnt_have_type_none_should_pass.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
-module(any_doesnt_have_type_none_should_pass).
22

3+
-export([f/2]).
4+
35
-type type() :: abstract_type().
46

57
-type abstract_type() :: af_tuple_type().

test/known_problems/should_pass/fun_subtyping.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-module(fun_subtyping).
22

3-
-compile([export_all, nowarn_export_all]).
3+
-export([return_fun_intersection/0]).
44

55
-spec return_fun_intersection() -> fun((number()) -> number()).
66
return_fun_intersection() -> fun number/1.

test/known_problems/should_pass/list_concat_op_should_pass.erl

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
-export([nil_concat_op_elem_gives_elem/0,
44
nonempty1_concat_op_elem_gives_improper/0,
5-
nonempty2_concat_op_elem_gives_improper/0,
6-
nil_concat_op_nonempty_gives_proper/0,
7-
nonempty_concat_op_nonempty_gives_proper/0]).
5+
nonempty2_concat_op_elem_gives_improper/0]).
86

97
-spec nil_concat_op_elem_gives_elem() -> b.
108
nil_concat_op_elem_gives_elem() ->
@@ -23,14 +21,6 @@ nonempty2_concat_op_elem_gives_improper() ->
2321
%% improper_concat_op_elem_gives_badarg() ->
2422
%% [a|b] ++ c.
2523

26-
-spec nil_concat_op_nonempty_gives_proper() -> [atom()].
27-
nil_concat_op_nonempty_gives_proper() ->
28-
[] ++ [a].
29-
30-
-spec nonempty_concat_op_nonempty_gives_proper() -> [atom()].
31-
nonempty_concat_op_nonempty_gives_proper() ->
32-
[a,b] ++ [c].
33-
3424
%% See list_op_should_fail.
3525
%% -spec improper_concat_op_nonempty_gives_badarg() -> none().
3626
%% improper_concat_op_nonempty_gives_badarg() ->
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-module(maybe_expr).
2+
3+
-ifdef(OTP_RELEASE).
4+
-if(?OTP_RELEASE >= 25).
5+
-if(?FEATURE_AVAILABLE(maybe_expr)).
6+
7+
-feature(maybe_expr, enable).
8+
9+
-export([syntax/0]).
10+
11+
syntax() ->
12+
maybe
13+
ok ?= ok
14+
end.
15+
16+
-endif. %% FEATURE_AVAILABLE
17+
-endif. %% OTP >= 25
18+
-endif. %% OTP_RELEASE

test/known_problems/should_pass/refine_mismatch_using_guard_bifs.erl

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
-module(refine_mismatch_using_guard_bifs).
22

33
-export([refine_by_guards_1/1,
4-
refine_by_guards_2/1,
5-
refine_literals_by_guards/1]).
4+
refine_by_guards_2/1]).
65

76
-spec refine_by_guards_1(atom() | pos_integer() | float() |
87
binary() | tuple() | [any()] |
@@ -24,10 +23,3 @@ refine_by_guards_2(X) when is_boolean(X) -> ok;
2423
refine_by_guards_2(X) when is_list(X) -> ok;
2524
refine_by_guards_2(X) when is_port(X) -> ok;
2625
refine_by_guards_2(X) -> X.
27-
28-
-spec refine_literals_by_guards(banana | 0 | {} | [] | pid()) -> pid().
29-
refine_literals_by_guards(X) when is_atom(X) -> self();
30-
refine_literals_by_guards(X) when is_integer(X) -> self();
31-
refine_literals_by_guards(X) when is_tuple(X) -> self();
32-
refine_literals_by_guards(X) when is_list(X) -> self();
33-
refine_literals_by_guards(X) -> X.

test/should_pass/list_concat_op_pass.erl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
nonempty1_concat_fun_elem_gives_improper/0,
55
nonempty2_concat_fun_elem_gives_improper/0,
66
nil_concat_fun_nonempty_gives_proper/0,
7+
nil_concat_op_nonempty_gives_proper/0,
78
nonempty_concat_fun_nonempty_gives_proper/0,
9+
nonempty_concat_op_nonempty_gives_proper/0,
810
proper_concat_fun_proper_gives_proper/0]).
911

1012
-spec nil_concat_fun_elem_gives_elem() -> b.
@@ -23,10 +25,18 @@ nonempty2_concat_fun_elem_gives_improper() ->
2325
nil_concat_fun_nonempty_gives_proper() ->
2426
erlang:'++'([], [a]).
2527

28+
-spec nil_concat_op_nonempty_gives_proper() -> [atom()].
29+
nil_concat_op_nonempty_gives_proper() ->
30+
[] ++ [a].
31+
2632
-spec nonempty_concat_fun_nonempty_gives_proper() -> [atom()].
2733
nonempty_concat_fun_nonempty_gives_proper() ->
2834
erlang:'++'([a,b], [c]).
2935

36+
-spec nonempty_concat_op_nonempty_gives_proper() -> [atom()].
37+
nonempty_concat_op_nonempty_gives_proper() ->
38+
[a,b] ++ [c].
39+
3040
-spec proper_concat_fun_proper_gives_proper() -> [integer()].
3141
proper_concat_fun_proper_gives_proper() ->
3242
erlang:'++'(generate_list(), generate_list()).

test/should_pass/type_refinement_pass.erl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
-module(type_refinement_pass).
22

3-
-compile([export_all, nowarn_export_all]).
3+
-export([basic_type_refinement/1,
4+
getenv/1,
5+
int_literals_1/1, int_literals_2/1, int_literals_3/1,
6+
disjoint_stuff_1/1, disjoint_stuff_2/1, disjoint_stuff_3/1, disjoint_stuff_4/1,
7+
var_pat/2,
8+
nil_elimination/1,
9+
tuple_union/1,
10+
tuple_union_2/1,
11+
beside_match_all/2,
12+
beside_singleton/2,
13+
refine_bound_var_by_guard_bifs/1,
14+
refine_literals_by_guards/1]).
415

516
%% Test that Value is not considered to be string() | false.
617
-spec basic_type_refinement(string()) -> string().
@@ -81,3 +92,10 @@ refine_bound_var_by_guard_bifs(X) ->
8192
is_pid(X) -> ok;
8293
true -> X
8394
end.
95+
96+
-spec refine_literals_by_guards(banana | 0 | {} | [] | pid()) -> pid().
97+
refine_literals_by_guards(X) when is_atom(X) -> self();
98+
refine_literals_by_guards(X) when is_integer(X) -> self();
99+
refine_literals_by_guards(X) when is_tuple(X) -> self();
100+
refine_literals_by_guards(X) when is_list(X) -> self();
101+
refine_literals_by_guards(X) -> X.

test/test.erl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ gen_should_fail() ->
5757
gen_known_problem_should_pass() ->
5858
map_erl_files(
5959
fun(File) ->
60-
?_assertNotEqual(ok, safe_type_check_file(File))
60+
{ok, Forms} = gradualizer_file_utils:get_forms_from_erl(File, []),
61+
ExpectedErrors = typechecker:number_of_exported_functions(Forms),
62+
ReturnedErrors = length(safe_type_check_file(File, [return_errors])),
63+
?_assertEqual(ExpectedErrors, ReturnedErrors)
6164
end, "test/known_problems/should_pass").
6265

6366
% Test succeeds if Gradualizer crashes or if it does type check.
@@ -85,8 +88,11 @@ map_erl_files(Fun, Dir) ->
8588
[{filename:basename(File), Fun(File)} || File <- Files].
8689

8790
safe_type_check_file(File) ->
91+
safe_type_check_file(File, []).
92+
93+
safe_type_check_file(File, Opts) ->
8894
try
89-
gradualizer:type_check_file(File)
95+
gradualizer:type_check_file(File, Opts)
9096
catch
9197
_:_ -> crash
9298
end.

0 commit comments

Comments
 (0)