josefs/Gradualizer

Crash with Uncaught error: {badkey, ...}

ilya-klyuchnikov opened this issue · 1 comments

A minimal repro:

-module(box).
-export_type([box/0]).

-record(box, {value = <<>> :: binary()}).
-type box() :: #box{}.
-module(gradualizer_repro3).
-compile([export_all, nowarn_export_all]).

-spec get_box([tuple()]) -> box:box() | undefined.
get_box([H | _T]) when is_record(H, box, 1) -> H;
get_box([_ | Tail]) -> get_box(Tail);
get_box(_) -> undefined.
===> Uncaught error in rebar_core. Run with DIAGNOSTIC=1 to see stacktrace or consult rebar3.crashdump
===> Uncaught error: {badkey,box}
===> Stack trace to the error location:
[{erlang,map_get,[box,#{}],[{error_info,#{module => erl_erts_errors}}]},
 {typechecker,get_record_fields,3,
              [{file,"/Users/ilyaklyuchnikov/code/gr-rebar3/_build/default/plugins/gradualizer/src/typechecker.erl"},
               {line,590}]},
 {typechecker,compat_ty,4,
              [{file,"/Users/ilyaklyuchnikov/code/gr-rebar3/_build/default/plugins/gradualizer/src/typechecker.erl"},
               {line,375}]},
 {typechecker,any_type,4,
              [{file,"/Users/ilyaklyuchnikov/code/gr-rebar3/_build/default/plugins/gradualizer/src/typechecker.erl"},
               {line,541}]},
 {typechecker,subtype,3,
              [{file,"/Users/ilyaklyuchnikov/code/gr-rebar3/_build/default/plugins/gradualizer/src/typechecker.erl"},
               {line,190}]},
 {typechecker,do_type_check_expr_in,3,
              [{file,"/Users/ilyaklyuchnikov/code/gr-rebar3/_build/default/plugins/gradualizer/src/typechecker.erl"},
               {line,2500}]},
 {typechecker,type_check_expr_in,3,
              [{file,"/Users/ilyaklyuchnikov/code/gr-rebar3/_build/default/plugins/gradualizer/src/typechecker.erl"},
               {line,2487}]},
 {typechecker,check_clause,5,
              [{file,"/Users/ilyaklyuchnikov/code/gr-rebar3/_build/default/plugins/gradualizer/src/typechecker.erl"},
               {line,4000}]}]

Interesting. The record definition is not available in the module, but it shouldn't have to be. is_record/3 shouldn't look up the record. It should just check if it's a tuple with the right size and the first element is the record name.

Josef tried to distinguish between tuples and records, but it's not really possible in situations like this.