Skip to content

Conversation

@sabiwara
Copy link
Contributor

@sabiwara sabiwara commented Jul 28, 2025

Close #14676

I think the ideal fix would be to improve macro expansion to never propagate generated: true to unquotes... but that might be tricky and maybe introduce other false positives?

Screenshot 2025-07-29 at 8 26 06

@josevalim
Copy link
Member

I think the ideal fix would be to improve macro expansion to never propagate generated: true to unquotes... but that might be tricky and maybe introduce other false positives?

As far as I know we don't do that. So there is something else at play here.

@josevalim
Copy link
Member

josevalim commented Jul 29, 2025

So there is something else at play here.

So when you emit generated: true and it has a macro, then that macro is expanded with generated: true over all of its AST. One option would be to not cascade generated, but that would mean the if would warn anyway. So what you said is true, but only for nested macros.

Another option is, given you added shallow_validate_ast, is to use shallow_validate_ast to annotate the root node with unquoted: true and then to stop the traversal in elixir_quote:linify_with_context_counter if unquoted: true is part of the metadata.

@josevalim
Copy link
Member

josevalim commented Jul 29, 2025

This is one option:

diff --git a/lib/elixir/src/elixir_quote.erl b/lib/elixir/src/elixir_quote.erl
index 3f872cd79..7985062f5 100644
--- a/lib/elixir/src/elixir_quote.erl
+++ b/lib/elixir/src/elixir_quote.erl
@@ -92,8 +92,8 @@ linify_with_context_counter(ContextMeta, Var, Exprs) when is_list(ContextMeta) -

   Fun =
     case lists:keyfind(generated, 1, ContextMeta) of
-      {generated, true} when Line =:= 0 -> fun elixir_utils:generated/1;
-      {generated, true} -> fun(Meta) -> elixir_utils:generated(keynew(line, Meta, Line)) end;
+      {generated, true} when Line =:= 0 -> fun generated_unless_unquoted/1;
+      {generated, true} -> fun(Meta) -> generated_unless_unquoted(keynew(line, Meta, Line)) end;

However the option above continues traversing unquoted nodes, which is probably not necessary? So a more aggressive approach would be this:

diff --git a/lib/elixir/src/elixir_quote.erl b/lib/elixir/src/elixir_quote.erl
index 3f872cd79..8b08b4559 100644
--- a/lib/elixir/src/elixir_quote.erl
+++ b/lib/elixir/src/elixir_quote.erl
@@ -118,7 +118,11 @@ do_linify(Fun, {Lexical, Meta, [_ | _] = Args}, {_, Counter} = Var)
   do_tuple_linify(Fun, keynew(counter, Meta, Counter), Lexical, Args, Var);

 do_linify(Fun, {Left, Meta, Right}, Var) when is_list(Meta) ->
-  do_tuple_linify(Fun, Meta, Left, Right, Var);
+  %% Stop traversing as the contents are unquoted
+  case lists:keyfind(unquoted, 1, Meta) of
+    {unquoted, true} -> {Left, Meta, Right};
+    _ -> do_tuple_linify(Fun, Meta, Left, Right, Var)
+  end;

 do_linify(Fun, {Left, Right}, Var) ->
   {do_linify(Fun, Left, Var), do_linify(Fun, Right, Var)};

And then the second part of the equation is changing shallow_validate_ast to have the shallow nodes annotated. Would you like to give it a try?

@sabiwara
Copy link
Contributor Author

@josevalim yes, I will try to send a PR!
Closing this one for now since it's the wrong approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

ExUnit assert swallowing unused variable warning

2 participants