From e68fde947e540c38366d6888dfd6945efb49a880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20Wei=C3=9F?= Date: Tue, 7 Jun 2011 01:37:20 +0200 Subject: Detect the available CPUs on IRIX Add support for querying the number of configured and online processors on SGI systems running IRIX. --- erts/lib_src/common/erl_misc_utils.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c index 5dbf98c7d1..0871ece0b0 100644 --- a/erts/lib_src/common/erl_misc_utils.c +++ b/erts/lib_src/common/erl_misc_utils.c @@ -55,6 +55,12 @@ # ifdef HAVE_UNISTD_H # include # endif +# if defined(_SC_NPROC_CONF) && !defined(_SC_NPROCESSORS_CONF) +# define _SC_NPROCESSORS_CONF _SC_NPROC_CONF +# endif +# if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN) +# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN +# endif # if (defined(NO_SYSCONF) || !defined(_SC_NPROCESSORS_CONF)) # ifdef HAVE_SYS_SYSCTL_H # include -- cgit v1.2.3 From 9cf9cde066d26569178f5f67600278ae67e102dd Mon Sep 17 00:00:00 2001 From: Michael Santos Date: Mon, 6 Jun 2011 10:55:19 -0400 Subject: ei: integer overflow in string/atom encoding ei_encode_atom() and ei_encode_string() use strlen() to get the length of the buffer. As strlen() returns an unsigned long long and both ei functions take a signed integer, the length fields may overflow. Check the results of strlen can be held in a signed integer. --- lib/erl_interface/src/encode/encode_atom.c | 6 +++++- lib/erl_interface/src/encode/encode_string.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/erl_interface/src/encode/encode_atom.c b/lib/erl_interface/src/encode/encode_atom.c index 69f2d1451c..b1a4479034 100644 --- a/lib/erl_interface/src/encode/encode_atom.c +++ b/lib/erl_interface/src/encode/encode_atom.c @@ -17,13 +17,17 @@ * %CopyrightEnd% */ #include +#include #include "eidef.h" #include "eiext.h" #include "putget.h" int ei_encode_atom(char *buf, int *index, const char *p) { - return ei_encode_atom_len(buf, index, p, strlen(p)); + size_t len = strlen(p); + + if (len >= INT_MAX) return -1; + return ei_encode_atom_len(buf, index, p, len); } int ei_encode_atom_len(char *buf, int *index, const char *p, int len) diff --git a/lib/erl_interface/src/encode/encode_string.c b/lib/erl_interface/src/encode/encode_string.c index 1d342cb605..593bbf2b6d 100644 --- a/lib/erl_interface/src/encode/encode_string.c +++ b/lib/erl_interface/src/encode/encode_string.c @@ -17,6 +17,7 @@ * %CopyrightEnd% */ #include +#include #include "eidef.h" #include "eiext.h" #include "putget.h" @@ -24,7 +25,10 @@ int ei_encode_string(char *buf, int *index, const char *p) { - return ei_encode_string_len(buf, index, p, strlen(p)); + size_t len = strlen(p); + + if (len >= INT_MAX) return -1; + return ei_encode_string_len(buf, index, p, len); } int ei_encode_string_len(char *buf, int *index, const char *p, int len) -- cgit v1.2.3 From 32228c665506b1d84e0758c81fcb9ff3d8f8bef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Holger=20Wei=C3=9F?= Date: Wed, 13 Jul 2011 15:49:04 +0200 Subject: Let epmd ignore empty ERL_EPMD_ADDRESS If the environment variable ERL_EPMD_ADDRESS is set to the empty string, empd now behaves like it does by default when ERL_EPMD_ADDRESS is unset. That is, in this case, epmd now listens on all available interfaces instead of using only the loopback interface, which happened because epmd added the loopback address to the (in this case empty) list of addresses specified via ERL_EPMD_ADDRESS. Also, epmd now ignores ERL_EPMD_ADDRESS if it contains only separator characters (comma and space). The same applies to epmd's -address option. --- erts/epmd/src/epmd_srv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c index 5debae26b6..da575affa1 100644 --- a/erts/epmd/src/epmd_srv.c +++ b/erts/epmd/src/epmd_srv.c @@ -102,7 +102,8 @@ void run(EpmdVars *g) dbg_printf(g,2,"try to initiate listening port %d", g->port); - if (g->addresses != NULL) + if (g->addresses != NULL && /* String contains non-separator characters if: */ + g->addresses[strspn(g->addresses," ,")] != '\000') { char *tmp; char *token; -- cgit v1.2.3 From 52230a417ad005711876132d144b3fe8a72d7e8e Mon Sep 17 00:00:00 2001 From: Dave Cottlehuber Date: Thu, 11 Aug 2011 13:21:16 +1200 Subject: Fix win32 OpenSSL static linking broken in 20c9d6e --- erts/configure.in | 4 ++-- lib/crypto/c_src/Makefile.in | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/erts/configure.in b/erts/configure.in index fac07f8b6a..ffa68cd296 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3722,7 +3722,7 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in SSL_RUNTIME_LIBDIR="$rdir/lib" SSL_LIBDIR="$dir/lib" SSL_CRYPTO_LIBNAME=libeay32 - SSL_CRYPTO_LIBNAME=ssleay32 + SSL_SSL_LIBNAME=ssleay32 elif test -f "$dir/lib/openssl.lib"; then SSL_RUNTIME_LIBDIR="$rdir/lib" SSL_LIBDIR="$dir/lib" @@ -3904,7 +3904,7 @@ dnl so it is - be adoptable elif test -f "$with_ssl/lib/libeay32.lib"; then SSL_LIBDIR="$with_ssl/lib" SSL_CRYPTO_LIBNAME=libeay32 - SSL_CRYPTO_LIBNAME=ssleay32 + SSL_SSL_LIBNAME=ssleay32 else # This probably wont work, but that's what the user said, so... SSL_LIBDIR="$with_ssl/lib" diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index 276c84d601..c2a986c334 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -41,6 +41,7 @@ CFLAGS = $(DED_CFLAGS) SSL_LIBDIR = @SSL_LIBDIR@ SSL_INCLUDE = @SSL_INCLUDE@ SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@ +SSL_SSL_LIBNAME = @SSL_SSL_LIBNAME@ INCLUDES = $(SSL_INCLUDE) $(DED_INCLUDES) @@ -84,7 +85,7 @@ DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@ ifeq ($(DYNAMIC_CRYPTO_LIB),yes) SSL_DED_LD_RUNTIME_LIBRARY_PATH = @SSL_DED_LD_RUNTIME_LIBRARY_PATH@ -CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME) +CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) else SSL_DED_LD_RUNTIME_LIBRARY_PATH= CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a @@ -112,7 +113,7 @@ $(LIBDIR)/crypto$(TYPEMARKER).so: $(OBJS) $(LIBDIR)/crypto$(TYPEMARKER).dll: $(OBJS) $(INSTALL_DIR) $(LIBDIR) - $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -l$(SSL_CRYPTO_LIBNAME) + $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) clean: ifeq ($(findstring win32,$(TARGET)), win32) -- cgit v1.2.3 From 1b2cea397131a36a39b18c6ce8c6944bf11db4c7 Mon Sep 17 00:00:00 2001 From: Filipe David Manana Date: Mon, 16 May 2011 17:00:25 +0100 Subject: Add erlang:external_size/2 BIF This BIF's second parameter is a list of options. Currently the only allowed option is {minor_version, Version} where version is either 0 (default) or 1. --- erts/doc/src/erlang.xml | 50 +++++++++++++++++++++++++++++++++++++ erts/emulator/beam/bif.tab | 2 ++ erts/emulator/beam/external.c | 49 ++++++++++++++++++++++++++++++++++++ erts/emulator/beam/external.h | 1 + erts/emulator/test/binary_SUITE.erl | 16 ++++++++++-- lib/hipe/cerl/erl_bif_types.erl | 3 +++ 6 files changed, 119 insertions(+), 2 deletions(-) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index ad7a57bd73..84d4160e6a 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -1034,6 +1034,56 @@ b exit reason killed.

+ + erlang:external_size(Term) -> integer() >= 0 + Calculate the maximum size for a term encoded in the Erlang + external term format + + Term = term() + + +

Calculates, without doing the encoding, the maximum byte size for + a term encoded in the Erlang external term format. The following + condition applies always:

+

+

+> Size1 = byte_size(term_to_binary(Term)),
+> Size2 = erlang:external_size(Term),
+> true = Size1 =< Size2.
+true
+          
+

+

This is equivalent to a call to: erlang:external_size(Term, []) +

+
+
+ + erlang:external_size(Term, [Option]) -> integer() >= 0 + Calculate the maximum size for a term encoded in the Erlang + external term format + + Term = term() + Option = {minor_version, Version} + + +

Calculates, without doing the encoding, the maximum byte size for + a term encoded in the Erlang external term format. The following + condition applies always:

+

+

+> Size1 = byte_size(term_to_binary(Term, Options)),
+> Size2 = erlang:external_size(Term, Options),
+> true = Size1 =< Size2.
+true
+          
+

+

The option {minor_version, Version} specifies how floats + are encoded. See + term_to_binary/2 for + a more detailed description. +

