-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Assert scope is not match/guard when using escaped regexes #14780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
lib/elixir/lib/kernel.ex
Outdated
## Shared functions | ||
|
||
@doc false | ||
defmacro __assert_assert_no_match_or_guard_scope__(exp) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in this case some code duplication is fine. Let's just reimplement the error message directly in the Regex module, since that's what we would expect library authors to do too.
lib/elixir/lib/regex.ex
Outdated
__assert_assert_no_match_or_guard_scope__("an escaped Regex") | ||
:re.import(unquote(Macro.escape(exported))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of generating additional code, we should call Regex.__import__(unquote(...))
, where __import__
itself is a macro which also checks the environment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds much better indeed 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arg, this might actually not work, since unlike Kernel
we need to require Regex
.
quote do
require Regex
Regex.__import_pattern__(unquote(Macro.escape(exported)))
end
Which then makes it impossible to compile elixir:
==> elixir (compile)
error: you are trying to use/import/require the module Regex which is currently being defined.
(although it seems weird to warn here, since it's happening within quote
🤔)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed the broken commit just in case: c1dee89
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the issue happens because we escape the struct defined by defstruct
inside Regex. An easy fix is to add this clause to the top of the cond
in __escape__
:
is_nil(regex.re_pattern) ->
nil
And then it compiles fine!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another idea to keep the emitted AST small 💡
We could leave a special meta when we escape a struct with __escape__
, and add an extra hint when we emit the scope error if the meta is there? (Hint: This happened because you tried to escape a Regex
).
Another benefit is that custom structs need to do nothing to benefit from this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think that metadata would work? The __escape__
function can return any node and it would be hard to know which node to annotate/which node would fail.
Another option is for us to allow this to work:
require Regex
quote do
Regex.__import__(...)
end
or even just this:
quote do
Regex.__import__(...)
end
Especially as I thought we already annotated within quote
that the module was already required...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think that metadata would work? The escape function can return any node and it would be hard to know which node to annotate/which node would fail.
That's true, I didn't think this through, sorry.
or even just this:
quote do Regex.__import__(...) end
That would be ideal, but isn't there a risk of allowing implicit require
s?
Wouldn't this mess with the lexical tracker?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, the way it works is that we annotate it is required and consider the require in both caller and callee. At least that’s how we handle imports and they are more complex than require.
another option is to allow requiring the current module as long as it happens inside a function? As you can assume that when the function is executed the module is indeed defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL about the required: true
meta, I think it fixed it nicely 0e671f4.
51e78e5
to
0e671f4
Compare
OK to backport? |
@sabiwara yes, let's backport! |
Following on #14720, I've been thinking if we could/should improve the error message when trying to use regex module attributes in guards/match scope.
This PR explores the idea, but feel free to close if this is overthinking on my part.
Before (confusing:

:re.compile
mentioned but not in the code)After
