From 65639094c79864dee86ec34c9e15ec77fa805817 Mon Sep 17 00:00:00 2001 From: istr Date: Thu, 25 Jul 2013 12:29:59 +0200 Subject: [PATCH] Make dialyzer happy Use ets:tab() instead of ets:tid(), refine type specs such that the code passes dialyzer with options -Wunmatched_returns, -Werror_handling, -Wrace_conditions, -Wunderspecs --- src/glc.erl | 6 ++++-- src/glc_code.erl | 26 ++++++++++++++++++-------- src/glc_lib.erl | 2 ++ src/glc_ops.erl | 19 ++++++++++--------- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/glc.erl b/src/glc.erl index ecca4b7..e57647f 100644 --- a/src/glc.erl +++ b/src/glc.erl @@ -87,7 +87,7 @@ -record(module, { 'query' :: term(), - tables :: [{atom(), ets:tid()}], + tables :: [{atom(), ets:tab()}], qtree :: term() }). @@ -140,7 +140,9 @@ null(Result) -> %% Updating the output action of a query finalizes it. Attempting %% to use a finalized query to construct a new query will result %% in a `badarg' error. --spec with(glc_ops:op(), fun((gre:event()) -> term())) -> glc_ops:op(). +-type qry() :: {atom(), '*'|false|true|[any(),...]} | {atom(), '<'|'='|'>', _}. +-type action() :: fun((_) -> any()). +-spec with(Query::qry(), Action::action()) -> {with, Query::qry(), Action::action()}. with(Query, Action) -> glc_ops:with(Query, Action). diff --git a/src/glc_code.erl b/src/glc_code.erl index 810ca3c..2659aa4 100644 --- a/src/glc_code.erl +++ b/src/glc_code.erl @@ -9,9 +9,10 @@ -record(module, { 'query' :: term(), - tables :: [{atom(), ets:tid()}], + tables :: [{atom(), ets:tab()}], qtree :: term() }). +-type mod() :: #module{}. -type syntaxTree() :: erl_syntax:syntaxTree(). @@ -20,11 +21,12 @@ fields = [] :: [{atom(), syntaxTree()}], fieldc = 0 :: non_neg_integer(), paramvars = [] :: [{term(), syntaxTree()}], - paramstab = undefined :: ets:tid() + paramstab = undefined :: ets:tab() }). -type nextFun() :: fun((#state{}) -> [syntaxTree()]). +-spec compile (Module::atom(), mod()) -> {ok, Module::atom()}. compile(Module, ModuleData) -> {ok, forms, Forms} = abstract_module(Module, ModuleData), {ok, Module, Binary} = compile_forms(Forms, [nowarn_unused_vars]), @@ -74,7 +76,7 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) -> [?erl:clause( [?erl:underscore()], none, [abstract_apply(erlang, error, [?erl:atom(badarg)])])]), - %% table(Name) -> ets:tid(). + %% table(Name) -> ets:tab(). ?erl:function( ?erl:atom(table), abstract_tables(Tables) ++ @@ -103,10 +105,14 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) -> AbstractMod. %% @private Return the clauses of the table/1 function. +%-spec abstract_tables([{term(), atom()|binary()|maybe_improper_list()|number()|tuple()}]) -> +% ?erl:syntax_tree(). abstract_tables(Tables) -> [?erl:clause( [?erl:abstract(K)], none, [?erl:abstract(V)]) +% [?erl:tree(variable,V)]) +% [?erl:variable("V")]) || {K, V} <- Tables]. %% @private Return the clauses of the info/1 function. @@ -277,7 +283,7 @@ abstract_getparam_(Term, OnBound, #state{paramstab=Table, ] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}). %% @private Generate a variable name for the value of a field. --spec field_variable(atom()) -> string(). +-spec field_variable(atom()) -> nonempty_string(). field_variable(Key) -> "Field_" ++ field_variable_(atom_to_list(Key)). @@ -314,7 +320,7 @@ param_variable(Key) -> %% @private Return an expression to increment a counter. %% @todo Pass state record. Only Generate code if `statistics' is enabled. --spec abstract_count(atom()) -> syntaxTree(). +-spec abstract_count(filter|input|output) -> syntaxTree(). abstract_count(Counter) -> abstract_apply(ets, update_counter, [abstract_apply(table, [?erl:atom(counters)]), @@ -324,7 +330,7 @@ abstract_count(Counter) -> %% @private Return an expression to get the value of a counter. %% @todo Pass state record. Only Generate code if `statistics' is enabled. --spec abstract_getcount(atom()) -> [syntaxTree()]. +-spec abstract_getcount(filter|input|output) -> [syntaxTree()]. abstract_getcount(Counter) -> [abstract_apply(ets, lookup_element, [abstract_apply(table, [?erl:atom(counters)]), @@ -356,11 +362,15 @@ load_binary(Module, Binary) -> end. %% @private Apply an exported function. --spec abstract_apply(atom(), atom(), [syntaxTree()]) -> syntaxTree(). +% underspec: -spec abstract_apply(atom(), atom(), [syntaxTree()]) -> syntaxTree(). +-spec abstract_apply(erlang|ets|gre, '<'|'=:='|'>'|error|find|lookup_element|update_counter, [any(),...]) -> + syntaxTree(). abstract_apply(Module, Function, Arguments) -> ?erl:application(?erl:atom(Module), ?erl:atom(Function), Arguments). %% @private Apply a module local function. --spec abstract_apply(atom(), [syntaxTree()]) -> syntaxTree(). +% underspec: -spec abstract_apply(atom(), [syntaxTree()]) -> syntaxTree(). +-spec abstract_apply (table, [{tree, atom(), {_,_,_,_}, _}, ...]) -> + syntaxTree(). abstract_apply(Function, Arguments) -> ?erl:application(?erl:atom(Function), Arguments). diff --git a/src/glc_lib.erl b/src/glc_lib.erl index 427551f..40d1593 100644 --- a/src/glc_lib.erl +++ b/src/glc_lib.erl @@ -87,6 +87,7 @@ repeat(Query, Fun) -> %% @doc Return the output action of a query. +-spec onoutput ({_, '<'|'='|'>', _} | {_,'*'}) -> output. onoutput({_, '<', _}) -> output; onoutput({_, '=', _}) -> @@ -99,6 +100,7 @@ onoutput(Query) -> erlang:error(badarg, [Query]). %% @doc Modify the output action of a query. +-spec onoutput (term(), term()) -> no_return(). onoutput(Action, Query) -> erlang:error(badarg, [Action, Query]). diff --git a/src/glc_ops.erl b/src/glc_ops.erl index 05067c4..e7f920c 100644 --- a/src/glc_ops.erl +++ b/src/glc_ops.erl @@ -31,28 +31,28 @@ -export_type([op/0]). %% @doc Test that a field value is less than a term. --spec lt(atom(), term()) -> op(). +-spec lt(Key::atom(), Term::term()) -> {Key::atom(), '<', Term::term()}. lt(Key, Term) when is_atom(Key) -> {Key, '<', Term}; lt(Key, Term) -> erlang:error(badarg, [Key, Term]). %% @doc Test that a field value is equal to a term. --spec eq(atom(), term()) -> op(). +-spec eq(Key::atom(), Term::term()) -> {Key::atom(), '=', Term::term()}. eq(Key, Term) when is_atom(Key) -> {Key, '=', Term}; eq(Key, Term) -> erlang:error(badarg, [Key, Term]). %% @doc Test that a field value is greater than a term. --spec gt(atom(), term()) -> op(). +-spec gt(Key::atom(), Term::term()) -> {Key::atom(), '>', Term::term()}. gt(Key, Term) when is_atom(Key) -> {Key, '>', Term}; gt(Key, Term) -> erlang:error(badarg, [Key, Term]). %% @doc Test that a field value is exists. --spec wc(atom()) -> op(). +-spec wc(Key::atom()) -> {Key::atom(), '*'}. wc(Key) when is_atom(Key) -> {Key, '*'}; wc(Key) -> @@ -64,7 +64,7 @@ wc(Key) -> %% in the list must hold for the input event. The list is expected to %% be a non-empty list. If the list of filters is an empty list a `badarg' %% error will be thrown. --spec all([op()]) -> op(). +-spec all(Conds::nonempty_maybe_improper_list()) -> {all, Conds::nonempty_maybe_improper_list()}. all([_|_]=Conds) -> {all, Conds}; all(Other) -> @@ -76,7 +76,7 @@ all(Other) -> %% in the list must hold for the input event. The list is expected to be %% a non-empty list. If the list of filters is an empty list a `badarg' %% error will be thrown. --spec any([op()]) -> op(). +-spec any(Conds::nonempty_maybe_improper_list()) -> {any, Conds::nonempty_maybe_improper_list()}. any([_|_]=Conds) -> {any, Conds}; any(Other) -> @@ -84,7 +84,7 @@ any(Other) -> %% @doc Always return `true' or `false'. --spec null(boolean()) -> op(). +-spec null(Result::boolean()) -> {null, Result::boolean()} | no_return(). null(Result) when is_boolean(Result) -> {null, Result}; null(Result) -> @@ -95,7 +95,8 @@ null(Result) -> %% Updating the output action of a query finalizes it. Attempting %% to use a finalized query to construct a new query will result %% in a `badarg' error. --spec with(op(), fun((gre:event()) -> term())) -> op(). +-spec with(Query::op(), Fun::fun((gre:event()) -> term())) -> + {with, Query::op(), Fun::fun((gre:event()) -> term())} | no_return(). with(Query, Fun) when is_function(Fun, 1) -> {with, Query, Fun}; with(Query, Fun) -> @@ -111,7 +112,7 @@ with(Query, Fun) -> %% All queries are expected to be valid and have an output action other %% than the default which is `output'. If these expectations don't hold %% a `badarg' error will be thrown. --spec union([op()]) -> op(). +-spec union(Queries::[op()]) -> {union, Queries::[op()]} | no_return(). union(Queries) -> case [Query || Query <- Queries, glc_lib:onoutput(Query) =:= output] of [] -> {union, Queries};