From 63c5b9cf76fc395b5bbc9c756db465885c74408a Mon Sep 17 00:00:00 2001 From: Alex Gubarev Date: Wed, 29 Jul 2026 17:27:53 +0300 Subject: [PATCH] Fix Code.Typespec.spec_to_quoted/2 incomplete variable type collection --- lib/elixir/lib/code/typespec.ex | 4 ++-- lib/elixir/test/elixir/typespec_test.exs | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/elixir/lib/code/typespec.ex b/lib/elixir/lib/code/typespec.ex index 7b1236c2bb5..b87a0547ffd 100644 --- a/lib/elixir/lib/code/typespec.ex +++ b/lib/elixir/lib/code/typespec.ex @@ -193,8 +193,8 @@ defmodule Code.Typespec do ## To AST conversion - defp collect_vars({:ann_type, _anno, args}) when is_list(args) do - [] + defp collect_vars({:ann_type, _anno, [_var, type]}) do + collect_vars(type) end defp collect_vars({:type, _anno, _kind, args}) when is_list(args) do diff --git a/lib/elixir/test/elixir/typespec_test.exs b/lib/elixir/test/elixir/typespec_test.exs index b226eceda48..ef94451e401 100644 --- a/lib/elixir/test/elixir/typespec_test.exs +++ b/lib/elixir/test/elixir/typespec_test.exs @@ -1313,6 +1313,19 @@ defmodule TypespecTest do end) end + test "spec_to_quoted collects nested type vars" do + bytecode = + test_module do + @spec foo(arg1 :: [t], arg2 :: [t]) :: atom() when t: var + def foo(_, _), do: :ok + end + + [{{:foo, 2}, [spec]}] = specs(bytecode) + + assert Macro.to_string(Code.Typespec.spec_to_quoted(:foo, spec)) == + "foo(arg1 :: [t], arg2 :: [t]) :: atom() when t: var" + end + test "spec_to_quoted preserves line metadata for elixir remote types" do bytecode = test_module do