From 5ac2943cee51f0f9e453243bb94e637378d7c838 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Thu, 22 Sep 2016 10:36:14 +0200 Subject: dialyzer: Fix opaque bug The "decoration" of opaque types works better than before when opaque types are used by other opaque types. --- lib/hipe/cerl/erl_types.erl | 82 ++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 42 deletions(-) (limited to 'lib/hipe/cerl') diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index a6a7efb1de..9ef119ba46 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -611,9 +611,13 @@ t_decorate_with_opaque(T1, T2, Opaques) -> false -> T1; true -> R = decorate(T1, T, Opaques), - ?debug(case catch t_is_equal(t_unopaque(R), t_unopaque(T1)) of - true -> ok; - false -> + ?debug(case catch + not t_is_equal(t_unopaque(R), t_unopaque(T1)) + orelse + t_is_equal(T1, T) andalso not t_is_equal(T1, R) + of + false -> ok; + _ -> io:format("T1 = ~p,\n", [T1]), io:format("T2 = ~p,\n", [T2]), io:format("O = ~p,\n", [Opaques]), @@ -642,7 +646,6 @@ decorate(?tuple_set(List), ?tuple_set(L), Opaques) -> decorate(?union(List), T, Opaques) when T =/= ?any -> ?union(L) = force_union(T), union_decorate(List, L, Opaques); -decorate(?opaque(_)=T, _, _Opaques) -> T; decorate(T, ?union(L), Opaques) when T =/= ?any -> ?union(List) = force_union(T), union_decorate(List, L, Opaques); @@ -656,7 +659,7 @@ decorate_with_opaque(Type, ?opaque(Set2), Opaques) -> case decoration(set_to_list(Set2), Type, Opaques, [], false) of {[], false} -> Type; {List, All} when List =/= [] -> - NewType = ?opaque(ordsets:from_list(List)), + NewType = sup_opaque(List), case All of true -> NewType; false -> t_sup(NewType, Type) @@ -670,9 +673,10 @@ decoration([#opaque{struct = S} = Opaque|OpaqueTypes], Type, Opaques, case not IsOpaque orelse t_is_none(I) of true -> decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes0, All); false -> - NewOpaque = Opaque#opaque{struct = decorate(I, S, Opaques)}, + NewI = decorate(I, S, Opaques), + NewOpaque = combine(NewI, [Opaque]), NewAll = All orelse t_is_equal(I, Type), - NewOpaqueTypes = [NewOpaque|NewOpaqueTypes0], + NewOpaqueTypes = NewOpaque ++ NewOpaqueTypes0, decoration(OpaqueTypes, Type, Opaques, NewOpaqueTypes, NewAll) end; decoration([], _Type, _Opaques, NewOpaqueTypes, All) -> @@ -2991,27 +2995,21 @@ inf_collect(_T1, [], _Opaques, OpL) -> OpL. combine(S, T1, T2) -> - #opaque{mod = Mod1, name = Name1, args = Args1} = T1, - #opaque{mod = Mod2, name = Name2, args = Args2} = T2, - Comb1 = comb(Mod1, Name1, Args1, S, T1), - case is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2}) of - true -> Comb1; - false -> Comb1 ++ comb(Mod2, Name2, Args2, S, T2) + case is_compat_opaque_names(T1, T2) of + true -> combine(S, [T1]); + false -> combine(S, [T1, T2]) end. -comb(Mod, Name, Args, S, T) -> - case can_combine_opaque_names(Mod, Name, Args, S) of - true -> - ?opaque(Set) = S, - Set; - false -> - [T#opaque{struct = S}] - end. +combine(?opaque(Set), Ts) -> + [comb2(O, T) || O <- Set, T <- Ts]; +combine(S, Ts) -> + [T#opaque{struct = S} || T <- Ts]. -can_combine_opaque_names(Mod1, Name1, Args1, - ?opaque([#opaque{mod = Mod2, name = Name2, args = Args2}])) -> - is_compat_opaque_names({Mod1, Name1, Args1}, {Mod2, Name2, Args2}); -can_combine_opaque_names(_, _, _, _) -> false. +comb2(O, T) -> + case is_compat_opaque_names(O, T) of + true -> O; + false -> T#opaque{struct = ?opaque(set_singleton(O))} + end. %% Combining two lists this way can be very time consuming... %% Note: two parameterized opaque types are not the same if their @@ -3020,32 +3018,27 @@ inf_opaque(Set1, Set2, Opaques) -> List1 = inf_look_up(Set1, Opaques), List2 = inf_look_up(Set2, Opaques), List0 = [combine(Inf, T1, T2) || - {Is1, ModNameArgs1, T1} <- List1, - {Is2, ModNameArgs2, T2} <- List2, - not t_is_none(Inf = inf_opaque_types(Is1, ModNameArgs1, T1, - Is2, ModNameArgs2, T2, - Opaques))], - List = lists:sort(lists:append(List0)), + {Is1, T1} <- List1, + {Is2, T2} <- List2, + not t_is_none(Inf = inf_opaque_types(Is1, T1, Is2, T2, Opaques))], + List = lists:append(List0), sup_opaque(List). %% Optimization: do just one lookup. inf_look_up(Set, Opaques) -> - [{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques), - {M, N, Args}, T} || - #opaque{mod = M, name = N, args = Args} = T <- set_to_list(Set)]. + [{Opaques =:= 'universe' orelse inf_is_opaque_type2(T, Opaques), T} || + T <- set_to_list(Set)]. inf_is_opaque_type2(T, {match, Opaques}) -> is_opaque_type2(T, Opaques); inf_is_opaque_type2(T, Opaques) -> is_opaque_type2(T, Opaques). -inf_opaque_types(IsOpaque1, ModNameArgs1, T1, - IsOpaque2, ModNameArgs2, T2, Opaques) -> +inf_opaque_types(IsOpaque1, T1, IsOpaque2, T2, Opaques) -> #opaque{struct = S1}=T1, #opaque{struct = S2}=T2, case - Opaques =:= 'universe' orelse - is_compat_opaque_names(ModNameArgs1, ModNameArgs2) + Opaques =:= 'universe' orelse is_compat_opaque_names(T1, T2) of true -> t_inf(S1, S2, Opaques); false -> @@ -3059,10 +3052,15 @@ inf_opaque_types(IsOpaque1, ModNameArgs1, T1, end end. -is_compat_opaque_names(ModNameArgs, ModNameArgs) -> true; -is_compat_opaque_names({Mod,Name,Args1}, {Mod,Name,Args2}) -> - is_compat_args(Args1, Args2); -is_compat_opaque_names(_, _) -> false. +is_compat_opaque_names(Opaque1, Opaque2) -> + #opaque{mod = Mod1, name = Name1, args = Args1} = Opaque1, + #opaque{mod = Mod2, name = Name2, args = Args2} = Opaque2, + case {{Mod1, Name1, Args1}, {Mod2, Name2, Args2}} of + {ModNameArgs, ModNameArgs} -> true; + {{Mod, Name, Args1}, {Mod, Name, Args2}} -> + is_compat_args(Args1, Args2); + _ -> false + end. is_compat_args([A1|Args1], [A2|Args2]) -> is_compat_arg(A1, A2) andalso is_compat_args(Args1, Args2); -- cgit v1.2.3