From ad6d08f863c6ea7a1f57b62f74fe8ed5dd9c69ea Mon Sep 17 00:00:00 2001 From: futhr Date: Wed, 22 Apr 2026 02:15:45 +0200 Subject: [PATCH] Load using-module bytecode before @after_compile checks Elixir 1.19's compiler no longer auto-loads the using module before @after_compile fires, so function_exported?/2 reports false for the freshly compiled struct and Brex.Operator (and any user struct rule) fails to compile with "is not a struct". Force-load the bytecode passed to the callback before running the struct + evaluate/2 checks, and add Elixir 1.19 / OTP 28 to the CI matrix so the regression is caught upstream. --- .github/workflows/ci.yml | 1 + lib/brex/rule/struct.ex | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 533c7b2..1bff905 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ jobs: with: matrix: | [ + {"elixir": "1.19", "otp": "28.0", "alpine": "3.21"}, {"elixir": "1.18", "otp": "27.0", "alpine": "3.20"}, {"elixir": "1.17", "otp": "27.0", "alpine": "3.20"}, {"elixir": "1.16", "otp": "26.2", "alpine": "3.20"} diff --git a/lib/brex/rule/struct.ex b/lib/brex/rule/struct.ex index ee3854c..700974c 100644 --- a/lib/brex/rule/struct.ex +++ b/lib/brex/rule/struct.ex @@ -28,7 +28,9 @@ defmodule Brex.Rule.Struct do end end - def __after_compile__(%{module: module} = env, _bytecode) do + def __after_compile__(%{module: module} = env, bytecode) do + ensure_loaded!(module, bytecode) + is_struct_module(module) || raise CompileError, file: env.file, @@ -44,6 +46,17 @@ defmodule Brex.Rule.Struct do "cannot use #{inspect(__MODULE__)} on module #{inspect(module)} without defining evaluate/2" end + defp ensure_loaded!(module, bytecode) do + case Code.ensure_loaded(module) do + {:module, ^module} -> + :ok + + {:error, _} -> + {:module, ^module} = :code.load_binary(module, ~c"nofile", bytecode) + :ok + end + end + defp is_struct_module(module) do function_exported?(module, :__struct__, 0) and function_exported?(module, :__struct__, 1) end