Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An example that correctly extracts the specs from '@spec'! #19

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions benchmarks/simple.ex
@@ -0,0 +1,13 @@
defmodule Addition do
@compile {:inline, ["add (overridable 1)": 2]}
use TypeCheck
spec add(number(), number()) :: number()
def add(a, b) do
a + b
end

def baseline_add(a, b) do
a + b
end
end

14 changes: 14 additions & 0 deletions benchmarks/simple.exs
@@ -0,0 +1,14 @@
Code.compile_file("benchmarks/simple.ex")

as = Enum.to_list(1..10_000)
bs = Enum.to_list(1..10_000)
input_list = Enum.zip(as, bs)

Benchee.run(
%{
"add with TypeCheck" => fn -> Enum.map(input_list, fn {a, b} -> Addition.add(a, b) end) end,
"baseline add" => fn -> Enum.map(input_list, fn {a, b} -> Addition.baseline_add(a, b) end) end,
},
time: 10,
memory_time: 2
)
14 changes: 14 additions & 0 deletions lib/example.ex
@@ -0,0 +1,14 @@
defmodule Example do
use TypeCheck
import Kernel, except: [@: 1]
require TypeCheck.Macros
import TypeCheck.Macros, only: [@: 1]

@type myint :: integer()

@doc "Does this documentation show up?"
@spec add(integer(), integer()) :: myint()
def add(a, b) do
a + b
end
end
44 changes: 35 additions & 9 deletions lib/type_check/macros.ex
Expand Up @@ -18,7 +18,8 @@ defmodule TypeCheck.Macros do
"""
defmacro __using__(_options) do
quote location: :keep do
import TypeCheck.Macros
import TypeCheck.Macros, only: [type: 1, typep: 1, opaque: 1, spec: 1]
@compile {:inline_size, 1080}

Module.register_attribute(__MODULE__, TypeCheck.TypeDefs, accumulate: true)
Module.register_attribute(__MODULE__, TypeCheck.Specs, accumulate: true)
Expand Down Expand Up @@ -47,16 +48,25 @@ defmodule TypeCheck.Macros do
# And now, define all specs:
definitions = Module.definitions_in(env.module)
specs = Module.get_attribute(env.module, TypeCheck.Specs)
spec_defs = create_spec_defs(specs, definitions, env)
spec_quotes = wrap_functions_with_specs(specs, definitions, env)

# And now for the tricky bit ;-)
quote do
unquote(spec_defs)

import unquote(compile_time_imports_module_name)

unquote(spec_quotes)
end
end

defp create_spec_defs(specs, definitions, caller) do
for {name, line, arity, _clean_params, params_ast, return_type_ast} <- specs do
TypeCheck.Spec.create_spec_def(name, arity, params_ast, return_type_ast)
end
end

defp wrap_functions_with_specs(specs, definitions, caller) do
for {name, line, arity, clean_params, params_ast, return_type_ast} <- specs do
unless {name, arity} in definitions do
Expand Down Expand Up @@ -377,14 +387,30 @@ defmodule TypeCheck.Macros do
unquote(Macro.escape(params_ast)), unquote(Macro.escape(return_type_ast))}
)

def unquote(spec_fun_name)() do
# import TypeCheck.Builtin
%TypeCheck.Spec{
name: unquote(name),
param_types: unquote(params_ast),
return_type: unquote(return_type_ast)
}
end
# def unquote(spec_fun_name)() do
# # import TypeCheck.Builtin
# %TypeCheck.Spec{
# name: unquote(name),
# param_types: unquote(params_ast),
# return_type: unquote(return_type_ast)
# }
# end
end
end

import Kernel, except: [@: 1]
defmacro @ast do
IO.inspect(ast)
case ast do
{name, _, expr} when name in ~w[type typep opaque spec]a ->
# apply(TypeCheck.Macros, name, expr)
quote do
TypeCheck.Macros.unquote(name)(unquote_splicing(expr))
end
_ ->
quote do
Kernel.@(unquote(ast))
end
end
end
end
17 changes: 17 additions & 0 deletions lib/type_check/spec.ex
Expand Up @@ -25,6 +25,23 @@ defmodule TypeCheck.Spec do
function_exported?(module, spec_fun_name(function, arity), 0)
end

@doc false
def create_spec_def(name, arity, params_ast, return_type_ast) do
spec_fun_name = :"__type_check_spec_for_#{name}/#{arity}__"

quote location: :keep do
@doc false
def unquote(spec_fun_name)() do
# import TypeCheck.Builtin
%TypeCheck.Spec{
name: unquote(name),
param_types: unquote(params_ast),
return_type: unquote(return_type_ast)
}
end
end
end

@doc false
def wrap_function_with_spec(name, line, arity, clean_params, params_spec_code, return_spec_code) do
quote line: line do
Expand Down
1 change: 1 addition & 0 deletions mix.exs
Expand Up @@ -50,6 +50,7 @@ defmodule TypeCheck.MixProject do
{:stream_data, "~> 0.5.0", optional: true},
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
{:dialyxir, "~> 1.0", only: [:dev], runtime: false},
{:benchee, "~> 1.0", only: :dev},
]
end

Expand Down
2 changes: 2 additions & 0 deletions mix.lock
@@ -1,4 +1,6 @@
%{
"benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
"earmark": {:hex, :earmark, "1.4.8", "a7d0b2a02d52ffd5ca73106f36cd7f7db333ded41c756f1f1407adadbeef9bb7", [:mix], [{:earmark_parser, ">= 1.4.9", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "138d6a1de01e14e33c6762a245829d7d413d63b6d49d55c0232bbc6a561127ba"},
"earmark_parser": {:hex, :earmark_parser, "1.4.9", "819bda2049e6ee1365424e4ced1ba65806eacf0d2867415f19f3f80047f8037b", [:mix], [], "hexpm", "8bf54fddabf2d7e137a0c22660e71b49d5a0a82d1fb05b5af62f2761cd6485c4"},
Expand Down