• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qqwy / elixir-type_check / 74337a046368146f28144b038a3d755209071c95

21 Oct 2024 03:12PM UTC coverage: 86.138% (+1.1%) from 85.004%
74337a046368146f28144b038a3d755209071c95

push

github

web-flow
Merge pull request #192 from skwerlman/patch-2

fix compilation on elixir 1.17.x

1162 of 1349 relevant lines covered (86.14%)

99710.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/lib/type_check/builtin/function.ex
1
defmodule TypeCheck.Builtin.Function do
2
  defstruct param_types: nil, return_type: %TypeCheck.Builtin.Any{}
3

4
  use TypeCheck
5

6
  @opaque! t :: %TypeCheck.Builtin.Function{
7✔
7
             param_types: list(TypeCheck.Type.t()) | nil,
8
             return_type: TypeCheck.Type.t()
9
           }
10
  @type! problem_tuple :: {t(), :no_match, %{}, any()}
7✔
11

12
  defimpl TypeCheck.Protocols.Escape do
13
    def escape(s) do
14
      s
15
      |> Map.update!(:param_types, fn
16
        nil -> nil
17
        list when is_list(list) -> Enum.map(list, &TypeCheck.Protocols.Escape.escape(&1))
×
18
      end)
19
      |> Map.update!(:return_type, &TypeCheck.Protocols.Escape.escape(&1))
×
20
    end
21
  end
22

23
  defimpl TypeCheck.Protocols.ToCheck do
24
    def to_check(s, param) do
25
      quote generated: true, location: :keep do
26
        p = unquote(param)
27

28
        case p do
29
          unquote(is_function_check(s)) ->
30
            wrapped_fun = unquote(@for.contravariant_wrapper(s, param))
31
            {:ok, [], wrapped_fun}
32

33
          _ ->
34
            {:error, {unquote(Macro.escape(s)), :no_match, %{}, unquote(param)}}
35
        end
36
      end
37
    end
38

39
    defp is_function_check(s) do
40
      case s.param_types do
49✔
41
        nil ->
42
          quote generated: true, location: :keep do
43
            x when is_function(x)
44
          end
45

46
        list ->
47
          quote generated: true, location: :keep do
48
            x when is_function(x, unquote(length(list)))
49
          end
50
      end
51
    end
52
  end
53

54
  def contravariant_wrapper(s, original) do
55
    case s do
49✔
56
      %{param_types: nil, return_type: %TypeCheck.Builtin.Any{}} ->
57
        original
28✔
58

59
      %{param_types: [], return_type: %TypeCheck.Builtin.Any{}} ->
60
        original
×
61

62
      %{param_types: nil, return_type: return_type} ->
63
        quote generated: true,
64
              location: :keep,
65
              bind_quoted: [
66
                fun: original,
67
                s: Macro.escape(s),
68
                return_type: Macro.escape(return_type)
69
              ] do
70
          {:arity, arity} = Function.info(fun, :arity)
71
          clean_params = Macro.generate_arguments(arity, __MODULE__)
72

73
          return_code_check =
74
            TypeCheck.Protocols.ToCheck.to_check(return_type, Macro.var(:result, nil))
75

76
          wrapper_ast =
77
            quote do
78
              fn unquote_splicing(clean_params) ->
79
                var!(result, nil) = var!(fun).(unquote_splicing(clean_params))
80

81
                case unquote(return_code_check) do
82
                  {:ok, _bindings, altered_return_value} ->
83
                    altered_return_value
84

85
                  {:error, problem} ->
86
                    raise TypeCheck.TypeError,
87
                          {unquote(Macro.escape(s)), :return_error,
88
                           %{problem: problem, arguments: unquote(clean_params)},
89
                           var!(result, nil)}
90
                end
91
              end
92
            end
93

94
          {fun, _} = Code.eval_quoted(wrapper_ast, [fun: fun], __ENV__)
95

96
          fun
97
        end
98

99
      %{param_types: [], return_type: return_type} ->
100
        return_code_check =
×
101
          TypeCheck.Protocols.ToCheck.to_check(return_type, Macro.var(:result, nil))
102

103
        quote generated: true, location: :keep do
104
          fn ->
105
            var!(result, nil) = unquote(original).()
106

107
            case unquote(return_code_check) do
108
              {:ok, _bindings, altered_return_value} ->
109
                altered_return_value
110

111
              {:error, problem} ->
112
                raise TypeCheck.TypeError,
113
                      {unquote(Macro.escape(s)), :return_error,
114
                       %{problem: problem, arguments: []}, var!(result, nil)}
115
            end
116
          end
117
        end
118

119
      %{param_types: param_types, return_type: return_type} ->
120
        clean_params = Macro.generate_arguments(length(param_types), __MODULE__)
21✔
121

122
        param_checks =
21✔
123
          param_types
124
          |> Enum.zip(clean_params)
125
          |> Enum.with_index()
126
          |> Enum.flat_map(fn {{param_type, clean_param}, index} ->
127
            param_check_code(param_type, clean_param, index)
42✔
128
          end)
129

130
        return_code_check =
21✔
131
          TypeCheck.Protocols.ToCheck.to_check(return_type, Macro.var(:result, nil))
