diff options
Diffstat (limited to 'lib/hipe/cerl')
-rw-r--r-- | lib/hipe/cerl/cerl_cconv.erl | 11 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_closurean.erl | 17 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_hipe_primops.hrl | 17 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_hipeify.erl | 9 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_lib.erl | 10 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_messagean.erl | 16 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_pmatch.erl | 9 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_prettypr.erl | 16 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_to_icode.erl | 10 | ||||
-rw-r--r-- | lib/hipe/cerl/cerl_typean.erl | 14 | ||||
-rw-r--r-- | lib/hipe/cerl/erl_bif_types.erl | 109 | ||||
-rw-r--r-- | lib/hipe/cerl/erl_types.erl | 286 |
12 files changed, 248 insertions, 276 deletions
diff --git a/lib/hipe/cerl/cerl_cconv.erl b/lib/hipe/cerl/cerl_cconv.erl index ac9d01ab0e..2cd0e261d5 100644 --- a/lib/hipe/cerl/cerl_cconv.erl +++ b/lib/hipe/cerl/cerl_cconv.erl @@ -1,8 +1,3 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2015. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,11 +9,9 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% %% -%% @author Richard Carlsson <[email protected]> %% @copyright 2000-2004 Richard Carlsson +%% @author Richard Carlsson <[email protected]> %% @doc Closure conversion of Core Erlang modules. This is done as a %% step in the translation from Core Erlang down to HiPE Icode, and is %% very much tied to the calling conventions used in HiPE native code. @@ -265,7 +258,7 @@ bind_module_defs([], Env, S) -> check_function_name(Name, S) -> case s__is_function_name(Name, S) of true -> - error_msg("multiple definitions of function `~w'.", [Name]), + error_msg("multiple definitions of function `~tw'.", [Name]), exit(error); false -> ok diff --git a/lib/hipe/cerl/cerl_closurean.erl b/lib/hipe/cerl/cerl_closurean.erl index d37c91e5c6..a2bd7fe0f0 100644 --- a/lib/hipe/cerl/cerl_closurean.erl +++ b/lib/hipe/cerl/cerl_closurean.erl @@ -1,8 +1,3 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -15,15 +10,9 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %% -%% %CopyrightEnd% -%% -%% ===================================================================== -%% Closure analysis of Core Erlang programs. -%% -%% Copyright (C) 2001-2002 Richard Carlsson -%% -%% Author contact: [email protected] -%% ===================================================================== +%% @copyright 2001-2002 Richard Carlsson +%% @author Richard Carlsson <[email protected]> +%% @doc Closure analysis of Core Erlang programs. %% TODO: might need a "top" (`any') element for any-length value lists. diff --git a/lib/hipe/cerl/cerl_hipe_primops.hrl b/lib/hipe/cerl/cerl_hipe_primops.hrl index 3efb9a3bdd..6e4d830b61 100644 --- a/lib/hipe/cerl/cerl_hipe_primops.hrl +++ b/lib/hipe/cerl/cerl_hipe_primops.hrl @@ -1,9 +1,3 @@ -%% ========================-*-erlang-*-================================= -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -15,15 +9,10 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% -%% -%% Predefined Core Erlang primitive operations used by HiPE -%% -%% Copyright (C) 2000 Richard Carlsson %% -%% Author contact: [email protected] -%% ===================================================================== +%% @copyright 2000 Richard Carlsson +%% @author Richard Carlsson <[email protected]> +%% @doc Predefined Core Erlang primitive operations used by HiPE. %% These definitions give the names of Core Erlang primops recognized by %% HiPE. Many of them (e.g., 'not'/'and'/'or', and the type tests), are diff --git a/lib/hipe/cerl/cerl_hipeify.erl b/lib/hipe/cerl/cerl_hipeify.erl index 6611abd204..137a54ba32 100644 --- a/lib/hipe/cerl/cerl_hipeify.erl +++ b/lib/hipe/cerl/cerl_hipeify.erl @@ -1,8 +1,3 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2015. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,11 +9,9 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% %% -%% @author Richard Carlsson <[email protected]> %% @copyright 2000-2004 Richard Carlsson +%% @author Richard Carlsson <[email protected]> %% @doc HiPE-ification of Core Erlang code. Prepares Core Erlang code %% for translation to ICode. %% @see cerl_to_icode diff --git a/lib/hipe/cerl/cerl_lib.erl b/lib/hipe/cerl/cerl_lib.erl index 0bc77909d9..3a6fb1cf51 100644 --- a/lib/hipe/cerl/cerl_lib.erl +++ b/lib/hipe/cerl/cerl_lib.erl @@ -1,8 +1,3 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,10 +9,9 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% %% - +%% @copyright 1999-2002 Richard Carlsson +%% @author Richard Carlsson <[email protected]> %% @doc Utility functions for Core Erlang abstract syntax trees. %% %% <p>Syntax trees are defined in the module <a diff --git a/lib/hipe/cerl/cerl_messagean.erl b/lib/hipe/cerl/cerl_messagean.erl index 7df0a245fb..c79e045bd0 100644 --- a/lib/hipe/cerl/cerl_messagean.erl +++ b/lib/hipe/cerl/cerl_messagean.erl @@ -1,8 +1,3 @@ -%% ===================================================================== -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -15,14 +10,9 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %% -%% %CopyrightEnd% -%% -%% Message analysis of Core Erlang programs. -%% -%% Copyright (C) 2002 Richard Carlsson -%% -%% Author contact: [email protected] -%% ===================================================================== +%% @copyright 2002 Richard Carlsson +%% @author Richard Carlsson <[email protected]> +%% @doc Message analysis of Core Erlang programs. %% TODO: might need a "top" (`any') element for any-length value lists. diff --git a/lib/hipe/cerl/cerl_pmatch.erl b/lib/hipe/cerl/cerl_pmatch.erl index ca27fff1dd..fd7f589f08 100644 --- a/lib/hipe/cerl/cerl_pmatch.erl +++ b/lib/hipe/cerl/cerl_pmatch.erl @@ -1,8 +1,3 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,11 +9,9 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% %% -%% @author Richard Carlsson <[email protected]> %% @copyright 2000-2006 Richard Carlsson +%% @author Richard Carlsson <[email protected]> %% %% @doc Core Erlang pattern matching compiler. %% diff --git a/lib/hipe/cerl/cerl_prettypr.erl b/lib/hipe/cerl/cerl_prettypr.erl index f0acab99e3..c1c7250bbd 100644 --- a/lib/hipe/cerl/cerl_prettypr.erl +++ b/lib/hipe/cerl/cerl_prettypr.erl @@ -1,8 +1,3 @@ -%% ===================================================================== -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -14,16 +9,9 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% -%% -%% Core Erlang prettyprinter, using the 'prettypr' module. -%% -%% Copyright (C) 1999-2002 Richard Carlsson -%% -%% Author contact: [email protected] -%% ===================================================================== %% +%% @copyright 1999-2002 Richard Carlsson +%% @author Richard Carlsson <[email protected]> %% @doc Core Erlang prettyprinter. %% %% <p>This module is a front end to the pretty-printing library module diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl index ab131c2d01..e37eae8a03 100644 --- a/lib/hipe/cerl/cerl_to_icode.erl +++ b/lib/hipe/cerl/cerl_to_icode.erl @@ -1,9 +1,5 @@ %% -*- erlang-indent-level: 4 -*- %% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2015. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -15,11 +11,9 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% %% -%% @author Richard Carlsson <[email protected]> %% @copyright 2000-2006 Richard Carlsson +%% @author Richard Carlsson <[email protected]> %% @doc Translation from Core Erlang to HiPE Icode. %% TODO: annotate Icode leaf functions as such. @@ -2627,7 +2621,7 @@ icode_switch_val(Arg, Fail, Length, Cases) -> hipe_icode:mk_switch_val(Arg, Fail, Length, Cases). icode_switch_tuple_arity(Arg, Fail, Length, Cases) -> - SortedCases = lists:keysort(1, Cases), %% immitate BEAM compiler - Kostis + SortedCases = lists:keysort(1, Cases), %% imitate BEAM compiler - Kostis hipe_icode:mk_switch_tuple_arity(Arg, Fail, Length, SortedCases). diff --git a/lib/hipe/cerl/cerl_typean.erl b/lib/hipe/cerl/cerl_typean.erl index ddc48c7915..c5d84bdf2b 100644 --- a/lib/hipe/cerl/cerl_typean.erl +++ b/lib/hipe/cerl/cerl_typean.erl @@ -1,9 +1,5 @@ %% -*- erlang-indent-level: 4 -*- %% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -15,15 +11,9 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -%% -%% %CopyrightEnd% -%% -%% Type analysis of Core Erlang programs. -%% -%% Copyright (C) 2001-2002 Richard Carlsson -%% -%% Author contact: [email protected] %% +%% @copyright 2001-2002 Richard Carlsson +%% @author Richard Carlsson <[email protected]> %% @doc Type analysis of Core Erlang programs. %% TODO: filters must handle conjunctions for better precision! diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 230fce2e68..a3a936322a 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -1,9 +1,5 @@ %% -*- erlang-indent-level: 2 -*- %% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -16,16 +12,12 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %% -%% %CopyrightEnd% -%% -%% ===================================================================== -%% Type information for Erlang Built-in functions (implemented in C) -%% -%% Copyright (C) 2002 Richard Carlsson -%% Copyright (C) 2006 Richard Carlsson, Tobias Lindahl and Kostis Sagonas -%% -%% ===================================================================== +%% @doc Type information for Erlang Built-in functions (implemented in C) +%% @copyright 2002 Richard Carlsson, 2006 Richard Carlsson, Tobias Lindahl +%% and Kostis Sagonas +%% @author Richard Carlsson <[email protected]> +%% @author Tobias Lindahl <[email protected]> +%% @author Kostis Sagonas <[email protected]> -module(erl_bif_types). @@ -560,6 +552,9 @@ type(erlang, byte_size, 1, Xs, Opaques) -> strict(erlang, byte_size, 1, Xs, fun (_) -> t_non_neg_integer() end, Opaques); %% Guard bif, needs to be here. +type(erlang, ceil, 1, Xs, Opaques) -> + strict(erlang, ceil, 1, Xs, fun (_) -> t_integer() end, Opaques); +%% Guard bif, needs to be here. %% Also much more expressive than anything you could write in a spec... type(erlang, element, 2, Xs, Opaques) -> strict(erlang, element, 2, Xs, @@ -588,6 +583,9 @@ type(erlang, element, 2, Xs, Opaques) -> type(erlang, float, 1, Xs, Opaques) -> strict(erlang, float, 1, Xs, fun (_) -> t_float() end, Opaques); %% Guard bif, needs to be here. +type(erlang, floor, 1, Xs, Opaques) -> + strict(erlang, floor, 1, Xs, fun (_) -> t_integer() end, Opaques); +%% Guard bif, needs to be here. type(erlang, hd, 1, Xs, Opaques) -> strict(erlang, hd, 1, Xs, fun ([X]) -> t_cons_hd(X) end, Opaques); type(erlang, info, 1, Xs, _) -> type(erlang, system_info, 1, Xs); % alias @@ -997,9 +995,9 @@ type(erlang, tuple_to_list, 1, Xs, Opaques) -> end, Opaques); %%-- hipe_bifs ---------------------------------------------------------------- type(hipe_bifs, add_ref, 2, Xs, Opaques) -> - strict(hipe_bifs, add_ref, 2, Xs, fun (_) -> t_nil() end, Opaques); -type(hipe_bifs, alloc_data, 2, Xs, Opaques) -> - strict(hipe_bifs, alloc_data, 2, Xs, + strict(hipe_bifs, add_ref, 2, Xs, fun (_) -> t_atom('ok') end, Opaques); +type(hipe_bifs, alloc_data, 3, Xs, Opaques) -> + strict(hipe_bifs, alloc_data, 3, Xs, fun (_) -> t_integer() end, Opaques); % address type(hipe_bifs, array, 2, Xs, Opaques) -> strict(hipe_bifs, array, 2, Xs, fun (_) -> t_immarray() end, Opaques); @@ -1046,16 +1044,16 @@ type(hipe_bifs, call_count_on, 1, Xs, Opaques) -> fun (_) -> t_sup(t_atom('true'), t_nil()) end, Opaques); type(hipe_bifs, check_crc, 1, Xs, Opaques) -> strict(hipe_bifs, check_crc, 1, Xs, fun (_) -> t_boolean() end, Opaques); -type(hipe_bifs, enter_code, 2, Xs, Opaques) -> - strict(hipe_bifs, enter_code, 2, Xs, +type(hipe_bifs, enter_code, 3, Xs, Opaques) -> + strict(hipe_bifs, enter_code, 3, Xs, fun (_) -> t_tuple([t_integer(), %% XXX: The tuple below contains integers and %% is of size same as the length of the MFA list t_sup(t_nil(), t_binary())]) end, Opaques); -type(hipe_bifs, enter_sdesc, 1, Xs, Opaques) -> - strict(hipe_bifs, enter_sdesc, 1, Xs, fun (_) -> t_nil() end, Opaques); -type(hipe_bifs, find_na_or_make_stub, 2, Xs, Opaques) -> - strict(hipe_bifs, find_na_or_make_stub, 2, Xs, +type(hipe_bifs, enter_sdesc, 2, Xs, Opaques) -> + strict(hipe_bifs, enter_sdesc, 2, Xs, fun (_) -> t_nil() end, Opaques); +type(hipe_bifs, find_na_or_make_stub, 1, Xs, Opaques) -> + strict(hipe_bifs, find_na_or_make_stub, 1, Xs, fun (_) -> t_integer() end, Opaques); % address type(hipe_bifs, fun_to_address, 1, Xs, Opaques) -> strict(hipe_bifs, fun_to_address, 1, Xs, @@ -1065,12 +1063,6 @@ type(hipe_bifs, get_fe, 2, Xs, Opaques) -> type(hipe_bifs, get_rts_param, 1, Xs, Opaques) -> strict(hipe_bifs, get_rts_param, 1, Xs, fun (_) -> t_sup(t_integer(), t_nil()) end, Opaques); -type(hipe_bifs, invalidate_funinfo_native_addresses, 1, Xs, Opaques) -> - strict(hipe_bifs, invalidate_funinfo_native_addresses, 1, Xs, - fun (_) -> t_nil() end, Opaques); -type(hipe_bifs, mark_referred_from, 1, Xs, Opaques) -> - strict(hipe_bifs, mark_referred_from, 1, Xs, - fun (_) -> t_nil() end, Opaques); type(hipe_bifs, merge_term, 1, Xs, Opaques) -> strict(hipe_bifs, merge_term, 1, Xs, fun ([X]) -> X end, Opaques); type(hipe_bifs, nstack_used_size, 0, _, _Opaques) -> @@ -1082,21 +1074,18 @@ type(hipe_bifs, patch_insn, 3, Xs, Opaques) -> type(hipe_bifs, primop_address, 1, Xs, Opaques) -> strict(hipe_bifs, primop_address, 1, Xs, fun (_) -> t_sup(t_integer(), t_atom('false')) end, Opaques); -type(hipe_bifs, redirect_referred_from, 1, Xs, Opaques) -> - strict(hipe_bifs, redirect_referred_from, 1, Xs, - fun (_) -> t_nil() end, Opaques); type(hipe_bifs, ref, 1, Xs, Opaques) -> strict(hipe_bifs, ref, 1, Xs, fun (_) -> t_immarray() end, Opaques); type(hipe_bifs, ref_get, 1, Xs, Opaques) -> strict(hipe_bifs, ref_get, 1, Xs, fun (_) -> t_immediate() end, Opaques); type(hipe_bifs, ref_set, 2, Xs, Opaques) -> strict(hipe_bifs, ref_set, 2, Xs, fun (_) -> t_nil() end, Opaques); -type(hipe_bifs, remove_refs_from, 1, Xs, Opaques) -> - strict(hipe_bifs, remove_refs_from, 1, Xs, - fun (_) -> t_atom('ok') end, Opaques); type(hipe_bifs, set_funinfo_native_address, 3, Xs, Opaques) -> strict(hipe_bifs, set_funinfo_native_address, 3, Xs, fun (_) -> t_nil() end, Opaques); +type(hipe_bifs, commit_patch_load, 1, Xs, Opaques) -> + strict(hipe_bifs, commit_patch_load, 1, Xs, + fun (_) -> t_atom() end, Opaques); type(hipe_bifs, set_native_address, 3, Xs, Opaques) -> strict(hipe_bifs, set_native_address, 3, Xs, fun (_) -> t_nil() end, Opaques); @@ -1108,15 +1097,14 @@ type(hipe_bifs, system_crc, 0, _, _Opaques) -> type(hipe_bifs, term_to_word, 1, Xs, Opaques) -> strict(hipe_bifs, term_to_word, 1, Xs, fun (_) -> t_integer() end, Opaques); -type(hipe_bifs, update_code_size, 3, Xs, Opaques) -> - strict(hipe_bifs, update_code_size, 3, Xs, - fun (_) -> t_nil() end, Opaques); type(hipe_bifs, write_u8, 2, Xs, Opaques) -> strict(hipe_bifs, write_u8, 2, Xs, fun (_) -> t_nil() end, Opaques); type(hipe_bifs, write_u32, 2, Xs, Opaques) -> strict(hipe_bifs, write_u32, 2, Xs, fun (_) -> t_nil() end, Opaques); type(hipe_bifs, write_u64, 2, Xs, Opaques) -> strict(hipe_bifs, write_u64, 2, Xs, fun (_) -> t_nil() end, Opaques); +type(hipe_bifs, alloc_loader_state, 1, Xs, Opaques) -> + strict(hipe_bifs, alloc_loader_state, 1, Xs, fun (_) -> t_binary() end, Opaques); %%-- lists -------------------------------------------------------------------- type(lists, all, 2, Xs, Opaques) -> strict(lists, all, 2, Xs, @@ -2038,17 +2026,14 @@ arith_rem(Min1, Max1, Min2, Max2) -> Min1_geq_zero = infinity_geq(Min1, 0), Max1_leq_zero = infinity_geq(0, Max1), Max_range2 = infinity_max([infinity_abs(Min2), infinity_abs(Max2)]), - Max_range2_leq_zero = infinity_geq(0, Max_range2), - New_min = + New_min = if Min1_geq_zero -> 0; Max_range2 =:= 0 -> 0; - Max_range2_leq_zero -> infinity_add(Max_range2, 1); true -> infinity_add(infinity_inv(Max_range2), 1) end, New_max = if Max1_leq_zero -> 0; Max_range2 =:= 0 -> 0; - Max_range2_leq_zero -> infinity_add(infinity_inv(Max_range2), -1); true -> infinity_add(Max_range2, -1) end, {New_min, New_max}. @@ -2341,6 +2326,9 @@ arg_types(erlang, bit_size, 1) -> %% Guard bif, needs to be here. arg_types(erlang, byte_size, 1) -> [t_bitstr()]; +%% Guard bif, needs to be here. +arg_types(erlang, ceil, 1) -> + [t_number()]; arg_types(erlang, halt, 0) -> []; arg_types(erlang, halt, 1) -> @@ -2361,6 +2349,9 @@ arg_types(erlang, element, 2) -> arg_types(erlang, float, 1) -> [t_number()]; %% Guard bif, needs to be here. +arg_types(erlang, floor, 1) -> + [t_number()]; +%% Guard bif, needs to be here. arg_types(erlang, hd, 1) -> [t_cons()]; arg_types(erlang, info, 1) -> @@ -2458,9 +2449,9 @@ arg_types(hipe_bifs, add_ref, 2) -> t_integer(), t_sup(t_atom('call'), t_atom('load_mfa')), t_trampoline(), - t_sup(t_atom('remote'), t_atom('local'))])]; -arg_types(hipe_bifs, alloc_data, 2) -> - [t_integer(), t_integer()]; + t_binary()])]; +arg_types(hipe_bifs, alloc_data, 3) -> + [t_integer(), t_integer(), t_binary()]; arg_types(hipe_bifs, array, 2) -> [t_non_neg_fixnum(), t_immediate()]; arg_types(hipe_bifs, array_length, 1) -> @@ -2495,22 +2486,19 @@ arg_types(hipe_bifs, call_count_on, 1) -> [t_mfa()]; arg_types(hipe_bifs, check_crc, 1) -> [t_crc32()]; -arg_types(hipe_bifs, enter_code, 2) -> - [t_binary(), t_sup(t_nil(), t_tuple())]; -arg_types(hipe_bifs, enter_sdesc, 1) -> - [t_tuple([t_integer(), t_integer(), t_integer(), t_integer(), t_integer(), t_mfa()])]; -arg_types(hipe_bifs, find_na_or_make_stub, 2) -> - [t_mfa(), t_boolean()]; +arg_types(hipe_bifs, enter_code, 3) -> + [t_binary(), t_sup(t_nil(), t_tuple()), t_binary()]; +arg_types(hipe_bifs, enter_sdesc, 2) -> + [t_tuple([t_integer(), t_integer(), t_integer(), t_integer(), t_integer(), t_mfa()]), + t_binary()]; +arg_types(hipe_bifs, find_na_or_make_stub, 1) -> + [t_mfa()]; arg_types(hipe_bifs, fun_to_address, 1) -> [t_mfa()]; arg_types(hipe_bifs, get_fe, 2) -> [t_atom(), t_tuple([t_integer(), t_integer(), t_integer()])]; arg_types(hipe_bifs, get_rts_param, 1) -> [t_fixnum()]; -arg_types(hipe_bifs, invalidate_funinfo_native_addresses, 1) -> - [t_list(t_mfa())]; -arg_types(hipe_bifs, mark_referred_from, 1) -> - [t_mfa()]; arg_types(hipe_bifs, merge_term, 1) -> [t_any()]; arg_types(hipe_bifs, nstack_used_size, 0) -> @@ -2521,18 +2509,16 @@ arg_types(hipe_bifs, patch_insn, 3) -> [t_integer(), t_integer(), t_insn_type()]; arg_types(hipe_bifs, primop_address, 1) -> [t_atom()]; -arg_types(hipe_bifs, redirect_referred_from, 1) -> - [t_mfa()]; arg_types(hipe_bifs, ref, 1) -> [t_immediate()]; arg_types(hipe_bifs, ref_get, 1) -> [t_hiperef()]; arg_types(hipe_bifs, ref_set, 2) -> [t_hiperef(), t_immediate()]; -arg_types(hipe_bifs, remove_refs_from, 1) -> - [t_sup([t_mfa(), t_atom('all')])]; arg_types(hipe_bifs, set_funinfo_native_address, 3) -> arg_types(hipe_bifs, set_native_address, 3); +arg_types(hipe_bifs, commit_patch_load, 1) -> + [t_binary()]; arg_types(hipe_bifs, set_native_address, 3) -> [t_mfa(), t_integer(), t_boolean()]; arg_types(hipe_bifs, set_native_address_in_fe, 2) -> @@ -2541,14 +2527,15 @@ arg_types(hipe_bifs, system_crc, 0) -> []; arg_types(hipe_bifs, term_to_word, 1) -> [t_any()]; -arg_types(hipe_bifs, update_code_size, 3) -> - [t_atom(), t_sup(t_nil(), t_binary()), t_integer()]; arg_types(hipe_bifs, write_u8, 2) -> [t_integer(), t_byte()]; arg_types(hipe_bifs, write_u32, 2) -> [t_integer(), t_integer()]; arg_types(hipe_bifs, write_u64, 2) -> [t_integer(), t_integer()]; +arg_types(hipe_bifs, alloc_loader_state, 1) -> + [t_atom()]; + %%------- lists --------------------------------------------------------------- arg_types(lists, all, 2) -> [t_fun([t_any()], t_boolean()), t_list()]; diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index a5a3e8c136..abb6c259f6 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -1,9 +1,5 @@ %% -*- erlang-indent-level: 2 -*- %% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2017. All Rights Reserved. -%% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at @@ -16,14 +12,13 @@ %% See the License for the specific language governing permissions and %% limitations under the License. %% -%% %CopyrightEnd% -%% -%% ====================================================================== -%% Copyright (C) 2000-2003 Richard Carlsson -%% -%% ====================================================================== -%% Provides a representation of Erlang types. -%% +%% @copyright 2000-2003 Richard Carlsson, 2006-2009 Tobias Lindahl +%% @author Richard Carlsson <[email protected]> +%% @author Tobias Lindahl <[email protected]> +%% @author Kostis Sagonas <[email protected]> +%% @author Manouk Manoukian +%% @doc Provides a representation of Erlang types. + %% The initial author of this file is Richard Carlsson (2000-2004). %% In July 2006, the type representation was totally re-designed by %% Tobias Lindahl. This is the representation which is used currently. @@ -31,9 +26,6 @@ %% opaque types to the structure-based representation of types. %% During February and March 2009, Kostis Sagonas significantly %% cleaned up the type representation and added spec declarations. -%% -%% ====================================================================== -module(erl_types). @@ -82,6 +74,7 @@ t_form_to_string/1, t_from_form/6, t_from_form_without_remote/3, + t_from_form_check_remote/4, t_check_record_fields/6, t_from_range/2, t_from_range_unsafe/2, @@ -236,7 +229,7 @@ -export([t_is_identifier/1]). -endif. --export_type([erl_type/0, opaques/0, type_table/0, mod_records/0, +-export_type([erl_type/0, opaques/0, type_table/0, var_table/0, cache/0]). %%-define(DEBUG, true). @@ -374,15 +367,17 @@ -type opaques() :: [erl_type()] | 'universe'. +-type file_line() :: {file:name(), erl_anno:line()}. -type record_key() :: {'record', atom()}. -type type_key() :: {'type' | 'opaque', mfa()}. --type record_value() :: [{atom(), erl_parse:abstract_expr(), erl_type()}]. --type type_value() :: {{module(), {file:name(), erl_anno:line()}, +-type field() :: {atom(), erl_parse:abstract_expr(), erl_type()}. +-type record_value() :: {file_line(), + [{RecordSize :: non_neg_integer(), [field()]}]}. +-type type_value() :: {{module(), file_line(), erl_parse:abstract_type(), ArgNames :: [atom()]}, erl_type()}. -type type_table() :: #{record_key() | type_key() => record_value() | type_value()}. --type mod_records() :: dict:dict(module(), type_table()). -opaque var_table() :: #{atom() => erl_type()}. @@ -536,7 +531,9 @@ list_contains_opaque(List, Opaques) -> 'error' | {'ok', erl_type(), erl_type()}. t_find_opaque_mismatch(T1, T2, Opaques) -> - catch t_find_opaque_mismatch(T1, T2, T2, Opaques). + try t_find_opaque_mismatch(T1, T2, T2, Opaques) + catch throw:error -> error + end. t_find_opaque_mismatch(?any, _Type, _TopType, _Opaques) -> error; t_find_opaque_mismatch(?none, _Type, _TopType, _Opaques) -> throw(error); @@ -588,8 +585,9 @@ t_find_opaque_mismatch_ordlists(L1, L2, TopType, Opaques) -> t_find_opaque_mismatch_list(List). t_find_opaque_mismatch_lists(L1, L2, _TopType, Opaques) -> - List = [catch t_find_opaque_mismatch(T1, T2, T2, Opaques) || - T1 <- L1, T2 <- L2], + List = [try t_find_opaque_mismatch(T1, T2, T2, Opaques) + catch throw:error -> error + end || T1 <- L1, T2 <- L2], t_find_opaque_mismatch_list(List). t_find_opaque_mismatch_list([]) -> throw(error); @@ -619,7 +617,9 @@ t_find_unknown_opaque(T1, T2, Opaques) -> %% is assumed to be taken from the contract. t_decorate_with_opaque(T1, T2, Opaques) -> - case t_is_equal(T1, T2) orelse not t_contains_opaque(T2) of + case + Opaques =:= [] orelse t_is_equal(T1, T2) orelse not t_contains_opaque(T2) + of true -> T1; false -> T = t_inf(T1, T2), @@ -1630,8 +1630,8 @@ lift_list_to_pos_empty(?list(Content, Termination, _)) -> %% * The keys in Pairs are singleton types. %% * The values of Pairs must not be unit, and may only be none if the %% mandatoriness tag is 'optional'. -%% * Optional must contain no pair {K,V} s.t. K is a subtype of DefaultKey and -%% V is equal to DefaultKey. +%% * There is no pair {K, 'optional', V} in Pairs s.t. +%% K is a subtype of DefaultKey and V is equal to DefaultValue. %% * DefaultKey must be the empty type iff DefaultValue is the empty type. %% * DefaultKey must not be a singleton type. %% * For every key K in Pairs, DefaultKey - K must not be representable; i.e. @@ -4257,8 +4257,8 @@ t_to_string(?opaque(Set), RecDict) -> <- set_to_list(Set)], " | "); t_to_string(?matchstate(Pres, Slots), RecDict) -> - flat_format("ms(~s,~s)", [t_to_string(Pres, RecDict), - t_to_string(Slots,RecDict)]); + flat_format("ms(~ts,~ts)", [t_to_string(Pres, RecDict), + t_to_string(Slots,RecDict)]); t_to_string(?nil, _RecDict) -> "[]"; t_to_string(?nonempty_list(Contents, Termination), RecDict) -> @@ -4436,10 +4436,10 @@ opaque_type(Mod, Name, Args, _S, RecDict) -> opaque_name(Mod, Name, Extra) -> S = mod_name(Mod, Name), - flat_format("~s(~s)", [S, Extra]). + flat_format("~ts(~ts)", [S, Extra]). mod_name(Mod, Name) -> - flat_format("~w:~w", [Mod, Name]). + flat_format("~w:~tw", [Mod, Name]). %%============================================================================= %% @@ -4454,9 +4454,17 @@ mod_name(Mod, Name) -> -type site() :: {'type', mta()} | {'spec', mfa()} | {'record', mra()}. -type cache_key() :: {module(), atom(), expand_depth(), [erl_type()], type_names()}. --opaque cache() :: #{cache_key() => {erl_type(), expand_limit()}}. +-type mod_type_table() :: ets:tid(). +-type mod_records() :: dict:dict(module(), type_table()). +-record(cache, + { + types = maps:new() :: #{cache_key() => {erl_type(), expand_limit()}}, + mod_recs = {mrecs, dict:new()} :: {'mrecs', mod_records()} + }). + +-opaque cache() :: #cache{}. --spec t_from_form(parse_form(), sets:set(mfa()), site(), mod_records(), +-spec t_from_form(parse_form(), sets:set(mfa()), site(), mod_type_table(), var_table(), cache()) -> {erl_type(), cache()}. t_from_form(Form, ExpTypes, Site, RecDict, VarTab, Cache) -> @@ -4464,46 +4472,66 @@ t_from_form(Form, ExpTypes, Site, RecDict, VarTab, Cache) -> %% Replace external types with with none(). -spec t_from_form_without_remote(parse_form(), site(), type_table()) -> - {erl_type(), cache()}. + erl_type(). t_from_form_without_remote(Form, Site, TypeTable) -> Module = site_module(Site), - RecDict = dict:from_list([{Module, TypeTable}]), + ModRecs = dict:from_list([{Module, TypeTable}]), ExpTypes = replace_by_none, VarTab = var_table__new(), - Cache = cache__new(), - t_from_form1(Form, ExpTypes, Site, RecDict, VarTab, Cache). - -%% REC_TYPE_LIMIT is used for limiting the depth of recursive types. -%% EXPAND_LIMIT is used for limiting the size of types by -%% limiting the number of elements of lists within one type form. -%% EXPAND_DEPTH is used in conjunction with EXPAND_LIMIT to make the -%% types balanced (unions will otherwise collapse to any()) by limiting -%% the depth the same way as t_limit/2 does. + Cache0 = cache__new(), + Cache = Cache0#cache{mod_recs = {mrecs, ModRecs}}, + {Type, _} = t_from_form1(Form, ExpTypes, Site, undefined, VarTab, Cache), + Type. -type expand_limit() :: integer(). -type expand_depth() :: integer(). --record(from_form, {site :: site(), +-record(from_form, {site :: site() | {'check', mta()}, xtypes :: sets:set(mfa()) | 'replace_by_none', - mrecs :: mod_records(), + mrecs :: 'undefined' | mod_type_table(), vtab :: var_table(), tnames :: type_names()}). +-spec t_from_form_check_remote(parse_form(), sets:set(mfa()), mta(), + mod_type_table()) -> 'ok'. +t_from_form_check_remote(Form, ExpTypes, MTA, RecDict) -> + State = #from_form{site = {check, MTA}, + xtypes = ExpTypes, + mrecs = RecDict, + vtab = var_table__new(), + tnames = []}, + D = (1 bsl 25), % unlimited + L = (1 bsl 25), + Cache0 = cache__new(), + _ = t_from_form2(Form, State, D, L, Cache0), + ok. + +%% REC_TYPE_LIMIT is used for limiting the depth of recursive types. +%% EXPAND_LIMIT is used for limiting the size of types by +%% limiting the number of elements of lists within one type form. +%% EXPAND_DEPTH is used in conjunction with EXPAND_LIMIT to make the +%% types balanced (unions will otherwise collapse to any()) by limiting +%% the depth the same way as t_limit/2 does. + -spec t_from_form1(parse_form(), sets:set(mfa()) | 'replace_by_none', - site(), mod_records(), var_table(), cache()) -> - {erl_type(), cache()}. + site(), 'undefined' | mod_type_table(), var_table(), + cache()) -> {erl_type(), cache()}. t_from_form1(Form, ET, Site, MR, V, C) -> TypeNames = initial_typenames(Site), + D = ?EXPAND_DEPTH, + L = ?EXPAND_LIMIT, State = #from_form{site = Site, xtypes = ET, mrecs = MR, vtab = V, tnames = TypeNames}, - L = ?EXPAND_LIMIT, - {T0, L0, C0} = from_form(Form, State, ?EXPAND_DEPTH, L, C), + t_from_form2(Form, State, D, L, C). + +t_from_form2(Form, State, D, L, C) -> + {T0, L0, C0} = from_form(Form, State, D, L, C), if L0 =< 0 -> {T1, _, C1} = from_form(Form, State, 1, L, C0), @@ -4647,7 +4675,8 @@ from_form({type, _L, map, List}, S, D0, L, C) -> end end(List, L, C), try - {Pairs, DefK, DefV} = map_from_form(Pairs1, [], [], [], ?none, ?none), + Pairs2 = singleton_elements(Pairs1), + {Pairs, DefK, DefV} = map_from_form(Pairs2, [], [], [], ?none, ?none), {t_map(Pairs, DefK, DefV), L5, C5} catch none -> {t_none(), L5, C5} end; @@ -4739,13 +4768,13 @@ from_form({opaque, _L, Name, {Mod, Args, Rep}}, _S, _D, L, C) -> builtin_type(Name, Type, S, D, L, C) -> #from_form{site = Site, mrecs = MR} = S, M = site_module(Site), - case dict:find(M, MR) of - {ok, R} -> + case lookup_module_types(M, MR, C) of + {R, C1} -> case lookup_type(Name, 0, R) of {_, {{_M, _FL, _F, _A}, _T}} -> - type_from_form(Name, [], S, D, L, C); + type_from_form(Name, [], S, D, L, C1); error -> - {Type, L, C} + {Type, L, C1} end; error -> {Type, L, C} @@ -4758,15 +4787,19 @@ type_from_form(Name, Args, S, D, L, C) -> TypeName = {type, {Module, Name, ArgsLen}}, case can_unfold_more(TypeName, TypeNames) of true -> - {ok, R} = dict:find(Module, MR), - type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, - S, D, L, C); + {R, C1} = lookup_module_types(Module, MR, C), + type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, Site, + S, D, L, C1); false -> {t_any(), L, C} end. -type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, S, D, L, C) -> +type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, Site, + S, D, L, C) -> case lookup_type(Name, ArgsLen, R) of + {_, {_, _}} when element(1, Site) =:= check -> + {_ArgTypes, L1, C1} = list_from_form(Args, S, D, L, C), + {t_any(), L1, C1}; {Tag, {{Module, _FileName, Form, ArgNames}, Type}} -> NewTypeNames = [TypeName|TypeNames], S1 = S#from_form{tnames = NewTypeNames}, @@ -4799,50 +4832,52 @@ type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, S, D, L, C) -> {NewType, L3, C4} end; error -> - Msg = io_lib:format("Unable to find type ~w/~w\n", + Msg = io_lib:format("Unable to find type ~tw/~w\n", [Name, ArgsLen]), throw({error, Msg}) end. remote_from_form(RemMod, Name, Args, S, D, L, C) -> - #from_form{xtypes = ET, mrecs = MR, tnames = TypeNames} = S, + #from_form{site = Site, xtypes = ET, mrecs = MR, tnames = TypeNames} = S, if ET =:= replace_by_none -> {t_none(), L, C}; true -> ArgsLen = length(Args), MFA = {RemMod, Name, ArgsLen}, - case dict:find(RemMod, MR) of + case lookup_module_types(RemMod, MR, C) of error -> self() ! {self(), ext_types, MFA}, {t_any(), L, C}; - {ok, RemDict} -> + {RemDict, C1} -> case sets:is_element(MFA, ET) of true -> RemType = {type, MFA}, case can_unfold_more(RemType, TypeNames) of true -> remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, - RemType, TypeNames, S, D, L, C); + RemType, TypeNames, Site, S, D, L, C1); false -> - {t_any(), L, C} + {t_any(), L, C1} end; false -> self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}, - {t_any(), L, C} + {t_any(), L, C1} end end end. remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames, - S, D, L, C) -> + Site, S, D, L, C) -> case lookup_type(Name, ArgsLen, RemDict) of + {_, {_, _}} when element(1, Site) =:= check -> + {_ArgTypes, L1, C1} = list_from_form(Args, S, D, L, C), + {t_any(), L1, C1}; {Tag, {{Mod, _FileLine, Form, ArgNames}, Type}} -> NewTypeNames = [RemType|TypeNames], S1 = S#from_form{tnames = NewTypeNames}, {ArgTypes, L1, C1} = list_from_form(Args, S1, D, L, C), CKey = cache_key(RemMod, Name, ArgTypes, TypeNames, D), - %% case error of case cache_find(CKey, C) of {CachedType, DeltaL} -> {CachedType, L - DeltaL, C}; @@ -4871,7 +4906,7 @@ remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames, {NewType, L3, C4} end; error -> - Msg = io_lib:format("Unable to find remote type ~w:~w()\n", + Msg = io_lib:format("Unable to find remote type ~w:~tw()\n", [RemMod, Name]), throw({error, Msg}) end. @@ -4904,33 +4939,35 @@ record_from_form({atom, _, Name}, ModFields, S, D0, L0, C) -> case can_unfold_more(RecordType, TypeNames) of true -> M = site_module(Site), - {ok, R} = dict:find(M, MR), + {R, C1} = lookup_module_types(M, MR, C), case lookup_record(Name, R) of + {ok, _} when element(1, Site) =:= check -> + {t_any(), L0, C1}; {ok, DeclFields} -> NewTypeNames = [RecordType|TypeNames], Site1 = {record, {M, Name, length(DeclFields)}}, S1 = S#from_form{site = Site1, tnames = NewTypeNames}, Fun = fun(D, L) -> - {GetModRec, L1, C1} = - get_mod_record(ModFields, DeclFields, S1, D, L, C), + {GetModRec, L1, C2} = + get_mod_record(ModFields, DeclFields, S1, D, L, C1), case GetModRec of {error, FieldName} -> throw({error, - io_lib:format("Illegal declaration of #~w{~w}\n", + io_lib:format("Illegal declaration of #~tw{~tw}\n", [Name, FieldName])}); {ok, NewFields} -> S2 = S1#from_form{vtab = var_table__new()}, - {NewFields1, L2, C2} = - fields_from_form(NewFields, S2, D, L1, C1), + {NewFields1, L2, C3} = + fields_from_form(NewFields, S2, D, L1, C2), Rec = t_tuple( [t_atom(Name)|[Type || {_FieldName, Type} <- NewFields1]]), - {Rec, L2, C2} + {Rec, L2, C3} end end, recur_limit(Fun, D0, L0, RecordType, TypeNames); error -> - throw({error, io_lib:format("Unknown record #~w{}\n", [Name])}) + throw({error, io_lib:format("Unknown record #~tw{}\n", [Name])}) end; false -> {t_any(), L0, C} @@ -4990,6 +5027,30 @@ list_from_form([H|Tail], S, D, L, C) -> {T1, L2, C2} = list_from_form(Tail, S, D, L1, C1), {[H1|T1], L2, C2}. +%% Separates singleton types in keys (see is_singleton_type/1). +singleton_elements([]) -> + []; +singleton_elements([{K,?mand,V}=Pair|Pairs]) -> + case is_singleton_type(K) of + true -> + [Pair|singleton_elements(Pairs)]; + false -> + singleton_elements([{K,?opt,V}|Pairs]) + end; +singleton_elements([{Key0,MNess,Val}|Pairs]) -> + [{Key,MNess,Val} || Key <- separate_key(Key0)] ++ singleton_elements(Pairs). + +%% To be in sync with is_singleton_type/1. +%% Does not separate tuples and maps as doing that has potential +%% to be very expensive. +separate_key(?atom(Atoms)) when Atoms =/= ?any -> + [t_atom(A) || A <- Atoms]; +separate_key(?number(_, _) = T) -> + t_elements(T); +separate_key(?union(List)) -> + lists:append([separate_key(K) || K <- List, not t_is_none(K)]); +separate_key(Key) -> [Key]. + %% Sorts, combines non-singleton pairs, and applies precendence and %% mandatoriness rules. map_from_form([], ShdwPs, MKs, Pairs, DefK, DefV) -> @@ -5056,7 +5117,7 @@ recur_limit(Fun, D, L, TypeName, TypeNames) -> end. -spec t_check_record_fields(parse_form(), sets:set(mfa()), site(), - mod_records(), var_table(), cache()) -> cache(). + mod_type_table(), var_table(), cache()) -> cache(). t_check_record_fields(Form, ExpTypes, Site, RecDict, VarTable, Cache) -> State = #from_form{site = Site, @@ -5100,13 +5161,13 @@ check_record_fields({user_type, _L, _Name, Args}, S, C) -> check_record({atom, _, Name}, ModFields, S, C) -> #from_form{site = Site, mrecs = MR} = S, M = site_module(Site), - {ok, R} = dict:find(M, MR), + {R, C1} = lookup_module_types(M, MR, C), {ok, DeclFields} = lookup_record(Name, R), - case check_fields(Name, ModFields, DeclFields, S, C) of + case check_fields(Name, ModFields, DeclFields, S, C1) of {error, FieldName} -> - throw({error, io_lib:format("Illegal declaration of #~w{~w}\n", - [Name, FieldName])}); - C1 -> C1 + throw({error, io_lib:format("Illegal declaration of #~tw{~tw}\n", + [Name, FieldName])}); + C2 -> C2 end. check_fields(RecName, [{type, _, field_type, [{atom, _, Name}, Abstr]}|Left], @@ -5136,7 +5197,7 @@ site_module({_, {Module, _, _}}) -> -spec cache__new() -> cache(). cache__new() -> - maps:new(). + #cache{}. -spec cache_key(module(), atom(), [erl_type()], type_names(), expand_depth()) -> cache_key(). @@ -5153,8 +5214,8 @@ cache_key(Module, Name, ArgTypes, TypeNames, D) -> -spec cache_find(cache_key(), cache()) -> {erl_type(), expand_limit()} | 'error'. -cache_find(Key, Cache) -> - case maps:find(Key, Cache) of +cache_find(Key, #cache{types = Types}) -> + case maps:find(Key, Types) of {ok, Value} -> Value; error -> @@ -5166,12 +5227,13 @@ cache_find(Key, Cache) -> cache_put(_Key, _Type, DeltaL, Cache) when DeltaL < 0 -> %% The type is truncated; do not reuse it. Cache; -cache_put(Key, Type, DeltaL, Cache) -> - maps:put(Key, {Type, DeltaL}, Cache). +cache_put(Key, Type, DeltaL, #cache{types = Types} = Cache) -> + NewTypes = maps:put(Key, {Type, DeltaL}, Types), + Cache#cache{types = NewTypes}. --spec t_var_names([erl_type()]) -> [atom()]. +-spec t_var_names([parse_form()]) -> [atom()]. -t_var_names([{var, _, Name}|L]) when L =/= '_' -> +t_var_names([{var, _, Name}|L]) when Name =/= '_' -> [Name|t_var_names(L)]; t_var_names([]) -> []. @@ -5197,10 +5259,10 @@ t_form_to_string({op, _L, _Op, _Arg1, _Arg2} = Op) -> t_form_to_string({ann_type, _L, [Var, Type]}) -> t_form_to_string(Var) ++ "::" ++ t_form_to_string(Type); t_form_to_string({paren_type, _L, [Type]}) -> - flat_format("(~s)", [t_form_to_string(Type)]); + flat_format("(~ts)", [t_form_to_string(Type)]); t_form_to_string({remote_type, _L, [{atom, _, Mod}, {atom, _, Name}, Args]}) -> ArgString = "(" ++ string:join(t_form_to_string_list(Args), ",") ++ ")", - flat_format("~w:~w", [Mod, Name]) ++ ArgString; + flat_format("~w:~tw", [Mod, Name]) ++ ArgString; t_form_to_string({type, _L, arity, []}) -> "arity()"; t_form_to_string({type, _L, binary, []}) -> "binary()"; t_form_to_string({type, _L, binary, [Base, Unit]} = Type) -> @@ -5250,12 +5312,12 @@ t_form_to_string({type, _L, range, [From, To]} = Type) -> _ -> flat_format("Badly formed type ~w",[Type]) end; t_form_to_string({type, _L, record, [{atom, _, Name}]}) -> - flat_format("#~w{}", [Name]); + flat_format("#~tw{}", [Name]); t_form_to_string({type, _L, record, [{atom, _, Name}|Fields]}) -> FieldString = string:join(t_form_to_string_list(Fields), ","), - flat_format("#~w{~s}", [Name, FieldString]); + flat_format("#~tw{~ts}", [Name, FieldString]); t_form_to_string({type, _L, field_type, [{atom, _, Name}, Type]}) -> - flat_format("~w::~s", [Name, t_form_to_string(Type)]); + flat_format("~tw::~ts", [Name, t_form_to_string(Type)]); t_form_to_string({type, _L, term, []}) -> "term()"; t_form_to_string({type, _L, timeout, []}) -> "timeout()"; t_form_to_string({type, _L, tuple, any}) -> "tuple()"; @@ -5266,14 +5328,12 @@ t_form_to_string({type, _L, union, Args}) -> t_form_to_string({type, _L, Name, []} = T) -> try M = mod, - D0 = maps:new(), - MR = dict:from_list([{M, D0}]), Site = {type, {M,Name,0}}, V = var_table__new(), C = cache__new(), State = #from_form{site = Site, xtypes = sets:new(), - mrecs = MR, + mrecs = 'undefined', vtab = V, tnames = []}, {T1, _, _} = from_form(T, State, _Deep=1000, _ALot=1000000, C), @@ -5281,7 +5341,7 @@ t_form_to_string({type, _L, Name, []} = T) -> catch throw:{error, _} -> atom_to_string(Name) ++ "()" end; t_form_to_string({user_type, _L, Name, List}) -> - flat_format("~w(~s)", + flat_format("~tw(~ts)", [Name, string:join(t_form_to_string_list(List), ",")]); t_form_to_string({type, L, Name, List}) -> %% Compatibility: modules compiled before Erlang/OTP 18.0. @@ -5298,7 +5358,7 @@ t_form_to_string_list([], Acc) -> -spec atom_to_string(atom()) -> string(). atom_to_string(Atom) -> - flat_format("~w", [Atom]). + flat_format("~tw", [Atom]). %%============================================================================= %% @@ -5327,6 +5387,24 @@ is_erl_type(?unit) -> true; is_erl_type(#c{}) -> true; is_erl_type(_) -> false. +-spec lookup_module_types(module(), mod_type_table(), cache()) -> + 'error' | {type_table(), cache()}. + +lookup_module_types(Module, CodeTable, Cache) -> + #cache{mod_recs = {mrecs, MRecs}} = Cache, + case dict:find(Module, MRecs) of + {ok, R} -> + {R, Cache}; + error -> + try ets:lookup_element(CodeTable, Module, 2) of + R -> + NewMRecs = dict:store(Module, R, MRecs), + {R, Cache#cache{mod_recs = {mrecs, NewMRecs}}} + catch + _:_ -> error + end + end. + -spec lookup_record(atom(), type_table()) -> 'error' | {'ok', [{atom(), parse_form(), erl_type()}]}. @@ -5422,7 +5500,8 @@ t_is_singleton(Type) -> t_is_singleton(Type, Opaques) -> do_opaque(Type, Opaques, fun is_singleton_type/1). -%% Incomplete; not all representable singleton types are included. +%% To be in sync with separate_key/1. +%% Used to also recognize maps and tuples. is_singleton_type(?nil) -> true; is_singleton_type(?atom(?any)) -> false; is_singleton_type(?atom(Set)) -> @@ -5430,13 +5509,6 @@ is_singleton_type(?atom(Set)) -> is_singleton_type(?int_range(V, V)) -> true; is_singleton_type(?int_set(Set)) -> ordsets:size(Set) =:= 1; -is_singleton_type(?tuple(Types, Arity, _)) when is_integer(Arity) -> - lists:all(fun is_singleton_type/1, Types); -is_singleton_type(?tuple_set([{Arity, [OnlyTuple]}])) when is_integer(Arity) -> - is_singleton_type(OnlyTuple); -is_singleton_type(?map(Pairs, ?none, ?none)) -> - lists:all(fun({_,MNess,V}) -> MNess =:= ?mand andalso is_singleton_type(V) - end, Pairs); is_singleton_type(_) -> false. @@ -5529,7 +5601,7 @@ set_size(Set) -> set_to_string(Set) -> L = [case is_atom(X) of true -> io_lib:write_string(atom_to_list(X), $'); % stupid emacs ' - false -> flat_format("~w", [X]) + false -> flat_format("~tw", [X]) end || X <- set_to_list(Set)], string:join(L, " | "). |