1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
-module(exact_api).
-export([new/0, exact_api_test/1, exact_api_new/1,
exact_adt_test/1, exact_adt_new/1]).
-export_type([exact_api/0]).
-record(digraph, {vtab = notable :: ets:tab(),
etab = notable :: ets:tab(),
ntab = notable :: ets:tab(),
cyclic = true :: boolean()}).
-spec new() -> digraph:graph().
new() ->
A = #digraph{},
set_type(A), % does not have an opaque term as 1st argument
A.
-spec set_type(digraph:graph()) -> true.
set_type(G) ->
digraph:delete(G).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% The derived spec of exact_api_new() is
%%% -spec exact_api_new(exact_api:exact_api()) -> exact_api:exact_api().
%%% This won't happen unless dialyzer_typesig uses
%%% t_is_exactly_equal() rather than t_is_equal().
%%% [As of R17B the latter considers two types equal if nothing but
%%% their ?opaque tags differ.]
-record(exact_api, {}).
-opaque exact_api() :: #exact_api{}.
exact_api_test(X) ->
#exact_api{} = exact_api_set_type(X). % OK
exact_api_new(A) ->
A = #exact_api{},
_ = exact_api_set_type(A), % OK (the opaque type is local)
A.
-spec exact_api_set_type(exact_api()) -> exact_api().
exact_api_set_type(#exact_api{}=E) -> E.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-record(exact_adt, {}).
exact_adt_test(X) ->
#exact_adt{} = exact_adt:exact_adt_set_type(X). % breaks the opaqueness
exact_adt_new(A) ->
A = #exact_adt{},
_ = exact_adt:exact_adt_set_type2(A), % does not have an opaque term as 1st argument
A.
|