132

133
        quote do
134
          fn unquote_splicing(clean_params) ->
135
            with unquote_splicing(param_checks) do
136
              var!(result, nil) = unquote(original).(unquote_splicing(clean_params))
137
              # TypeCheck.conforms!(result, unquote(type))
138
              case unquote(return_code_check) do
139
                {:ok, _bindings, altered_return_value} ->
140
                  altered_return_value
141

142
                {:error, problem} ->
143
                  raise TypeCheck.TypeError,
144
                        {unquote(Macro.escape(s)), :return_error,
145
                         %{problem: problem, arguments: unquote(clean_params)}, var!(result, nil)}
146
              end
147
            else
148
              {{:error, problem}, index, param_type} ->
149
                raise TypeCheck.TypeError,
150
                      {
151
                        {unquote(Macro.escape(s)), :param_error,
152
                         %{index: index, problem: problem}, unquote(clean_params)},
153
                        []
154
                      }
155
            end
156
          end
157
        end
158
    end
159
  end
160

161
  def param_check_code(param_type, clean_param, index) do
162
    impl = TypeCheck.Protocols.ToCheck.to_check(param_type, clean_param)
42✔
163

164
    quote generated: true, location: :keep do
165
      [
166
        {{:ok, _bindings, altered_param}, _index, _param_type} <-
167
          {unquote(impl), unquote(index), unquote(Macro.escape(param_type))},
168
        clean_param = altered_param
169
      ]
170
    end
171
  end
172

173
  defimpl TypeCheck.Protocols.Inspect do
174
    def inspect(s, opts) do
175
      case s do
23,755✔
176
        %{param_types: nil, return_type: %TypeCheck.Builtin.Any{}} ->
177
          "function()"
178
          |> Inspect.Algebra.color(:builtin_type, opts)
21,613✔
179

180
        %{param_types: nil, return_type: return_type} ->
181
          inspected_return_type = TypeCheck.Protocols.Inspect.inspect(return_type, opts)
7✔
182

183
          "(..."
184
          |> Inspect.Algebra.color(:builtin_type, opts)
185
          |> Inspect.Algebra.glue(Inspect.Algebra.color("->", :builtin_type, opts))
186
          |> Inspect.Algebra.glue(inspected_return_type)
187
          |> Inspect.Algebra.concat(Inspect.Algebra.color(")", :builtin_type, opts))
7✔
188

189
        %{param_types: types, return_type: return_type} ->
190
          inspected_param_types =
2,135✔
191
            types
192
            |> Enum.map(&TypeCheck.Protocols.Inspect.inspect(&1, opts))
4,242✔
193
            |> Inspect.Algebra.fold_doc(fn doc, acc ->
194
              Inspect.Algebra.concat([doc, Inspect.Algebra.color(", ", :builtin_type, opts), acc])
2,114✔
195
            end)
196

197
          inspected_return_type = TypeCheck.Protocols.Inspect.inspect(return_type, opts)
2,135✔
198

199
          "("
200
          |> Inspect.Algebra.color(:builtin_type, opts)
201
          |> Inspect.Algebra.concat(inspected_param_types)
202
          |> Inspect.Algebra.glue(Inspect.Algebra.color("->", :builtin_type, opts))
203
          |> Inspect.Algebra.glue(inspected_return_type)
204
          |> Inspect.Algebra.concat(Inspect.Algebra.color(")", :builtin_type, opts))
2,135✔
205
      end
206
    end
207
  end
208

209
  if Code.ensure_loaded?(StreamData) do
210
    defimpl TypeCheck.Protocols.ToStreamData do
211
      def to_gen(s) do
212
        case s do
14✔
213
          %{param_types: nil, return_type: result_type} ->
214
            {StreamData.positive_integer(), StreamData.positive_integer()}
215
            |> StreamData.bind(fn {arity, seed} ->
×
216
              create_wrapper(result_type, arity, seed)
×
217
            end)
218

219
          %{param_types: param_types, return_type: result_type} when is_list(param_types) ->
220
            arity = length(param_types)
14✔
221

222
            StreamData.positive_integer()
223
            |> StreamData.bind(fn seed ->
14✔
224
              create_wrapper(result_type, arity, seed)
1,400✔
225
            end)
226
        end
227
      end
228

229
      defp create_wrapper(result_type, arity, hash_seed) do
230
        clean_params = Macro.generate_arguments(arity, __MODULE__)
1,400✔
231

232
        wrapper_ast =
1,400✔
233
          quote do
234
            fn unquote_splicing(clean_params) ->
235
              persistent_seed = :erlang.phash2(unquote(clean_params), unquote(hash_seed))
236

237
              unquote(Macro.escape(result_type))
238
              |> TypeCheck.Protocols.ToStreamData.to_gen()
239
              |> StreamData.seeded(persistent_seed)
240
              |> Enum.take(1)
241
              |> List.first()
242
            end
243
          end
244

245
        {fun, _} = Code.eval_quoted(wrapper_ast)
1,400✔
246
        StreamData.constant(fun)
1,400✔
247
      end
248
    end
249
  end
250
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc