2
2
%%-----------------------------------------------------------------------
5
%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
5
%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
7
7
%% The contents of this file are subject to the Erlang Public License,
8
8
%% Version 1.1, (the "License"); you may not use this file except in
62
62
-type dep() :: integer(). %% type variable names used as constraint ids
63
63
-type type_var() :: erl_types:erl_type(). %% actually: {'c','var',_,_}
65
-record(fun_var, {'fun' :: fun((_) -> erl_types:erl_type()), deps :: [dep()]}).
65
-record(fun_var, {'fun' :: fun((_) -> erl_types:erl_type()), deps :: [dep()],
66
origin :: integer()}).
67
68
-type constr_op() :: 'eq' | 'sub'.
68
69
-type fvar_or_type() :: #fun_var{} | erl_types:erl_type().
123
124
-define(debug(__String, __Args), io:format(__String, __Args)).
125
-define(mk_fun_var(Fun, Vars), mk_fun_var(?LINE, Fun, Vars)).
125
127
-define(debug(__String, __Args), ok).
128
-define(mk_fun_var(Fun, Vars), mk_fun_var(Fun, Vars)).
128
131
%% ============================================================================
219
222
{State1, SegTypes} = traverse_list(cerl:binary_segments(Tree),
220
223
DefinedVars, State),
221
Type = mk_fun_var(fun(Map) ->
222
TmpSegTypes = lookup_type_list(SegTypes, Map),
223
t_bitstr_concat(TmpSegTypes)
224
Type = ?mk_fun_var(fun(Map) ->
225
TmpSegTypes = lookup_type_list(SegTypes, Map),
226
t_bitstr_concat(TmpSegTypes)
225
228
{state__store_conj(mk_var(Tree), sub, Type, State1), mk_var(Tree)};
227
230
Size = cerl:bitstr_size(Tree),
236
239
N when is_integer(N) -> {State1, t_bitstr(0, N)};
237
240
any -> % Size is not a literal
238
241
{state__store_conj(SizeType, sub, t_non_neg_integer(), State1),
239
mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])}
242
?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])}
242
245
case cerl:concrete(cerl:bitstr_type(Tree)) of
250
253
case state__is_in_match(State1) of
252
255
Flags = cerl:concrete(cerl:bitstr_flags(Tree)),
253
mk_fun_var(bitstr_val_constr(SizeType, UnitVal, Flags),
256
?mk_fun_var(bitstr_val_constr(SizeType, UnitVal, Flags),
255
258
false -> t_integer()
257
260
utf8 -> t_integer();
281
284
{State, t_cons(HdVar, TlVar)};
283
286
ConsVar = mk_var(Tree),
284
ConsType = mk_fun_var(fun(Map) ->
285
t_cons(lookup_type(HdVar, Map),
286
lookup_type(TlVar, Map))
287
end, [HdVar, TlVar]),
288
HdType = mk_fun_var(fun(Map) ->
289
Cons = lookup_type(ConsVar, Map),
290
case t_is_cons(Cons) of
292
true -> t_cons_hd(Cons)
295
TlType = mk_fun_var(fun(Map) ->
296
Cons = lookup_type(ConsVar, Map),
297
case t_is_cons(Cons) of
299
true -> t_cons_tl(Cons)
287
ConsType = ?mk_fun_var(fun(Map) ->
288
t_cons(lookup_type(HdVar, Map),
289
lookup_type(TlVar, Map))
290
end, [HdVar, TlVar]),
291
HdType = ?mk_fun_var(fun(Map) ->
292
Cons = lookup_type(ConsVar, Map),
293
case t_is_cons(Cons) of
295
true -> t_cons_hd(Cons)
298
TlType = ?mk_fun_var(fun(Map) ->
299
Cons = lookup_type(ConsVar, Map),
300
case t_is_cons(Cons) of
302
true -> t_cons_tl(Cons)
302
305
State2 = state__store_conj_lists([HdVar, TlVar, ConsVar], sub,
303
306
[HdType, TlType, ConsType],
656
659
{RetType, ArgCs} =
659
{mk_fun_var(fun(Map) ->
660
ArgTypes = lookup_type_list(ArgVars, Map),
661
dialyzer_contracts:get_contract_return(C, ArgTypes)
662
end, ArgVars), GenArgs};
662
{?mk_fun_var(fun(Map) ->
663
ArgTypes = lookup_type_list(ArgVars, Map),
664
dialyzer_contracts:get_contract_return(C, ArgTypes)
665
end, ArgVars), GenArgs};
663
666
{value, {PltRetType, PltArgTypes}} ->
664
667
%% Need to combine the contract with the success typing.
667
ArgTypes0 = lookup_type_list(ArgVars, Map),
668
ArgTypes = case FunModule =:= Module of
670
List = lists:zip(PltArgTypes, ArgTypes0),
671
[erl_types:t_unopaque_on_mismatch(T1, T2, Opaques)
672
|| {T1, T2} <- List];
675
CRet = dialyzer_contracts:get_contract_return(C, ArgTypes),
676
t_inf(CRet, PltRetType, opaque)
670
ArgTypes0 = lookup_type_list(ArgVars, Map),
671
ArgTypes = case FunModule =:= Module of
673
List = lists:zip(PltArgTypes, ArgTypes0),
674
[erl_types:t_unopaque_on_mismatch(T1, T2, Opaques)
675
|| {T1, T2} <- List];
678
CRet = dialyzer_contracts:get_contract_return(C, ArgTypes),
679
t_inf(CRet, PltRetType, opaque)
678
681
[t_inf(X, Y, opaque) || {X, Y} <- lists:zip(GenArgs, PltArgTypes)]}
680
683
state__store_conj_lists([Dst|ArgVars], sub, [RetType|ArgCs], State)
766
769
case SubtrTypes =:= overflow of
769
SubtrPatVar = mk_fun_var(fun(Map) ->
770
TmpType = lookup_type(Arg, Map),
771
t_subtract_list(TmpType, SubtrTypes)
772
SubtrPatVar = ?mk_fun_var(fun(Map) ->
773
TmpType = lookup_type(Arg, Map),
774
t_subtract_list(TmpType, SubtrTypes)
773
776
state__store_conj(Arg, sub, SubtrPatVar, S)
1044
1047
get_bif_constr({erlang, Op, 2}, Dst, Args = [Arg1, Arg2], _State)
1045
1048
when Op =:= '+'; Op =:= '-'; Op =:= '*' ->
1046
ReturnType = mk_fun_var(fun(Map) ->
1047
TmpArgTypes = lookup_type_list(Args, Map),
1048
erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
1049
ReturnType = ?mk_fun_var(fun(Map) ->
1050
TmpArgTypes = lookup_type_list(Args, Map),
1051
erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
1131
1134
'>=' -> {ArgFun(Arg1, Arg2, '>='), ArgFun(Arg2, Arg1, '=<')}
1133
1136
DstArgs = [Dst, Arg1, Arg2],
1134
Arg1Var = mk_fun_var(Arg1Fun, DstArgs),
1135
Arg2Var = mk_fun_var(Arg2Fun, DstArgs),
1136
DstVar = mk_fun_var(fun(Map) ->
1137
TmpArgTypes = lookup_type_list(Args, Map),
1138
erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
1137
Arg1Var = ?mk_fun_var(Arg1Fun, DstArgs),
1138
Arg2Var = ?mk_fun_var(Arg2Fun, DstArgs),
1139
DstVar = ?mk_fun_var(fun(Map) ->
1140
TmpArgTypes = lookup_type_list(Args, Map),
1141
erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
1140
1143
mk_conj_constraint_list([mk_constraint(Dst, sub, DstVar),
1141
1144
mk_constraint(Arg1, sub, Arg1Var),
1142
1145
mk_constraint(Arg2, sub, Arg2Var)]);
1175
HdVar = mk_fun_var(HdFun, DstL),
1176
TlVar = mk_fun_var(TlFun, DstL),
1178
HdVar = ?mk_fun_var(HdFun, DstL),
1179
TlVar = ?mk_fun_var(TlFun, DstL),
1177
1180
ArgTypes = erl_bif_types:arg_types(erlang, '++', 2),
1178
ReturnType = mk_fun_var(fun(Map) ->
1179
TmpArgTypes = lookup_type_list(Args, Map),
1180
erl_bif_types:type(erlang, '++', 2, TmpArgTypes)
1181
ReturnType = ?mk_fun_var(fun(Map) ->
1182
TmpArgTypes = lookup_type_list(Args, Map),
1183
erl_bif_types:type(erlang, '++', 2, TmpArgTypes)
1182
1185
Cs = mk_constraints(Args, sub, ArgTypes),
1183
1186
mk_conj_constraint_list([mk_constraint(Dst, sub, ReturnType),
1184
1187
mk_constraint(Hd, sub, HdVar),
1209
1212
false -> t_any()
1212
ArgV = mk_fun_var(ArgFun, [Dst, Arity]),
1215
ArgV = ?mk_fun_var(ArgFun, [Dst, Arity]),
1213
1216
mk_conj_constraint_list([mk_constraint(Dst, sub, t_boolean()),
1214
1217
mk_constraint(Arity, sub, t_integer()),
1215
1218
mk_constraint(Fun, sub, ArgV)]);
1232
1235
false -> t_any()
1235
ArgV = mk_fun_var(ArgFun, [Dst]),
1238
ArgV = ?mk_fun_var(ArgFun, [Dst]),
1236
1239
DstFun = fun(Map) ->
1237
1240
TmpArgTypes = lookup_type_list(Args, Map),
1238
1241
erl_bif_types:type(erlang, is_record, 2, TmpArgTypes)
1240
DstV = mk_fun_var(DstFun, Args),
1243
DstV = ?mk_fun_var(DstFun, Args),
1241
1244
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
1242
1245
mk_constraint(Tag, sub, t_atom()),
1243
1246
mk_constraint(Var, sub, ArgV)]);
1280
1283
false -> t_any()
1283
ArgV = mk_fun_var(ArgFun, [Tag, Arity, Dst]),
1286
ArgV = ?mk_fun_var(ArgFun, [Tag, Arity, Dst]),
1284
1287
DstFun = fun(Map) ->
1285
1288
[TmpVar, TmpTag, TmpArity] = TmpArgTypes = lookup_type_list(Args, Map),
1315
1318
erl_bif_types:type(erlang, is_record, 3, TmpArgTypes2)
1317
DstV = mk_fun_var(DstFun, Args),
1320
DstV = ?mk_fun_var(DstFun, Args),
1318
1321
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
1319
1322
mk_constraint(Arity, sub, t_integer()),
1320
1323
mk_constraint(Tag, sub, t_atom()),
1362
ArgV1 = mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
1363
ArgV2 = mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
1364
DstV = mk_fun_var(DstFun, Args),
1365
ArgV1 = ?mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
1366
ArgV2 = ?mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
1367
DstV = ?mk_fun_var(DstFun, Args),
1365
1368
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
1366
1369
mk_constraint(Arg1, sub, ArgV1),
1367
1370
mk_constraint(Arg2, sub, ArgV2)]);
1406
ArgV1 = mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
1407
ArgV2 = mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
1408
DstV = mk_fun_var(DstFun, Args),
1409
Disj = mk_disj_constraint_list([mk_constraint(Arg1, sub, True),
1410
mk_constraint(Arg2, sub, True),
1411
mk_constraint(Dst, sub, False)]),
1409
ArgV1 = ?mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
1410
ArgV2 = ?mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
1411
DstV = ?mk_fun_var(DstFun, Args),
1413
try [mk_constraint(A, sub, True)]
1414
catch throw:error -> []
1417
Constrs = F(Arg1) ++ F(Arg2),
1418
Disj = mk_disj_constraint_list([mk_constraint(Dst, sub, False)|Constrs]),
1412
1419
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
1413
1420
mk_constraint(Arg1, sub, ArgV1),
1414
1421
mk_constraint(Arg2, sub, ArgV2),
1432
ArgV = mk_fun_var(Fun(Dst), [Dst]),
1433
DstV = mk_fun_var(Fun(Arg), Args),
1439
ArgV = ?mk_fun_var(Fun(Dst), [Dst]),
1440
DstV = ?mk_fun_var(Fun(Arg), Args),
1434
1441
mk_conj_constraint_list([mk_constraint(Arg, sub, ArgV),
1435
1442
mk_constraint(Dst, sub, DstV)]);
1436
1443
get_bif_constr({erlang, '=:=', 2}, Dst, [Arg1, Arg2] = Args, _State) ->
1465
1472
DstArgs = [Dst, Arg1, Arg2],
1466
ArgV1 = mk_fun_var(ArgFun(Arg1, Arg2), DstArgs),
1467
ArgV2 = mk_fun_var(ArgFun(Arg2, Arg1), DstArgs),
1468
DstV = mk_fun_var(DstFun, Args),
1473
ArgV1 = ?mk_fun_var(ArgFun(Arg1, Arg2), DstArgs),
1474
ArgV2 = ?mk_fun_var(ArgFun(Arg2, Arg1), DstArgs),
1475
DstV = ?mk_fun_var(DstFun, Args),
1469
1476
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
1470
1477
mk_constraint(Arg1, sub, ArgV1),
1471
1478
mk_constraint(Arg2, sub, ArgV2)]);
1509
DstV = mk_fun_var(DstFun, Args),
1516
DstV = ?mk_fun_var(DstFun, Args),
1510
1517
ArgL = [Arg1, Arg2, Dst],
1511
ArgV1 = mk_fun_var(ArgFun(Arg2, Arg1), ArgL),
1512
ArgV2 = mk_fun_var(ArgFun(Arg1, Arg2), ArgL),
1518
ArgV1 = ?mk_fun_var(ArgFun(Arg2, Arg1), ArgL),
1519
ArgV2 = ?mk_fun_var(ArgFun(Arg1, Arg2), ArgL),
1513
1520
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
1514
1521
mk_constraint(Arg1, sub, ArgV1),
1515
1522
mk_constraint(Arg2, sub, ArgV2)]);
1528
1535
erl_bif_types:type(erlang, element, 2, ATs2)
1530
ReturnType = mk_fun_var(Fun, Args),
1537
ReturnType = ?mk_fun_var(Fun, Args),
1531
1538
ArgTypes = erl_bif_types:arg_types(erlang, element, 2),
1532
1539
Cs = mk_constraints(Args, sub, ArgTypes),
1552
ReturnType = mk_fun_var(fun(Map) ->
1559
ReturnType = ?mk_fun_var(fun(Map) ->
1553
1560
TmpArgTypes0 = lookup_type_list(Args, Map),
1554
1561
TmpArgTypes = [UnopaqueFun(T) || T<- TmpArgTypes0],
1555
1562
erl_bif_types:type(M, F, A, TmpArgTypes)
1604
1611
false -> t_any()
1607
ArgV = mk_fun_var(ArgFun, [Dst]),
1614
ArgV = ?mk_fun_var(ArgFun, [Dst]),
1608
1615
DstFun = fun(Map) ->
1609
1616
ArgType = lookup_type(Arg, Map),
1610
1617
case t_is_none(t_inf(ArgType, Type)) of
1632
DstV = mk_fun_var(DstFun, [Arg]),
1639
DstV = ?mk_fun_var(DstFun, [Arg]),
1633
1640
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
1634
1641
mk_constraint(Arg, sub, ArgV)]).
1681
1688
?debug("SCC ~w reached fixpoint\n", [SCC]),
1682
1689
NewTypes = unsafe_lookup_type_list(Funs, Map2),
1683
case lists:all(fun(T) -> t_is_none(t_fun_range(T)) end, NewTypes)
1690
case erl_types:any_none([t_fun_range(T) || T <- NewTypes])
1684
1691
andalso TryingUnit =:= false of
1686
UnitTypes = [t_fun(state__fun_arity(F, State), t_unit())
1694
[case t_is_none(t_fun_range(T)) of
1696
true -> t_fun(t_fun_args(T), t_unit())
1697
end || T <- NewTypes],
1688
1698
Map3 = enter_type_lists(Funs, UnitTypes, Map2),
1689
1699
solve_scc(SCC, Map3, State, true);
2151
2160
case lists:member(error, MFAs) of
2155
State1 = state__new_constraint_context(State),
2156
State2 = get_plt_constr(MFA, Dst, ArgTypes, State1),
2158
end || {ok, MFA} <- MFAs],
2159
ApplyConstr = mk_disj_constraint_list(Constrs),
2160
{ok, state__store_conj(ApplyConstr, State)}
2165
State1 = state__new_constraint_context(State),
2166
try get_plt_constr(MFA, Dst, ArgTypes, State1) of
2167
State2 -> state__cs(State2)
2169
throw:error -> error
2171
end || {ok, MFA} <- MFAs],
2172
case [C || C <- Constrs0, C =/= error] of
2175
ApplyConstr = mk_disj_constraint_list(Constrs),
2176
{ok, state__store_conj(ApplyConstr, State)}
2163
2180
state__scc(#state{scc = SCC}) ->
2316
2333
constraint_opnd_is_any(#fun_var{}) -> false;
2317
2334
constraint_opnd_is_any(Type) -> t_is_any(Type).
2338
-spec mk_fun_var(fun((_) -> erl_types:erl_type()), [erl_types:erl_type()],
2339
integer()) -> #fun_var{}.
2341
mk_fun_var(Line, Fun, Types) ->
2342
Deps = [t_var_name(Var) || Var <- t_collect_vars(t_product(Types))],
2343
#fun_var{'fun' = Fun, deps = ordsets:from_list(Deps), origin = Line}.
2319
2347
-spec mk_fun_var(fun((_) -> erl_types:erl_type()), [erl_types:erl_type()]) -> #fun_var{}.
2321
2349
mk_fun_var(Fun, Types) ->
2322
2350
Deps = [t_var_name(Var) || Var <- t_collect_vars(t_product(Types))],
2323
2351
#fun_var{'fun' = Fun, deps = ordsets:from_list(Deps)}.
2325
2355
-spec get_deps(constr()) -> [dep()].
2327
2357
get_deps(#constraint{deps = D}) -> D;
2675
format_type(#fun_var{deps = Deps}) ->
2676
io_lib:format("Fun(~s)", [lists:flatten([format_type(t_var(X))||X<-Deps])]);
2705
format_type(#fun_var{deps = Deps, origin = Origin}) ->
2706
io_lib:format("Fun@L~p(~s)",
2707
[Origin, lists:flatten([format_type(t_var(X))||X<-Deps])]);
2677
2708
format_type(Type) ->
2678
2709
case cerl:is_literal(Type) of
2679
2710
true -> io_lib:format("~w", [cerl:concrete(Type)]);