diff --git a/Makefile b/Makefile index 87985a3..a9f7599 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,15 @@ REBAR=$(shell which rebar || echo ./rebar) -.PHONY: rel all clean +.PHONY: rel all deps clean -all: compile +all: deps compile compile: $(REBAR) compile +deps: + ./rebar get-deps + clean: $(REBAR) clean diff --git a/examples/Makefile b/examples/Makefile index a74c41c..32b3692 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -14,13 +14,13 @@ test_exprecs.beam: ../ebin/exprecs.beam test_exprecs.erl @echo Compiling test_exprecs.erl @erlc +debug_info -pa ../ebin -pa . -I ../include test_exprecs.erl +test.beam: test_pt.beam +ex_pmod.beam: pmod.beam + %.beam: %.erl $(HEADERS) @echo Compiling $< @erlc +debug_info -pa ../ebin -pa . -I ../include $< -test.beam: test_pt.beam - - clean: @echo Cleaning @rm -f *.beam diff --git a/rebar b/rebar index 0c9c987..51db68c 100755 Binary files a/rebar and b/rebar differ diff --git a/src/exprecs.erl b/src/exprecs.erl index 1e4886c..0b140fa 100755 --- a/src/exprecs.erl +++ b/src/exprecs.erl @@ -142,9 +142,8 @@ %% '#pos-'(s, Attr) -> %% '#pos-s'(Attr). %% -%% -spec '#is_record-'(#r{}) -> true; -%% (#s{}) -> true; -%% (any()) -> false. +%% -spec '#is_record-'(any()) -> boolean(). +%% %% '#is_record-'(X) -> %% if %% is_record(X, r) -> @@ -155,9 +154,8 @@ %% false %% end. %% -%% -spec '#is_record-'(r, #r{}) -> true; -%% (s, #s{}) -> true; -%% (any(), any()) -> false. +%% -spec '#is_record-'(any(), any()) -> boolean(). +%% %% '#is_record-'(s, Rec) when tuple_size(Rec) == 2, element(1, Rec) == s -> %% true; %% '#is_record-'(r, Rec) when tuple_size(Rec) == 4, element(1, Rec) == r -> @@ -836,6 +834,7 @@ t_integer(L, I) -> {integer, L, I}. t_list(L, Es) -> {type, L, list, Es}. t_fun(L, As, Res) -> {type, L, 'fun', [{type, L, product, As}, Res]}. t_tuple(L, Es) -> {type, L, tuple, Es}. +t_boolean(L) -> {type, L, boolean, []}. t_record(L, A) -> {type, L, record, [{atom, L, A}]}. f_set_2(Rname, Flds, L, Acc) -> @@ -1013,10 +1012,14 @@ f_info(Acc, L) -> f_isrec_2(#pass1{records = Rs, exports = Es} = Acc, L) -> Fname = list_to_atom(fname_prefix(is_record, Acc)), Info = [{R,length(As) + 1} || {R,As} <- Rs, lists:member(R, Es)], - [funspec(L, Fname, - [{[t_atom(L, R), t_record(L, R)], t_atom(L, true)} - || R <- Es] ++ - [{[t_any(L), t_any(L)], t_atom(L, false)}]), + [%% This contract is correct, but is ignored by Dialyzer because it + %% has overlapping domains: + %% funspec(L, Fname, + %% [{[t_atom(L, R), t_record(L, R)], t_atom(L, true)} + %% || R <- Es] ++ + %% [{[t_any(L), t_any(L)], t_atom(L, false)}]), + %% This is less specific, but more useful to Dialyzer: + funspec(L, Fname, [{[t_any(L), t_any(L)], t_boolean(L)}]), {function, L, Fname, 2, lists:map( fun({R, Ln}) -> @@ -1091,10 +1094,14 @@ f_pos_2(#pass1{exports = Es} = Acc, L) -> f_isrec_1(Acc, L) -> Fname = list_to_atom(fname_prefix(is_record, Acc)), - [funspec(L, Fname, - [{[t_record(L, R)], t_atom(L, true)} - || R <- Acc#pass1.exports] - ++ [{[t_any(L)], t_atom(L, false)}]), + [%% This contract is correct, but is ignored by Dialyzer because it + %% has overlapping domains: + %% funspec(L, Fname, + %% [{[t_record(L, R)], t_atom(L, true)} + %% || R <- Acc#pass1.exports] + %% ++ [{[t_any(L)], t_atom(L, false)}]), + %% This is less specific, but more useful to Dialyzer: + funspec(L, Fname, [{[t_any(L)], t_boolean(L)}]), {function, L, Fname, 1, [{clause, L, [{var, L, 'X'}],