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

Improve compile performance #41

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 42 additions & 33 deletions lib/type_class.ex
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ defmodule TypeClass do

TypeClass.run_where!()
TypeClass.Dependency.run()

# FIXME if check_time: :aot, :compile?
TypeClass.Property.ensure!()
end
end
Expand Down Expand Up @@ -230,6 +232,13 @@ defmodule TypeClass do
# __MODULE__ == datatype
datatype_module = unquote(datatype)

# FIXME if to run at test time
# defmodule unquote(datatype).Property do
# @moduledoc false
#
# unquote(body)
# end

defimpl unquote(class).Proto, for: datatype_module do
import TypeClass.Property.Generator.Custom

Expand All @@ -250,35 +259,36 @@ defmodule TypeClass do
def __force_type_instance__, do: @force_type_instance
end

cond do
unquote(class).__force_type_class__() ->
IO.warn("""
The type class #{unquote(class)} has been forced to bypass \
all property checks for all data types. This is very rarely valid, \
as all type classes should have properties associted with them.

For more, please see the TypeClass README:
https://github.com/expede/type_class/blob/master/README.md
""")

instance.__force_type_instance__() ->
IO.warn("""
The data type #{unquote(datatype)} has been forced to skip property \
validation for the type class #{unquote(class)}

This is sometimes valid, since TypeClass's property checker \
may not be able to accurately validate all data types correctly for \
all possible cases. Forcing a type instance in this way is like telling \
the checker "trust me this is correct", and should only be used as \
a last resort.

For more, please see the TypeClass README:
https://github.com/expede/type_class/blob/master/README.md
""")

true ->
unquote(datatype) |> conforms(to: unquote(class))
end
# FIXME only if checked AOT
# cond do
# unquote(class).__force_type_class__() ->
# IO.warn("""
# The type class #{unquote(class)} has been forced to bypass \
# all property checks for all data types. This is very rarely valid, \
# as all type classes should have properties associted with them.

# For more, please see the TypeClass README:
# https://github.com/expede/type_class/blob/master/README.md
# """)

# instance.__force_type_instance__() ->
# IO.warn("""
# The data type #{unquote(datatype)} has been forced to skip property \
# validation for the type class #{unquote(class)}

# This is sometimes valid, since TypeClass's property checker \
# may not be able to accurately validate all data types correctly for \
# all possible cases. Forcing a type instance in this way is like telling \
# the checker "trust me this is correct", and should only be used as \
# a last resort.

# For more, please see the TypeClass README:
# https://github.com/expede/type_class/blob/master/README.md
# """)

# true ->
# unquote(datatype) |> conforms(to: unquote(class))
# end
end
end

Expand Down Expand Up @@ -506,15 +516,14 @@ defmodule TypeClass do
for dependency <- unquote(class).__dependencies__ do
proto = Module.concat(Module.split(dependency) ++ ["Proto"])

# NOTE: does not follow chain if dependency has no `where`
# NOTE: only follows chain if dependency has a `where`
if Exceptional.Safe.safe(&Protocol.assert_protocol!/1).(proto) == :ok do
Protocol.assert_impl!(proto, unquote(datatype))
end
end

for {prop_name, _one} <- unquote(class).Property.__info__(:functions) do
TypeClass.Property.run!(unquote(datatype), unquote(class), prop_name)
end
# FIXME only if at compile time
TypeClass.Property.check_all!(unquote(class), unquote(class)) # FIXME
end
end

Expand Down
13 changes: 10 additions & 3 deletions lib/type_class/property.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ defmodule TypeClass.Property do
end
end

@doc "Run all properties for the type class"
@spec run!(module(), module(), atom(), non_neg_integer()) :: no_return()
def run!(datatype, class, prop_name, times \\ 100) do
@doc "Check all properties for the type class"
@spec check!(module(), module(), atom(), non_neg_integer()) :: no_return()
def check!(datatype, class, prop_name, times \\ 100) do
property_module = Module.concat(class, Property)
custom_generator = Module.concat([class, "Proto", datatype]).__custom_generator__()

Expand All @@ -37,6 +37,13 @@ defmodule TypeClass.Property do
|> Enum.take(times)
end

