elixir-lang / elixir

Elixir is a dynamic, functional language for building scalable and maintainable applications
https://elixir-lang.org/
Apache License 2.0
24.3k stars 3.35k forks source link

Dialyzer Warnings #2478

Closed fishcakez closed 10 years ago

fishcakez commented 10 years ago

There are some frequent warnings:

The following warning occurs for elixir modules because a stricter spec is possible:

lib/access.ex:1: Type specification 'Elixir.Access':'__info__'(atom()) -> term() is a supertype of the success typing: 'Elixir.Access':'__info__'('attributes' | 'compile' | 'exports' | 'functions' | 'imports' | 'macros' | 'module' | 'native_addresses') -> atom() | [{atom(),_} | {atom(),byte(),integer()}]

Similar cases often show how specs can be improved:

lib/file.ex:609: Type specification 'Elixir.File':write('Elixir.Path':t(),iodata(),[any()]) -> 'ok' | {'error',posix()} is a supertype of the success typing: 'Elixir.File':write(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []),['append' | 'binary' | 'compressed' | 'delayed_write' | 'exclusive' | 'raw' | 'read' | 'read_ahead' | 'sync' | 'write' | {'encoding','latin1' | 'unicode' | 'utf16' | 'utf32' | 'utf8' | {'utf16','big' | 'little'} | {'utf32','big' | 'little'}} | {'read_ahead',pos_integer()} | {'delayed_write',non_neg_integer(),non_neg_integer()}]) -> 'ok' | {'error',atom()}

The following warning occurs because the default specs do not include binary arguments. This can be solved by manually adding the spec to ArgumentError and RuntimeError:

lib/access.ex:56: The call 'Elixir.ArgumentError':exception(<<_:8,_:_*1>>) breaks the contract ('Elixir.Keyword':t()) -> 'Elixir.Exception':t()

The following warning (or similar) occurs because a function that does not just return a singular atom does not have its return value matched on. Most of these case occurs because a function can return :ok or {:error, reason} and it has not been ensured that the return value is :ok. It is likely most of these are bugs as the assumption has been made that they return :ok. If it is safe not to match the return value an explicit _ = can be used to show the return value is ignored.

lib/ex_unit.ex:135: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched

The following warning (or similar) occurs because dialyzer is smarter than elixir's compile in inferring types. These are probably not be bugs when the variable starts with _@.

lib/eex/compiler.ex:50: The call _@3:'quoted'() requires that _@3 is of type atom() | tuple() not #{}

The following warning (or similar) might be a bug but usually the function is only called from a macro. In future elixir's compiler could remove these:

lib/ex_unit/doc_test.ex:370: Function adjust_indent/1 will never be called

The following warning occurs when a function always raises and it is not spec-ed to no_return():

lib/kernel/parallel_compiler.ex:80: The created fun only terminates with explicit exception

A similar message, which might be a bug in code or specs because dialyzer believes, due to the specs, the function must raise (though it may just call a function that explicitly raises). These all need to be checked.

lib/access.ex:135: Function get_and_update/3 has no local return

There are many unknown functions, these are unimplemented protocol callbacks or :cover because I missed it from the plt.

There is one unknown type, 'Elixir.Range':t/0, which can be resolved by defining it. It is likely this, and perhaps others, were not explicitly re-added when the default struct type declaration was removed.

Here's the full list of warnings, there maybe some warnings not mentioned above that need addressing:

