aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Bolinder <[email protected]>2015-09-09 10:12:06 +0200
committerHans Bolinder <[email protected]>2015-09-09 10:12:06 +0200
commit65486a69b20878cd5852f2cd98161e071b7e8160 (patch)
tree6c02bafe23d33286ec3ffcd9823523095fe3d82c
parentae274fd207a2643a858bbe2dfa254b3936990b6e (diff)
parentd57f5e34e58a49298c2c2d6210392df6629a740b (diff)
downloadotp-65486a69b20878cd5852f2cd98161e071b7e8160.tar.gz
otp-65486a69b20878cd5852f2cd98161e071b7e8160.tar.bz2
otp-65486a69b20878cd5852f2cd98161e071b7e8160.zip
Merge branch 'hb/dialyzer/opaque_parms/OTP-12866' into maint
* hb/dialyzer/opaque_parms/OTP-12866: dialyzer: Correct the handling of parameters of opaque types
-rw-r--r--lib/hipe/cerl/erl_types.erl82
1 files changed, 81 insertions, 1 deletions
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 56ec757dbf..cd2d2fe207 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -2712,7 +2712,87 @@ is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
is_compat_arg(A, A) -> true;
-is_compat_arg(A1, A2) -> t_is_any(A1) orelse t_is_any(A2).
+is_compat_arg(A1, A2) ->
+ is_specialization(A1, A2) orelse is_specialization(A2, A1).
+
+-spec is_specialization(erl_type(), erl_type()) -> boolean().
+
+%% Returns true if the first argument is a specialization of the
+%% second argument in the sense that every type is a specialization of
+%% any(). For example, {_,_} is a specialization of any(), but not of
+%% tuple(). Does not handle variables, but any() and unions (sort of).
+
+is_specialization(_, ?any) -> true;
+is_specialization(?any, _) -> false;
+is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
+ (is_specialization(Domain1, Domain2) andalso
+ is_specialization(Range1, Range2));
+is_specialization(?list(Contents1, Termination1, Size1),
+ ?list(Contents2, Termination2, Size2)) ->
+ (Size1 =:= Size2 andalso
+ is_specialization(Contents1, Contents2) andalso
+ is_specialization(Termination1, Termination2));
+is_specialization(?product(Types1), ?product(Types2)) ->
+ specialization_list(Types1, Types2);
+is_specialization(?tuple(?any, ?any, ?any), ?tuple(_, _, _)) -> false;
+is_specialization(?tuple(_, _, _), ?tuple(?any, ?any, ?any)) -> false;
+is_specialization(?tuple(Elements1, Arity, _),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ specialization_list(Elements1, Elements2);
+is_specialization(?tuple_set([{Arity, List}]),
+ ?tuple(Elements2, Arity, _)) when Arity =/= ?any ->
+ specialization_list(sup_tuple_elements(List), Elements2);
+is_specialization(?tuple(Elements1, Arity, _),
+ ?tuple_set([{Arity, List}])) when Arity =/= ?any ->
+ specialization_list(Elements1, sup_tuple_elements(List));
+is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
+ try
+ specialization_list(lists:append([T || {_Arity, T} <- List1]),
+ lists:append([T || {_Arity, T} <- List2]))
+ catch _:_ -> false
+ end;
+is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
+ case specialization_union2(T1, T2) of
+ {yes, Type1, Type2} -> is_specialization(Type1, Type2);
+ no -> specialization_list(List1, List2)
+ end;
+is_specialization(?union(List), T2) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(Type, T2);
+ no -> false
+ end;
+is_specialization(T1, ?union(List)) ->
+ case unify_union(List) of
+ {yes, Type} -> is_specialization(T1, Type);
+ no -> false
+ end;
+is_specialization(?opaque(_) = T1, T2) ->
+ is_specialization(t_opaque_structure(T1), T2);
+is_specialization(T1, ?opaque(_) = T2) ->
+ is_specialization(T1, t_opaque_structure(T2));
+is_specialization(?var(_), _) -> exit(error);
+is_specialization(_, ?var(_)) -> exit(error);
+is_specialization(T, T) -> true;
+is_specialization(?none, _) -> false;
+is_specialization(_, ?none) -> false;
+is_specialization(?unit, _) -> false;
+is_specialization(_, ?unit) -> false;
+is_specialization(#c{}, #c{}) -> false.
+
+specialization_list(L1, L2) ->
+ length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
+
+specialization_list1([], []) -> true;
+specialization_list1([T1|L1], [T2|L2]) ->
+ is_specialization(T1, T2) andalso specialization_list1(L1, L2).
+
+specialization_union2(?union(List1)=T1, ?union(List2)=T2) ->
+ case {unify_union(List1), unify_union(List2)} of
+ {{yes, Type1}, {yes, Type2}} -> {yes, Type1, Type2};
+ {{yes, Type1}, no} -> {yes, Type1, T2};
+ {no, {yes, Type2}} -> {yes, T1, Type2};
+ {no, no} -> no
+ end.
-spec t_inf_lists([erl_type()], [erl_type()]) -> [erl_type()].