From 13e0b9420276b71bdac89692f00dc20c3112bc1b Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Wed, 8 Jun 2016 16:12:46 +0200 Subject: dialyzer: Improve the translation of forms to types Spend less of the limited resources on recursive types. --- lib/hipe/cerl/erl_types.erl | 74 +++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 23 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 9a94132b4c..b62cd5ba35 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -4741,12 +4741,13 @@ type_from_form1(Name, Args, ArgsLen, R, TypeName, TypeNames, S, D, L, C) -> List = lists:zip(ArgNames, ArgTypes), TmpV = maps:from_list(List), S2 = S1#from_form{site = TypeName, vtab = TmpV}, + Fun = fun(DD, LL) -> from_form(Form, S2, DD, LL, C1) end, {NewType, L3, C3} = case Tag of type -> - from_form(Form, S2, D, L1, C1); + recur_limit(Fun, D, L1, TypeName, TypeNames); opaque -> - {Rep, L2, C2} = from_form(Form, S2, D, L1, C1), + {Rep, L2, C2} = recur_limit(Fun, D, L1, TypeName, TypeNames), Rep1 = choose_opaque_type(Rep, Type), Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of true -> Rep1; @@ -4811,12 +4812,13 @@ remote_from_form1(RemMod, Name, Args, ArgsLen, RemDict, RemType, TypeNames, List = lists:zip(ArgNames, ArgTypes), TmpVarTab = maps:from_list(List), S2 = S1#from_form{site = RemType, vtab = TmpVarTab}, + Fun = fun(DD, LL) -> from_form(Form, S2, DD, LL, C1) end, {NewType, L3, C3} = case Tag of type -> - from_form(Form, S2, D, L1, C1); + recur_limit(Fun, D, L1, RemType, TypeNames); opaque -> - {NewRep, L2, C2} = from_form(Form, S2, D, L1, C1), + {NewRep, L2, C2} = recur_limit(Fun, D, L1, RemType, TypeNames), NewRep1 = choose_opaque_type(NewRep, Type), NewRep2 = case cannot_have_opaque(NewRep1, RemType, TypeNames) of @@ -4858,37 +4860,42 @@ choose_opaque_type(Type, DeclType) -> false -> DeclType end. -record_from_form({atom, _, Name}, ModFields, S, D, L, C) -> +record_from_form({atom, _, Name}, ModFields, S, D0, L0, C) -> #from_form{site = Site, mrecs = MR, tnames = TypeNames} = S, - case can_unfold_more({record, Name}, TypeNames) of + RecordType = {record, Name}, + case can_unfold_more(RecordType, TypeNames) of true -> M = site_module(Site), {ok, R} = dict:find(M, MR), case lookup_record(Name, R) of {ok, DeclFields} -> - NewTypeNames = [{record, Name}|TypeNames], + NewTypeNames = [RecordType|TypeNames], Site1 = {record, {M, Name, length(DeclFields)}}, S1 = S#from_form{site = Site1, tnames = NewTypeNames}, - {GetModRec, L1, C1} = - get_mod_record(ModFields, DeclFields, S1, D, L, C), - case GetModRec of - {error, FieldName} -> - throw({error, io_lib:format("Illegal declaration of #~w{~w}\n", - [Name, FieldName])}); - {ok, NewFields} -> - S2 = S1#from_form{vtab = var_table__new()}, - {NewFields1, L2, C2} = - fields_from_form(NewFields, S2, D, L1, C1), - Rec = t_tuple( - [t_atom(Name)|[Type - || {_FieldName, Type} <- NewFields1]]), - {Rec, L2, C2} - end; + Fun = fun(D, L) -> + {GetModRec, L1, C1} = + get_mod_record(ModFields, DeclFields, S1, D, L, C), + case GetModRec of + {error, FieldName} -> + throw({error, + io_lib:format("Illegal declaration of #~w{~w}\n", + [Name, FieldName])}); + {ok, NewFields} -> + S2 = S1#from_form{vtab = var_table__new()}, + {NewFields1, L2, C2} = + fields_from_form(NewFields, S2, D, L1, C1), + Rec = t_tuple( + [t_atom(Name)|[Type + || {_FieldName, Type} <- NewFields1]]), + {Rec, L2, C2} + end + end, + recur_limit(Fun, D0, L0, RecordType, TypeNames); error -> throw({error, io_lib:format("Unknown record #~w{}\n", [Name])}) end; false -> - {t_any(), L, C} + {t_any(), L0, C} end. get_mod_record([], DeclFields, _S, _D, L, C) -> @@ -4989,6 +4996,27 @@ promote_to_mand(MKs, [E={K,_,V}|T]) -> false -> E end|promote_to_mand(MKs, T)]. +-define(RECUR_EXPAND_LIMIT, 10). +-define(RECUR_EXPAND_DEPTH, 2). + +%% If more of the limited resources is spent on the non-recursive +%% forms, more warnings are found. And the analysis is also a bit +%% faster. +%% +%% Setting REC_TYPE_LIMIT to 1 would work also work well. + +recur_limit(Fun, D, L, _, _) when L =< ?RECUR_EXPAND_DEPTH, + D =< ?RECUR_EXPAND_LIMIT -> + Fun(D, L); +recur_limit(Fun, D, L, TypeName, TypeNames) -> + case is_recursive(TypeName, TypeNames) of + true -> + {T, L1, C1} = Fun(?RECUR_EXPAND_DEPTH, ?RECUR_EXPAND_LIMIT), + {T, L - L1, C1}; + false -> + Fun(D, L) + end. + -spec t_check_record_fields(parse_form(), sets:set(mfa()), site(), mod_records(), var_table(), cache()) -> cache(). -- cgit v1.2.3