Skip to content

Add String.to_existing_atom/2 to validate against a list of allowed atoms#15483

Merged
sabiwara merged 7 commits into
elixir-lang:mainfrom
sabiwara:to_existing_atom
Jun 16, 2026
Merged

Add String.to_existing_atom/2 to validate against a list of allowed atoms#15483
sabiwara merged 7 commits into
elixir-lang:mainfrom
sabiwara:to_existing_atom

Conversation

@sabiwara

Copy link
Copy Markdown
Contributor
  • the second commit inlines it in the compiler in the case of a static list, using much faster pattern-matching (bench)
  • the third commit special cases it in the type sytem so that we can narrow down the return type to :foo | :bar

I'd like to get proper type warnings if the variable is not a list of atoms, but not sure what the best way to do this.

Comment thread lib/elixir/lib/module/types/apply.ex Outdated
Comment on lines +718 to +727
atom_type =
with {_, atom_type} when atom_type != nil <- list_of(atoms_type),
true <- subtype?(atom_type, atom()) do
atom_type
else
_ ->
atom()
end

{return(atom_type, [string_type, atoms_type], stack), context}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You can probably change remote_apply instead. do_remote customizes how the whole function is type checked. remote_apply changes only how you compute the return type. This means that, if someone passes to_existing_atom(string, "not a list"), we will type check it already. You don't have anything else to do. And the implementation of remote_apply is likely a simple call to list_hd!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I managed to make it work in 4456ce4.

And the implementation of remote_apply is likely a simple call to list_hd!

It seems we still need to run remote_apply/3 first to check the domain in our custom remote_apply/5 clause, otherwise it doesn't properly validate args against the signature? But it was fairly straightforward with this method.

Comment thread lib/elixir/lib/string.ex Outdated

"""
@spec to_existing_atom(String.t(), [atom]) :: atom
def to_existing_atom(string, allowed_atoms)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we want to check it is a non-empty list? As an empty list will always fail anyway?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Indeed, done in c3094ca

Comment thread lib/elixir/lib/module/types/apply.ex Outdated

@josevalim josevalim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ship it! We likely want to add List.to_existing_atom too? It can be either here or in a separate PR :)

@sabiwara

Copy link
Copy Markdown
Contributor Author

Ship it! We likely want to add List.to_existing_atom too? It can be either here or in a separate PR :)

Yes, I thought I'd just do it as a follow-up once this one is done 👍

Co-authored-by: José Valim <jose.valim@gmail.com>
Comment thread lib/elixir/lib/module/types/apply.ex
@sabiwara sabiwara merged commit fd1109e into elixir-lang:main Jun 16, 2026
15 checks passed
@sabiwara sabiwara deleted the to_existing_atom branch June 16, 2026 08:45
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.

2 participants