diff options
20 files changed, 292 insertions, 62 deletions
diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl index fd214228c7..c41532ed87 100644 --- a/erts/preloaded/src/erts_code_purger.erl +++ b/erts/preloaded/src/erts_code_purger.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2016. All Rights Reserved. +%% Copyright Ericsson AB 2016-2018. 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. @@ -25,7 +25,7 @@ -export([start/0, purge/1, soft_purge/1, pending_purge_lambda/3, finish_after_on_load/2]). --spec start() -> term(). +-spec start() -> no_return(). start() -> register(erts_code_purger, self()), process_flag(trap_exit, true), diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index a4ef42204d..6f53e67901 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2017. All Rights Reserved. +%% Copyright Ericsson AB 2003-2018. 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. @@ -87,7 +87,7 @@ %%------------------------------------------------------------------------ %% Public data types. --type zstream() :: term(). +-type zstream() :: reference(). -type zflush() :: 'none' | 'sync' | 'full' | 'finish'. -type zlevel() :: @@ -102,11 +102,11 @@ -type zmethod() :: 'deflated'. -record(zlib_opts, { - stream :: zstream(), - method :: term(), - input_chunk_size :: integer(), - output_chunk_size :: integer(), - flush :: integer() + stream :: zstream() | 'undefined', + method :: function(), + input_chunk_size :: pos_integer(), + output_chunk_size :: pos_integer(), + flush :: non_neg_integer() }). %%------------------------------------------------------------------------ @@ -168,7 +168,7 @@ deflateInit_nif(_Z, _Level, _Method, _WindowBits, _MemLevel, _Strategy) -> -spec deflateSetDictionary(Z, Dictionary) -> Adler32 when Z :: zstream(), Dictionary :: iodata(), - Adler32 :: integer(). + Adler32 :: non_neg_integer(). deflateSetDictionary(Z, Dictionary) -> deflateSetDictionary_nif(Z, Dictionary). deflateSetDictionary_nif(_Z, _Dictionary) -> @@ -295,7 +295,7 @@ inflate(Z, Data) -> Options :: list({exception_on_need_dict, boolean()}), Decompressed :: iolist() | {need_dictionary, - Adler32 :: integer(), + Adler32 :: non_neg_integer(), Output :: iolist()}. inflate(Z, Data, Options) -> enqueue_input(Z, Data), @@ -357,7 +357,7 @@ exception_on_need_dict(Z, Output) when is_list(Output); is_binary(Output) -> Result :: {continue, Output :: iolist()} | {finished, Output :: iolist()} | {need_dictionary, - Adler32 :: integer(), + Adler32 :: non_neg_integer(), Output :: iolist()}. safeInflate(Z, Data) -> enqueue_input(Z, Data), @@ -389,7 +389,7 @@ getBufSize_nif(_Z) -> -spec crc32(Z) -> CRC when Z :: zstream(), - CRC :: integer(). + CRC :: non_neg_integer(). crc32(Z) -> crc32_nif(Z). crc32_nif(_Z) -> @@ -398,7 +398,7 @@ crc32_nif(_Z) -> -spec crc32(Z, Data) -> CRC when Z :: zstream(), Data :: iodata(), - CRC :: integer(). + CRC :: non_neg_integer(). crc32(Z, Data) when is_reference(Z) -> erlang:crc32(Data); crc32(_Z, _Data) -> @@ -406,9 +406,9 @@ crc32(_Z, _Data) -> -spec crc32(Z, PrevCRC, Data) -> CRC when Z :: zstream(), - PrevCRC :: integer(), + PrevCRC :: non_neg_integer(), Data :: iodata(), - CRC :: integer(). + CRC :: non_neg_integer(). crc32(Z, CRC, Data) when is_reference(Z) -> erlang:crc32(CRC, Data); crc32(_Z, _CRC, _Data) -> @@ -416,10 +416,10 @@ crc32(_Z, _CRC, _Data) -> -spec crc32_combine(Z, CRC1, CRC2, Size2) -> CRC when Z :: zstream(), - CRC :: integer(), - CRC1 :: integer(), - CRC2 :: integer(), - Size2 :: integer(). + CRC :: non_neg_integer(), + CRC1 :: non_neg_integer(), + CRC2 :: non_neg_integer(), + Size2 :: non_neg_integer(). crc32_combine(Z, CRC1, CRC2, Size2) when is_reference(Z) -> erlang:crc32_combine(CRC1, CRC2, Size2); crc32_combine(_Z, _CRC1, _CRC2, _Size2) -> @@ -428,7 +428,7 @@ crc32_combine(_Z, _CRC1, _CRC2, _Size2) -> -spec adler32(Z, Data) -> CheckSum when Z :: zstream(), Data :: iodata(), - CheckSum :: integer(). + CheckSum :: non_neg_integer(). adler32(Z, Data) when is_reference(Z) -> erlang:adler32(Data); adler32(_Z, _Data) -> @@ -436,9 +436,9 @@ adler32(_Z, _Data) -> -spec adler32(Z, PrevAdler, Data) -> CheckSum when Z :: zstream(), - PrevAdler :: integer(), + PrevAdler :: non_neg_integer(), Data :: iodata(), - CheckSum :: integer(). + CheckSum :: non_neg_integer(). adler32(Z, Adler, Data) when is_reference(Z) -> erlang:adler32(Adler, Data); adler32(_Z, _Adler, _Data) -> @@ -446,10 +446,10 @@ adler32(_Z, _Adler, _Data) -> -spec adler32_combine(Z, Adler1, Adler2, Size2) -> Adler when Z :: zstream(), - Adler :: integer(), - Adler1 :: integer(), - Adler2 :: integer(), - Size2 :: integer(). + Adler :: non_neg_integer(), + Adler1 :: non_neg_integer(), + Adler2 :: non_neg_integer(), + Size2 :: non_neg_integer(). adler32_combine(Z, Adler1, Adler2, Size2) when is_reference(Z) -> erlang:adler32_combine(Adler1, Adler2, Size2); adler32_combine(_Z, _Adler1, _Adler2, _Size2) -> diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl index 5ef340c831..df0321e85a 100644 --- a/lib/compiler/src/beam_asm.erl +++ b/lib/compiler/src/beam_asm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -475,7 +475,7 @@ encode_alloc_list_1([{floats,Floats}|T], Dict, Acc0) -> encode_alloc_list_1([], Dict, Acc) -> {iolist_to_binary(Acc),Dict}. --spec encode(non_neg_integer(), integer()) -> iodata(). +-spec encode(non_neg_integer(), integer()) -> iolist() | integer(). encode(Tag, N) when N < 0 -> encode1(Tag, negative_to_bytes(N)); diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 1538174d4a..185c8c9ae6 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -409,6 +409,10 @@ message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}) -> io_lib:format("The specification for ~w:~tw/~w states that the function" " might also return ~ts but the inferred return is ~ts\n", [M, F, A, ExtraRanges, SigRange]); +message_to_string({missing_range, [M, F, A, ExtraRanges, ContrRange]}) -> + io_lib:format("The success typing for ~w:~tw/~w implies that the function" + " might also return ~ts but the specification return is ~ts\n", + [M, F, A, ExtraRanges, ContrRange]); message_to_string({overlapping_contract, [M, F, A]}) -> io_lib:format("Overloaded contract for ~w:~tw/~w has overlapping domains;" " such contracts are currently unsupported and are simply ignored\n", diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index 0df15e55f9..af7f4385ad 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -197,9 +197,11 @@ check_contracts(Contracts, Callgraph, FunTypes, ModOpaques) -> false -> [{MFA, Contract}|NewContracts] end; - {error, {extra_range, _, _}} -> - %% do not treat extra range as an error in this check - %% since that prevents discovering other actual errors + {range_warnings, _} -> + %% do not treat extra range, either in contract or + %% in success typing, as an error in this check + %% since that prevents discovering other actual + %% errors [{MFA, Contract}|NewContracts]; {error, _Error} -> NewContracts end; @@ -210,14 +212,26 @@ check_contracts(Contracts, Callgraph, FunTypes, ModOpaques) -> end, orddict:from_list(lists:foldl(FoldFun, [], orddict:to_list(FunTypes))). +-type check_contract_return() :: + 'ok' + | {'error', + 'invalid_contract' + | {'opaque_mismatch', erl_types:erl_type()} + | {'overlapping_contract', [module() | atom() | byte()]} + | string()} + | {'range_warnings', + [{'error', {'extra_range' | 'missing_range', + erl_types:erl_type(), + erl_types:erl_type()}}]}. + %% Checks all components of a contract --spec check_contract(#contract{}, erl_types:erl_type()) -> 'ok' | {'error', term()}. +-spec check_contract(#contract{}, erl_types:erl_type()) -> check_contract_return(). check_contract(Contract, SuccType) -> check_contract(Contract, SuccType, 'universe'). -spec check_contract(#contract{}, erl_types:erl_type(), erl_types:opaques()) -> - 'ok' | {'error', term()}. + check_contract_return(). check_contract(#contract{contracts = Contracts}, SuccType, Opaques) -> try @@ -290,15 +304,23 @@ check_contract_inf_list([], _SuccType, _Opaques, OM) -> check_extraneous([], _SuccType) -> ok; check_extraneous([C|Cs], SuccType) -> case check_extraneous_1(C, SuccType) of - ok -> check_extraneous(Cs, SuccType); - Error -> Error + {error, invalid_contract} = Error -> + Error; + {error, {extra_range, _, _}} = Error -> + {range_warnings, [Error | check_missing(C, SuccType)]}; + ok -> + case check_missing(C, SuccType) of + [] -> check_extraneous(Cs, SuccType); + ErrorL -> {range_warnings, ErrorL} + end end. check_extraneous_1(Contract, SuccType) -> CRng = erl_types:t_fun_range(Contract), CRngs = erl_types:t_elements(CRng), STRng = erl_types:t_fun_range(SuccType), - ?debug("CR = ~tp\nSR = ~tp\n", [CRngs, STRng]), + ?debug("\nCR = ~ts\nSR = ~ts\n", [erl_types:t_to_string(CRng), + erl_types:t_to_string(STRng)]), case [CR || CR <- CRngs, erl_types:t_is_none(erl_types:t_inf(CR, STRng))] of [] -> @@ -341,6 +363,18 @@ map_part(Type) -> is_empty_map(Type) -> erl_types:t_is_equal(Type, erl_types:t_from_term(#{})). +check_missing(Contract, SuccType) -> + CRng = erl_types:t_fun_range(Contract), + STRng = erl_types:t_fun_range(SuccType), + STRngs = erl_types:t_elements(STRng), + ?debug("\nCR = ~ts\nSR = ~ts\n", [erl_types:t_to_string(CRng), + erl_types:t_to_string(STRng)]), + case [STR || STR <- STRngs, + erl_types:t_is_none(erl_types:t_inf(STR, CRng))] of + [] -> []; + STRs -> [{error, {missing_range, erl_types:t_sup(STRs), CRng}}] + end. + %% This is the heart of the "range function" -spec process_contracts([contract_pair()], [erl_types:erl_type()]) -> erl_types:erl_type(). @@ -712,22 +746,30 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left], [W|Acc]; {error, {overlapping_contract, []}} -> [overlapping_contract_warning(MFA, WarningInfo)|Acc]; - {error, {extra_range, ExtraRanges, STRange}} -> - Warn = - case t_from_forms_without_remote(Contract#contract.forms, - MFA, RecDict) of - {ok, NoRemoteType} -> - CRet = erl_types:t_fun_range(NoRemoteType), - erl_types:t_is_subtype(ExtraRanges, CRet); - unsupported -> - true - end, - case Warn of - true -> - [extra_range_warning(MFA, WarningInfo, ExtraRanges, STRange)|Acc]; - false -> - Acc - end; + {range_warnings, Errors} -> + Fun = + fun({error, {extra_range, ExtraRanges, STRange}}, Acc0) -> + Warn = + case t_from_forms_without_remote(Contract#contract.forms, + MFA, RecDict) of + {ok, NoRemoteType} -> + CRet = erl_types:t_fun_range(NoRemoteType), + erl_types:t_is_subtype(ExtraRanges, CRet); + unsupported -> + true + end, + case Warn of + true -> + [extra_range_warning(MFA, WarningInfo, + ExtraRanges, STRange)|Acc0]; + false -> + Acc0 + end; + ({error, {missing_range, ExtraRanges, CRange}}, Acc0) -> + [missing_range_warning(MFA, WarningInfo, + ExtraRanges, CRange)|Acc0] + end, + lists:foldl(Fun, Acc, Errors); {error, Msg} -> [{?WARN_CONTRACT_SYNTAX, WarningInfo, Msg}|Acc]; ok -> @@ -745,6 +787,9 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left], {error, _} -> [invalid_contract_warning(MFA, WarningInfo, BifSig, RecDict) |Acc]; + {range_warnings, _} -> + picky_contract_check(CSig, BifSig, MFA, WarningInfo, + Contract, RecDict, Acc); ok -> picky_contract_check(CSig, BifSig, MFA, WarningInfo, Contract, RecDict, Acc) @@ -778,6 +823,12 @@ extra_range_warning({M, F, A}, WarningInfo, ExtraRanges, STRange) -> {?WARN_CONTRACT_SUPERTYPE, WarningInfo, {extra_range, [M, F, A, ERangesStr, STRangeStr]}}. +missing_range_warning({M, F, A}, WarningInfo, ExtraRanges, CRange) -> + ERangesStr = erl_types:t_to_string(ExtraRanges), + CRangeStr = erl_types:t_to_string(CRange), + {?WARN_CONTRACT_SUBTYPE, WarningInfo, + {missing_range, [M, F, A, ERangesStr, CRangeStr]}}. + picky_contract_check(CSig0, Sig0, MFA, WarningInfo, Contract, RecDict, Acc) -> CSig = erl_types:t_abstract_records(CSig0, RecDict), Sig = erl_types:t_abstract_records(Sig0, RecDict), diff --git a/lib/dialyzer/src/typer.erl b/lib/dialyzer/src/typer.erl index 9d3d9ce438..4b99f5f72e 100644 --- a/lib/dialyzer/src/typer.erl +++ b/lib/dialyzer/src/typer.erl @@ -401,7 +401,7 @@ get_type({{M, F, A} = MFA, Range, Arg}, CodeServer, Records) -> Sig = erl_types:t_fun(Arg, Range), case dialyzer_contracts:check_contract(Contract, Sig) of ok -> {{F, A}, {contract, Contract}}; - {error, {extra_range, _, _}} -> + {range_warnings, _} -> {{F, A}, {contract, Contract}}; {error, {overlapping_contract, []}} -> {{F, A}, {contract, Contract}}; diff --git a/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options b/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options new file mode 100644 index 0000000000..ff4517e59d --- /dev/null +++ b/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options @@ -0,0 +1 @@ +{dialyzer_options, [{warnings, [overspecs]}]}. diff --git a/lib/dialyzer/test/overspecs_SUITE_data/results/iodata b/lib/dialyzer/test/overspecs_SUITE_data/results/iodata new file mode 100644 index 0000000000..d9c70330ec --- /dev/null +++ b/lib/dialyzer/test/overspecs_SUITE_data/results/iodata @@ -0,0 +1,2 @@ + +iodata.erl:7: The success typing for iodata:encode/2 implies that the function might also return integer() but the specification return is binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []) diff --git a/lib/dialyzer/test/overspecs_SUITE_data/results/iolist b/lib/dialyzer/test/overspecs_SUITE_data/results/iolist new file mode 100644 index 0000000000..ca556f017c --- /dev/null +++ b/lib/dialyzer/test/overspecs_SUITE_data/results/iolist @@ -0,0 +1,2 @@ + +iolist.erl:7: The success typing for iolist:encode/2 implies that the function might also return integer() but the specification return is maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []) diff --git a/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl b/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl new file mode 100644 index 0000000000..caa44f6c91 --- /dev/null +++ b/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl @@ -0,0 +1,41 @@ +-module(iodata). + +%% A small part of beam_asm. + +-export([encode/2]). + +-spec encode(non_neg_integer(), integer()) -> iodata(). % extra range binary() + +encode(Tag, N) when Tag >= 0, N < 0 -> + encode1(Tag, negative_to_bytes(N)); +encode(Tag, N) when Tag >= 0, N < 16 -> + (N bsl 4) bor Tag; % not in the specification +encode(Tag, N) when Tag >= 0, N < 16#800 -> + [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff]; +encode(Tag, N) when Tag >= 0 -> + encode1(Tag, to_bytes(N)). + +encode1(Tag, Bytes) -> + case iolist_size(Bytes) of + Num when 2 =< Num, Num =< 8 -> + [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes]; + Num when 8 < Num -> + [2#11111000 bor Tag, encode(0, Num-9)| Bytes] + end. + +to_bytes(N) -> + Bin = binary:encode_unsigned(N), + case Bin of + <<0:1,_/bits>> -> Bin; + <<1:1,_/bits>> -> [0,Bin] + end. + +negative_to_bytes(N) when N >= -16#8000 -> + <<N:16>>; +negative_to_bytes(N) -> + Bytes = byte_size(binary:encode_unsigned(-N)), + Bin = <<N:Bytes/unit:8>>, + case Bin of + <<0:1,_/bits>> -> [16#ff,Bin]; + <<1:1,_/bits>> -> Bin + end. diff --git a/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl b/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl new file mode 100644 index 0000000000..7cceeda24e --- /dev/null +++ b/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl @@ -0,0 +1,41 @@ +-module(iolist). + +%% A small part of beam_asm. + +-export([encode/2]). + +-spec encode(non_neg_integer(), integer()) -> iolist(). + +encode(Tag, N) when Tag >= 0, N < 0 -> + encode1(Tag, negative_to_bytes(N)); +encode(Tag, N) when Tag >= 0, N < 16 -> + (N bsl 4) bor Tag; % not in the specification +encode(Tag, N) when Tag >= 0, N < 16#800 -> + [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff]; +encode(Tag, N) when Tag >= 0 -> + encode1(Tag, to_bytes(N)). + +encode1(Tag, Bytes) -> + case iolist_size(Bytes) of + Num when 2 =< Num, Num =< 8 -> + [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes]; + Num when 8 < Num -> + [2#11111000 bor Tag, encode(0, Num-9)| Bytes] + end. + +to_bytes(N) -> + Bin = binary:encode_unsigned(N), + case Bin of + <<0:1,_/bits>> -> Bin; + <<1:1,_/bits>> -> [0,Bin] + end. + +negative_to_bytes(N) when N >= -16#8000 -> + <<N:16>>; +negative_to_bytes(N) -> + Bytes = byte_size(binary:encode_unsigned(-N)), + Bin = <<N:Bytes/unit:8>>, + case Bin of + <<0:1,_/bits>> -> [16#ff,Bin]; + <<1:1,_/bits>> -> Bin + end. diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options b/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options new file mode 100644 index 0000000000..56b36f2ed4 --- /dev/null +++ b/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options @@ -0,0 +1 @@ +{dialyzer_options, [{warnings, [specdiffs]}]}. diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata b/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata new file mode 100644 index 0000000000..3fb12fe000 --- /dev/null +++ b/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata @@ -0,0 +1,3 @@ + +iodata.erl:7: The specification for iodata:encode/2 states that the function might also return binary() but the inferred return is nonempty_maybe_improper_list(<<_:8,_:_*8>> | nonempty_maybe_improper_list(<<_:8,_:_*8>> | nonempty_maybe_improper_list(any(),<<_:8,_:_*8>> | []) | byte(),<<_:8,_:_*8>> | []) | integer(),<<_:8,_:_*8>> | []) | integer() +iodata.erl:7: The success typing for iodata:encode/2 implies that the function might also return integer() but the specification return is binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []) diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist b/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist new file mode 100644 index 0000000000..ca556f017c --- /dev/null +++ b/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist @@ -0,0 +1,2 @@ + +iolist.erl:7: The success typing for iolist:encode/2 implies that the function might also return integer() but the specification return is maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []) diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl b/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl new file mode 100644 index 0000000000..caa44f6c91 --- /dev/null +++ b/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl @@ -0,0 +1,41 @@ +-module(iodata). + +%% A small part of beam_asm. + +-export([encode/2]). + +-spec encode(non_neg_integer(), integer()) -> iodata(). % extra range binary() + +encode(Tag, N) when Tag >= 0, N < 0 -> + encode1(Tag, negative_to_bytes(N)); +encode(Tag, N) when Tag >= 0, N < 16 -> + (N bsl 4) bor Tag; % not in the specification +encode(Tag, N) when Tag >= 0, N < 16#800 -> + [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff]; +encode(Tag, N) when Tag >= 0 -> + encode1(Tag, to_bytes(N)). + +encode1(Tag, Bytes) -> + case iolist_size(Bytes) of + Num when 2 =< Num, Num =< 8 -> + [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes]; + Num when 8 < Num -> + [2#11111000 bor Tag, encode(0, Num-9)| Bytes] + end. + +to_bytes(N) -> + Bin = binary:encode_unsigned(N), + case Bin of + <<0:1,_/bits>> -> Bin; + <<1:1,_/bits>> -> [0,Bin] + end. + +negative_to_bytes(N) when N >= -16#8000 -> + <<N:16>>; +negative_to_bytes(N) -> + Bytes = byte_size(binary:encode_unsigned(-N)), + Bin = <<N:Bytes/unit:8>>, + case Bin of + <<0:1,_/bits>> -> [16#ff,Bin]; + <<1:1,_/bits>> -> Bin + end. diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl b/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl new file mode 100644 index 0000000000..7cceeda24e --- /dev/null +++ b/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl @@ -0,0 +1,41 @@ +-module(iolist). + +%% A small part of beam_asm. + +-export([encode/2]). + +-spec encode(non_neg_integer(), integer()) -> iolist(). + +encode(Tag, N) when Tag >= 0, N < 0 -> + encode1(Tag, negative_to_bytes(N)); +encode(Tag, N) when Tag >= 0, N < 16 -> + (N bsl 4) bor Tag; % not in the specification +encode(Tag, N) when Tag >= 0, N < 16#800 -> + [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff]; +encode(Tag, N) when Tag >= 0 -> + encode1(Tag, to_bytes(N)). + +encode1(Tag, Bytes) -> + case iolist_size(Bytes) of + Num when 2 =< Num, Num =< 8 -> + [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes]; + Num when 8 < Num -> + [2#11111000 bor Tag, encode(0, Num-9)| Bytes] + end. + +to_bytes(N) -> + Bin = binary:encode_unsigned(N), + case Bin of + <<0:1,_/bits>> -> Bin; + <<1:1,_/bits>> -> [0,Bin] + end. + +negative_to_bytes(N) when N >= -16#8000 -> + <<N:16>>; +negative_to_bytes(N) -> + Bytes = byte_size(binary:encode_unsigned(-N)), + Bin = <<N:Bytes/unit:8>>, + case Bin of + <<0:1,_/bits>> -> [16#ff,Bin]; + <<1:1,_/bits>> -> Bin + end. diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index f143a49d2f..7faef93609 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2017. All Rights Reserved. +%% Copyright Ericsson AB 1996-2018. 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. @@ -630,7 +630,7 @@ do_par_recv(N, Good, Bad) -> call(Req) -> code_server:call(Req). --spec start_link() -> {'ok', pid()} | {'error', 'crash'}. +-spec start_link() -> {'ok', pid()}. start_link() -> do_start(). diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index ecc1ffbdd6..29eaa23375 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2017. All Rights Reserved. +%% Copyright Ericsson AB 2000-2018. 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. @@ -73,7 +73,7 @@ stop() -> %% {stop, Reason} %%---------------------------------------------------------------------- --spec init([]) -> {'ok', state()} | {'stop', term()}. +-spec init([]) -> {'ok', state()}. init([]) -> process_flag(trap_exit, true), @@ -225,7 +225,7 @@ handle_cast(Msg, State) -> %%---------------------------------------------------------------------- -spec handle_info(term(), state()) -> - {'noreply', state()} | {'stop', 'normal', state()}. + {'noreply', state()}. handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) -> ets:delete(?FILE_IO_SERVER_TABLE, Pid), diff --git a/lib/kernel/src/kernel_refc.erl b/lib/kernel/src/kernel_refc.erl index 05076dc885..8e04ff99d8 100644 --- a/lib/kernel/src/kernel_refc.erl +++ b/lib/kernel/src/kernel_refc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2017. All Rights Reserved. +%% Copyright Ericsson AB 2017-2018. 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. @@ -44,7 +44,7 @@ scheduler_wall_time(Bool) -> %% Callback functions from gen_server %%----------------------------------------------------------------- --spec init([]) -> {'ok', map()} | {'stop', term()}. +-spec init([]) -> {'ok', map()}. init([]) -> resource(scheduler_wall_time, false), diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl index a237eaa489..939b1fb488 100644 --- a/lib/stdlib/src/array.erl +++ b/lib/stdlib/src/array.erl @@ -290,7 +290,7 @@ new(Size, Fixed, Default) -> end, #array{size = Size, max = M, default = Default, elements = E}. --spec find_max(integer(), integer()) -> integer(). +-spec find_max(integer(), non_neg_integer()) -> non_neg_integer(). find_max(I, M) when I >= M -> find_max(I, ?extend(M)); |