call_without_opaque.ex (2294B)
1 defmodule Dialyxir.Warnings.CallWithoutOpaque do 2 @moduledoc """ 3 Function call without opaqueness type mismatch. 4 5 ## Example 6 7 defmodule OpaqueStruct do 8 defstruct [:opaque] 9 10 @opaque t :: %OpaqueStruct{} 11 end 12 13 defmodule Example do 14 @spec error(OpaqueStruct.t()) :: :error 15 def error(struct = %OpaqueStruct{}) do 16 do_error(struct) 17 end 18 19 @spec do_error(OpaqueStruct.t()) :: :error 20 defp do_error(_) do 21 :error 22 end 23 end 24 """ 25 26 @behaviour Dialyxir.Warning 27 28 @impl Dialyxir.Warning 29 @spec warning() :: :call_without_opaque 30 def warning(), do: :call_without_opaque 31 32 @impl Dialyxir.Warning 33 @spec format_short([String.t()]) :: String.t() 34 def format_short([_module, function | _]) do 35 "Type mismatch in call without opaque term in #{function}." 36 end 37 38 @impl Dialyxir.Warning 39 @spec format_long([String.t()]) :: String.t() 40 def format_long([module, function, args, expected_triples]) do 41 expected = form_expected_without_opaque(expected_triples) 42 pretty_module = Erlex.pretty_print(module) 43 pretty_args = Erlex.pretty_print_args(args) 44 45 """ 46 Function call without opaqueness type mismatch. 47 48 Call does not have expected #{expected}. 49 50 #{pretty_module}.#{function}#{pretty_args} 51 """ 52 end 53 54 # We know which positions N are to blame; 55 # the list of triples will never be empty. 56 defp form_expected_without_opaque([{position, type, type_string}]) do 57 pretty_type = Erlex.pretty_print_type(type_string) 58 form_position_string = Dialyxir.WarningHelpers.form_position_string([position]) 59 60 if :erl_types.t_is_opaque(type) do 61 "opaque term of type #{pretty_type} in the #{form_position_string} position" 62 else 63 "term of type #{pretty_type} (with opaque subterms) in the #{form_position_string} position" 64 end 65 end 66 67 # TODO: can do much better here 68 defp form_expected_without_opaque(expected_triples) do 69 {arg_positions, _typess, _type_strings} = :lists.unzip3(expected_triples) 70 form_position_string = Dialyxir.WarningHelpers.form_position_string(arg_positions) 71 "opaque terms in the #{form_position_string} position" 72 end 73 74 @impl Dialyxir.Warning 75 @spec explain() :: String.t() 76 def explain() do 77 @moduledoc 78 end 79 end