lib/access.ex:135: Function get_and_update/3 has no local return
lib/access.ex:144: Function undefined/1 only terminates with explicit exception
lib/application.ex:204: Type specification 'Elixir.Application':ensure_all_started(app(),start_type()) -> {'ok',[app()]} | {'error',term()} is a supertype of the success typing: 'Elixir.Application':ensure_all_started(atom(),'permanent' | 'temporary' | 'transient') -> {'error',{atom(),_}} | {'ok',[atom()]}
lib/dict.ex:690: Function unsupported_dict/1 only terminates with explicit exception
lib/eex/compiler.ex:49: The call _@2:'file'() requires that _@2 is of type atom() | tuple() not #{}
lib/eex/compiler.ex:49: The call _@1:'start_line'() requires that _@1 is of type atom() | tuple() not #{}
lib/eex/compiler.ex:50: The call _@3:'quoted'() requires that _@3 is of type atom() | tuple() not #{}
lib/ex_unit.ex:135: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/ex_unit.ex:136: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/ex_unit/assertions.ex:339: Guard test is_binary(_@4::atom() | tuple() | #{}) can never succeed
lib/ex_unit/cli_formatter.ex:41: The call _@3:'tests_counter'() requires that _@3 is of type atom() | tuple() not #{}
lib/ex_unit/cli_formatter.ex:56: The call _@3:'tests_counter'() requires that _@3 is of type atom() | tuple() not #{}
lib/ex_unit/cli_formatter.ex:57: The call _@4:'invalids_counter'() requires that _@4 is of type atom() | tuple() not #{}
lib/ex_unit/cli_formatter.ex:145: The call _@7:'seed'() requires that _@7 is of type atom() | tuple() not #{}
lib/ex_unit/doc_test.ex:365: Function extract_tests/2 has no local return
lib/ex_unit/doc_test.ex:366: The call 'Elixir.String':split(doc@1::any(),#{},[{'trim','false'},...]) does not have a term of type binary() | [binary()] | 'Elixir.Regex':t() (with opaque subterms) as 2nd argument
lib/ex_unit/formatter.ex:130: The call _@1:'message'() requires that _@1 is of type atom() | tuple() not #{}
lib/ex_unit/formatter.ex:131: The call _@2:'expr'() requires that _@2 is of type atom() | tuple() not #{}
lib/ex_unit/formatter.ex:132: The call _@3:'left'() requires that _@3 is of type atom() | tuple() not #{}
lib/ex_unit/formatter.ex:133: The call _@4:'right'() requires that _@4 is of type atom() | tuple() not #{}
lib/ex_unit/runner.ex:27: The call _@1:'manager'() requires that _@1 is of type atom() | tuple() not #{}
lib/ex_unit/runner.ex:32: The call _@1:'manager'() requires that _@1 is of type atom() | tuple() not #{}
lib/ex_unit/runner.ex:33: The call _@2:'manager'() requires that _@2 is of type atom() | tuple() not #{}
lib/ex_unit/runner.ex:122: The call _@4:'manager'() requires that _@4 is of type atom() | tuple() not #{}
lib/ex_unit/runner.ex:128: The call _@1:'include'() requires that _@1 is of type atom() | tuple() not #{}
lib/ex_unit/runner.ex:129: The call _@2:'exclude'() requires that _@2 is of type atom() | tuple() not #{}
lib/ex_unit/runner.ex:131: The created fun has no local return
lib/ex_unit/runner.ex:144: The created fun only terminates with explicit exception
lib/ex_unit/runner.ex:195: The created fun only terminates with explicit exception
lib/ex_unit/runner.ex:258: Expression produces a value of type 'undefined' | {integer(),integer(),integer()}, but this value is unmatched
lib/exception.ex:69: Overloaded contract for 'Elixir.Exception':normalize/3 has overlapping domains; such contracts are currently unsupported and are simply ignored
lib/file.ex:312: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/file.ex:540: The call _@1:'mode'() requires that _@1 is of type atom() | tuple() not #{}
lib/file.ex:551: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/file.ex:572: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/file.ex:609: Type specification 'Elixir.File':write('Elixir.Path':t(),iodata(),[any()]) -> 'ok' | {'error',posix()} is a supertype of the success typing: 'Elixir.File':write(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []),['append' | 'binary' | 'compressed' | 'delayed_write' | 'exclusive' | 'raw' | 'read' | 'read_ahead' | 'sync' | 'write' | {'encoding','latin1' | 'unicode' | 'utf16' | 'utf32' | 'utf8' | {'utf16','big' | 'little'} | {'utf32','big' | 'little'}} | {'read_ahead',pos_integer()} | {'delayed_write',non_neg_integer(),non_neg_integer()}]) -> 'ok' | {'error',atom()}
lib/file.ex:617: Type specification 'Elixir.File':'write!'('Elixir.Path':t(),iodata(),[any()]) -> 'ok' | no_return() is a supertype of the success typing: 'Elixir.File':'write!'(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []),['append' | 'binary' | 'compressed' | 'delayed_write' | 'exclusive' | 'raw' | 'read' | 'read_ahead' | 'sync' | 'write' | {'encoding','latin1' | 'unicode' | 'utf16' | 'utf32' | 'utf8' | {'utf16','big' | 'little'} | {'utf32','big' | 'little'}} | {'read_ahead',pos_integer()} | {'delayed_write',non_neg_integer(),non_neg_integer()}]) -> 'ok'
lib/file.ex:668: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/file.ex:1115: Type specification 'Elixir.File':chmod('Elixir.Path':t(),integer()) -> 'ok' | {'error',posix()} is a supertype of the success typing: 'Elixir.File':chmod(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),non_neg_integer()) -> 'ok' | {'error',atom()}
lib/file.ex:1123: Type specification 'Elixir.File':'chmod!'('Elixir.Path':t(),integer()) -> 'ok' | no_return() is a supertype of the success typing: 'Elixir.File':'chmod!'(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),non_neg_integer()) -> 'ok'
lib/file.ex:1138: Type specification 'Elixir.File':chgrp('Elixir.Path':t(),integer()) -> 'ok' | {'error',posix()} is a supertype of the success typing: 'Elixir.File':chgrp(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),non_neg_integer()) -> 'ok' | {'error',atom()}
lib/file.ex:1146: Type specification 'Elixir.File':'chgrp!'('Elixir.Path':t(),integer()) -> 'ok' | no_return() is a supertype of the success typing: 'Elixir.File':'chgrp!'(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),non_neg_integer()) -> 'ok'
lib/file.ex:1161: Type specification 'Elixir.File':chown('Elixir.Path':t(),integer()) -> 'ok' | {'error',posix()} is a supertype of the success typing: 'Elixir.File':chown(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),non_neg_integer()) -> 'ok' | {'error',atom()}
lib/file.ex:1169: Type specification 'Elixir.File':'chown!'('Elixir.Path':t(),integer()) -> 'ok' | no_return() is a supertype of the success typing: 'Elixir.File':'chown!'(binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | char(),binary() | []),non_neg_integer()) -> 'ok'
lib/file/stream.ex:60: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/float.ex:168: Type specification 'Elixir.Float':round(float(),integer()) -> float() is a supertype of the success typing: 'Elixir.Float':round(float(),byte()) -> float()
lib/gen_event.ex:355: Type specification 'Elixir.GenEvent':notify(manager(),term()) -> 'ok' is a supertype of the success typing: 'Elixir.GenEvent':notify(atom() | pid() | {atom(),atom()} | {'via',atom(),_},_) -> 'ok'
lib/gen_event.ex:366: Type specification 'Elixir.GenEvent':sync_notify(manager(),term()) -> 'ok' is a supertype of the success typing: 'Elixir.GenEvent':sync_notify(atom() | pid() | {atom(),atom()} | {'via',atom(),_},_) -> 'ok'
lib/gen_event.ex:380: Type specification 'Elixir.GenEvent':call(manager(),handler(),term(),timeout()) -> term() | {'error',term()} is a supertype of the success typing: 'Elixir.GenEvent':call(atom() | pid() | {atom(),atom()} | {'via',atom(),_},atom() | {atom(),_},_,'infinity' | non_neg_integer()) -> any()
lib/gen_event.ex:400: Expression produces a value of type [any()], but this value is unmatched
lib/gen_event.ex:415: Type specification 'Elixir.GenEvent':remove_handler(manager(),handler(),term()) -> term() | {'error',term()} is a supertype of the success typing: 'Elixir.GenEvent':remove_handler(atom() | pid() | {atom(),atom()} | {'via',atom(),_},atom() | {atom(),_},_) -> any()
lib/gen_event.ex:452: Type specification 'Elixir.GenEvent':which_handlers(manager()) -> [handler()] is a supertype of the success typing: 'Elixir.GenEvent':which_handlers(atom() | pid() | {atom(),atom()} | {'via',atom(),_}) -> [atom() | {atom(),_}]
lib/gen_event.ex:461: Type specification 'Elixir.GenEvent':stop(manager()) -> 'ok' is a supertype of the success typing: 'Elixir.GenEvent':stop(atom() | pid() | {atom(),atom()} | {'via',atom(),_}) -> 'ok'
lib/gen_event.ex:574: The created fun has no local return
lib/gen_event.ex:626: Function exit_handler/3 only terminates with explicit exception
lib/hash_dict.ex:46: The created fun only terminates with explicit exception
lib/iex.ex:454: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/iex.ex:455: Expression produces a value of type [any()], but this value is unmatched
lib/iex.ex:467: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/iex.ex:468: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/iex.ex:482: Expression produces a value of type 'nil' | {'module',_}, but this value is unmatched
lib/iex/autocomplete.ex:209: Clause guard cannot succeed. The variable _@3 was matched against the type binary()
lib/iex/cli.ex:129: The created fun has no local return
lib/iex/introspection.ex:189: Expression produces a value of type 'ok' | [], but this value is unmatched
lib/iex/server.ex:80: Invalid type specification for function 'Elixir.IEx.Server':start/2. The success typing is (_,{atom(),atom(),[any()]}) -> any()
lib/inspect.ex:301: The call _@3:'limit'() requires that _@3 is of type atom() | tuple() not #{}
lib/inspect.ex:303: The call _@4:'limit'() requires that _@4 is of type atom() | tuple() not #{}
lib/inspect.ex:456: Guard test is_map(_@2::atom()) can never succeed
lib/inspect/algebra.ex:176: The call _@1:'structs'() requires that _@1 is of type atom() | tuple() not #{}
lib/inspect/algebra.ex:184: The call _@5:'width'() requires that _@5 is of type atom() | tuple() not #{}
lib/inspect/algebra.ex:277: Type specification 'Elixir.Inspect.Algebra':break() -> doc_break() is a supertype of the success typing: 'Elixir.Inspect.Algebra':break() -> {'doc_break',<<_:8>>}
lib/inspect/algebra.ex:386: The specification for 'Elixir.Inspect.Algebra':surround/3 states that the function might also return 'doc_line' | 'doc_nil' | binary() | {'doc_break',binary()} | {'doc_cons','doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_},'doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_}} | {'doc_nest','doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_},non_neg_integer()} but the inferred return is {'doc_group','doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_}}
lib/inspect/algebra.ex:411: The specification for 'Elixir.Inspect.Algebra':surround_many/6 states that the function might also return 'doc_line' | 'doc_nil' | binary() | {'doc_break',binary()} | {'doc_nest','doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_},non_neg_integer()} but the inferred return is {'doc_group','doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_}} | {'doc_cons','doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_},'doc_line' | 'doc_nil' | binary() | {_,_} | {_,_,_}}
lib/integer.ex:102: Type specification 'Elixir.Integer':to_string(integer(),pos_integer()) -> 'Elixir.String':t() is a supertype of the success typing: 'Elixir.Integer':to_string(integer(),1..255) -> binary()
lib/integer.ex:135: Type specification 'Elixir.Integer':to_char_list(integer(),pos_integer()) -> elixir:char_list() is a supertype of the success typing: 'Elixir.Integer':to_char_list(integer(),1..255) -> string()
lib/io.ex:185: Overloaded contract for 'Elixir.IO':getn/2 has overlapping domains; such contracts are currently unsupported and are simply ignored
lib/io/ansi/docs.ex:189: Function write_text/4 has no local return
lib/io/ansi/docs.ex:194: The call 'Elixir.String':split(binary(),#{}) does not have a term of type binary() | [binary()] | 'Elixir.Regex':t() (with opaque subterms) as 2nd argument
lib/kernel.ex:647: Type specification 'Elixir.Kernel':spawn_monitor(module(),atom(),[any()]) -> {pid(),reference()} is a supertype of the success typing: 'Elixir.Kernel':spawn_monitor(atom(),atom(),[any()]) -> {pid(),reference()}
lib/kernel.ex:1395: The call _@1:'pretty'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:1396: The call _@2:'width'() requires that _@2 is of type atom() | tuple() not #{}
lib/kernel.ex:1939: The pattern 'false' can never match the type 'true'
lib/kernel.ex:1942: The call _@1:'function'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:1952: The pattern 'false' can never match the type 'true'
lib/kernel.ex:1983: The call _@1:'module'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:1987: The pattern [] can never match the type [{_,_,_,[{_,_},...]},...]
lib/kernel.ex:2030: The call _@1:'vars'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:2049: The call _@1:'vars'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:2053: The call _@1:'vars'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:2075: The call _@1:'vars'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:2362: Type specification 'Elixir.Kernel':'function_exported?'(atom() | tuple(),atom(),integer()) -> boolean() is a supertype of the success typing: 'Elixir.Kernel':'function_exported?'(atom() | tuple(),atom(),byte()) -> boolean()
lib/kernel.ex:2433: The call _@1:'context'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:2437: The pattern 'false' can never match the type 'true'
lib/kernel.ex:2602: The pattern 'false' can never match the type 'true'
lib/kernel.ex:2612: The call _@1:'module'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:2621: The call _@2:'vars'() requires that _@2 is of type atom() | tuple() not #{}
lib/kernel.ex:3200: The call _@1:'module'() requires that _@1 is of type atom() | tuple() not #{}
lib/kernel.ex:3580: The pattern 'false' can never match the type 'true'
lib/kernel/cli.ex:36: Function run/1 has no local return
lib/kernel/cli.ex:36: The call 'Elixir.Kernel.CLI':run(x0@1::any(),'true') will never return since it differs in the 2nd argument from the success typing arguments: (fun((_) -> any()),'false' | 'nil')
lib/kernel/cli.ex:366: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/kernel/error_handler.ex:7: Expression produces a value of type 'ok' | [], but this value is unmatched
lib/kernel/error_handler.ex:12: Expression produces a value of type 'ok' | [], but this value is unmatched
lib/kernel/parallel_compiler.ex:46: Expression produces a value of type {'error','badfile' | 'embedded' | 'native_code' | 'nofile' | 'on_load'} | {'module',atom() | tuple()}, but this value is unmatched
lib/kernel/parallel_compiler.ex:80: The created fun only terminates with explicit exception
lib/kernel/parallel_compiler.ex:90: Expression produces a value of type [any()], but this value is unmatched
lib/kernel/parallel_require.ex:38: The created fun only terminates with explicit exception
lib/kernel/typespec.ex:423: Type specification 'Elixir.Kernel.Typespec':beam_types(module() | binary()) -> [tuple()] | 'nil' is a supertype of the success typing: 'Elixir.Kernel.Typespec':beam_types(atom() | binary()) -> 'nil' | [{'opaque',{_,_,_}} | {'type',{_,_,_}} | {'typep',{_,_,_}}]
lib/kernel/typespec.ex:802: The created fun has no local return
lib/kernel/typespec.ex:980: Function compile_error/2 only terminates with explicit exception
lib/keyword.ex:50: Type specification 'Elixir.Keyword':new() -> t() is a supertype of the success typing: 'Elixir.Keyword':new() -> []
lib/keyword.ex:295: Type specification 'Elixir.Keyword':put(t(),key(),value()) -> t() is a supertype of the success typing: 'Elixir.Keyword':put([{atom(),_}],atom(),_) -> [{atom(),_},...]
lib/list.ex:250: Type specification 'Elixir.List':keystore([tuple()],any(),non_neg_integer(),tuple()) -> [tuple()] is a supertype of the success typing: 'Elixir.List':keystore([tuple()],_,non_neg_integer(),tuple()) -> [tuple(),...]
lib/list.ex:535: Type specification 'Elixir.List':to_integer(elixir:char_list(),non_neg_integer()) -> integer() is a supertype of the success typing: 'Elixir.List':to_integer(string(),1..255) -> integer()
lib/macro.ex:30: Type specification 'Elixir.Macro':binary_op_props(atom()) -> {'left' | 'right',precedence::integer()} is a supertype of the success typing: 'Elixir.Macro':binary_op_props(atom()) -> {'left',40 | 130 | 140 | 150 | 160 | 170 | 180 | 210 | 220 | 250 | 310} | {'right',50 | 60 | 70 | 90 | 200}
lib/macro/env.ex:108: The call _@1:'module'() requires that _@1 is of type atom() | tuple() not #{}
lib/macro/env.ex:110: The call _@2:'function'() requires that _@2 is of type atom() | tuple() not #{}
lib/macro/env.ex:111: The call _@3:'module'() requires that _@3 is of type atom() | tuple() not #{}
lib/macro/env.ex:113: The call _@4:'function'() requires that _@4 is of type atom() | tuple() not #{}
lib/macro/env.ex:114: The call _@5:'module'() requires that _@5 is of type atom() | tuple() not #{}
lib/mix.ex:18: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/mix.ex:81: Function raise/1 only terminates with explicit exception
lib/mix.ex:92: Function raise/2 only terminates with explicit exception
lib/mix.ex:93: Guard test is_atom(_@2::#{}) can never succeed
lib/mix.ex:93: Guard test is_binary(_@1::#{}) can never succeed
lib/mix/cli.ex:32: Expression produces a value of type 'nil' | [any()], but this value is unmatched
lib/mix/cli.ex:65: Clause guard cannot succeed. The variable _@3 was matched against the type 'nil'
lib/mix/cli.ex:79: The call _@11:'__struct__'() requires that _@11 is of type atom() | tuple() not #{}
lib/mix/cli.ex:82: Guard test is_atom(_@8::#{}) can never succeed
lib/mix/cli.ex:82: Guard test is_binary(_@7::#{}) can never succeed
lib/mix/compilers/elixir.ex:33: The created fun has no local return
lib/mix/compilers/elixir.ex:83: Expression produces a value of type [any()], but this value is unmatched
lib/mix/compilers/elixir.ex:110: Clause guard cannot succeed. The variable _@4 was matched against the type binary()
lib/mix/compilers/elixir.ex:143: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/mix/compilers/erlang.ex:80: Fun application will fail since _callback@1 :: none() is not a function of arity 2
lib/mix/compilers/erlang.ex:112: The created fun has no local return
lib/mix/config.ex:138: Guard test is_atom(_@5::#{}) can never succeed
lib/mix/config.ex:138: Guard test is_binary(_@4::#{}) can never succeed
lib/mix/dep.ex:190: The call _@1:'from'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/dep/converger.ex:160: The call _@2:'deps'() requires that _@2 is of type atom() | tuple() not #{}
lib/mix/dep/converger.ex:165: The call _@5:'deps'() requires that _@5 is of type atom() | tuple() not #{}
lib/mix/dep/converger.ex:165: The call _@4:'deps'() requires that _@4 is of type atom() | tuple() not #{}
lib/mix/dep/converger.ex:218: The call _@1:'status'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/dep/converger.ex:220: The call _@3:'app'() requires that _@3 is of type atom() | tuple() not #{}
lib/mix/dep/converger.ex:220: The call _@2:'requirement'() requires that _@2 is of type atom() | tuple() not #{}
lib/mix/dep/fetcher.ex:30: Expression produces a value of type [any()], but this value is unmatched
lib/mix/dep/fetcher.ex:111: Expression produces a value of type [any()], but this value is unmatched
lib/mix/dep/loader.ex:46: The call _@1:'status'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/dep/loader.ex:129: Expression produces a value of type 'nil' | 'true' | {'error','bad_directory'}, but this value is unmatched
lib/mix/dep/loader.ex:183: Function invalid_dep_format/1 has no local return
lib/mix/dep/loader.ex:214: The call _@3:'app'() requires that _@3 is of type atom() | tuple() not #{}
lib/mix/dep/loader.ex:242: The call _@1:'app'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/dep/umbrella.ex:33: The call _@1:'deps'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/dep/umbrella.ex:34: The call _@2:'app'() requires that _@2 is of type atom() | tuple() not #{}
lib/mix/project.ex:306: Expression produces a value of type 'ok' | {'error','enoent'} | {'ok',[binary()]}, but this value is unmatched
lib/mix/project.ex:309: Expression produces a value of type [binary()], but this value is unmatched
lib/mix/project.ex:315: Expression produces a value of type 'ok' | {'error','enoent'} | {'ok',[binary()]}, but this value is unmatched
lib/mix/project.ex:316: Expression produces a value of type 'ok' | {'error','enoent'} | {'ok',[binary()]}, but this value is unmatched
lib/mix/project.ex:344: Expression produces a value of type 'nil' | [any()], but this value is unmatched
lib/mix/project.ex:350: The pattern 'false' can never match the type 'true'
lib/mix/project_stack.ex:24: The call _@1:'post_config'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/project_stack.ex:32: The call _@3:'stack'() requires that _@3 is of type atom() | tuple() not #{}
lib/mix/scm/git.ex:76: Expression produces a value of type [binary()], but this value is unmatched
lib/mix/scm/git.ex:89: Expression produces a value of type string(), but this value is unmatched
lib/mix/scm/path.ex:45: Function checkout/1 has no local return
lib/mix/tasks/archive.build.ex:47: Clause guard cannot succeed. The variable _@5 was matched against the type 'nil'
lib/mix/tasks/clean.ex:23: Expression produces a value of type [any()], but this value is unmatched
lib/mix/tasks/clean.ex:26: Guard test is_map(_@4::atom() | tuple()) can never succeed
lib/mix/tasks/compile.app.ex:87: Guard test is_map(_@7::'nil') can never succeed
lib/mix/tasks/compile.app.ex:184: Function invalid/1 has no local return
lib/mix/tasks/compile.elixir.ex:60: Expression produces a value of type 'true' | {'error','bad_directory'}, but this value is unmatched
lib/mix/tasks/compile.erlang.ex:130: Expression produces a value of type [any()], but this value is unmatched
lib/mix/tasks/compile.erlang.ex:134: Expression produces a value of type [any()], but this value is unmatched
lib/mix/tasks/compile.erlang.ex:135: Expression produces a value of type [any()], but this value is unmatched
lib/mix/tasks/compile.erlang.ex:136: Expression produces a value of type [any()], but this value is unmatched
lib/mix/tasks/compile.erlang.ex:148: The created fun has no local return
lib/mix/tasks/compile.ex:31: Clause guard cannot succeed. The variable _@3 was matched against the type binary()
lib/mix/tasks/compile.ex:59: Expression produces a value of type 'true' | {'error','bad_directory'}, but this value is unmatched
lib/mix/tasks/compile.ex:79: Guard test is_map(_@2::atom() | tuple()) can never succeed
lib/mix/tasks/compile.protocols.ex:50: Expression produces a value of type [any()], but this value is unmatched
lib/mix/tasks/deps.check.ex:24: Expression produces a value of type 'nil' | [any()], but this value is unmatched
lib/mix/tasks/deps.check.ex:82: Expression produces a value of type boolean() | {'error','bad_name'}, but this value is unmatched
lib/mix/tasks/deps.compile.ex:122: Expression produces a value of type 'ok' | {'error',atom()}, but this value is unmatched
lib/mix/tasks/deps.ex:114: The call _@2:'opts'() requires that _@2 is of type atom() | tuple() not #{}
lib/mix/tasks/escript.build.ex:151: The call _@1:'mode'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/tasks/escript.build.ex:155: Clause guard cannot succeed. The variable _@1 was matched against the type [any()]
lib/mix/tasks/escript.build.ex:177: Guard test is_map(_@2::'nil') can never succeed
lib/mix/tasks/help.ex:64: Clause guard cannot succeed. The variable _@3 was matched against the type binary()
lib/mix/tasks/iex.ex:8: Function run/1 has no local return
lib/mix/tasks/local.hex.ex:42: Expression produces a value of type 'nil' | 'true' | {'error','bad_directory'}, but this value is unmatched
lib/mix/tasks/run.ex:59: Expression produces a value of type 'nil' | [any()], but this value is unmatched
lib/mix/tasks/test.ex:7: Expression produces a value of type {'error',_} | {'ok',pid()}, but this value is unmatched
lib/mix/tasks/test.ex:8: Expression produces a value of type [any()] | {'error',atom() | {'no_translation',binary()}}, but this value is unmatched
lib/mix/tasks/test.ex:158: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/mix/utils.ex:311: Expression produces a value of type [binary()], but this value is unmatched
lib/mix/utils.ex:370: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/mix/utils.ex:371: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
lib/mix/utils.ex:381: Expression produces a value of type 'nil' | 'ok' | {'error',_}, but this value is unmatched
lib/mix/utils.ex:382: Expression produces a value of type 'nil' | 'ok' | {'error',_}, but this value is unmatched
lib/mix/utils.ex:402: The call _@1:'scheme'() requires that _@1 is of type atom() | tuple() not #{}
lib/mix/utils.ex:403: The call _@3:'port'() requires that _@3 is of type atom() | tuple() not #{}
lib/mix/utils.ex:403: The call _@2:'host'() requires that _@2 is of type atom() | tuple() not #{}
lib/mix/utils.ex:418: The call _@1:'scheme'() requires that _@1 is of type atom() | tuple() not #{}
lib/module.ex:346: The call _@1:'module'() requires that _@1 is of type atom() | tuple() not #{}
lib/module.ex:943: Expression produces a value of type {'error','badfile' | 'embedded' | 'native_code' | 'nofile' | 'on_load'} | {'module',atom() | tuple()}, but this value is unmatched
lib/module/locals_tracker.ex:148: Clause guard cannot succeed. The variable _@3 was matched against the type [any()]
lib/module/locals_tracker.ex:280: Expression produces a value of type 'nil' | nonempty_maybe_improper_list(), but this value is unmatched
lib/module/locals_tracker.ex:285: Expression produces a value of type 'nil' | nonempty_maybe_improper_list(), but this value is unmatched
lib/module/locals_tracker.ex:295: The created fun has no local return
lib/module/locals_tracker.ex:295: Expression produces a value of type ['nil' | nonempty_maybe_improper_list()], but this value is unmatched
lib/module/locals_tracker.ex:305: Expression produces a value of type ['nil' | nonempty_maybe_improper_list()], but this value is unmatched
lib/module/locals_tracker.ex:310: Expression produces a value of type ['nil' | nonempty_maybe_improper_list()], but this value is unmatched
lib/module/locals_tracker.ex:339: Expression produces a value of type 'nil' | nonempty_maybe_improper_list(), but this value is unmatched
lib/node.ex:33: Type specification 'Elixir.Node':stop() -> 'ok' | {'error',term()} is a supertype of the success typing: 'Elixir.Node':stop() -> 'ok' | {'error','not_allowed' | 'not_found'}
lib/node.ex:190: Type specification 'Elixir.Node':spawn(t(),module(),atom(),[any()]) -> pid() is a supertype of the success typing: 'Elixir.Node':spawn(atom(),atom(),atom(),[any()]) -> pid()
lib/node.ex:234: Type specification 'Elixir.Node':spawn_link(t(),module(),atom(),[any()]) -> pid() is a supertype of the success typing: 'Elixir.Node':spawn_link(atom(),atom(),atom(),[any()]) -> pid()
lib/process.ex:348: Type specification 'Elixir.Process':flag(pid(),process_flag(),term()) -> term() is a supertype of the success typing: 'Elixir.Process':flag(pid(),'save_calls',non_neg_integer()) -> non_neg_integer()
lib/protocol.ex:60: Type specification 'Elixir.Protocol':'assert_protocol!'(module()) -> 'ok' | no_return() is a supertype of the success typing: 'Elixir.Protocol':'assert_protocol!'(atom()) -> 'ok'
lib/protocol.ex:559: The call _@1:'module'() requires that _@1 is of type atom() | tuple() not #{}
lib/protocol.ex:563: Guard test is_map(_@2::atom()) can never succeed
lib/protocol.ex:586: The call _@1:'line'() requires that _@1 is of type atom() | tuple() not #{}
lib/set.ex:333: Function unsupported_set/1 only terminates with explicit exception
lib/stream.ex:431: Expression produces a value of type {'done',_} | {'halted',_} | {'suspended',_,fun((_) -> any())}, but this value is unmatched
lib/string.ex:234: The call 'Elixir.String':split(binary@1::any(),#{},options@1::any()) does not have a term of type binary() | [binary()] | 'Elixir.Regex':t() (with opaque subterms) as 2nd argument
lib/string.ex:1196: Invalid type specification for function 'Elixir.String':'match?'/2. The success typing is (binary(),#{}) -> boolean()
lib/string.ex:1331: Type specification 'Elixir.String':to_integer('Elixir.String':t(),pos_integer()) -> integer() is a supertype of the success typing: 'Elixir.String':to_integer(binary(),1..255) -> integer()
lib/supervisor.ex:291: Type specification 'Elixir.Supervisor':terminate_child(supervisor(),pid() | 'Elixir.Supervisor.Spec':child_id()) -> 'ok' | {'error',error} when is_subtype(error,'not_found' | 'simple_one_for_one') is a supertype of the success typing: 'Elixir.Supervisor':terminate_child(atom() | pid() | {atom(),atom()} | {'via',atom() | tuple(),_},_) -> 'ok' | {'error','not_found' | 'simple_one_for_one'}
lib/supervisor.ex:307: Type specification 'Elixir.Supervisor':delete_child(supervisor(),'Elixir.Supervisor.Spec':child_id()) -> 'ok' | {'error',error} when is_subtype(error,'not_found' | 'simple_one_for_one' | 'running' | 'restarting') is a supertype of the success typing: 'Elixir.Supervisor':delete_child(atom() | pid() | {atom(),atom()} | {'via',atom() | tuple(),_},_) -> 'ok' | {'error','not_found' | 'restarting' | 'running' | 'simple_one_for_one'}
lib/supervisor.ex:335: Type specification 'Elixir.Supervisor':restart_child(supervisor(),'Elixir.Supervisor.Spec':child_id()) -> {'ok',child()} | {'ok',child(),term()} | {'error',error} when is_subtype(error,'not_found' | 'simple_one_for_one' | 'running' | 'restarting' | term()) is a supertype of the success typing: 'Elixir.Supervisor':restart_child(atom() | pid() | {atom(),atom()} | {'via',atom() | tuple(),_},_) -> {'error',_} | {'ok','undefined' | pid()} | {'ok','undefined' | pid(),_}
lib/supervisor.ex:359: Type specification 'Elixir.Supervisor':which_children(supervisor()) -> [{'Elixir.Supervisor.Spec':child_id() | 'undefined',child() | 'restarting','Elixir.Supervisor.Spec':worker(),'Elixir.Supervisor.Spec':modules()}] is a supertype of the success typing: 'Elixir.Supervisor':which_children(atom() | pid() | {atom(),atom()} | {'via',atom() | tuple(),_}) -> [{_,'restarting' | 'undefined' | pid(),'supervisor' | 'worker','dynamic' | [atom() | tuple()]}]
lib/supervisor.ex:383: Invalid type specification for function 'Elixir.Supervisor':count_children/1. The success typing is (atom() | pid() | {atom(),atom()} | {'via',atom() | tuple(),_}) -> #{}
lib/system.ex:194: The call _@2:'access'() requires that _@2 is of type atom() | tuple() not #{}
lib/system.ex:194: The call _@1:'type'() requires that _@1 is of type atom() | tuple() not #{}
lib/task.ex:169: The call _@1:'pid'() requires that _@1 is of type atom() | tuple() not #{}
lib/task/supervised.ex:81: Function exit/3 only terminates with explicit exception
src/elixir.erl:20: Function start/2 has no local return
src/elixir.erl:31: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
src/elixir.erl:32: The call io:setopts('standard_error',[{'unicode','true'},...]) breaks the contract (IoDevice,Opts) -> 'ok' | {'error',Reason} when is_subtype(IoDevice,device()), is_subtype(Opts,[setopt()]), is_subtype(Reason,term())
src/elixir.erl:54: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
src/elixir.erl:60: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
src/elixir_code_server.erl:31: Expression produces a value of type {'error','badfile' | 'embedded' | 'native_code' | 'nofile' | 'on_load'} | {'module',atom() | tuple()}, but this value is unmatched
src/elixir_code_server.erl:32: Expression produces a value of type {'error','badfile' | 'embedded' | 'native_code' | 'nofile' | 'on_load'} | {'module',atom() | tuple()}, but this value is unmatched
src/elixir_code_server.erl:33: Expression produces a value of type {'error','badfile' | 'embedded' | 'native_code' | 'nofile' | 'on_load'} | {'module',atom() | tuple()}, but this value is unmatched
src/elixir_code_server.erl:123: Expression produces a value of type [{'elixir_code_server',reference(),'loaded'}], but this value is unmatched
src/elixir_compiler.erl:43: Expression produces a value of type [binary() | string()], but this value is unmatched
src/elixir_compiler.erl:147: Expression produces a value of type {'error','badarg' | 'badfile' | 'native_code' | 'nofile' | 'not_purged' | 'on_load' | 'sticky_directory'} | {'module',atom() | tuple()}, but this value is unmatched
src/elixir_compiler.erl:160: Expression produces a value of type 'ok' | {'error',_}, but this value is unmatched
src/elixir_compiler.erl:167: Expression produces a value of type [binary() | string()], but this value is unmatched
src/elixir_def.erl:86: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_def.erl:92: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_def.erl:106: Expression produces a value of type 'ok' | {'struct_available',atom() | ets:tid()}, but this value is unmatched
src/elixir_def.erl:175: Expression produces a value of type 'ok' | [any()], but this value is unmatched
src/elixir_def.erl:234: Expression produces a value of type 'ok' | [], but this value is unmatched
src/elixir_dispatch.erl:40: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_dispatch.erl:44: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_dispatch.erl:57: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_dispatch.erl:67: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_dispatch.erl:142: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_dispatch.erl:150: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_dispatch.erl:159: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_exp.erl:455: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_lexical.erl:19: Expression produces a value of type ['ok' | []], but this value is unmatched
src/elixir_lexical.erl:20: Expression produces a value of type ['ok' | []], but this value is unmatched
src/elixir_locals.erl:149: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_locals.erl:163: Expression produces a value of type ['ok' | []], but this value is unmatched
src/elixir_module.erl:49: Expression produces a value of type 'ok' | [], but this value is unmatched
src/elixir_module.erl:55: Expression produces a value of type 'ok' | [boolean() | [any()]], but this value is unmatched
src/elixir_module.erl:82: Expression produces a value of type boolean() | [any()], but this value is unmatched
src/elixir_module.erl:104: Expression produces a value of type atom() | ets:tid(), but this value is unmatched
src/elixir_module.erl:129: Expression produces a value of type ['ok' | 'true'], but this value is unmatched
src/elixir_module.erl:132: Expression produces a value of type ['ok' | 'true'], but this value is unmatched
src/elixir_module.erl:308: Expression produces a value of type 'ok' | [], but this value is unmatched
src/elixir_parser.erl:2267: Function yeccpars2_81/7 has no local return
src/elixir_parser.erl:3317: Function yeccpars2_234/7 has no local return
src/elixir_parser.erl:4587: Function yeccpars2_344/7 has no local return
src/elixir_parser.erl:4619: Function yeccpars2_350/7 has no local return
src/elixir_parser.erl:4624: Function yeccpars2_351/7 has no local return
src/elixir_parser.yrl:399: Function yeccpars2_234_/1 has no local return
src/elixir_parser.yrl:416: Function yeccpars2_344_/1 has no local return
src/elixir_parser.yrl:417: Function yeccpars2_350_/1 has no local return
src/elixir_parser.yrl:418: Function yeccpars2_351_/1 has no local return
src/elixir_parser.yrl:429: Function yeccpars2_356_/1 has no local return
src/elixir_parser.yrl:429: Function yeccpars2_81_/1 has no local return
src/elixir_parser.yrl:722: Function throw/3 only terminates with explicit exception
src/elixir_parser.yrl:725: Function throw_no_parens_strict/1 has no local return
src/elixir_parser.yrl:730: Function throw_no_parens_many_strict/1 has no local return
src/elixir_quote.erl:117: Function argument_error/1 only terminates with explicit exception
Unknown functions:
  'Elixir.Access.BitString':'__impl__'/1
  'Elixir.Access.Float':'__impl__'/1
  'Elixir.Access.Function':'__impl__'/1
  'Elixir.Access.Integer':'__impl__'/1
  'Elixir.Access.PID':'__impl__'/1
  'Elixir.Access.Port':'__impl__'/1
  'Elixir.Access.Reference':'__impl__'/1
  'Elixir.Access.Tuple':'__impl__'/1
  'Elixir.Collectable.Atom':'__impl__'/1
  'Elixir.Collectable.Float':'__impl__'/1
  'Elixir.Collectable.Integer':'__impl__'/1
  'Elixir.Collectable.PID':'__impl__'/1
  'Elixir.Collectable.Port':'__impl__'/1
  'Elixir.Collectable.Reference':'__impl__'/1
  'Elixir.Collectable.Tuple':'__impl__'/1
  'Elixir.Enumerable.Atom':'__impl__'/1
  'Elixir.Enumerable.BitString':'__impl__'/1
  'Elixir.Enumerable.Float':'__impl__'/1
  'Elixir.Enumerable.Integer':'__impl__'/1
  'Elixir.Enumerable.PID':'__impl__'/1
  'Elixir.Enumerable.Port':'__impl__'/1
  'Elixir.Enumerable.Reference':'__impl__'/1
  'Elixir.Enumerable.Tuple':'__impl__'/1
  'Elixir.Hex':start/0
  'Elixir.Hex':version/0
  'Elixir.List.Chars.Function':'__impl__'/1
  'Elixir.List.Chars.Map':'__impl__'/1
  'Elixir.List.Chars.PID':'__impl__'/1
  'Elixir.List.Chars.Port':'__impl__'/1
  'Elixir.List.Chars.Reference':'__impl__'/1
  'Elixir.List.Chars.Tuple':'__impl__'/1
  'Elixir.Range.Iterator.Atom':'__impl__'/1
  'Elixir.Range.Iterator.BitString':'__impl__'/1
  'Elixir.Range.Iterator.Float':'__impl__'/1
  'Elixir.Range.Iterator.Function':'__impl__'/1
  'Elixir.Range.Iterator.List':'__impl__'/1
  'Elixir.Range.Iterator.Map':'__impl__'/1
  'Elixir.Range.Iterator.PID':'__impl__'/1
  'Elixir.Range.Iterator.Port':'__impl__'/1
  'Elixir.Range.Iterator.Reference':'__impl__'/1
  'Elixir.Range.Iterator.Tuple':'__impl__'/1
  'Elixir.String.Chars.Function':'__impl__'/1
  'Elixir.String.Chars.Map':'__impl__'/1
  'Elixir.String.Chars.PID':'__impl__'/1
  'Elixir.String.Chars.Port':'__impl__'/1
  'Elixir.String.Chars.Reference':'__impl__'/1
  'Elixir.String.Chars.Tuple':'__impl__'/1

Updated: 3rd July 2014

josevalim commented 10 years ago

I have fixed the ArgumentError, RuntimeError and the missing Range.t type. I will add cover to PLT and fix the underspecified module type specs. Although I think we should remove the warning that explicitly requires _ = to be used. It is too much work just to appease the dialyzer god.

I will post more updates here.

fishcakez commented 10 years ago

I can find some time tomorrow to fix some of these, let me know what you resolve.

josevalim commented 10 years ago

Ok, let me be specific then. I will solve:

fishcakez commented 10 years ago

I will do:

josevalim commented 10 years ago

@fishcakez isn't this a dialyzer bug:

lib/behaviour.ex:108: The call _@1:'line'() requires that _@1 is of type atom() | tuple() not #{}

In the generated code, that clause will never be a map because we always match on maps before. It feels like they should take it into account?

fishcakez commented 10 years ago

I think that one is not a bug because the erlang code generated is roughly equivalent to:

% It is casing on a map not a variable so dialyzer see this is a bug, which really it is if it were erlang.
case #{line => 108} of
    Map when is_map(Map) ->
        'Elixir.Map':'fetch!'(Map, line);
    Other ->
         Other:line()
end
josevalim commented 10 years ago

I am 90% confident the warnings are actually on variables. The cases it would be a literal would be on __CALLER__ but we inline those.

fishcakez commented 10 years ago

You picked an example where it was hard to tell from the elixir code, looking at others though dialyzer isn't inferring the case patterns can't match because we aren't getting warnings that "pattern can never match" on these case clauses. This is a bug for sure. I am unsure if I used 17.0 or 17.1, so will need to check it is present in 17.1.

josevalim commented 10 years ago

I have pushed commits that:

I will update the description as soon as the results come out.

josevalim commented 10 years ago

Closing this. The majority of remaining warnings can only be fixed if Elixir has a better idea of types in the system and this is something we will tackle on after 1.0. Thanks for all the contributions @fishcakez!