From a5a093b6914174d14ebecd10c9dc0c8bb86e01d5 Mon Sep 17 00:00:00 2001 From: Yuri Artemev Date: Tue, 13 Aug 2019 13:45:51 +0300 Subject: [PATCH] ensure module is compiled when checking for Construct def --- .travis.yml | 4 ++++ lib/construct.ex | 15 +++++++++------ test/integration/build_test.exs | 24 ++++++++++++------------ 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index 542c79c..a68712b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,10 @@ sudo: false matrix: include: + - elixir: 1.9.1 + otp_release: 22.0.7 + - elixir: 1.8.2 + otp_release: 21.3.8 - elixir: 1.7.2 otp_release: 21.0 - elixir: 1.7.2 diff --git a/lib/construct.ex b/lib/construct.ex index 7a4809a..7e08c41 100644 --- a/lib/construct.ex +++ b/lib/construct.ex @@ -30,6 +30,9 @@ defmodule Construct do @type_checker_name Construct.TypeRegistry @no_default :__construct_no_default__ + # elixir 1.9.0 do not raise deadlocks for Code.ensure_compiled/1 + @no_raise_on_deadlocks Version.compare(System.version(), "1.9.0") != :lt + @doc false defmacro __using__(opts \\ []) @@ -117,11 +120,11 @@ defmodule Construct do module = unquote(struct) unless Code.ensure_compiled?(module) do - raise Construct.DefinitionError, "undefined module #{module}" + raise Construct.DefinitionError, "undefined module #{inspect(module)}" end unless function_exported?(module, :__construct__, 1) do - raise Construct.DefinitionError, "provided #{module} is not Construct module" + raise Construct.DefinitionError, "provided #{inspect(module)} is not Construct module" end Enum.each(module.__construct__(:types), fn({name, {type, opts}}) -> @@ -354,13 +357,15 @@ defmodule Construct do end defp check_type_complex!(module) do + if @no_raise_on_deadlocks, do: Code.ensure_compiled(module) + unless construct_module?(module) do unless Code.ensure_compiled?(module) do - raise Construct.DefinitionError, "undefined module #{module}" + raise Construct.DefinitionError, "undefined module #{inspect(module)}" end unless function_exported?(module, :cast, 1) do - raise Construct.DefinitionError, "undefined function cast/1 for #{module}" + raise Construct.DefinitionError, "undefined function cast/1 for #{inspect(module)}" end end end @@ -407,8 +412,6 @@ defmodule Construct do end defp construct_module?(module) do - Code.ensure_compiled(module) - Agent.get(@type_checker_name, &MapSet.member?(&1, module)) || Code.ensure_compiled?(module) && function_exported?(module, :__construct__, 1) end diff --git a/test/integration/build_test.exs b/test/integration/build_test.exs index 352cf93..317d44e 100644 --- a/test/integration/build_test.exs +++ b/test/integration/build_test.exs @@ -120,19 +120,19 @@ defmodule Construct.Integration.BuildTest do end test "raise when trying to use undefined module as custom type" do - assert_raise(Construct.DefinitionError, ~s(undefined module Elixir.UndefinedModule), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined module UndefinedModule), fn -> create_construct do field :key, UndefinedModule end end) - assert_raise(Construct.DefinitionError, ~s(undefined module Elixir.UndefinedModule), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined module UndefinedModule), fn -> create_construct do field :key, {:array, UndefinedModule} end end) - assert_raise(Construct.DefinitionError, ~s(undefined module Elixir.UndefinedModule), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined module UndefinedModule), fn -> create_construct do field :key, {:map, UndefinedModule} end @@ -144,13 +144,13 @@ defmodule Construct.Integration.BuildTest do end end) - assert_raise(Construct.DefinitionError, ~s(undefined module Elixir.UndefinedModule), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined module UndefinedModule), fn -> create_construct do field :key, [UndefinedModule] end end) - assert_raise(Construct.DefinitionError, ~s(undefined module Elixir.UndefinedModule), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined module UndefinedModule), fn -> create_construct do field :key, [CustomType, UndefinedModule] end @@ -158,19 +158,19 @@ defmodule Construct.Integration.BuildTest do end test "raise when trying to use custom type that doesn't have cast/1 function" do - assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for Elixir.CustomTypeEmpty), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for CustomTypeEmpty), fn -> create_construct do field :key, CustomTypeEmpty end end) - assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for Elixir.CustomTypeEmpty), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for CustomTypeEmpty), fn -> create_construct do field :key, {:array, CustomTypeEmpty} end end) - assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for Elixir.CustomTypeEmpty), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for CustomTypeEmpty), fn -> create_construct do field :key, {:map, CustomTypeEmpty} end @@ -182,13 +182,13 @@ defmodule Construct.Integration.BuildTest do end end) - assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for Elixir.CustomTypeEmpty), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for CustomTypeEmpty), fn -> create_construct do field :key, [CustomTypeEmpty] end end) - assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for Elixir.CustomTypeEmpty), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined function cast/1 for CustomTypeEmpty), fn -> create_construct do field :key, [CustomType, CustomTypeEmpty] end @@ -196,7 +196,7 @@ defmodule Construct.Integration.BuildTest do end test "raise when trying to include undefined module" do - assert_raise(Construct.DefinitionError, ~s(undefined module Elixir.UndefinedModule), fn -> + assert_raise(Construct.DefinitionError, ~s(undefined module UndefinedModule), fn -> create_construct do include UndefinedModule end @@ -204,7 +204,7 @@ defmodule Construct.Integration.BuildTest do end test "raise when trying to include invalid structure (some module)" do - assert_raise(Construct.DefinitionError, ~s(provided Elixir.CustomTypeEmpty is not Construct module), fn -> + assert_raise(Construct.DefinitionError, ~s(provided CustomTypeEmpty is not Construct module), fn -> create_construct do include CustomTypeEmpty end