Skip to content

Conversation

sabiwara
Copy link
Contributor

Close #14771


%% quote/unquote

do_quote({quote, Meta, [Arg]}, Q) when is_list(Meta) ->
Copy link
Member

@josevalim josevalim Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not be entering this clause altogether. If I am escaping a value, the {:quote, _, _} triplet should not have any semantic value nor behave in any special way. So I think the fix is this:

Suggested change
do_quote({quote, Meta, [Arg]}, Q) when is_list(Meta) ->
do_quote({quote, Meta, [Arg]}, #elixir_quote{op=add_context} = Q) when is_list(Meta) ->

My suggestion is actually to rename op to something clearer. Perhaps it should be:

op=quote | escape | escape_and_prune

That should make it clearer that the above should not be executed while escaping.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was my original attempt (actually I tried adding escape=true), but it seemed to break the compiler, we might be relying on it.

Also, with this reasoning, I was wondering: is there any reason for these other do_quote clauses, why couldn't we just call escape() -> do_escape()?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can escape -> do_escape but we need to be careful with unquote, as some escape may unquote.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh gotcha, perhaps we could skip it if unquote=false then? Will give it a try.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I think I managed to split do_quote and do_escape apart: 58e1369.

But it's not directly related to the fix, still need to apply the op=quote | escape | escape_and_prune change I think, and skip these {:quote, _, _} clauses.

Copy link
Contributor Author

@sabiwara sabiwara Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion is actually to rename op to something clearer. Perhaps it should be:

op=quote | escape | escape_and_prune

Done in ff5c1d2

But then skipping the clause seems to indeed kill bootstrap - I'll need to narrow it down 😅
f054dd2

file=nil,
context=nil,
op=none, % none | prune_metadata | add_context
op=none, % none | escape | escape_and_prune | add_context
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be:

Suggested change
op=none, % none | escape | escape_and_prune | add_context
op=escape, % escape | escape_and_prune | quote

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I thought elixir_quote:quote would be adding :none too, but turns out it's add_context. Got it!

@sabiwara sabiwara merged commit 2ee1d0e into elixir-lang:main Sep 16, 2025
13 checks passed
@sabiwara sabiwara deleted the escape-quote branch September 16, 2025 09:36
sabiwara added a commit that referenced this pull request Sep 16, 2025
Close #14771

Also internally renames the `op` field inside `elixir_quote`: `none -> escape`, `prune_metadata` -> `escape_and_prune`, `add_context -> quote`.
@sabiwara
Copy link
Contributor Author

Added the doc comment a96d1ee and backported ✅

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.

Macro.escape/1 does not properly escape {:quote, _, _} tuples

2 participants