aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/cerl
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2015-06-30 14:35:53 +0200
committerHans Bolinder <[email protected]>2015-08-25 09:24:55 +0200
commit85f6fe3b1343c726a380b6efa4b108ab98eff00d (patch)
tree18200e7096cfa58c84390e7653979cd4bd5ca0c3 /lib/hipe/cerl
parentbe602ec806a37fb3951dc3327ff5f2a96fe9cc86 (diff)
downloadotp-85f6fe3b1343c726a380b6efa4b108ab98eff00d.tar.gz
otp-85f6fe3b1343c726a380b6efa4b108ab98eff00d.tar.bz2
otp-85f6fe3b1343c726a380b6efa4b108ab98eff00d.zip
dialyzer: Improve the handling of recursive parameterized opaque types
Diffstat (limited to 'lib/hipe/cerl')
-rw-r--r--lib/hipe/cerl/erl_types.erl38
1 files changed, 27 insertions, 11 deletions
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index f0b907f86c..ad92324911 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -4010,16 +4010,25 @@ t_from_form_without_remote(Form, Site, TypeTable) ->
-type expand_depth() :: integer().
+-spec t_from_form1(parse_form(), sets:set(mfa()) | 'replace_by_none',
+ site(), mod_records(), var_table()) ->
+ {erl_type(), expand_limit()}.
+
t_from_form1(Form, ET, Site, MR, V) ->
- t_from_form1(Form, ET, Site, MR, V, ?EXPAND_DEPTH).
+ TypeNames = initial_typenames(Site),
+ t_from_form1(Form, TypeNames, ET, Site, MR, V, ?EXPAND_DEPTH).
+
+initial_typenames({type, _MTA}=Site) -> [Site];
+initial_typenames({spec, _MFA}) -> [];
+initial_typenames({record, _MRA}) -> [].
-t_from_form1(Form, ET, Site, MR, V, D) ->
+t_from_form1(Form, TypeNames, ET, Site, MR, V, D) ->
L = ?EXPAND_LIMIT,
- {T, L1} = t_from_form(Form, [], ET, Site, MR, V, D, L),
+ {T, L1} = t_from_form(Form, TypeNames, ET, Site, MR, V, D, L),
if
L1 =< 0, D > 1 ->
D1 = D div 2,
- t_from_form1(Form, ET, Site, MR, V, D1);
+ t_from_form1(Form, TypeNames, ET, Site, MR, V, D1);
true ->
{T, L1}
end.
@@ -4259,7 +4268,7 @@ type_from_form(Name, Args, TypeNames, ET, Site0, MR, V, D, L) ->
false -> {t_any(), L1}
end,
Rep1 = choose_opaque_type(Rep, Type),
- Rep2 = case t_is_none(Rep1) of
+ Rep2 = case cannot_have_opaque(Rep1, TypeName, TypeNames) of
true -> Rep1;
false ->
ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
@@ -4307,18 +4316,19 @@ remote_from_form(RemMod, Name, Args, TypeNames, ET, S, MR, V, D, L) ->
case can_unfold_more(RemType, TypeNames) of
true ->
NewTypeNames = [RemType|TypeNames],
- t_from_form(Form, NewTypeNames, ET, RemMod, MR,
+ Site = RemType,
+ t_from_form(Form, NewTypeNames, ET, Site, MR,
TmpVarDict, D, L1);
- false ->
- {t_any(), L1}
+ false -> {t_any(), L1}
end,
NewRep1 = choose_opaque_type(NewRep, Type),
- NewRep2 = case t_is_none(NewRep1) of
- true -> NewRep1;
+ NewRep2 =
+ case cannot_have_opaque(NewRep1, RemType, TypeNames) of
+ true -> NewRep1;
false ->
ArgTypes2 = subst_all_vars_to_any_list(ArgTypes),
t_opaque(Mod, Name, ArgTypes2, NewRep1)
- end,
+ end,
{NewRep2, L2};
error ->
Msg = io_lib:format("Unable to find remote type ~w:~w()\n",
@@ -4704,6 +4714,12 @@ lookup_type(Name, Arity, RecDict) ->
type_is_defined(TypeOrOpaque, Name, Arity, RecDict) ->
dict:is_key({TypeOrOpaque, Name, Arity}, RecDict).
+cannot_have_opaque(Type, TypeName, TypeNames) ->
+ t_is_none(Type) orelse is_recursive(TypeName, TypeNames).
+
+is_recursive(TypeName, TypeNames) ->
+ lists:member(TypeName, TypeNames).
+
can_unfold_more(TypeName, TypeNames) ->
Fun = fun(E, Acc) -> case E of TypeName -> Acc + 1; _ -> Acc end end,
lists:foldl(Fun, 0, TypeNames) < ?REC_TYPE_LIMIT.