diff options
author | Magnus Lång <[email protected]> | 2016-03-01 12:51:16 +0100 |
---|---|---|
committer | Hans Bolinder <[email protected]> | 2016-04-28 16:16:10 +0200 |
commit | 67c7fd3c516b08d3d8814debca0db2a295e0c0b8 (patch) | |
tree | f4b1cc958870dcbf381a1fb08ae34f07e149c29d /lib/dialyzer/src | |
parent | 50054b94fee69fd39af32b4161d005588ed5f22f (diff) | |
download | otp-67c7fd3c516b08d3d8814debca0db2a295e0c0b8.tar.gz otp-67c7fd3c516b08d3d8814debca0db2a295e0c0b8.tar.bz2 otp-67c7fd3c516b08d3d8814debca0db2a295e0c0b8.zip |
dialyzer_contracts: Consider #{} a violation
This is analogous to the case of nil. Since #{} is a base-case of almost
all map types, contract and success typing sharing #{} does not mean
much, and is often sign of a violation.
Diffstat (limited to 'lib/dialyzer/src')
-rw-r--r-- | lib/dialyzer/src/dialyzer_contracts.erl | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl index e03e4d5bb4..1895a98e96 100644 --- a/lib/dialyzer/src/dialyzer_contracts.erl +++ b/lib/dialyzer/src/dialyzer_contracts.erl @@ -277,28 +277,45 @@ check_extraneous_1(Contract, SuccType) -> case [CR || CR <- CRngs, erl_types:t_is_none(erl_types:t_inf(CR, STRng))] of [] -> - CRngList = list_part(CRng), - STRngList = list_part(STRng), - case is_not_nil_list(CRngList) andalso is_not_nil_list(STRngList) of - false -> ok; - true -> - CRngElements = erl_types:t_list_elements(CRngList), - STRngElements = erl_types:t_list_elements(STRngList), - Inf = erl_types:t_inf(CRngElements, STRngElements), - case erl_types:t_is_none(Inf) of - true -> {error, invalid_contract}; - false -> ok - end + case bad_extraneous_list(CRng, STRng) + orelse bad_extraneous_map(CRng, STRng) + of + true -> {error, invalid_contract}; + false -> ok end; CRs -> {error, {extra_range, erl_types:t_sup(CRs), STRng}} end. +bad_extraneous_list(CRng, STRng) -> + CRngList = list_part(CRng), + STRngList = list_part(STRng), + case is_not_nil_list(CRngList) andalso is_not_nil_list(STRngList) of + false -> false; + true -> + CRngElements = erl_types:t_list_elements(CRngList), + STRngElements = erl_types:t_list_elements(STRngList), + Inf = erl_types:t_inf(CRngElements, STRngElements), + erl_types:t_is_none(Inf) + end. + list_part(Type) -> erl_types:t_inf(erl_types:t_list(), Type). is_not_nil_list(Type) -> erl_types:t_is_list(Type) andalso not erl_types:t_is_nil(Type). +bad_extraneous_map(CRng, STRng) -> + CRngMap = map_part(CRng), + STRngMap = map_part(STRng), + (not is_empty_map(CRngMap)) andalso (not is_empty_map(STRngMap)) + andalso is_empty_map(erl_types:t_inf(CRngMap, STRngMap)). + +map_part(Type) -> + erl_types:t_inf(erl_types:t_map(), Type). + +is_empty_map(Type) -> + erl_types:t_is_equal(Type, erl_types:t_from_term(#{})). + %% This is the heart of the "range function" -spec process_contracts([contract_pair()], [erl_types:erl_type()]) -> erl_types:erl_type(). |