# FIXME doc & typespec
def check_all!(datatype, class, times \\ 100) do
for {prop_name, _one} <- Module.concat(class, Property).__info__(:functions) do
TypeClass.Property.check!(datatype, class, prop_name, times)
end
end

@doc ~S"""
Check for equality while handling special cases that normally don't equate in Elixir.
For example, only check float accuracy to 5 decimal places due to internal rounding
Expand Down
6 changes: 3 additions & 3 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ defmodule TypeClass.Mixfile do
preferred_cli_env: [espec: :test],

# Versions
version: "1.2.7",
version: "2.0.0-rc.1",
elixir: "~> 1.11",

# Docs
Expand All @@ -35,8 +35,8 @@ defmodule TypeClass.Mixfile do
[
{:exceptional, "~> 2.1"},

{:espec, "~> 1.8", only: :test, runtime: false},
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
{:espec, "~> 1.8", only: :test, runtime: false},
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
{:inch_ex, "~> 2.0", only: [:dev, :docs, :test], runtime: false},

{:dialyxir, "~> 1.1", only: :dev, runtime: false},
Expand Down
24 changes: 12 additions & 12 deletions nix/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"homepage": "",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e716ddfac4be879ffbae75c3914a538dd5d4d12e",
"sha256": "0c2090sz4nvd1bqa9bfz3b6mj0q8b7v4jzgsykn2hf291l3h94d6",
"rev": "ac60476ed94fd5424d9f3410c438825f793a8cbb",
"sha256": "1dlvpdsy5v09c7rj5f7xgakyj722yqr4415davjpcmrk4n5kw76v",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/e716ddfac4be879ffbae75c3914a538dd5d4d12e.tar.gz",
"url": "https://github.com/NixOS/nixpkgs/archive/ac60476ed94fd5424d9f3410c438825f793a8cbb.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"niv": {
Expand All @@ -17,10 +17,10 @@
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
"rev": "af958e8057f345ee1aca714c1247ef3ba1c15f5e",
"sha256": "1qjavxabbrsh73yck5dcq8jggvh3r2jkbr6b5nlz5d9yrqm9255n",
"rev": "94080ae8286024820c570a2a24ed7c36d7ad04a9",
"sha256": "0wlk52zwlrq727x3z1vg9d9qq4zw62ab5jzg4068iqb6hyb0cr0w",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/af958e8057f345ee1aca714c1247ef3ba1c15f5e.tar.gz",
"url": "https://github.com/nmattia/niv/archive/94080ae8286024820c570a2a24ed7c36d7ad04a9.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs": {
Expand All @@ -29,10 +29,10 @@
"homepage": "",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "60b18a066e8ce5dd21ebff5324345d3586a67ad9",
"sha256": "1cr7r16vb4nxifykhak8awspdpr775kafrl7p6asgwicsng7giya",
"rev": "1f7155200fa1eb752054e2c9062bfdeb023e8098",
"sha256": "0l03az63aw649lyh037csiyarxgbwbmk49lk5n466nmv5glpgzl5",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/60b18a066e8ce5dd21ebff5324345d3586a67ad9.tar.gz",
"url": "https://github.com/NixOS/nixpkgs/archive/1f7155200fa1eb752054e2c9062bfdeb023e8098.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"unstable": {
Expand All @@ -41,10 +41,10 @@
"homepage": null,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c5147860e23ed75ce9d40298c66b416c00be1167",
"sha256": "104mw4rfbzyrfkxq468dlk38drrjx92dgyvkazgci67a6cx3n6nx",
"rev": "efee454783c5c14ae78687439077c1d3f0544d97",
"sha256": "1qk4g8rav2mkbd6y2zr1pi3pxs4rwlkpr8xk51m0p26khprxvjaf",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/c5147860e23ed75ce9d40298c66b416c00be1167.tar.gz",
"url": "https://github.com/NixOS/nixpkgs/archive/efee454783c5c14ae78687439077c1d3f0544d97.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}
3 changes: 2 additions & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

elixir =
[ unstable.elixir
unstable.elixir_ls
];

platform =
Expand All @@ -35,7 +36,7 @@
in

pkgs.mkShell {
name = "Quark";
name = "TypeClass";
nativeBuildInputs = builtins.concatLists [
deps.common
deps.elixir
Expand Down