+
+
float(Number) -> float() Convert a number to a float diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index b171e99e03..831c0b1ce6 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -87,6 +87,8 @@ bif erlang:exit/2 bif 'erl.lang.proc':signal/2 ebif_signal_2 exit_2 bif erlang:external_size/1 bif 'erl.lang.term':external_size/1 ebif_external_size_1 +bif erlang:external_size/2 +bif 'erl.lang.term':external_size/2 ebif_external_size_2 ubif erlang:float/1 ubif 'erl.lang.number':to_float/1 ebif_to_float_1 float_1 bif erlang:float_to_list/1 diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 1a102f7187..6953e7fe7d 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -459,6 +459,12 @@ Uint erts_encode_ext_size(Eterm term) + 1 /* VERSION_MAGIC */; } +Uint erts_encode_ext_size_2(Eterm term, unsigned dflags) +{ + return encode_size_struct2(NULL, term, TERM_TO_BINARY_DFLAGS|dflags) + + 1 /* VERSION_MAGIC */; +} + Uint erts_encode_ext_size_ets(Eterm term) { return encode_size_struct2(NULL, term, TERM_TO_BINARY_DFLAGS|DFLAGS_INTERNAL_TAGS); @@ -1261,6 +1267,49 @@ external_size_1(Process* p, Eterm Term) } } +Eterm +external_size_2(Process* p, Eterm Term, Eterm Flags) +{ + Uint size; + Uint flags = TERM_TO_BINARY_DFLAGS; + + while (is_list(Flags)) { + Eterm arg = CAR(list_val(Flags)); + Eterm* tp; + + if (is_tuple(arg) && *(tp = tuple_val(arg)) == make_arityval(2)) { + if (tp[1] == am_minor_version && is_small(tp[2])) { + switch (signed_val(tp[2])) { + case 0: + break; + case 1: + flags |= DFLAG_NEW_FLOATS; + break; + default: + goto error; + } + } else { + goto error; + } + } else { + error: + BIF_ERROR(p, BADARG); + } + Flags = CDR(list_val(Flags)); + } + if (is_not_nil(Flags)) { + goto error; + } + + size = erts_encode_ext_size_2(Term, flags); + if (IS_USMALL(0, size)) { + BIF_RET(make_small(size)); + } else { + Eterm* hp = HAlloc(p, BIG_UINT_HEAP_SIZE); + BIF_RET(uint_to_big(size, hp)); + } +} + Eterm erts_term_to_binary(Process* p, Eterm Term, int level, Uint flags) { diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h index d8287b96a4..72fe74baf2 100644 --- a/erts/emulator/beam/external.h +++ b/erts/emulator/beam/external.h @@ -160,6 +160,7 @@ Uint erts_encode_dist_ext_size(Eterm, Uint32, ErtsAtomCacheMap *); void erts_encode_dist_ext(Eterm, byte **, Uint32, ErtsAtomCacheMap *); Uint erts_encode_ext_size(Eterm); +Uint erts_encode_ext_size_2(Eterm, unsigned); Uint erts_encode_ext_size_ets(Eterm); void erts_encode_ext(Eterm, byte **); byte* erts_encode_ext_ets(Eterm, byte *, struct erl_off_heap_header** ext_off_heap); diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl index 4e82381fba..fed5854112 100644 --- a/erts/emulator/test/binary_SUITE.erl +++ b/erts/emulator/test/binary_SUITE.erl @@ -478,6 +478,11 @@ terms(Config) when is_list(Config) -> Sz when is_integer(Sz), size(Bin) =< Sz -> ok end, + Bin1 = term_to_binary(Term, [{minor_version, 1}]), + case erlang:external_size(Bin1, [{minor_version, 1}]) of + Sz1 when is_integer(Sz1), size(Bin1) =< Sz1 -> + ok + end, Term = binary_to_term(Bin), Term = binary_to_term(Bin, [safe]), Unaligned = make_unaligned_sub_binary(Bin), @@ -510,7 +515,12 @@ terms_float(Config) when is_list(Config) -> Term = binary_to_term(Bin0), Bin1 = term_to_binary(Term, [{minor_version,1}]), Term = binary_to_term(Bin1), - true = size(Bin1) < size(Bin0) + true = size(Bin1) < size(Bin0), + Size0 = erlang:external_size(Term), + Size00 = erlang:external_size(Term, [{minor_version, 0}]), + Size1 = erlang:external_size(Term, [{minor_version, 1}]), + true = (Size0 =:= Size00), + true = Size1 < Size0 end). external_size(Config) when is_list(Config) -> @@ -526,7 +536,9 @@ external_size(Config) when is_list(Config) -> io:format(" Aligned size: ~p\n", [Sz1]), io:format("Unaligned size: ~p\n", [Sz2]), ?line ?t:fail() - end. + end, + ?line erlang:external_size(Bin) =:= erlang:external_size(Bin, [{minor_version, 1}]), + ?line erlang:external_size(Unaligned) =:= erlang:external_size(Unaligned, [{minor_version, 1}]). external_size_1(Term, Size0, Limit) when Size0 < Limit -> case erlang:external_size(Term) of diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 82e3675938..acc7366d6b 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -739,6 +739,7 @@ type(erlang, element, 2, Xs) -> type(erlang, erase, 0, _) -> t_any(); type(erlang, erase, 1, _) -> t_any(); type(erlang, external_size, 1, _) -> t_integer(); +type(erlang, external_size, 2, _) -> t_integer(); type(erlang, finish_after_on_load, 2, Xs) -> %% Internal BIF used by on_load. strict(arg_types(erlang, finish_after_on_load, 2), Xs, @@ -3446,6 +3447,8 @@ arg_types(erlang, exit, 2) -> [t_sup(t_pid(), t_port()), t_any()]; arg_types(erlang, external_size, 1) -> [t_any()]; % takes any term as input +arg_types(erlang, external_size, 2) -> + [t_any(), t_list()]; % takes any term as input and a list of options arg_types(erlang, finish_after_on_load, 2) -> [t_atom(), t_boolean()]; arg_types(erlang, float, 1) -> -- cgit v1.2.3 From c68f922aed845b43fc8dd9889fb7d78daca7f140 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Wed, 24 Aug 2011 12:44:44 +0300 Subject: Update r9c/{inets,mnesia} results in dialyzer's test suite --- lib/dialyzer/test/r9c_SUITE_data/results/inets | 20 ++++++++++++++------ lib/dialyzer/test/r9c_SUITE_data/results/mnesia | 2 -- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets index 6b16dba2ff..0177dcc88c 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/results/inets +++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets @@ -3,9 +3,14 @@ ftp.erl:1243: The pattern {'ok', {N, Bytes}} can never match the type 'eof' | {' ftp.erl:640: The pattern {'closed', _Why} can never match the type 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'trans_neg_compl' | 'trans_no_space' | {'error' | 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'pos_prel' | 'trans_neg_compl' | 'trans_no_space',atom() | [any()] | {'invalid_server_response',[any(),...]}} http.erl:117: The pattern {'error', Reason} can never match the type #req_headers{connection::[45 | 97 | 101 | 105 | 107 | 108 | 112 | 118,...],content_length::[48,...],other::[{_,_}]} http.erl:138: Function close_session/2 will never be called -http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},any()) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',any()) -http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type any() -http_lib.erl:438: The variable _ can never match since previous clauses completely covered the type any() +http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},port() | {'sslsocket',_,_}) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',port() | {'sslsocket',_,pid() | {_,{'config',_,_,_,_,{_,_,_,_}}} | {'sslsocket',_,pid() | {'sslsocket',_,pid() | {_,_,_}}}}) +http_lib.erl:415: The pattern 61 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} +http_lib.erl:417: The pattern 59 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} +http_lib.erl:420: The pattern 13 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} +http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} +http_lib.erl:428: Function read_chunk_ext_val/6 will never be called +http_lib.erl:444: The pattern 10 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()} +http_lib.erl:552: Call to missing or unexported function ssl:accept/2 http_lib.erl:99: Function getHeaderValue/2 will never be called httpc_handler.erl:660: Function exit_session_ok/2 has no local return httpc_manager.erl:145: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}} @@ -21,11 +26,14 @@ httpd_manager.erl:885: The pattern {'EXIT', Reason} can never match since previo httpd_manager.erl:919: Function auth_status/1 will never be called httpd_manager.erl:926: Function sec_status/1 will never be called httpd_manager.erl:933: Function acceptor_status/1 will never be called -httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) -httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) -httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) +httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) +httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) +httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any()) +httpd_request_handler.erl:489: The variable Other can never match since previous clauses completely covered the type {'error',_} | {'ok','http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | {'http_request','DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),'*' | binary() | string() | {'abs_path',binary() | [any()]} | {'scheme',binary() | [any()],binary() | [any()]} | {'absoluteURI','http' | 'https',binary() | [any()],'undefined' | non_neg_integer(),binary() | [any()]},{non_neg_integer(),non_neg_integer()}} | {'http_response',{non_neg_integer(),non_neg_integer()},integer(),binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}} httpd_request_handler.erl:644: The call lists:reverse(Fields0::{'error',_} | {'ok',_}) will never return since it differs in the 1st argument from the success typing arguments: ([any()]) httpd_request_handler.erl:645: Function will never be called +httpd_socket.erl:129: Call to missing or unexported function ssl:accept/2 +httpd_socket.erl:49: The pattern {'ok', _} can never match the type {'error',_} httpd_sup.erl:63: The variable Else can never match since previous clauses completely covered the type {'error',_} | {'ok',[any()],_,_} httpd_sup.erl:88: The pattern {'error', Reason} can never match the type {'ok',_,_} httpd_sup.erl:92: The variable Else can never match since previous clauses completely covered the type {'ok',_,_} diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia index b0f4d12ae5..2be71ac7d7 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia +++ b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia @@ -6,8 +6,6 @@ mnesia_bup.erl:111: The created fun has no local return mnesia_bup.erl:574: Function fallback_receiver/2 has no local return mnesia_bup.erl:967: Function uninstall_fallback_master/2 has no local return mnesia_checkpoint.erl:1014: The variable Error can never match since previous clauses completely covered the type {'ok',#checkpoint_args{nodes::[any()],retainers::[any(),...]}} -mnesia_checkpoint.erl:1209: Function system_continue/3 has no local return -mnesia_checkpoint.erl:792: Function retainer_loop/1 has no local return mnesia_checkpoint.erl:894: The call sys:handle_system_msg(Msg::any(),From::any(),'no_parent','mnesia_checkpoint',[],Cp::#checkpoint_args{}) breaks the contract (Msg,From,Parent,Module,Debug,Misc) -> Void when is_subtype(Msg,term()), is_subtype(From,{pid(),Tag::_}), is_subtype(Parent,pid()), is_subtype(Module,module()), is_subtype(Debug,[dbg_opt()]), is_subtype(Misc,term()), is_subtype(Void,term()) mnesia_controller.erl:1666: The variable Tab can never match since previous clauses completely covered the type [any()] mnesia_controller.erl:1679: The pattern {'stop', Reason, Reply, State2} can never match the type {'noreply',_} | {'reply',_,_} | {'stop','shutdown',#state{}} -- cgit v1.2.3 From ae96591f1110cd8dae0aa628ecf74f8f81676e3d Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Mon, 2 May 2011 14:48:54 +0300 Subject: Minor fix in dead code --- lib/dialyzer/src/dialyzer_dataflow.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 8cb16d8f09..2b70c372de 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -528,7 +528,7 @@ handle_apply(Tree, Map, State) -> {CallSitesKnown, FunList} = case state__lookup_call_site(Tree, State2) of error -> {false, []}; - {ok, [external]} -> {false, {}}; + {ok, [external]} -> {false, []}; {ok, List} -> {true, List} end, case CallSitesKnown of -- cgit v1.2.3 From 25b2e4850a231ac868c966f8ef3c2fbfe2f7dfde Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Mon, 2 May 2011 15:14:14 +0300 Subject: Fix infinite loop in dataflow --- lib/dialyzer/src/dialyzer_dataflow.erl | 8 +- .../test/small_SUITE_data/results/common_eunit | 2 + .../test/small_SUITE_data/src/common_eunit.erl | 121 +++++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 lib/dialyzer/test/small_SUITE_data/results/common_eunit create mode 100644 lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 2b70c372de..df411342cb 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -554,7 +554,13 @@ handle_apply(Tree, Map, State) -> {State3, enter_type(Op, OpType1, Map2), t_none()}; false -> Map3 = enter_type_lists(Args, NewArgs, Map2), - {State2, enter_type(Op, OpType1, Map3), t_fun_range(OpType1)} + Range0 = t_fun_range(OpType1), + Range = + case t_is_unit(Range0) of + true -> t_none(); + false -> Range0 + end, + {State2, enter_type(Op, OpType1, Map3), Range} end end; true -> diff --git a/lib/dialyzer/test/small_SUITE_data/results/common_eunit b/lib/dialyzer/test/small_SUITE_data/results/common_eunit new file mode 100644 index 0000000000..bb5fd1c9ac --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/common_eunit @@ -0,0 +1,2 @@ + +common_eunit.erl:57: The created fun has no local return diff --git a/lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl b/lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl new file mode 100644 index 0000000000..bca390068e --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl @@ -0,0 +1,121 @@ +%%===================================================================== +%% Program with an erroneous type declaration that caused dialyzer to +%% go into an infinite loop. There are some comments that explain the +%% symptoms and the culprit: the return of test_fun() is erroneous and +%% its type should read +%% fun((config()) -> test_rep() | [test_rep()]) +%% instead. But this should not throw dialyzer into an infinite loop. +%% This concerned dialyzer in R14B02 (and probably prior). +%%===================================================================== +-module(common_eunit). + +-export([expand_cases/2]). + +-type test_name() :: atom() | {'group', atom()}. + +-type test_rep() :: {{atom(), atom(), arity()}, fun()} + | {'setup', fun(), fun()} + | {'setup', fun(), fun(), fun()} + | {atom(), test_rep()} + | {atom(), term(), test_rep()}. + +-type config() :: [proplists:property()]. + +-type control() :: tuple() | atom(). + +%% The combination of the following type and the (erroneous) spec for +%% expand_cases/2 is the reason for the infinite loop in dialyzer. +-type test_fun() :: fun((config()) -> test_rep()). + +%% If one comments out this spec the infinite loop disappears. +-spec expand_cases(atom(), test_name() | [test_name()]) -> test_fun(). +expand_cases(Module, Cases) -> + if is_list(Cases) -> + TestFuns = [expand_case(Module, Case) || Case <- Cases], + fun(Config) -> [F(Config) || F <- TestFuns] end; + is_atom(Cases); is_tuple(Cases) -> + expand_cases(Module, [Cases]) + end. + +-spec expand_case(atom(), test_name()) -> test_fun(). +expand_case(Module, CaseName) when is_atom(CaseName) -> + TestFun = fun(Config) -> + {{Module, CaseName, 1}, + fun() -> apply(Module, CaseName, [Config]) end} + end, + setup_wrapper(Module, TestFun, {init_per_testcase, [CaseName]}, + {end_per_testcase, [CaseName]}); +expand_case(Module, {group, GroupName}) -> + {Control, Cases} = group_specification(Module, GroupName), + TestFun = control_wrapper(Control, expand_cases(Module, Cases)), + setup_wrapper(Module, TestFun, {init_per_group, [GroupName]}, + {end_per_group, [GroupName]}). + +-spec control_wrapper([control()], test_fun()) -> test_fun(). +control_wrapper([Control|T], TestFun0) -> + TestFun1 = control_wrapper(T, TestFun0), + fun(Config) -> + case Control of + parallel -> + {inparallel, TestFun1(Config)}; + sequence -> + {inorder, TestFun1(Config)}; + {timetrap, Time} -> + Seconds = case Time of + {hours, Hs} -> Hs * 60 * 60; + {minutes, Ms} -> Ms * 60; + {seconds, Ss} -> Ss; + MSs -> MSs / 1000 + end, + {timeout, Seconds, TestFun1(Config)}; + C when is_atom(C) -> + {C, TestFun1(Config)}; + {C, Arg} -> + {C, Arg, TestFun1(Config)} + end + end; +control_wrapper([], TestFun) -> + TestFun. + +-spec setup_wrapper(atom(), test_fun(), Callback, Callback) -> test_fun() + when Callback :: {atom(), list()}. +setup_wrapper(Module, TestFun, {Setup, SA}, {Cleanup, CA}) -> + case erlang:function_exported(Module, Setup, length(SA) + 1) of + true -> + case erlang:function_exported(Module, Cleanup, length(CA) + 1) of + true -> + fun(Config0) -> + {setup, + fun() -> + apply(Module, Setup, SA ++ [Config0]) + end, + fun(Config1) -> + apply(Module, Cleanup, CA ++ [Config1]) + end, + TestFun} + end; + false -> + fun(Config) -> + {setup, + fun() -> + apply(Module, Setup, SA ++ [Config]) + end, + TestFun} + end + end; + false -> + TestFun + end. + +-spec group_specification(atom(), atom()) -> {[control()], [test_name()]}. +group_specification(Module, GroupName) -> + case lists:keyfind(GroupName, 1, Module:groups()) of + {_, Control, Cases} when is_list(Control), is_list(Cases) -> + {Control, Cases}; + {_, Cases} when is_list(Cases) -> + {[], Cases}; + false -> + exit({missing_group, GroupName}); + _ -> + exit({bad_group_spec, GroupName}) + end. -- cgit v1.2.3 From e7f7a3052096286a3df0b6c2217a9fe3248be7f4 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Thu, 21 Jul 2011 00:29:58 +0200 Subject: Enhance Dialyzer's inference on comparisons This patch makes Dialyzer aware of Erlang's total ordering of terms, enabling discrepancy detection in cases where e.g. integer() < tuple() is treated as a comparison that might also return false (when it is certain to always return true). --- .../test/small_SUITE_data/results/comparisons | 153 ++++++++++ .../test/small_SUITE_data/src/comparisons.erl | 322 +++++++++++++++++++++ lib/hipe/cerl/erl_bif_types.erl | 52 +++- 3 files changed, 523 insertions(+), 4 deletions(-) create mode 100644 lib/dialyzer/test/small_SUITE_data/results/comparisons create mode 100644 lib/dialyzer/test/small_SUITE_data/src/comparisons.erl diff --git a/lib/dialyzer/test/small_SUITE_data/results/comparisons b/lib/dialyzer/test/small_SUITE_data/results/comparisons new file mode 100644 index 0000000000..642585d25e --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/comparisons @@ -0,0 +1,153 @@ + +comparisons.erl:100: The pattern 'true' can never match the type 'false' +comparisons.erl:101: The pattern 'true' can never match the type 'false' +comparisons.erl:102: The pattern 'false' can never match the type 'true' +comparisons.erl:103: The pattern 'false' can never match the type 'true' +comparisons.erl:104: The pattern 'true' can never match the type 'false' +comparisons.erl:105: The pattern 'true' can never match the type 'false' +comparisons.erl:107: The pattern 'true' can never match the type 'false' +comparisons.erl:108: The pattern 'true' can never match the type 'false' +comparisons.erl:109: The pattern 'false' can never match the type 'true' +comparisons.erl:110: The pattern 'false' can never match the type 'true' +comparisons.erl:111: The pattern 'true' can never match the type 'false' +comparisons.erl:112: The pattern 'true' can never match the type 'false' +comparisons.erl:113: The pattern 'false' can never match the type 'true' +comparisons.erl:114: The pattern 'false' can never match the type 'true' +comparisons.erl:115: The pattern 'true' can never match the type 'false' +comparisons.erl:116: The pattern 'true' can never match the type 'false' +comparisons.erl:117: The pattern 'false' can never match the type 'true' +comparisons.erl:118: The pattern 'false' can never match the type 'true' +comparisons.erl:123: The pattern 'false' can never match the type 'true' +comparisons.erl:124: The pattern 'false' can never match the type 'true' +comparisons.erl:125: The pattern 'true' can never match the type 'false' +comparisons.erl:126: The pattern 'true' can never match the type 'false' +comparisons.erl:127: The pattern 'false' can never match the type 'true' +comparisons.erl:128: The pattern 'false' can never match the type 'true' +comparisons.erl:129: The pattern 'true' can never match the type 'false' +comparisons.erl:130: The pattern 'true' can never match the type 'false' +comparisons.erl:132: The pattern 'true' can never match the type 'false' +comparisons.erl:133: The pattern 'true' can never match the type 'false' +comparisons.erl:134: The pattern 'false' can never match the type 'true' +comparisons.erl:135: The pattern 'false' can never match the type 'true' +comparisons.erl:136: The pattern 'true' can never match the type 'false' +comparisons.erl:137: The pattern 'true' can never match the type 'false' +comparisons.erl:138: The pattern 'false' can never match the type 'true' +comparisons.erl:139: The pattern 'false' can never match the type 'true' +comparisons.erl:140: The pattern 'true' can never match the type 'false' +comparisons.erl:141: The pattern 'true' can never match the type 'false' +comparisons.erl:142: The pattern 'false' can never match the type 'true' +comparisons.erl:143: The pattern 'false' can never match the type 'true' +comparisons.erl:144: The pattern 'true' can never match the type 'false' +comparisons.erl:145: The pattern 'true' can never match the type 'false' +comparisons.erl:146: The pattern 'false' can never match the type 'true' +comparisons.erl:147: The pattern 'false' can never match the type 'true' +comparisons.erl:152: The pattern 'false' can never match the type 'true' +comparisons.erl:153: The pattern 'false' can never match the type 'true' +comparisons.erl:154: The pattern 'true' can never match the type 'false' +comparisons.erl:155: The pattern 'true' can never match the type 'false' +comparisons.erl:157: The pattern 'true' can never match the type 'false' +comparisons.erl:158: The pattern 'true' can never match the type 'false' +comparisons.erl:159: The pattern 'false' can never match the type 'true' +comparisons.erl:160: The pattern 'false' can never match the type 'true' +comparisons.erl:161: The pattern 'true' can never match the type 'false' +comparisons.erl:162: The pattern 'true' can never match the type 'false' +comparisons.erl:163: The pattern 'false' can never match the type 'true' +comparisons.erl:164: The pattern 'false' can never match the type 'true' +comparisons.erl:165: The pattern 'true' can never match the type 'false' +comparisons.erl:166: The pattern 'true' can never match the type 'false' +comparisons.erl:167: The pattern 'false' can never match the type 'true' +comparisons.erl:168: The pattern 'false' can never match the type 'true' +comparisons.erl:169: The pattern 'true' can never match the type 'false' +comparisons.erl:170: The pattern 'true' can never match the type 'false' +comparisons.erl:171: The pattern 'false' can never match the type 'true' +comparisons.erl:172: The pattern 'false' can never match the type 'true' +comparisons.erl:173: The pattern 'true' can never match the type 'false' +comparisons.erl:174: The pattern 'true' can never match the type 'false' +comparisons.erl:175: The pattern 'false' can never match the type 'true' +comparisons.erl:176: The pattern 'false' can never match the type 'true' +comparisons.erl:186: The pattern 'false' can never match the type 'true' +comparisons.erl:187: The pattern 'false' can never match the type 'true' +comparisons.erl:188: The pattern 'true' can never match the type 'false' +comparisons.erl:189: The pattern 'true' can never match the type 'false' +comparisons.erl:190: The pattern 'false' can never match the type 'true' +comparisons.erl:191: The pattern 'false' can never match the type 'true' +comparisons.erl:192: The pattern 'true' can never match the type 'false' +comparisons.erl:193: The pattern 'true' can never match the type 'false' +comparisons.erl:203: The pattern 'false' can never match the type 'true' +comparisons.erl:204: The pattern 'false' can never match the type 'true' +comparisons.erl:205: The pattern 'true' can never match the type 'false' +comparisons.erl:206: The pattern 'true' can never match the type 'false' +comparisons.erl:208: The pattern 'true' can never match the type 'false' +comparisons.erl:209: The pattern 'true' can never match the type 'false' +comparisons.erl:210: The pattern 'false' can never match the type 'true' +comparisons.erl:211: The pattern 'false' can never match the type 'true' +comparisons.erl:221: The pattern 'true' can never match the type 'false' +comparisons.erl:222: The pattern 'true' can never match the type 'false' +comparisons.erl:223: The pattern 'false' can never match the type 'true' +comparisons.erl:224: The pattern 'false' can never match the type 'true' +comparisons.erl:225: The pattern 'true' can never match the type 'false' +comparisons.erl:226: The pattern 'true' can never match the type 'false' +comparisons.erl:227: The pattern 'false' can never match the type 'true' +comparisons.erl:228: The pattern 'false' can never match the type 'true' +comparisons.erl:242: The pattern 'false' can never match the type 'true' +comparisons.erl:243: The pattern 'false' can never match the type 'true' +comparisons.erl:244: The pattern 'true' can never match the type 'false' +comparisons.erl:245: The pattern 'true' can never match the type 'false' +comparisons.erl:246: The pattern 'false' can never match the type 'true' +comparisons.erl:247: The pattern 'false' can never match the type 'true' +comparisons.erl:248: The pattern 'true' can never match the type 'false' +comparisons.erl:249: The pattern 'true' can never match the type 'false' +comparisons.erl:251: The pattern 'true' can never match the type 'false' +comparisons.erl:252: The pattern 'true' can never match the type 'false' +comparisons.erl:253: The pattern 'false' can never match the type 'true' +comparisons.erl:254: The pattern 'false' can never match the type 'true' +comparisons.erl:263: The pattern 'false' can never match the type 'true' +comparisons.erl:264: The pattern 'false' can never match the type 'true' +comparisons.erl:265: The pattern 'true' can never match the type 'false' +comparisons.erl:266: The pattern 'true' can never match the type 'false' +comparisons.erl:268: The pattern 'true' can never match the type 'false' +comparisons.erl:269: The pattern 'true' can never match the type 'false' +comparisons.erl:270: The pattern 'false' can never match the type 'true' +comparisons.erl:271: The pattern 'false' can never match the type 'true' +comparisons.erl:272: The pattern 'true' can never match the type 'false' +comparisons.erl:273: The pattern 'true' can never match the type 'false' +comparisons.erl:274: The pattern 'false' can never match the type 'true' +comparisons.erl:275: The pattern 'false' can never match the type 'true' +comparisons.erl:293: The pattern 'false' can never match the type 'true' +comparisons.erl:294: The pattern 'false' can never match the type 'true' +comparisons.erl:295: The pattern 'true' can never match the type 'false' +comparisons.erl:296: The pattern 'true' can never match the type 'false' +comparisons.erl:311: The pattern 'true' can never match the type 'false' +comparisons.erl:312: The pattern 'true' can never match the type 'false' +comparisons.erl:313: The pattern 'false' can never match the type 'true' +comparisons.erl:314: The pattern 'false' can never match the type 'true' +comparisons.erl:44: The pattern 'false' can never match the type 'true' +comparisons.erl:45: The pattern 'false' can never match the type 'true' +comparisons.erl:46: The pattern 'true' can never match the type 'false' +comparisons.erl:47: The pattern 'true' can never match the type 'false' +comparisons.erl:48: The pattern 'false' can never match the type 'true' +comparisons.erl:49: The pattern 'false' can never match the type 'true' +comparisons.erl:50: The pattern 'true' can never match the type 'false' +comparisons.erl:51: The pattern 'true' can never match the type 'false' +comparisons.erl:52: The pattern 'false' can never match the type 'true' +comparisons.erl:53: The pattern 'false' can never match the type 'true' +comparisons.erl:54: The pattern 'true' can never match the type 'false' +comparisons.erl:55: The pattern 'true' can never match the type 'false' +comparisons.erl:69: The pattern 'false' can never match the type 'true' +comparisons.erl:70: The pattern 'false' can never match the type 'true' +comparisons.erl:71: The pattern 'true' can never match the type 'false' +comparisons.erl:72: The pattern 'true' can never match the type 'false' +comparisons.erl:73: The pattern 'false' can never match the type 'true' +comparisons.erl:74: The pattern 'false' can never match the type 'true' +comparisons.erl:75: The pattern 'true' can never match the type 'false' +comparisons.erl:76: The pattern 'true' can never match the type 'false' +comparisons.erl:77: The pattern 'false' can never match the type 'true' +comparisons.erl:78: The pattern 'false' can never match the type 'true' +comparisons.erl:79: The pattern 'true' can never match the type 'false' +comparisons.erl:80: The pattern 'true' can never match the type 'false' +comparisons.erl:94: The pattern 'false' can never match the type 'true' +comparisons.erl:95: The pattern 'false' can never match the type 'true' +comparisons.erl:96: The pattern 'true' can never match the type 'false' +comparisons.erl:97: The pattern 'true' can never match the type 'false' +comparisons.erl:98: The pattern 'false' can never match the type 'true' +comparisons.erl:99: The pattern 'false' can never match the type 'true' diff --git a/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl b/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl new file mode 100644 index 0000000000..70e3cb6af4 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl @@ -0,0 +1,322 @@ +-module(comparisons). + +-compile(export_all). + +-define(r, get(r)). + +integer() -> integer(?r). +integer(X) when is_integer(X) -> X. + +mfloat() -> float(?r). +mfloat(X) when is_float(X) -> X. + +atom() -> atom(?r). +atom(X) when is_atom(X) -> X. + +tuple() -> tuple(?r). +tuple(X) when is_tuple(X) -> X. + +list() -> list(?r). +list(X) when is_list(X) -> X. + +i() -> integer(). +f() -> mfloat(). +n() -> case ?r of 1 -> i(); 2 -> f() end. +a() -> atom(). +t() -> tuple(). +l() -> list(). +na() -> case ?r of 1 -> n(); 2 -> a() end. +at() -> case ?r of 1 -> t(); 2 -> a() end. +tl() -> case ?r of 1 -> t(); 2 -> l() end. + +test_i_ll_i() -> case i() < i() of true -> maybe; false -> maybe_too end. +test_i_le_i() -> case i() =< i() of true -> maybe; false -> maybe_too end. +test_i_gg_i() -> case i() > i() of true -> maybe; false -> maybe_too end. +test_i_ge_i() -> case i() >= i() of true -> maybe; false -> maybe_too end. +test_i_ll_f() -> case i() < f() of true -> maybe; false -> maybe_too end. +test_i_le_f() -> case i() =< f() of true -> maybe; false -> maybe_too end. +test_i_gg_f() -> case i() > f() of true -> maybe; false -> maybe_too end. +test_i_ge_f() -> case i() >= f() of true -> maybe; false -> maybe_too end. +test_i_ll_n() -> case i() < n() of true -> maybe; false -> maybe_too end. +test_i_le_n() -> case i() =< n() of true -> maybe; false -> maybe_too end. +test_i_gg_n() -> case i() > n() of true -> maybe; false -> maybe_too end. +test_i_ge_n() -> case i() >= n() of true -> maybe; false -> maybe_too end. +test_i_ll_a() -> case i() < a() of true -> always; false -> never end. +test_i_le_a() -> case i() =< a() of true -> always; false -> never end. +test_i_gg_a() -> case i() > a() of true -> never; false -> always end. +test_i_ge_a() -> case i() >= a() of true -> never; false -> always end. +test_i_ll_t() -> case i() < t() of true -> always; false -> never end. +test_i_le_t() -> case i() =< t() of true -> always; false -> never end. +test_i_gg_t() -> case i() > t() of true -> never; false -> always end. +test_i_ge_t() -> case i() >= t() of true -> never; false -> always end. +test_i_ll_l() -> case i() < l() of true -> always; false -> never end. +test_i_le_l() -> case i() =< l() of true -> always; false -> never end. +test_i_gg_l() -> case i() > l() of true -> never; false -> always end. +test_i_ge_l() -> case i() >= l() of true -> never; false -> always end. + +test_f_ll_i() -> case f() < i() of true -> maybe; false -> maybe_too end. +test_f_le_i() -> case f() =< i() of true -> maybe; false -> maybe_too end. +test_f_gg_i() -> case f() > i() of true -> maybe; false -> maybe_too end. +test_f_ge_i() -> case f() >= i() of true -> maybe; false -> maybe_too end. +test_f_ll_f() -> case f() < f() of true -> maybe; false -> maybe_too end. +test_f_le_f() -> case f() =< f() of true -> maybe; false -> maybe_too end. +test_f_gg_f() -> case f() > f() of true -> maybe; false -> maybe_too end. +test_f_ge_f() -> case f() >= f() of true -> maybe; false -> maybe_too end. +test_f_ll_n() -> case f() < n() of true -> maybe; false -> maybe_too end. +test_f_le_n() -> case f() =< n() of true -> maybe; false -> maybe_too end. +test_f_gg_n() -> case f() > n() of true -> maybe; false -> maybe_too end. +test_f_ge_n() -> case f() >= n() of true -> maybe; false -> maybe_too end. +test_f_ll_a() -> case f() < a() of true -> always; false -> never end. +test_f_le_a() -> case f() =< a() of true -> always; false -> never end. +test_f_gg_a() -> case f() > a() of true -> never; false -> always end. +test_f_ge_a() -> case f() >= a() of true -> never; false -> always end. +test_f_ll_t() -> case f() < t() of true -> always; false -> never end. +test_f_le_t() -> case f() =< t() of true -> always; false -> never end. +test_f_gg_t() -> case f() > t() of true -> never; false -> always end. +test_f_ge_t() -> case f() >= t() of true -> never; false -> always end. +test_f_ll_l() -> case f() < l() of true -> always; false -> never end. +test_f_le_l() -> case f() =< l() of true -> always; false -> never end. +test_f_gg_l() -> case f() > l() of true -> never; false -> always end. +test_f_ge_l() -> case f() >= l() of true -> never; false -> always end. + +test_n_ll_i() -> case n() < i() of true -> maybe; false -> maybe_too end. +test_n_le_i() -> case n() =< i() of true -> maybe; false -> maybe_too end. +test_n_gg_i() -> case n() > i() of true -> maybe; false -> maybe_too end. +test_n_ge_i() -> case n() >= i() of true -> maybe; false -> maybe_too end. +test_n_ll_f() -> case n() < f() of true -> maybe; false -> maybe_too end. +test_n_le_f() -> case n() =< f() of true -> maybe; false -> maybe_too end. +test_n_gg_f() -> case n() > f() of true -> maybe; false -> maybe_too end. +test_n_ge_f() -> case n() >= f() of true -> maybe; false -> maybe_too end. +test_n_ll_n() -> case n() < n() of true -> maybe; false -> maybe_too end. +test_n_le_n() -> case n() =< n() of true -> maybe; false -> maybe_too end. +test_n_gg_n() -> case n() > n() of true -> maybe; false -> maybe_too end. +test_n_ge_n() -> case n() >= n() of true -> maybe; false -> maybe_too end. +test_n_ll_a() -> case n() < a() of true -> always; false -> never end. +test_n_le_a() -> case n() =< a() of true -> always; false -> never end. +test_n_gg_a() -> case n() > a() of true -> never; false -> always end. +test_n_ge_a() -> case n() >= a() of true -> never; false -> always end. +test_n_ll_t() -> case n() < t() of true -> always; false -> never end. +test_n_le_t() -> case n() =< t() of true -> always; false -> never end. +test_n_gg_t() -> case n() > t() of true -> never; false -> always end. +test_n_ge_t() -> case n() >= t() of true -> never; false -> always end. +test_n_ll_l() -> case n() < l() of true -> always; false -> never end. +test_n_le_l() -> case n() =< l() of true -> always; false -> never end. +test_n_gg_l() -> case n() > l() of true -> never; false -> always end. +test_n_ge_l() -> case n() >= l() of true -> never; false -> always end. + +test_a_ll_i() -> case a() < i() of true -> never; false -> always end. +test_a_le_i() -> case a() =< i() of true -> never; false -> always end. +test_a_gg_i() -> case a() > i() of true -> always; false -> never end. +test_a_ge_i() -> case a() >= i() of true -> always; false -> never end. +test_a_ll_f() -> case a() < f() of true -> never; false -> always end. +test_a_le_f() -> case a() =< f() of true -> never; false -> always end. +test_a_gg_f() -> case a() > f() of true -> always; false -> never end. +test_a_ge_f() -> case a() >= f() of true -> always; false -> never end. +test_a_ll_n() -> case a() < n() of true -> never; false -> always end. +test_a_le_n() -> case a() =< n() of true -> never; false -> always end. +test_a_gg_n() -> case a() > n() of true -> always; false -> never end. +test_a_ge_n() -> case a() >= n() of true -> always; false -> never end. +test_a_ll_a() -> case a() < a() of true -> maybe; false -> maybe_too end. +test_a_le_a() -> case a() =< a() of true -> maybe; false -> maybe_too end. +test_a_gg_a() -> case a() > a() of true -> maybe; false -> maybe_too end. +test_a_ge_a() -> case a() >= a() of true -> maybe; false -> maybe_too end. +test_a_ll_t() -> case a() < t() of true -> always; false -> never end. +test_a_le_t() -> case a() =< t() of true -> always; false -> never end. +test_a_gg_t() -> case a() > t() of true -> never; false -> always end. +test_a_ge_t() -> case a() >= t() of true -> never; false -> always end. +test_a_ll_l() -> case a() < l() of true -> always; false -> never end. +test_a_le_l() -> case a() =< l() of true -> always; false -> never end. +test_a_gg_l() -> case a() > l() of true -> never; false -> always end. +test_a_ge_l() -> case a() >= l() of true -> never; false -> always end. + +test_t_ll_i() -> case t() < i() of true -> never; false -> always end. +test_t_le_i() -> case t() =< i() of true -> never; false -> always end. +test_t_gg_i() -> case t() > i() of true -> always; false -> never end. +test_t_ge_i() -> case t() >= i() of true -> always; false -> never end. +test_t_ll_f() -> case t() < f() of true -> never; false -> always end. +test_t_le_f() -> case t() =< f() of true -> never; false -> always end. +test_t_gg_f() -> case t() > f() of true -> always; false -> never end. +test_t_ge_f() -> case t() >= f() of true -> always; false -> never end. +test_t_ll_n() -> case t() < n() of true -> never; false -> always end. +test_t_le_n() -> case t() =< n() of true -> never; false -> always end. +test_t_gg_n() -> case t() > n() of true -> always; false -> never end. +test_t_ge_n() -> case t() >= n() of true -> always; false -> never end. +test_t_ll_a() -> case t() < a() of true -> never; false -> always end. +test_t_le_a() -> case t() =< a() of true -> never; false -> always end. +test_t_gg_a() -> case t() > a() of true -> always; false -> never end. +test_t_ge_a() -> case t() >= a() of true -> always; false -> never end. +test_t_ll_t() -> case t() < t() of true -> maybe; false -> maybe_too end. +test_t_le_t() -> case t() =< t() of true -> maybe; false -> maybe_too end. +test_t_gg_t() -> case t() > t() of true -> maybe; false -> maybe_too end. +test_t_ge_t() -> case t() >= t() of true -> maybe; false -> maybe_too end. +test_t_ll_l() -> case t() < l() of true -> always; false -> never end. +test_t_le_l() -> case t() =< l() of true -> always; false -> never end. +test_t_gg_l() -> case t() > l() of true -> never; false -> always end. +test_t_ge_l() -> case t() >= l() of true -> never; false -> always end. + +test_l_ll_i() -> case l() < i() of true -> never; false -> always end. +test_l_le_i() -> case l() =< i() of true -> never; false -> always end. +test_l_gg_i() -> case l() > i() of true -> always; false -> never end. +test_l_ge_i() -> case l() >= i() of true -> always; false -> never end. +test_l_ll_f() -> case l() < f() of true -> never; false -> always end. +test_l_le_f() -> case l() =< f() of true -> never; false -> always end. +test_l_gg_f() -> case l() > f() of true -> always; false -> never end. +test_l_ge_f() -> case l() >= f() of true -> always; false -> never end. +test_l_ll_n() -> case l() < n() of true -> never; false -> always end. +test_l_le_n() -> case l() =< n() of true -> never; false -> always end. +test_l_gg_n() -> case l() > n() of true -> always; false -> never end. +test_l_ge_n() -> case l() >= n() of true -> always; false -> never end. +test_l_ll_a() -> case l() < a() of true -> never; false -> always end. +test_l_le_a() -> case l() =< a() of true -> never; false -> always end. +test_l_gg_a() -> case l() > a() of true -> always; false -> never end. +test_l_ge_a() -> case l() >= a() of true -> always; false -> never end. +test_l_ll_t() -> case l() < t() of true -> never; false -> always end. +test_l_le_t() -> case l() =< t() of true -> never; false -> always end. +test_l_gg_t() -> case l() > t() of true -> always; false -> never end. +test_l_ge_t() -> case l() >= t() of true -> always; false -> never end. +test_l_ll_l() -> case l() < l() of true -> maybe; false -> maybe_too end. +test_l_le_l() -> case l() =< l() of true -> maybe; false -> maybe_too end. +test_l_gg_l() -> case l() > l() of true -> maybe; false -> maybe_too end. +test_l_ge_l() -> case l() >= l() of true -> maybe; false -> maybe_too end. + +test_n_ll_na() -> case n() < na() of true -> maybe; false -> maybe_too end. +test_n_le_na() -> case n() =< na() of true -> maybe; false -> maybe_too end. +test_n_gg_na() -> case n() > na() of true -> maybe; false -> maybe_too end. +test_n_ge_na() -> case n() >= na() of true -> maybe; false -> maybe_too end. +test_n_ll_at() -> case n() < at() of true -> always; false -> never end. +test_n_le_at() -> case n() =< at() of true -> always; false -> never end. +test_n_gg_at() -> case n() > at() of true -> never; false -> always end. +test_n_ge_at() -> case n() >= at() of true -> never; false -> always end. +test_n_ll_tl() -> case n() < tl() of true -> always; false -> never end. +test_n_le_tl() -> case n() =< tl() of true -> always; false -> never end. +test_n_gg_tl() -> case n() > tl() of true -> never; false -> always end. +test_n_ge_tl() -> case n() >= tl() of true -> never; false -> always end. + +test_a_ll_na() -> case a() < na() of true -> maybe; false -> maybe_too end. +test_a_le_na() -> case a() =< na() of true -> maybe; false -> maybe_too end. +test_a_gg_na() -> case a() > na() of true -> maybe; false -> maybe_too end. +test_a_ge_na() -> case a() >= na() of true -> maybe; false -> maybe_too end. +test_a_ll_at() -> case a() < at() of true -> maybe; false -> maybe_too end. +test_a_le_at() -> case a() =< at() of true -> maybe; false -> maybe_too end. +test_a_gg_at() -> case a() > at() of true -> maybe; false -> maybe_too end. +test_a_ge_at() -> case a() >= at() of true -> maybe; false -> maybe_too end. +test_a_ll_tl() -> case a() < tl() of true -> always; false -> never end. +test_a_le_tl() -> case a() =< tl() of true -> always; false -> never end. +test_a_gg_tl() -> case a() > tl() of true -> never; false -> always end. +test_a_ge_tl() -> case a() >= tl() of true -> never; false -> always end. + +test_t_ll_na() -> case t() < na() of true -> never; false -> always end. +test_t_le_na() -> case t() =< na() of true -> never; false -> always end. +test_t_gg_na() -> case t() > na() of true -> always; false -> never end. +test_t_ge_na() -> case t() >= na() of true -> always; false -> never end. +test_t_ll_at() -> case t() < at() of true -> maybe; false -> maybe_too end. +test_t_le_at() -> case t() =< at() of true -> maybe; false -> maybe_too end. +test_t_gg_at() -> case t() > at() of true -> maybe; false -> maybe_too end. +test_t_ge_at() -> case t() >= at() of true -> maybe; false -> maybe_too end. +test_t_ll_tl() -> case t() < tl() of true -> maybe; false -> maybe_too end. +test_t_le_tl() -> case t() =< tl() of true -> maybe; false -> maybe_too end. +test_t_gg_tl() -> case t() > tl() of true -> maybe; false -> maybe_too end. +test_t_ge_tl() -> case t() >= tl() of true -> maybe; false -> maybe_too end. + +test_l_ll_na() -> case l() < na() of true -> never; false -> always end. +test_l_le_na() -> case l() =< na() of true -> never; false -> always end. +test_l_gg_na() -> case l() > na() of true -> always; false -> never end. +test_l_ge_na() -> case l() >= na() of true -> always; false -> never end. +test_l_ll_at() -> case l() < at() of true -> never; false -> always end. +test_l_le_at() -> case l() =< at() of true -> never; false -> always end. +test_l_gg_at() -> case l() > at() of true -> always; false -> never end. +test_l_ge_at() -> case l() >= at() of true -> always; false -> never end. +test_l_ll_tl() -> case l() < tl() of true -> maybe; false -> maybe_too end. +test_l_le_tl() -> case l() =< tl() of true -> maybe; false -> maybe_too end. +test_l_gg_tl() -> case l() > tl() of true -> maybe; false -> maybe_too end. +test_l_ge_tl() -> case l() >= tl() of true -> maybe; false -> maybe_too end. + +test_na_ll_n() -> case na() < n() of true -> maybe; false -> maybe_too end. +test_na_le_n() -> case na() =< n() of true -> maybe; false -> maybe_too end. +test_na_gg_n() -> case na() > n() of true -> maybe; false -> maybe_too end. +test_na_ge_n() -> case na() >= n() of true -> maybe; false -> maybe_too end. +test_na_ll_a() -> case na() < a() of true -> maybe; false -> maybe_too end. +test_na_le_a() -> case na() =< a() of true -> maybe; false -> maybe_too end. +test_na_gg_a() -> case na() > a() of true -> maybe; false -> maybe_too end. +test_na_ge_a() -> case na() >= a() of true -> maybe; false -> maybe_too end. +test_na_ll_t() -> case na() < t() of true -> always; false -> never end. +test_na_le_t() -> case na() =< t() of true -> always; false -> never end. +test_na_gg_t() -> case na() > t() of true -> never; false -> always end. +test_na_ge_t() -> case na() >= t() of true -> never; false -> always end. +test_na_ll_l() -> case na() < l() of true -> always; false -> never end. +test_na_le_l() -> case na() =< l() of true -> always; false -> never end. +test_na_gg_l() -> case na() > l() of true -> never; false -> always end. +test_na_ge_l() -> case na() >= l() of true -> never; false -> always end. + +test_at_ll_n() -> case at() < n() of true -> never; false -> always end. +test_at_le_n() -> case at() =< n() of true -> never; false -> always end. +test_at_gg_n() -> case at() > n() of true -> always; false -> never end. +test_at_ge_n() -> case at() >= n() of true -> always; false -> never end. +test_at_ll_a() -> case at() < a() of true -> maybe; false -> maybe_too end. +test_at_le_a() -> case at() =< a() of true -> maybe; false -> maybe_too end. +test_at_gg_a() -> case at() > a() of true -> maybe; false -> maybe_too end. +test_at_ge_a() -> case at() >= a() of true -> maybe; false -> maybe_too end. +test_at_ll_t() -> case at() < t() of true -> maybe; false -> maybe_too end. +test_at_le_t() -> case at() =< t() of true -> maybe; false -> maybe_too end. +test_at_gg_t() -> case at() > t() of true -> maybe; false -> maybe_too end. +test_at_ge_t() -> case at() >= t() of true -> maybe; false -> maybe_too end. +test_at_ll_l() -> case at() < l() of true -> always; false -> never end. +test_at_le_l() -> case at() =< l() of true -> always; false -> never end. +test_at_gg_l() -> case at() > l() of true -> never; false -> always end. +test_at_ge_l() -> case at() >= l() of true -> never; false -> always end. + +test_tl_ll_n() -> case tl() < n() of true -> never; false -> always end. +test_tl_le_n() -> case tl() =< n() of true -> never; false -> always end. +test_tl_gg_n() -> case tl() > n() of true -> always; false -> never end. +test_tl_ge_n() -> case tl() >= n() of true -> always; false -> never end. +test_tl_ll_a() -> case tl() < a() of true -> never; false -> always end. +test_tl_le_a() -> case tl() =< a() of true -> never; false -> always end. +test_tl_gg_a() -> case tl() > a() of true -> always; false -> never end. +test_tl_ge_a() -> case tl() >= a() of true -> always; false -> never end. +test_tl_ll_t() -> case tl() < t() of true -> maybe; false -> maybe_too end. +test_tl_le_t() -> case tl() =< t() of true -> maybe; false -> maybe_too end. +test_tl_gg_t() -> case tl() > t() of true -> maybe; false -> maybe_too end. +test_tl_ge_t() -> case tl() >= t() of true -> maybe; false -> maybe_too end. +test_tl_ll_l() -> case tl() < l() of true -> maybe; false -> maybe_too end. +test_tl_le_l() -> case tl() =< l() of true -> maybe; false -> maybe_too end. +test_tl_gg_l() -> case tl() > l() of true -> maybe; false -> maybe_too end. +test_tl_ge_l() -> case tl() >= l() of true -> maybe; false -> maybe_too end. + +test_na_ll_na() -> case na() < na() of true -> maybe; false -> maybe_too end. +test_na_le_na() -> case na() =< na() of true -> maybe; false -> maybe_too end. +test_na_gg_na() -> case na() > na() of true -> maybe; false -> maybe_too end. +test_na_ge_na() -> case na() >= na() of true -> maybe; false -> maybe_too end. +test_na_ll_at() -> case na() < at() of true -> maybe; false -> maybe_too end. +test_na_le_at() -> case na() =< at() of true -> maybe; false -> maybe_too end. +test_na_gg_at() -> case na() > at() of true -> maybe; false -> maybe_too end. +test_na_ge_at() -> case na() >= at() of true -> maybe; false -> maybe_too end. +test_na_ll_tl() -> case na() < tl() of true -> always; false -> never end. +test_na_le_tl() -> case na() =< tl() of true -> always; false -> never end. +test_na_gg_tl() -> case na() > tl() of true -> never; false -> always end. +test_na_ge_tl() -> case na() >= tl() of true -> never; false -> always end. + +test_at_ll_na() -> case at() < na() of true -> maybe; false -> maybe_too end. +test_at_le_na() -> case at() =< na() of true -> maybe; false -> maybe_too end. +test_at_gg_na() -> case at() > na() of true -> maybe; false -> maybe_too end. +test_at_ge_na() -> case at() >= na() of true -> maybe; false -> maybe_too end. +test_at_ll_at() -> case at() < at() of true -> maybe; false -> maybe_too end. +test_at_le_at() -> case at() =< at() of true -> maybe; false -> maybe_too end. +test_at_gg_at() -> case at() > at() of true -> maybe; false -> maybe_too end. +test_at_ge_at() -> case at() >= at() of true -> maybe; false -> maybe_too end. +test_at_ll_tl() -> case at() < tl() of true -> maybe; false -> maybe_too end. +test_at_le_tl() -> case at() =< tl() of true -> maybe; false -> maybe_too end. +test_at_gg_tl() -> case at() > tl() of true -> maybe; false -> maybe_too end. +test_at_ge_tl() -> case at() >= tl() of true -> maybe; false -> maybe_too end. + +test_tl_ll_na() -> case tl() < na() of true -> never; false -> always end. +test_tl_le_na() -> case tl() =< na() of true -> never; false -> always end. +test_tl_gg_na() -> case tl() > na() of true -> always; false -> never end. +test_tl_ge_na() -> case tl() >= na() of true -> always; false -> never end. +test_tl_ll_at() -> case tl() < at() of true -> maybe; false -> maybe_too end. +test_tl_le_at() -> case tl() =< at() of true -> maybe; false -> maybe_too end. +test_tl_gg_at() -> case tl() > at() of true -> maybe; false -> maybe_too end. +test_tl_ge_at() -> case tl() >= at() of true -> maybe; false -> maybe_too end. +test_tl_ll_tl() -> case tl() < tl() of true -> maybe; false -> maybe_too end. +test_tl_le_tl() -> case tl() =< tl() of true -> maybe; false -> maybe_too end. +test_tl_gg_tl() -> case tl() > tl() of true -> maybe; false -> maybe_too end. +test_tl_ge_tl() -> case tl() >= tl() of true -> maybe; false -> maybe_too end. diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 82e3675938..cd5d23c50c 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -366,7 +366,7 @@ type(erlang, '>', 2, Xs = [Lhs, Rhs]) -> is_integer(LhsMax), is_integer(RhsMin), RhsMin >= LhsMax -> F; true -> t_boolean() end; - false -> t_boolean() + false -> compare('>', Lhs, Rhs) end, strict(Xs, Ans); type(erlang, '>=', 2, Xs = [Lhs, Rhs]) -> @@ -384,7 +384,7 @@ type(erlang, '>=', 2, Xs = [Lhs, Rhs]) -> is_integer(LhsMax), is_integer(RhsMin), RhsMin > LhsMax -> F; true -> t_boolean() end; - false -> t_boolean() + false -> compare('>=', Lhs, Rhs) end, strict(Xs, Ans); type(erlang, '<', 2, Xs = [Lhs, Rhs]) -> @@ -402,7 +402,7 @@ type(erlang, '<', 2, Xs = [Lhs, Rhs]) -> is_integer(LhsMin), is_integer(RhsMax), RhsMax =< LhsMin -> F; true -> t_boolean() end; - false -> t_boolean() + false -> compare('<', Lhs, Rhs) end, strict(Xs, Ans); type(erlang, '=<', 2, Xs = [Lhs, Rhs]) -> @@ -420,7 +420,7 @@ type(erlang, '=<', 2, Xs = [Lhs, Rhs]) -> is_integer(LhsMin), is_integer(RhsMax), RhsMax < LhsMin -> F; true -> t_boolean() end; - false -> t_boolean() + false -> compare('=<', Lhs, Rhs) end, strict(Xs, Ans); type(erlang, '+', 1, Xs) -> @@ -3177,6 +3177,50 @@ arith(Op, X1, X2) -> end end. +%%============================================================================= +%% Comparison of terms +%%============================================================================= + +compare(Op, Lhs, Rhs) -> + case t_is_none(t_inf(Lhs, Rhs)) of + false -> t_boolean(); + true -> + case Op of + '<' -> always_smaller(Lhs, Rhs); + '>' -> always_smaller(Rhs, Lhs); + '=<' -> always_smaller(Lhs, Rhs); + '>=' -> always_smaller(Rhs, Lhs) + end + end. + +always_smaller(Type1, Type2) -> + {Min1, Max1} = type_ranks(Type1), + {Min2, Max2} = type_ranks(Type2), + if Max1 < Min2 -> t_atom('true'); + Min1 > Max2 -> t_atom('false'); + true -> t_boolean() + end. + +type_ranks(Type) -> + type_ranks(Type, 1, 0, 0, type_order()). + +type_ranks(_Type, _I, Min, Max, []) -> {Min, Max}; +type_ranks(Type, I, Min, Max, [TypeClass|Rest]) -> + {NewMin, NewMax} = + case t_is_none(t_inf(Type, TypeClass)) of + true -> {Min, Max}; + false -> case Min of + 0 -> {I, I}; + _ -> {Min, I} + end + end, + type_ranks(Type, I+1, NewMin, NewMax, Rest). + +type_order() -> + [t_number(), t_atom(), t_reference(), t_fun(), t_port(), t_pid(), t_tuple(), + t_list(), t_binary()]. + + %%============================================================================= -spec arg_types(atom(), atom(), arity()) -> [erl_types:erl_type()] | 'unknown'. -- cgit v1.2.3 From 45537dc582a4fe44a3407e97acb0e1e391fdcd6d Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Sun, 20 Mar 2011 23:43:53 +0200 Subject: Suppress some warnings about generation of non-returning funs No warnings are emitted for funs that are non-returning when the function that generates them has a contract that specifies that it will return such a non-returning fun. The actual bug, reported by Tuncer Ayaz and simplified by Maria Christakis is included in Dialyzer's tests. --- lib/dialyzer/src/dialyzer_dataflow.erl | 29 ++- .../test/small_SUITE_data/results/failing_funs | 20 ++ .../test/small_SUITE_data/src/failing_funs.erl | 250 +++++++++++++++++++++ .../test/small_SUITE_data/src/rebar_no_return.erl | 19 ++ 4 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 lib/dialyzer/test/small_SUITE_data/results/failing_funs create mode 100644 lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl create mode 100644 lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index df411342cb..659297f993 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -2952,7 +2952,7 @@ state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab, %% Check if the function has a contract that allows this. Warn = case Contract of - none -> true; + none -> not parent_allows_this(FunLbl, State); {value, C} -> GenRet = dialyzer_contracts:get_contract_return(C), not t_is_unit(GenRet) @@ -3440,6 +3440,33 @@ map_pats(Pats) -> end, cerl_trees:map(Fun, Pats). +parent_allows_this(FunLbl, #state{callgraph = Callgraph, plt = Plt} =State) -> + case state__is_escaping(FunLbl, State) of + false -> false; % if it isn't escaping it can't be a return value + true -> + case state__lookup_name(FunLbl, State) of + {_M, _F, _A} -> false; % if it has a name it is not a fun + _ -> + case dialyzer_callgraph:in_neighbours(FunLbl, Callgraph) of + [Parent] -> + case state__lookup_name(Parent, State) of + {_M, _F, _A} = PMFA -> + case dialyzer_plt:lookup_contract(Plt, PMFA) of + none -> false; + {value, C} -> + GenRet = dialyzer_contracts:get_contract_return(C), + case erl_types:t_is_fun(GenRet) of + false -> false; % element of structure? far-fetched... + true -> t_is_unit(t_fun_range(GenRet)) + end + end; + _ -> false % parent should have a name to have a contract + end; + _ -> false % called in other funs? far-fetched... + end + end + end. + classify_returns(Tree) -> case find_terminals(cerl:fun_body(Tree)) of {false, false} -> no_match; diff --git a/lib/dialyzer/test/small_SUITE_data/results/failing_funs b/lib/dialyzer/test/small_SUITE_data/results/failing_funs new file mode 100644 index 0000000000..a1fb22cbc6 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/results/failing_funs @@ -0,0 +1,20 @@ + +failing_funs.erl:101: The created fun has no local return +failing_funs.erl:104: The created fun has no local return +failing_funs.erl:127: The created fun has no local return +failing_funs.erl:135: The created fun has no local return +failing_funs.erl:138: The created fun has no local return +failing_funs.erl:13: Function foo3/0 has no local return +failing_funs.erl:13: The pattern 'b' can never match the type 'a' +failing_funs.erl:161: The created fun has no local return +failing_funs.erl:169: The created fun has no local return +failing_funs.erl:172: The created fun has no local return +failing_funs.erl:17: The pattern 'b' can never match the type 'a' +failing_funs.erl:195: The created fun has no local return +failing_funs.erl:203: The created fun has no local return +failing_funs.erl:206: The created fun has no local return +failing_funs.erl:229: The created fun has no local return +failing_funs.erl:55: The created fun has no local return +failing_funs.erl:62: The created fun has no local return +failing_funs.erl:69: The created fun has no local return +failing_funs.erl:76: The created fun has no local return diff --git a/lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl b/lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl new file mode 100644 index 0000000000..1784c4a494 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl @@ -0,0 +1,250 @@ +-module(failing_funs). + +-compile(export_all). + +% Crashes with system call. No spec. +foo1() -> halt(). + +% Crashes with system call. With spec. +-spec foo2() -> no_return(). +foo2() -> halt(). + +% Crashes on its own. No spec. +foo3() -> case a of b -> ok end. + +% Crashes on its own. With spec. +-spec foo4() -> no_return(). +foo4() -> case a of b -> ok end. + +% Creates fun that crashes with system call. No spec. +foo5() -> fun() -> halt() end. + +% Creates fun that crashes with system call. With spec. +-spec foo6() -> fun(() -> no_return()). +foo6() -> fun() -> halt() end. + +% Creates fun from named fun that will crash. Neither have spec. +foo7() -> fun foo1/0. + +% Creates fun from named fun that will crash. Has spec. +-spec foo8() -> fun(() -> no_return()). +foo8() -> fun foo1/0. + +% Creates fun from named fun that will crash. Named has spec. +foo9() -> fun foo2/0. + +% Creates fun from named fun that will crash. Both have specs. +-spec foo10() -> fun(() -> no_return()). +foo10() -> fun foo2/0. + +% Creates fun from named fun that will crash. Neither have spec. +foo11() -> fun foo3/0. + +% Creates fun from named fun that will crash. Has spec. +-spec foo12() -> fun(() -> no_return()). +foo12() -> fun foo3/0. + +% Creates fun from named fun that will crash. Named has spec. +foo13() -> fun foo4/0. + +% Creates fun from named fun that will crash. Both have specs. +-spec foo14() -> fun(() -> no_return()). +foo14() -> fun foo4/0. + +% Creates fun calling a named fun that will crash. Neither have spec. +foo15() -> fun() -> foo1() end. + +% Creates fun calling a named fun that will crash. Has spec. +-spec foo16() -> fun(() -> no_return()). +foo16() -> fun() -> foo1() end. + +% Creates fun calling a named fun that will crash. Named has spec. +foo17() -> fun() -> foo2() end. + +% Creates fun calling a named fun that will crash. Both have specs. +-spec foo18() -> fun(() -> no_return()). +foo18() -> fun() -> foo2() end. + +% Creates fun calling a named fun that will crash. Neither have spec. +foo19() -> fun() -> foo3() end. + +% Creates fun calling a named fun that will crash. Has spec. +-spec foo20() -> fun(() -> no_return()). +foo20() -> fun() -> foo3() end. + +% Creates fun calling a named fun that will crash. Named has spec. +foo21() -> fun() -> foo4() end. + +% Creates fun calling a named fun that will crash. Both have specs. +-spec foo22() -> fun(() -> no_return()). +foo22() -> fun() -> foo4() end. + +% Creates two funs with no local return and will return one or die. No spec. +foo23() -> + Bomb = fun() -> halt() end, + case get(42) of + a -> Bomb(); + b -> fun() -> halt() end + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo24() -> fun(() -> no_return()). +foo24() -> + Bomb = fun() -> halt() end, + case get(42) of + a -> Bomb(); + b -> fun() -> halt() end + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo25() -> + Bomb = fun() -> foo1() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo1() end + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo26() -> fun(() -> no_return()). +foo26() -> + Bomb = fun foo1/0, + case get(42) of + a -> Bomb(); + b -> fun foo1/0 + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo27() -> + Bomb = fun foo1/0, + case get(42) of + a -> Bomb(); + b -> fun foo1/0 + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo28() -> fun(() -> no_return()). +foo28() -> + Bomb = fun() -> foo1() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo1() end + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo29() -> + Bomb = fun() -> foo2() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo2() end + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo30() -> fun(() -> no_return()). +foo30() -> + Bomb = fun foo2/0, + case get(42) of + a -> Bomb(); + b -> fun foo2/0 + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo31() -> + Bomb = fun foo2/0, + case get(42) of + a -> Bomb(); + b -> fun foo2/0 + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo32() -> fun(() -> no_return()). +foo32() -> + Bomb = fun() -> foo2() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo2() end + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo33() -> + Bomb = fun() -> foo3() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo3() end + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo34() -> fun(() -> no_return()). +foo34() -> + Bomb = fun foo3/0, + case get(42) of + a -> Bomb(); + b -> fun foo3/0 + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo35() -> + Bomb = fun foo3/0, + case get(42) of + a -> Bomb(); + b -> fun foo3/0 + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo36() -> fun(() -> no_return()). +foo36() -> + Bomb = fun() -> foo3() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo3() end + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo37() -> + Bomb = fun() -> foo4() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo4() end + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo38() -> fun(() -> no_return()). +foo38() -> + Bomb = fun foo4/0, + case get(42) of + a -> Bomb(); + b -> fun foo4/0 + end. + +% Creates two funs with no local return and will return one or die. No spec. +foo39() -> + Bomb = fun foo4/0, + case get(42) of + a -> Bomb(); + b -> fun foo4/0 + end. + +% Creates two funs with no local return and will return one or die. With spec. +-spec foo40() -> fun(() -> no_return()). +foo40() -> + Bomb = fun() -> foo4() end, + case get(42) of + a -> Bomb(); + b -> fun() -> foo4() end + end. + +% Obtains two funs with no local return and will return one or die. No spec. +foo41() -> + Bomb = foo5(), + case get(42) of + a -> Bomb(); + b -> foo5() + end. + +% Obtains two funs with no local return and will return one or die. With spec. +-spec foo42() -> fun(() -> no_return()). +foo42() -> + Bomb = foo5(), + case get(42) of + a -> Bomb(); + b -> foo5() + end. diff --git a/lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl b/lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl new file mode 100644 index 0000000000..d3b504ae04 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl @@ -0,0 +1,19 @@ +-module(rebar_no_return). + +-export([t/0]). + +-spec t() -> no_return(). +t() -> + F = log_and_halt("baz"), + F("foo", 123). + +-spec log_and_halt(string()) -> fun((string(),integer()) -> no_return()). +log_and_halt(Msg) -> + fun(_, _) -> + abort(Msg) + end. + +-spec abort(string()) -> no_return(). +abort(Msg) -> + io:format("~s~n", [Msg]), + halt(1). -- cgit v1.2.3 From 4d9bf5ceed7e98e607b62cd39cc3c948e8fb79a7 Mon Sep 17 00:00:00 2001 From: Stavros Aronis Date: Sun, 30 Jan 2011 17:14:22 +0200 Subject: Add origin information to #fun_var closures --- lib/dialyzer/src/dialyzer_typesig.erl | 195 ++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 89 deletions(-) diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl index 65c2ff76bb..06863d89a7 100644 --- a/lib/dialyzer/src/dialyzer_typesig.erl +++ b/lib/dialyzer/src/dialyzer_typesig.erl @@ -62,7 +62,8 @@ -type dep() :: integer(). %% type variable names used as constraint ids -type type_var() :: erl_types:erl_type(). %% actually: {'c','var',_,_} --record(fun_var, {'fun' :: fun((_) -> erl_types:erl_type()), deps :: [dep()]}). +-record(fun_var, {'fun' :: fun((_) -> erl_types:erl_type()), deps :: [dep()], + origin :: integer()}). -type constr_op() :: 'eq' | 'sub'. -type fvar_or_type() :: #fun_var{} | erl_types:erl_type(). @@ -121,8 +122,10 @@ -ifdef(DEBUG). -define(debug(__String, __Args), io:format(__String, __Args)). +-define(mk_fun_var(Fun, Vars), mk_fun_var(?LINE, Fun, Vars)). -else. -define(debug(__String, __Args), ok). +-define(mk_fun_var(Fun, Vars), mk_fun_var(Fun, Vars)). -endif. %% ============================================================================ @@ -218,10 +221,10 @@ traverse(Tree, DefinedVars, State) -> binary -> {State1, SegTypes} = traverse_list(cerl:binary_segments(Tree), DefinedVars, State), - Type = mk_fun_var(fun(Map) -> - TmpSegTypes = lookup_type_list(SegTypes, Map), - t_bitstr_concat(TmpSegTypes) - end, SegTypes), + Type = ?mk_fun_var(fun(Map) -> + TmpSegTypes = lookup_type_list(SegTypes, Map), + t_bitstr_concat(TmpSegTypes) + end, SegTypes), {state__store_conj(mk_var(Tree), sub, Type, State1), mk_var(Tree)}; bitstr -> Size = cerl:bitstr_size(Tree), @@ -236,7 +239,7 @@ traverse(Tree, DefinedVars, State) -> N when is_integer(N) -> {State1, t_bitstr(0, N)}; any -> % Size is not a literal {state__store_conj(SizeType, sub, t_non_neg_integer(), State1), - mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])} + ?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])} end, ValTypeConstr = case cerl:concrete(cerl:bitstr_type(Tree)) of @@ -250,8 +253,8 @@ traverse(Tree, DefinedVars, State) -> case state__is_in_match(State1) of true -> Flags = cerl:concrete(cerl:bitstr_flags(Tree)), - mk_fun_var(bitstr_val_constr(SizeType, UnitVal, Flags), - [SizeType]); + ?mk_fun_var(bitstr_val_constr(SizeType, UnitVal, Flags), + [SizeType]); false -> t_integer() end; utf8 -> t_integer(); @@ -281,24 +284,24 @@ traverse(Tree, DefinedVars, State) -> {State, t_cons(HdVar, TlVar)}; false -> ConsVar = mk_var(Tree), - ConsType = mk_fun_var(fun(Map) -> - t_cons(lookup_type(HdVar, Map), - lookup_type(TlVar, Map)) - end, [HdVar, TlVar]), - HdType = mk_fun_var(fun(Map) -> - Cons = lookup_type(ConsVar, Map), - case t_is_cons(Cons) of - false -> t_any(); - true -> t_cons_hd(Cons) - end - end, [ConsVar]), - TlType = mk_fun_var(fun(Map) -> - Cons = lookup_type(ConsVar, Map), - case t_is_cons(Cons) of - false -> t_any(); - true -> t_cons_tl(Cons) - end - end, [ConsVar]), + ConsType = ?mk_fun_var(fun(Map) -> + t_cons(lookup_type(HdVar, Map), + lookup_type(TlVar, Map)) + end, [HdVar, TlVar]), + HdType = ?mk_fun_var(fun(Map) -> + Cons = lookup_type(ConsVar, Map), + case t_is_cons(Cons) of + false -> t_any(); + true -> t_cons_hd(Cons) + end + end, [ConsVar]), + TlType = ?mk_fun_var(fun(Map) -> + Cons = lookup_type(ConsVar, Map), + case t_is_cons(Cons) of + false -> t_any(); + true -> t_cons_tl(Cons) + end + end, [ConsVar]), State2 = state__store_conj_lists([HdVar, TlVar, ConsVar], sub, [HdType, TlType, ConsType], State1), @@ -656,25 +659,25 @@ get_plt_constr(MFA, Dst, ArgVars, State) -> {RetType, ArgCs} = case PltRes of none -> - {mk_fun_var(fun(Map) -> - ArgTypes = lookup_type_list(ArgVars, Map), - dialyzer_contracts:get_contract_return(C, ArgTypes) - end, ArgVars), GenArgs}; + {?mk_fun_var(fun(Map) -> + ArgTypes = lookup_type_list(ArgVars, Map), + dialyzer_contracts:get_contract_return(C, ArgTypes) + end, ArgVars), GenArgs}; {value, {PltRetType, PltArgTypes}} -> %% Need to combine the contract with the success typing. - {mk_fun_var( - fun(Map) -> - ArgTypes0 = lookup_type_list(ArgVars, Map), - ArgTypes = case FunModule =:= Module of - false -> - List = lists:zip(PltArgTypes, ArgTypes0), - [erl_types:t_unopaque_on_mismatch(T1, T2, Opaques) - || {T1, T2} <- List]; - true -> ArgTypes0 - end, - CRet = dialyzer_contracts:get_contract_return(C, ArgTypes), - t_inf(CRet, PltRetType, opaque) - end, ArgVars), + {?mk_fun_var( + fun(Map) -> + ArgTypes0 = lookup_type_list(ArgVars, Map), + ArgTypes = case FunModule =:= Module of + false -> + List = lists:zip(PltArgTypes, ArgTypes0), + [erl_types:t_unopaque_on_mismatch(T1, T2, Opaques) + || {T1, T2} <- List]; + true -> ArgTypes0 + end, + CRet = dialyzer_contracts:get_contract_return(C, ArgTypes), + t_inf(CRet, PltRetType, opaque) + end, ArgVars), [t_inf(X, Y, opaque) || {X, Y} <- lists:zip(GenArgs, PltArgTypes)]} end, state__store_conj_lists([Dst|ArgVars], sub, [RetType|ArgCs], State) @@ -766,10 +769,10 @@ handle_clauses_1([Clause|Tail], TopVar, Arg, DefinedVars, case SubtrTypes =:= overflow of true -> S; false -> - SubtrPatVar = mk_fun_var(fun(Map) -> - TmpType = lookup_type(Arg, Map), - t_subtract_list(TmpType, SubtrTypes) - end, [Arg]), + SubtrPatVar = ?mk_fun_var(fun(Map) -> + TmpType = lookup_type(Arg, Map), + t_subtract_list(TmpType, SubtrTypes) + end, [Arg]), state__store_conj(Arg, sub, SubtrPatVar, S) end end, @@ -1043,10 +1046,10 @@ handle_guard(Guard, DefinedVars, State) -> get_bif_constr({erlang, Op, 2}, Dst, Args = [Arg1, Arg2], _State) when Op =:= '+'; Op =:= '-'; Op =:= '*' -> - ReturnType = mk_fun_var(fun(Map) -> - TmpArgTypes = lookup_type_list(Args, Map), - erl_bif_types:type(erlang, Op, 2, TmpArgTypes) - end, Args), + ReturnType = ?mk_fun_var(fun(Map) -> + TmpArgTypes = lookup_type_list(Args, Map), + erl_bif_types:type(erlang, Op, 2, TmpArgTypes) + end, Args), ArgFun = fun(A, Pos) -> F = @@ -1074,7 +1077,7 @@ get_bif_constr({erlang, Op, 2}, Dst, Args = [Arg1, Arg2], _State) end end end, - mk_fun_var(F, [Dst, A]) + ?mk_fun_var(F, [Dst, A]) end, Arg1FunVar = ArgFun(Arg2, 2), Arg2FunVar = ArgFun(Arg1, 1), @@ -1131,12 +1134,12 @@ get_bif_constr({erlang, Op, 2}, Dst, [Arg1, Arg2] = Args, _State) '>=' -> {ArgFun(Arg1, Arg2, '>='), ArgFun(Arg2, Arg1, '=<')} end, DstArgs = [Dst, Arg1, Arg2], - Arg1Var = mk_fun_var(Arg1Fun, DstArgs), - Arg2Var = mk_fun_var(Arg2Fun, DstArgs), - DstVar = mk_fun_var(fun(Map) -> - TmpArgTypes = lookup_type_list(Args, Map), - erl_bif_types:type(erlang, Op, 2, TmpArgTypes) - end, Args), + Arg1Var = ?mk_fun_var(Arg1Fun, DstArgs), + Arg2Var = ?mk_fun_var(Arg2Fun, DstArgs), + DstVar = ?mk_fun_var(fun(Map) -> + TmpArgTypes = lookup_type_list(Args, Map), + erl_bif_types:type(erlang, Op, 2, TmpArgTypes) + end, Args), mk_conj_constraint_list([mk_constraint(Dst, sub, DstVar), mk_constraint(Arg1, sub, Arg1Var), mk_constraint(Arg2, sub, Arg2Var)]); @@ -1172,13 +1175,13 @@ get_bif_constr({erlang, '++', 2}, Dst, [Hd, Tl] = Args, _State) -> end end, DstL = [Dst], - HdVar = mk_fun_var(HdFun, DstL), - TlVar = mk_fun_var(TlFun, DstL), + HdVar = ?mk_fun_var(HdFun, DstL), + TlVar = ?mk_fun_var(TlFun, DstL), ArgTypes = erl_bif_types:arg_types(erlang, '++', 2), - ReturnType = mk_fun_var(fun(Map) -> - TmpArgTypes = lookup_type_list(Args, Map), - erl_bif_types:type(erlang, '++', 2, TmpArgTypes) - end, Args), + ReturnType = ?mk_fun_var(fun(Map) -> + TmpArgTypes = lookup_type_list(Args, Map), + erl_bif_types:type(erlang, '++', 2, TmpArgTypes) + end, Args), Cs = mk_constraints(Args, sub, ArgTypes), mk_conj_constraint_list([mk_constraint(Dst, sub, ReturnType), mk_constraint(Hd, sub, HdVar), @@ -1209,7 +1212,7 @@ get_bif_constr({erlang, is_function, 2}, Dst, [Fun, Arity], _State) -> false -> t_any() end end, - ArgV = mk_fun_var(ArgFun, [Dst, Arity]), + ArgV = ?mk_fun_var(ArgFun, [Dst, Arity]), mk_conj_constraint_list([mk_constraint(Dst, sub, t_boolean()), mk_constraint(Arity, sub, t_integer()), mk_constraint(Fun, sub, ArgV)]); @@ -1232,12 +1235,12 @@ get_bif_constr({erlang, is_record, 2}, Dst, [Var, Tag] = Args, _State) -> false -> t_any() end end, - ArgV = mk_fun_var(ArgFun, [Dst]), + ArgV = ?mk_fun_var(ArgFun, [Dst]), DstFun = fun(Map) -> TmpArgTypes = lookup_type_list(Args, Map), erl_bif_types:type(erlang, is_record, 2, TmpArgTypes) end, - DstV = mk_fun_var(DstFun, Args), + DstV = ?mk_fun_var(DstFun, Args), mk_conj_constraint_list([mk_constraint(Dst, sub, DstV), mk_constraint(Tag, sub, t_atom()), mk_constraint(Var, sub, ArgV)]); @@ -1280,7 +1283,7 @@ get_bif_constr({erlang, is_record, 3}, Dst, [Var, Tag, Arity] = Args, State) -> false -> t_any() end end, - ArgV = mk_fun_var(ArgFun, [Tag, Arity, Dst]), + ArgV = ?mk_fun_var(ArgFun, [Tag, Arity, Dst]), DstFun = fun(Map) -> [TmpVar, TmpTag, TmpArity] = TmpArgTypes = lookup_type_list(Args, Map), TmpArgTypes2 = @@ -1314,7 +1317,7 @@ get_bif_constr({erlang, is_record, 3}, Dst, [Var, Tag, Arity] = Args, State) -> end, erl_bif_types:type(erlang, is_record, 3, TmpArgTypes2) end, - DstV = mk_fun_var(DstFun, Args), + DstV = ?mk_fun_var(DstFun, Args), mk_conj_constraint_list([mk_constraint(Dst, sub, DstV), mk_constraint(Arity, sub, t_integer()), mk_constraint(Tag, sub, t_atom()), @@ -1359,9 +1362,9 @@ get_bif_constr({erlang, 'and', 2}, Dst, [Arg1, Arg2] = Args, _State) -> end end end, - ArgV1 = mk_fun_var(ArgFun(Arg2), [Arg2, Dst]), - ArgV2 = mk_fun_var(ArgFun(Arg1), [Arg1, Dst]), - DstV = mk_fun_var(DstFun, Args), + ArgV1 = ?mk_fun_var(ArgFun(Arg2), [Arg2, Dst]), + ArgV2 = ?mk_fun_var(ArgFun(Arg1), [Arg1, Dst]), + DstV = ?mk_fun_var(DstFun, Args), mk_conj_constraint_list([mk_constraint(Dst, sub, DstV), mk_constraint(Arg1, sub, ArgV1), mk_constraint(Arg2, sub, ArgV2)]); @@ -1403,9 +1406,9 @@ get_bif_constr({erlang, 'or', 2}, Dst, [Arg1, Arg2] = Args, _State) -> end end end, - ArgV1 = mk_fun_var(ArgFun(Arg2), [Arg2, Dst]), - ArgV2 = mk_fun_var(ArgFun(Arg1), [Arg1, Dst]), - DstV = mk_fun_var(DstFun, Args), + ArgV1 = ?mk_fun_var(ArgFun(Arg2), [Arg2, Dst]), + ArgV2 = ?mk_fun_var(ArgFun(Arg1), [Arg1, Dst]), + DstV = ?mk_fun_var(DstFun, Args), F = fun(A) -> try [mk_constraint(A, sub, True)] catch throw:error -> [] @@ -1433,8 +1436,8 @@ get_bif_constr({erlang, 'not', 1}, Dst, [Arg] = Args, _State) -> end end end, - ArgV = mk_fun_var(Fun(Dst), [Dst]), - DstV = mk_fun_var(Fun(Arg), Args), + ArgV = ?mk_fun_var(Fun(Dst), [Dst]), + DstV = ?mk_fun_var(Fun(Arg), Args), mk_conj_constraint_list([mk_constraint(Arg, sub, ArgV), mk_constraint(Dst, sub, DstV)]); get_bif_constr({erlang, '=:=', 2}, Dst, [Arg1, Arg2] = Args, _State) -> @@ -1467,9 +1470,9 @@ get_bif_constr({erlang, '=:=', 2}, Dst, [Arg1, Arg2] = Args, _State) -> end end, DstArgs = [Dst, Arg1, Arg2], - ArgV1 = mk_fun_var(ArgFun(Arg1, Arg2), DstArgs), - ArgV2 = mk_fun_var(ArgFun(Arg2, Arg1), DstArgs), - DstV = mk_fun_var(DstFun, Args), + ArgV1 = ?mk_fun_var(ArgFun(Arg1, Arg2), DstArgs), + ArgV2 = ?mk_fun_var(ArgFun(Arg2, Arg1), DstArgs), + DstV = ?mk_fun_var(DstFun, Args), mk_conj_constraint_list([mk_constraint(Dst, sub, DstV), mk_constraint(Arg1, sub, ArgV1), mk_constraint(Arg2, sub, ArgV2)]); @@ -1510,10 +1513,10 @@ get_bif_constr({erlang, '==', 2}, Dst, [Arg1, Arg2] = Args, _State) -> end end end, - DstV = mk_fun_var(DstFun, Args), + DstV = ?mk_fun_var(DstFun, Args), ArgL = [Arg1, Arg2, Dst], - ArgV1 = mk_fun_var(ArgFun(Arg2, Arg1), ArgL), - ArgV2 = mk_fun_var(ArgFun(Arg1, Arg2), ArgL), + ArgV1 = ?mk_fun_var(ArgFun(Arg2, Arg1), ArgL), + ArgV2 = ?mk_fun_var(ArgFun(Arg1, Arg2), ArgL), mk_conj_constraint_list([mk_constraint(Dst, sub, DstV), mk_constraint(Arg1, sub, ArgV1), mk_constraint(Arg2, sub, ArgV2)]); @@ -1531,7 +1534,7 @@ get_bif_constr({erlang, element, 2} = _BIF, Dst, Args, end, erl_bif_types:type(erlang, element, 2, ATs2) end, - ReturnType = mk_fun_var(Fun, Args), + ReturnType = ?mk_fun_var(Fun, Args), ArgTypes = erl_bif_types:arg_types(erlang, element, 2), Cs = mk_constraints(Args, sub, ArgTypes), NewCs = @@ -1553,7 +1556,7 @@ get_bif_constr({M, F, A} = _BIF, Dst, Args, State) -> false -> T end end, - ReturnType = mk_fun_var(fun(Map) -> + ReturnType = ?mk_fun_var(fun(Map) -> TmpArgTypes0 = lookup_type_list(Args, Map), TmpArgTypes = [UnopaqueFun(T) || T<- TmpArgTypes0], erl_bif_types:type(M, F, A, TmpArgTypes) @@ -1608,7 +1611,7 @@ get_bif_test_constr(Dst, Arg, Type, State) -> false -> t_any() end end, - ArgV = mk_fun_var(ArgFun, [Dst]), + ArgV = ?mk_fun_var(ArgFun, [Dst]), DstFun = fun(Map) -> ArgType = lookup_type(Arg, Map), case t_is_none(t_inf(ArgType, Type)) of @@ -1633,7 +1636,7 @@ get_bif_test_constr(Dst, Arg, Type, State) -> end end end, - DstV = mk_fun_var(DstFun, [Arg]), + DstV = ?mk_fun_var(DstFun, [Arg]), mk_conj_constraint_list([mk_constraint(Dst, sub, DstV), mk_constraint(Arg, sub, ArgV)]). @@ -2323,12 +2326,25 @@ mk_constraint(Lhs, Op, Rhs) -> constraint_opnd_is_any(#fun_var{}) -> false; constraint_opnd_is_any(Type) -> t_is_any(Type). +-ifdef(DEBUG). + +-spec mk_fun_var(fun((_) -> erl_types:erl_type()), [erl_types:erl_type()], + integer()) -> #fun_var{}. + +mk_fun_var(Line, Fun, Types) -> + Deps = [t_var_name(Var) || Var <- t_collect_vars(t_product(Types))], + #fun_var{'fun' = Fun, deps = ordsets:from_list(Deps), origin = Line}. + +-else. + -spec mk_fun_var(fun((_) -> erl_types:erl_type()), [erl_types:erl_type()]) -> #fun_var{}. mk_fun_var(Fun, Types) -> Deps = [t_var_name(Var) || Var <- t_collect_vars(t_product(Types))], #fun_var{'fun' = Fun, deps = ordsets:from_list(Deps)}. +-endif. + -spec get_deps(constr()) -> [dep()]. get_deps(#constraint{deps = D}) -> D; @@ -2679,8 +2695,9 @@ find_constraint(Tuple, [_|Cs]) -> -endif. -ifdef(DEBUG). -format_type(#fun_var{deps = Deps}) -> - io_lib:format("Fun(~s)", [lists:flatten([format_type(t_var(X))||X<-Deps])]); +format_type(#fun_var{deps = Deps, origin = Origin}) -> + io_lib:format("Fun@L~p(~s)", + [Origin, lists:flatten([format_type(t_var(X))||X<-Deps])]); format_type(Type) -> case cerl:is_literal(Type) of true -> io_lib:format("~w", [cerl:concrete(Type)]); -- cgit v1.2.3 From 4c63d9d9dd5327b555c197071cf96a150d387315 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Fri, 19 Aug 2011 17:50:48 +0200 Subject: Remove dead code in erl_compile --- lib/stdlib/src/erl_compile.erl | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl index abff37e4bc..d833f626bf 100644 --- a/lib/stdlib/src/erl_compile.erl +++ b/lib/stdlib/src/erl_compile.erl @@ -41,7 +41,6 @@ compiler(".idl") -> {ic, compile}; compiler(".asn1") -> {asn1ct, compile_asn1}; compiler(".asn") -> {asn1ct, compile_asn}; compiler(".py") -> {asn1ct, compile_py}; -compiler(".xml") -> {xmerl_scan, process}; compiler(_) -> no. %% Entry from command line. -- cgit v1.2.3 From 03d8c2877342d5ed57596330a61ec0374092f136 Mon Sep 17 00:00:00 2001 From: Filipe David Manana Date: Thu, 1 Sep 2011 02:05:05 +0100 Subject: Fix enif_compare on 64bits machines In 64bits machines the Sint type has a size of 8 bytes, while on 32bits machines it has a 4 bytes size. enif_compare was ignoring this and therefore returning incorrect values when the result of the CMP function (which returns a Sint value) doesn't fit in 4 bytes. For example, passing the operands -1294536544000 and -1178704800000 to enif_compare would trigger the bug. --- erts/emulator/beam/erl_nif.c | 10 +++++++++- erts/emulator/test/nif_SUITE.erl | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index d9b1a8e89d..6e7ac43676 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -578,7 +578,15 @@ int enif_is_identical(Eterm lhs, Eterm rhs) int enif_compare(Eterm lhs, Eterm rhs) { - return CMP(lhs,rhs); + Sint result = CMP(lhs,rhs); + + if (result < 0) { + return -1; + } else if (result > 0) { + return 1; + } + + return result; } int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, const Eterm** array) diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 2867e8e2e4..f6344791f1 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -281,6 +281,12 @@ types(Config) when is_list(Config) -> end, int_list()), ?line verify_tmpmem(TmpMem), + ?line true = (compare(-1294536544000, -1178704800000) < 0), + ?line true = (compare(-1178704800000, -1294536544000) > 0), + ?line true = (compare(-295147905179352825856, -36893488147419103232) < 0), + ?line true = (compare(-36893488147419103232, -295147905179352825856) > 0), + ?line true = (compare(-29514790517935282585612345678, -36893488147419103232) < 0), + ?line true = (compare(-36893488147419103232, -29514790517935282585612345678) > 0), ok. int_list() -> -- cgit v1.2.3