231
232
cl_halt({error, Msg}, #options{}).
233
234
gui_halt(R, Opts) ->
234
cl_halt(R, Opts#options{report_mode=quiet}).
235
cl_halt(R, Opts#options{report_mode = quiet}).
236
237
-spec cl_halt({'ok',dial_ret()} | {'error',string()}, #options{}) -> no_return().
238
cl_halt({ok, R = ?RET_NOTHING_SUSPICIOUS}, #options{report_mode=quiet}) ->
240
cl_halt({ok, R = ?RET_DISCREPANCIES}, #options{report_mode=quiet}) ->
242
cl_halt({ok, R = ?RET_NOTHING_SUSPICIOUS}, #options{}) ->
239
cl_halt({ok, R = ?RET_NOTHING_SUSPICIOUS}, #options{report_mode = quiet}) ->
241
cl_halt({ok, R = ?RET_DISCREPANCIES}, #options{report_mode = quiet}) ->
243
cl_halt({ok, R = ?RET_NOTHING_SUSPICIOUS}, #options{}) ->
243
244
io:put_chars("done (passed successfully)\n"),
245
cl_halt({ok, R = ?RET_DISCREPANCIES}, #options{output_file=Output}) ->
246
cl_halt({ok, R = ?RET_DISCREPANCIES}, #options{output_file = Output}) ->
246
247
io:put_chars("done (warnings were emitted)\n"),
247
248
cl_check_log(Output),
249
cl_halt({error, Msg1}, #options{output_file=Output}) ->
250
Msg2 = "dialyzer: Internal problems were encountered in the analysis.",
251
io:format("\n~s\n~s\n", [Msg1, Msg2]),
250
cl_halt({error, Msg1}, #options{output_file = Output}) ->
251
%% Msg2 = "dialyzer: Internal problems were encountered in the analysis",
252
io:format("\ndialyzer: ~s\n", [Msg1]),
252
253
cl_check_log(Output),
253
254
halt(?RET_INTERNAL_ERROR).
255
-spec cl_check_log(string()) -> 'ok'.
256
-spec cl_check_log('none' | filename()) -> 'ok'.
257
258
cl_check_log(none) ->
267
268
String = lists:flatten(message_to_string(Msg)),
268
269
lists:flatten(io_lib:format("~s:~w: ~s", [BaseName, Line, String])).
270
message_to_string({binary_construction, [Size, Seg, Type]}) ->
271
io_lib:format("Binary construction will fail since the size field ~s in "
272
"binary segment ~s has type ~s\n",
274
message_to_string({fun_app_no_fun, [Op, Type]}) ->
275
io_lib:format("Fun application will fail since ~s :: ~s is not a function\n",
277
message_to_string({fun_app_args, [Args, Type]}) ->
278
io_lib:format("Fun application with arguments ~s will fail "
279
"since the function has type ~s\n",
272
%%-----------------------------------------------------------------------------
273
%% Message classification and pretty-printing below. Messages appear in
274
%% categories and iin more or less alphabetical ordering within each category.
275
%%-----------------------------------------------------------------------------
277
%%----- Warnings for general discrepancies ----------------
278
message_to_string({apply, [Args, ArgNs, FailReason,
279
SigArgs, SigRet, Contract]}) ->
280
io_lib:format("Fun application with arguments ~s ", [Args]) ++
281
call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract);
282
message_to_string({app_call, [M, F, Args, Culprit, ExpectedType, FoundType]}) ->
283
io_lib:format("The call ~s:~s~s requires that ~s is of type ~s not ~s\n",
284
[M, F, Args, Culprit, ExpectedType, FoundType]);
285
message_to_string({bin_construction, [Culprit, Size, Seg, Type]}) ->
286
io_lib:format("Binary construction will fail since the ~s field ~s in"
287
" segment ~s has type ~s\n", [Culprit, Size, Seg, Type]);
281
288
message_to_string({call, [M, F, Args, ArgNs, FailReason,
282
289
SigArgs, SigRet, Contract]}) ->
283
290
io_lib:format("The call ~w:~w~s ", [M, F, Args]) ++
284
291
call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract);
285
message_to_string({apply, [Args, ArgNs, FailReason,
286
SigArgs, SigRet, Contract]}) ->
287
io_lib:format("Fun application with arguments ~s ", [Args]) ++
288
call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract);
289
message_to_string({exact_eq, [Type1, Type2]}) ->
290
io_lib:format("~s =:= ~s can never evaluate to 'true'\n", [Type1, Type2]);
291
message_to_string({improper_list_constr, [TlType]}) ->
292
io_lib:format("Cons will produce an improper list since its "
293
"2nd argument is ~s\n", [TlType]);
294
message_to_string({record_matching, [String, Name]}) ->
295
io_lib:format("The ~s violates the "
296
"declared type for #~w{}\n", [String, Name]);
297
message_to_string({record_constr, [Types, Name]}) ->
298
io_lib:format("Record construction ~s violates the "
299
"declared type for #~w{}\n", [Types, Name]);
300
message_to_string({record_constr, [Name, Field, Type]}) ->
301
io_lib:format("Record construction violates the declared type for #~w{}"
302
" since ~s cannot be of type ~s\n",
303
[Name, Field, Type]);
304
message_to_string({pattern_match_cov, [Pat, Type]}) ->
305
io_lib:format("The ~s can never match since previous"
306
" clauses completely covered the type ~s\n",
308
message_to_string({pattern_match, [Pat, Type]}) ->
309
io_lib:format("The ~s can never match the type ~s\n", [Pat, Type]);
292
message_to_string({call_to_missing, [M, F, A]}) ->
293
io_lib:format("Call to missing or unexported function ~w:~w/~w\n", [M, F, A]);
294
message_to_string({exact_eq, [Type1, Op, Type2]}) ->
295
io_lib:format("The test ~s ~s ~s can never evaluate to 'true'\n",
297
message_to_string({fun_app_args, [Args, Type]}) ->
298
io_lib:format("Fun application with arguments ~s will fail"
299
" since the function has type ~s\n", [Args, Type]);
300
message_to_string({fun_app_no_fun, [Op, Type, Arity]}) ->
301
io_lib:format("Fun application will fail since ~s :: ~s"
302
" is not a function of arity ~w\n", [Op, Type, Arity]);
310
303
message_to_string({guard_fail, []}) ->
311
304
"Clause guard cannot succeed.\n";
312
305
message_to_string({guard_fail, [Arg1, Infix, Arg2]}) ->
313
io_lib:format("Guard test ~s ~s ~s can never succeed\n",
314
[Arg1, Infix, Arg2]);
306
io_lib:format("Guard test ~s ~s ~s can never succeed\n", [Arg1, Infix, Arg2]);
315
307
message_to_string({guard_fail, [Guard, Args]}) ->
316
308
io_lib:format("Guard test ~w~s can never succeed\n", [Guard, Args]);
317
309
message_to_string({guard_fail_pat, [Pat, Type]}) ->
318
310
io_lib:format("Clause guard cannot succeed. The ~s was matched"
319
311
" against the type ~s\n", [Pat, Type]);
320
message_to_string({unused_fun, []}) ->
321
io_lib:format("Function will never be called\n", []);
322
message_to_string({unused_fun, [F, A]}) ->
323
io_lib:format("Function ~w/~w will never be called\n", [F, A]);
312
message_to_string({improper_list_constr, [TlType]}) ->
313
io_lib:format("Cons will produce an improper list"
314
" since its 2nd argument is ~s\n", [TlType]);
324
315
message_to_string({no_return, [Type|Name]}) ->
318
[] -> "The created fun ";
328
319
[F, A] -> io_lib:format("Function ~w/~w ", [F, A])
332
323
only_normal -> NameString ++ "has no local return\n";
333
324
both -> NameString ++ "has no local return\n"
335
message_to_string({spec_missing_fun, [M, F, A]}) ->
336
io_lib:format("Contract for function that does not exist: ~w:~w/~w\n",
326
message_to_string({record_constr, [Types, Name]}) ->
327
io_lib:format("Record construction ~s violates the"
328
" declared type for #~w{}\n", [Types, Name]);
329
message_to_string({record_constr, [Name, Field, Type]}) ->
330
io_lib:format("Record construction violates the declared type for #~w{}"
331
" since ~s cannot be of type ~s\n", [Name, Field, Type]);
332
message_to_string({record_matching, [String, Name]}) ->
333
io_lib:format("The ~s violates the"
334
" declared type for #~w{}\n", [String, Name]);
335
message_to_string({pattern_match, [Pat, Type]}) ->
336
io_lib:format("The ~s can never match the type ~s\n", [Pat, Type]);
337
message_to_string({pattern_match_cov, [Pat, Type]}) ->
338
io_lib:format("The ~s can never match since previous"
339
" clauses completely covered the type ~s\n",
341
message_to_string({unmatched_return, [Type]}) ->
342
io_lib:format("Expression produces a value of type ~s,"
343
" but this value is unmatched\n", [Type]);
344
message_to_string({unused_fun, []}) ->
345
io_lib:format("Function will never be called\n", []);
346
message_to_string({unused_fun, [F, A]}) ->
347
io_lib:format("Function ~w/~w will never be called\n", [F, A]);
348
%%----- Warnings for specs and contracts -------------------
349
message_to_string({contract_diff, [M, F, _A, Contract, Sig]}) ->
350
io_lib:format("Type specification ~w:~w~s"
351
" is not equal to the success typing: ~w:~w~s\n",
352
[M, F, Contract, M, F, Sig]);
353
message_to_string({contract_subtype, [M, F, _A, Contract, Sig]}) ->
354
io_lib:format("Type specification ~w:~w~s"
355
" is a subtype of the success typing: ~w:~w~s\n",
356
[M, F, Contract, M, F, Sig]);
357
message_to_string({contract_supertype, [M, F, _A, Contract, Sig]}) ->
358
io_lib:format("Type specification ~w:~w~s"
359
" is a supertype of the success typing: ~w:~w~s\n",
360
[M, F, Contract, M, F, Sig]);
338
361
message_to_string({invalid_contract, [M, F, A, Sig]}) ->
339
io_lib:format("Invalid type specification for function ~w:~w/~w. "
340
"The success typing is ~s\n",
362
io_lib:format("Invalid type specification for function ~w:~w/~w."
363
" The success typing is ~s\n", [M, F, A, Sig]);
342
364
message_to_string({overlapping_contract, []}) ->
343
365
"Overloaded contract has overlapping domains;"
344
366
" such contracts are currently unsupported and are simply ignored\n";
345
message_to_string({contract_subtype, [M, F, A, Contract, Sig]}) ->
346
io_lib:format("Type specification ~w:~w/~w :: ~s "
347
"is a subtype of the success typing: ~s\n",
348
[M, F, A, Contract, Sig]);
349
message_to_string({contract_supertype, [M, F, A, Contract, Sig]}) ->
350
io_lib:format("Type specification ~w:~w/~w :: ~s "
351
"is a supertype of the success typing: ~s\n",
352
[M, F, A, Contract, Sig]);
353
message_to_string({contract_diff, [M, F, A, Contract, Sig]}) ->
354
io_lib:format("Type specification ~w:~w/~w :: ~s "
355
"is not equal to the success typing: ~s\n",
356
[M, F, A, Contract, Sig]);
357
message_to_string({call_to_missing, [M, F, A]}) ->
358
io_lib:format("Call to missing or unexported function ~w:~w/~w\n", [M, F, A]);
359
message_to_string({unmatched_return, [Type]}) ->
360
io_lib:format("Expression produces a value of type ~s, "
361
"but this value is unmatched\n", [Type]).
367
message_to_string({spec_missing_fun, [M, F, A]}) ->
368
io_lib:format("Contract for function that does not exist: ~w:~w/~w\n",
370
%%----- Warnings for opaque type violations -------------------
371
message_to_string({call_with_opaque, [M, F, Args, ArgNs, ExpArgs]}) ->
372
io_lib:format("The call ~w:~w~s contains ~s when ~s\n",
373
[M, F, Args, form_positions(ArgNs), form_expected(ExpArgs)]);
374
message_to_string({call_without_opaque, [M, F, Args, ExpectedTriples]}) ->
375
io_lib:format("The call ~w:~w~s does not have ~s\n",
376
[M, F, Args, form_expected_without_opaque(ExpectedTriples)]);
377
message_to_string({opaque_eq, [Type, _Op, OpaqueType]}) ->
378
io_lib:format("Attempt to test for equality between a term of type ~s"
379
" and a term of opaque type ~s\n", [Type, OpaqueType]);
380
message_to_string({opaque_guard, [Guard, Args]}) ->
381
io_lib:format("Guard test ~w~s breaks the opaqueness of its argument\n",
383
message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}) ->
384
Term = if OpaqueType =:= OpaqueTerm -> "the term";
387
io_lib:format("The attempt to match a term of type ~s against the ~s"
388
" breaks the opaqueness of ~s\n", [OpaqueType, Pat, Term]);
389
message_to_string({opaque_neq, [Type, _Op, OpaqueType]}) ->
390
io_lib:format("Attempt to test for inequality between a term of type ~s"
391
" and a term of opaque type ~s\n", [Type, OpaqueType]);
392
message_to_string({opaque_type_test, [Fun, Opaque]}) ->
393
io_lib:format("The type test ~s(~s) breaks the opaqueness of the term ~s\n", [Fun, Opaque, Opaque]);
394
%%----- Warnings for concurrency errors --------------------
395
message_to_string({possible_race, [M, F, Args, Reason]}) ->
396
io_lib:format("The call ~w:~w~s ~s\n", [M, F, Args, Reason]).
399
%%-----------------------------------------------------------------------------
400
%% Auxiliary functions below
401
%%-----------------------------------------------------------------------------
363
403
call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet,
364
404
{IsOverloaded, Contract}) ->
368
[N1] -> io_lib:format("position ~w", [N1]);
370
" and"++ArgString = lists:flatten([io_lib:format(" and ~w", [N])
372
"positions" ++ ArgString
405
PositionString = form_position_string(ArgNs),
374
406
case FailReason of
376
408
case ArgNs =:= [] of
378
%% We do not know which arguments caused the failure.
410
%% We do not know which argument(s) caused the failure
379
411
io_lib:format("will never return since the success typing arguments"
380
412
" are ~s\n", [SigArgs]);
382
414
io_lib:format("will never return since it differs in argument"
383
415
" ~s from the success typing arguments: ~s\n",
384
416
[PositionString, SigArgs])
387
419
case (ArgNs =:= []) orelse IsOverloaded of
389
%% We do not know which arguments caused the failure.
421
%% We do not know which arguments caused the failure
390
422
io_lib:format("breaks the contract ~s\n", [Contract]);
392
424
io_lib:format("breaks the contract ~s in argument ~s\n",
393
425
[Contract, PositionString])
396
428
io_lib:format("will never return since the success typing is ~s -> ~s"
397
429
" and the contract is ~s\n", [SigArgs, SigRet, Contract])
432
form_positions(ArgNs) ->
434
[_] -> "an opaque term in ";
435
[_,_|_] -> "opaque terms in "
436
end ++ form_position_string(ArgNs).
438
%% We know which positions N are to blame;
439
%% the list of triples will never be empty.
440
form_expected_without_opaque([{N, T, TStr}]) ->
441
case erl_types:t_is_opaque(T) of
443
io_lib:format("an opaque term of type ~s in ", [TStr]);
445
io_lib:format("a term of type ~s (with opaque subterms) in ", [TStr])
446
end ++ form_position_string([N]);
447
form_expected_without_opaque(ExpectedTriples) -> %% TODO: can do much better here
448
{ArgNs, _Ts, _TStrs} = lists:unzip3(ExpectedTriples),
449
"opaque terms in " ++ form_position_string(ArgNs).
451
form_expected(ExpectedArgs) ->
454
TS = erl_types:t_to_string(T),
455
case erl_types:t_is_opaque(T) of
456
true -> io_lib:format("an opaque term of type ~s is expected", [TS]);
457
false -> io_lib:format("a structured term of type ~s is expected", [TS])
459
[_,_|_] -> "terms of different types are expected in these positions"
462
form_position_string(ArgNs) ->
465
[N1] -> io_lib:format("position ~w", [N1]);
467
" and"++ArgString = lists:flatten([io_lib:format(" and ~w", [N])
469
"positions" ++ ArgString