From 2c1ad10d8ab95aa602337b389dbefedddfb1747c Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Fri, 23 Jan 2015 14:57:31 +0100 Subject: [dialyzer] Correct handling of limited opaque types --- lib/hipe/cerl/erl_types.erl | 62 +++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 19 deletions(-) (limited to 'lib/hipe/cerl/erl_types.erl') 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 -> -- cgit v1.2.3