diff options
author | Hans Bolinder <[email protected]> | 2015-01-23 14:57:31 +0100 |
---|---|---|
committer | Hans Bolinder <[email protected]> | 2015-03-10 10:49:15 +0100 |
commit | 2c1ad10d8ab95aa602337b389dbefedddfb1747c (patch) | |
tree | d7df64e9feeeebabec97d5831df45035074369ca /lib | |
parent | 747955f26376486eb7ecbd8f9a6144ba668a21c7 (diff) | |
download | otp-2c1ad10d8ab95aa602337b389dbefedddfb1747c.tar.gz otp-2c1ad10d8ab95aa602337b389dbefedddfb1747c.tar.bz2 otp-2c1ad10d8ab95aa602337b389dbefedddfb1747c.zip |
[dialyzer] Correct handling of limited opaque types
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dialyzer/src/dialyzer_utils.erl | 20 | ||||
-rw-r--r-- | lib/hipe/cerl/erl_types.erl | 62 |
2 files changed, 56 insertions, 26 deletions
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl index 62a214a886..1cc9528fed 100644 --- a/lib/dialyzer/src/dialyzer_utils.erl +++ b/lib/dialyzer/src/dialyzer_utils.erl @@ -63,13 +63,13 @@ print_types(RecDict) -> print_types1([], _) -> ok; -print_types1([{type, _Name} = Key|T], RecDict) -> - {ok, {_Mod, Form, _Args}} = dict:find(Key, RecDict), - io:format("\n~w: ~w\n", [Key, erl_types:t_from_form(Form, RecDict)]), +print_types1([{type, _Name, _NArgs} = Key|T], RecDict) -> + {ok, {{_Mod, _Form, _Args}, Type}} = dict:find(Key, RecDict), + io:format("\n~w: ~w\n", [Key, Type]), print_types1(T, RecDict); -print_types1([{opaque, _Name} = Key|T], RecDict) -> - {ok, {_Mod, Form, _Args}} = dict:find(Key, RecDict), - io:format("\n~w: ~w\n", [Key, erl_types:t_from_form(Form, RecDict)]), +print_types1([{opaque, _Name, _NArgs} = Key|T], RecDict) -> + {ok, {{_Mod, _Form, _Args}, Type}} = dict:find(Key, RecDict), + io:format("\n~w: ~w\n", [Key, Type]), print_types1(T, RecDict); print_types1([{record, _Name} = Key|T], RecDict) -> {ok, [{_Arity, _Fields} = AF]} = dict:find(Key, RecDict), @@ -258,7 +258,8 @@ add_new_type(TypeOrOpaque, Name, TypeForm, ArgForms, Module, RecDict) -> try erl_types:t_var_names(ArgForms) of ArgNames -> dict:store({TypeOrOpaque, Name, Arity}, - {Module, TypeForm, ArgNames}, RecDict) + {{Module, TypeForm, ArgNames}, + erl_types:t_any()}, RecDict) catch _:_ -> throw({error, flat_format("Type declaration for ~w does not " @@ -327,6 +328,11 @@ process_record_remote_types(CServer) -> || {Name, Field, _} <- Fields] end, orddict:map(FieldFun, Value); + {opaque, _, _} -> + {{_Module, Form, _ArgNames}=F, _Type} = Value, + Type = erl_types:t_from_form(Form, TempExpTypes, Module, + TempRecords), + {F, Type}; _Other -> Value end end, diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index d092e3fe40..09dffe1280 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -749,7 +749,7 @@ t_opaque_from_records(RecDict) -> end end, RecDict), OpaqueTypeDict = - dict:map(fun({opaque, Name, _Arity}, {Module, _Type, ArgNames}) -> + dict:map(fun({opaque, Name, _Arity}, {{Module, _Form, ArgNames}, _Type}) -> %% Args = args_to_types(ArgNames), %% List = lists:zip(ArgNames, Args), %% TmpVarDict = dict:from_list(List), @@ -3963,7 +3963,8 @@ t_from_form(Form, ExpTypes, Module, RecDict) -> module(), mod_records(), var_table()) -> erl_type(). t_from_form(Form, ExpTypes, Module, RecDict, VarDict) -> - t_from_form1(Form, [], ExpTypes, Module, RecDict, VarDict). + {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, VarDict), + T. %% Replace external types with with none(). -spec t_from_form_without_remote(parse_form(), type_table()) -> erl_type(). @@ -3972,7 +3973,8 @@ t_from_form_without_remote(Form, TypeTable) -> Module = mod, RecDict = dict:from_list([{Module, TypeTable}]), ExpTypes = replace_by_none, - t_from_form1(Form, [], ExpTypes, Module, RecDict, dict:new()). + {T, _} = t_from_form1(Form, [], ExpTypes, Module, RecDict, dict:new()), + T. %% REC_TYPE_LIMIT is used for limiting the depth of recursive types. %% EXPAND_LIMIT is used for limiting the size of types by @@ -3996,7 +3998,7 @@ t_from_form1(Form, TypeNames, ET, M, MR, V, D) -> D1 = D div 2, t_from_form1(Form, TypeNames, ET, M, MR, V, D1); true -> - T + {T, L1} end. -spec t_from_form(parse_form(), type_names(), @@ -4196,7 +4198,7 @@ builtin_type(Name, Type, TypeNames, ET, M, MR, V, D, L) -> case dict:find(M, MR) of {ok, R} -> case lookup_type(Name, 0, R) of - {_, {_M, _T, _A}} -> + {_, {{_M, _F, _A}, _T}} -> type_from_form(Name, [], TypeNames, ET, M, MR, V, D, L); error -> {Type, L} @@ -4210,28 +4212,29 @@ type_from_form(Name, Args, TypeNames, ET, M, MR, V, D, L) -> {ArgTypes, L1} = list_from_form(Args, TypeNames, ET, M, MR, V, D, L), {ok, R} = dict:find(M, MR), case lookup_type(Name, ArgsLen, R) of - {type, {Module, Type, ArgNames}} -> + {type, {{Module, Form, ArgNames}, _Type}} -> TypeName = {type, Module, Name, ArgsLen}, case can_unfold_more(TypeName, TypeNames) of true -> List = lists:zip(ArgNames, ArgTypes), TmpV = dict:from_list(List), - t_from_form(Type, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1); + t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1); false -> {t_any(), L1} end; - {opaque, {Module, Type, ArgNames}} -> - TypeName = {opaque, Module, Name, ArgsLen}, % 'type' would do... - {Rep, L3} = + {opaque, {{Module, Form, ArgNames}, Type}} -> + TypeName = {opaque, Module, Name, ArgsLen}, + {Rep, L2} = case can_unfold_more(TypeName, TypeNames) of true -> List = lists:zip(ArgNames, ArgTypes), TmpV = dict:from_list(List), - t_from_form(Type, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1); + t_from_form(Form, [TypeName|TypeNames], ET, M, MR, TmpV, D, L1); false -> {t_any(), L1} end, + Rep1 = choose_opaque_type(Rep, Type), Args2 = [subst_all_vars_to_any(ArgType) || ArgType <- ArgTypes], - {skip_opaque_alias(Rep, Module, Name, Args2), L3}; + {skip_opaque_alias(Rep1, Module, Name, Args2), L2}; error -> Msg = io_lib:format("Unable to find type ~w/~w\n", [Name, ArgsLen]), throw({error, Msg}) @@ -4248,7 +4251,6 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) -> {t_none(), L1}; true -> ArgsLen = length(Args), - RemType = {type, RemMod, Name, ArgsLen}, case dict:find(RemMod, MR) of error -> self() ! {self(), ext_types, {RemMod, Name, ArgsLen}}, @@ -4258,30 +4260,33 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) -> case sets:is_element(MFA, ET) of true -> case lookup_type(Name, ArgsLen, RemDict) of - {type, {_Mod, Type, ArgNames}} -> + {type, {{_Mod, Form, ArgNames}, _Type}} -> + RemType = {type, RemMod, Name, ArgsLen}, case can_unfold_more(RemType, TypeNames) of true -> List = lists:zip(ArgNames, ArgTypes), TmpVarDict = dict:from_list(List), NewTypeNames = [RemType|TypeNames], - t_from_form(Type, NewTypeNames, ET, + t_from_form(Form, NewTypeNames, ET, RemMod, MR, TmpVarDict, D, L1); false -> {t_any(), L1} end; - {opaque, {Mod, Type, ArgNames}} -> + {opaque, {{Mod, Form, ArgNames}, Type}} -> + RemType = {opaque, RemMod, Name, ArgsLen}, List = lists:zip(ArgNames, ArgTypes), TmpVarDict = dict:from_list(List), {NewRep, L2} = case can_unfold_more(RemType, TypeNames) of true -> NewTypeNames = [RemType|TypeNames], - t_from_form(Type, NewTypeNames, ET, - RemMod, MR, TmpVarDict, D, L1); + t_from_form(Form, NewTypeNames, ET, RemMod, MR, + TmpVarDict, D, L1); false -> {t_any(), L1} end, - {skip_opaque_alias(NewRep, Mod, Name, ArgTypes), L2}; + NewRep1 = choose_opaque_type(NewRep, Type), + {skip_opaque_alias(NewRep1, Mod, Name, ArgTypes), L2}; error -> Msg = io_lib:format("Unable to find remote type ~w:~w()\n", [RemMod, Name]), @@ -4294,6 +4299,25 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, M, MR, V, D, L) -> end end. +%% Opaque types (both local and remote) are problematic when it comes +%% to the limits (TypeNames, D, and L). The reason is that if any() is +%% substituted for a more specialized subtype of an opaque type, the +%% property stated along with decorate_with_opaque() (the type has to +%% be a subtype of the declared type) no longer holds. +%% +%% The less than perfect remedy: if the opaque type created from a +%% form is not a subset of the declared type, the declared type is +%% used instead, effectively bypassing the limits, and potentially +%% resulting in huge types. +choose_opaque_type(Type, DeclType) -> + case + t_is_subtype(subst_all_vars_to_any(Type), + subst_all_vars_to_any(DeclType)) + of + true -> Type; + false -> DeclType + end. + record_from_form({atom, _, Name}, ModFields, TypeNames, ET, M, MR, V, D, L) -> case can_unfold_more({record, Name}, TypeNames) of true -> |