From 8498a35ce141c6e16feed198540b910b9475b2e2 Mon Sep 17 00:00:00 2001 From: Hans Bolinder Date: Tue, 13 May 2014 08:31:19 +0200 Subject: [dialyzer] Fix handling of literal records This ticket is about records in Erlang code, and when to check the fields against the (optional) types given when defining records. Dialyzer operates on the Erlang Core format, where there are no trace of records. The fix implemented is a Real Hack: Given the new option 'dialyzer' erl_expand_records marks the line number of records in a way that is undone by v3_core, which in turn inserts annotations that can be recognized by Dialyzer. --- .../src/confusing_record_warning.erl | 19 ------------- lib/dialyzer/test/small_SUITE_data/src/fun2ms.erl | 21 ++++++++++++++ .../test/small_SUITE_data/src/literals.erl | 33 ++++++++++++++++++++++ .../src/relevant_record_warning.erl | 23 +++++++++++++++ 4 files changed, 77 insertions(+), 19 deletions(-) delete mode 100644 lib/dialyzer/test/small_SUITE_data/src/confusing_record_warning.erl create mode 100644 lib/dialyzer/test/small_SUITE_data/src/fun2ms.erl create mode 100644 lib/dialyzer/test/small_SUITE_data/src/literals.erl create mode 100644 lib/dialyzer/test/small_SUITE_data/src/relevant_record_warning.erl (limited to 'lib/dialyzer/test/small_SUITE_data/src') diff --git a/lib/dialyzer/test/small_SUITE_data/src/confusing_record_warning.erl b/lib/dialyzer/test/small_SUITE_data/src/confusing_record_warning.erl deleted file mode 100644 index 8af74e0914..0000000000 --- a/lib/dialyzer/test/small_SUITE_data/src/confusing_record_warning.erl +++ /dev/null @@ -1,19 +0,0 @@ -%%--------------------------------------------------------------------- -%% A user complained that dialyzer produces a weird warning for the -%% following program. I explained to him that there is an implicit -%% assumption that when a record is typed one cannot have types of -%% the same size which are tagged by the record name whose elements -%% have different types than the ones declared in the record. -%% -%% But the warning from dialyzer was weird nonetheless: -%% The pattern {'r', [_]} can never match the type any() -%% We should clearly give some less confusing warning in this case. -%%--------------------------------------------------------------------- --module(confusing_record_warning). - --export([test/1]). - --record(r, {field :: binary}). - -test({r, [_]}) -> - #r{field = <<42>>}. diff --git a/lib/dialyzer/test/small_SUITE_data/src/fun2ms.erl b/lib/dialyzer/test/small_SUITE_data/src/fun2ms.erl new file mode 100644 index 0000000000..9e7df85e4c --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/fun2ms.erl @@ -0,0 +1,21 @@ +-module(fun2ms). +-export([return/0]). +-include_lib("stdlib/include/ms_transform.hrl"). + +-record(snapshot, {id :: integer(), arg1 :: atom(), arg2 :: tuple()}). + +return() -> + TableId = ets:new(table, [public, {keypos, #snapshot.id}]), + + ets:insert(TableId, [#snapshot{id = 1, arg1 = hard, arg2 = {1,2}}, + #snapshot{id = 2, arg1 = rock, arg2 = {1,2}}, + #snapshot{id = 3, arg1 = hallelujah, arg2 = + {1,2}}]), + + + Example = ets:fun2ms( + fun(#snapshot{id = Arg1, arg1 = Arg2}) -> + {Arg1, Arg2} + end), + + ets:select(TableId, Example). diff --git a/lib/dialyzer/test/small_SUITE_data/src/literals.erl b/lib/dialyzer/test/small_SUITE_data/src/literals.erl new file mode 100644 index 0000000000..abd7033712 --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/literals.erl @@ -0,0 +1,33 @@ +-module(literals). + +%% Bad records inside structures used to be ignored. The reason: +%% v3_core:unfold() does not annotate the parts of a literal. +%% This example does not work perfectly yet, in particular Maps. + +-export([t1/0, t2/0, t3/0, t4/0, m1/1, m2/1, m3/1, m4/1]). + +-record(r, {id :: integer}). + +t1() -> + #r{id = a}. % violation + +t2() -> + [#r{id = a}]. % violation + +t3() -> + {#r{id = a}}. % violation + +t4() -> + #{a => #r{id = a}}. % violation found, but t4() returns... (bug) + +m1(#r{id = a}) -> % violation + ok. + +m2([#r{id = a}]) -> % violation + ok. + +m3({#r{id = a}}) -> % can never match; not so good + ok. + +m4(#{a := #r{id = a}}) -> % violation not found + ok. diff --git a/lib/dialyzer/test/small_SUITE_data/src/relevant_record_warning.erl b/lib/dialyzer/test/small_SUITE_data/src/relevant_record_warning.erl new file mode 100644 index 0000000000..3ff65458df --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/relevant_record_warning.erl @@ -0,0 +1,23 @@ +%% Formerly confusing_record_warning.erl. +%% The warning output is relevant as of Erlang/OTP 17.1. +%% The original comment kept below. + +%%--------------------------------------------------------------------- +%% A user complained that dialyzer produces a weird warning for the +%% following program. I explained to him that there is an implicit +%% assumption that when a record is typed one cannot have types of +%% the same size which are tagged by the record name whose elements +%% have different types than the ones declared in the record. +%% +%% But the warning from dialyzer was weird nonetheless: +%% The pattern {'r', [_]} can never match the type any() +%% We should clearly give some less confusing warning in this case. +%%--------------------------------------------------------------------- +-module(relevant_record_warning). + +-export([test/1]). + +-record(r, {field :: binary}). + +test({r, [_]}) -> + #r{field = <<42>>}. -- cgit v1.2.3