Skip to content

Instantly share code, notes, and snippets.

@seriyps
Created July 28, 2020 13:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seriyps/d4daa42185ba2ce2e319184199cd4039 to your computer and use it in GitHub Desktop.
Save seriyps/d4daa42185ba2ce2e319184199cd4039 to your computer and use it in GitHub Desktop.
Parameterized record types dialyzer oddity
$ rebar3 dialyzer [15:33:30]
===> Verifying dependencies...
===> Compiling mylib
===> Dialyzer starting, this may take a while...
===> Updating plt...
===> Resolving files...
===> Checking 202 files in "sandbox/mylib/_build/default/rebar3_23.0_plt"...
===> Doing success typing analysis...
===> Resolving files...
===> Analyzing 2 files with "sandbox/mylib/_build/default/rebar3_23.0_plt"...
src/parameterized_record.erl
38: Function test2/0 has no local return
40: The call parameterized_record:take_type1_rec(Rec2::#my_record{id::2,type::2}) breaks the contract (#my_record{id::integer(),type::1}) -> 'ok'
42: Invalid type specification for function parameterized_record:take_type1_rec/1. The success typing is (#my_record{id::2,type::2}) -> any()
58: Invalid type specification for function parameterized_record:should_make_type2_rec/0. The success typing is () -> #my_record{id::1,type::1}
src/parameterized_tuple.erl
29: Function test1/0 has no local return
31: The call parameterized_tuple:take_type1(Rec2::{'my_tag',pos_integer(),2}) breaks the contract (my_record(1)) -> 'ok'
33: Invalid type specification for function parameterized_tuple:take_type1/1. The success typing is ({'my_tag',pos_integer(),2}) -> any()
38: Function test2/0 has no local return
40: The call parameterized_tuple:take_type1_rec(Rec2::{'my_tag',pos_integer(),2}) breaks the contract ({'my_tag',integer(),1}) -> 'ok'
42: Invalid type specification for function parameterized_tuple:take_type1_rec/1. The success typing is ({'my_tag',pos_integer(),2}) -> any()
50: Invalid type specification for function parameterized_tuple:should_make_type2/0. The success typing is () -> {'my_tag',pos_integer(),1}
58: Invalid type specification for function parameterized_tuple:should_make_type2_rec/0. The success typing is () -> {'my_tag',pos_integer(),1}
===> Warnings written to sandbox/mylib/_build/default/23.0.dialyzer_warnings
===> Warnings occurred running dialyzer: 12
-module(parameterized_record).
-export([mk_type1/0, mk_type2/0]).
-export([test1/0, test2/0, test3/0, test4/0]).
-export_type([my_record/1, my_record/0, my_rec_type/0]).
-define(TYPE1, 1).
-define(TYPE2, 2).
-record(my_record,
{id = [] :: [] | integer(),
type = []}).
-type my_record(Type) :: #my_record{id :: integer(), type :: Type}.
-type my_record() :: my_record(my_rec_type()).
-type my_rec_type() :: ?TYPE1..?TYPE2.
-spec mk_type1() -> my_record(?TYPE1).
mk_type1() ->
#my_record{id = 1, type = ?TYPE1}.
-spec mk_type2() -> my_record(?TYPE2).
mk_type2() ->
#my_record{id = 2, type = ?TYPE2}.
test1() ->
Rec2 = mk_type2(),
take_type1(Rec2). %expects ?TYPE1, gets ?TYPE2. NOT reported!!!
-spec take_type1(my_record(?TYPE1)) -> ok.
take_type1(Rec) ->
gen_server:call(somewhere, Rec).
test2() ->
Rec2 = mk_type2(),
take_type1_rec(Rec2). %expects ?TYPE1, gets ?TYPE2. Reported.
-spec take_type1_rec(#my_record{id :: integer(), type :: ?TYPE1}) -> ok.
take_type1_rec(Rec) ->
gen_server:call(somewhere, Rec).
test3() ->
should_make_type2(). %spec says returns ?TYPE2, returns ?TYPE1. NOT Reported!!
-spec should_make_type2() -> my_record(?TYPE2).
should_make_type2() ->
mk_type1().
test4() ->
should_make_type2_rec(). %spec says returns ?TYPE2, returns ?TYPE1. Reported.
-spec should_make_type2_rec() -> #my_record{id :: integer(), type :: ?TYPE2}.
should_make_type2_rec() ->
mk_type1().
-module(parameterized_tuple).
-export([mk_type1/0, mk_type2/0]).
-export([test1/0, test2/0, test3/0, test4/0]).
-export_type([my_record/1, my_record/0, my_rec_type/0]).
-define(TYPE1, 1).
-define(TYPE2, 2).
-type my_record(Type) :: {my_tag,
Id :: integer(),
Type}.
-type my_record() :: my_record(my_rec_type()).
-type my_rec_type() :: ?TYPE1..?TYPE2.
-spec mk_type1() -> my_record(?TYPE1).
mk_type1() ->
{my_tag, rand:uniform(10), ?TYPE1}.
-spec mk_type2() -> my_record(?TYPE2).
mk_type2() ->
{my_tag, rand:uniform(10), ?TYPE2}.
test1() ->
Rec2 = mk_type2(),
take_type1(Rec2). %expects ?TYPE1, gets ?TYPE2. Reported!
-spec take_type1(my_record(?TYPE1)) -> ok.
take_type1(Rec) ->
gen_server:call(somewhere, Rec).
test2() ->
Rec2 = mk_type2(),
take_type1_rec(Rec2). %expects ?TYPE1, gets ?TYPE2. Reported!
-spec take_type1_rec({my_tag, integer(), ?TYPE1}) -> ok.
take_type1_rec(Rec) ->
gen_server:call(somewhere, Rec).
test3() ->
should_make_type2(). %spec says returns ?TYPE2, returns ?TYPE1. Reported!
-spec should_make_type2() -> my_record(?TYPE2).
should_make_type2() ->
mk_type1().
test4() ->
should_make_type2_rec(). %spec says returns ?TYPE2, returns ?TYPE1. Reported!
-spec should_make_type2_rec() -> {my_tag, integer(), ?TYPE2}.
should_make_type2_rec() ->
mk_type1().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment