-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[Bug Fix] Allow wants_docs=true to be used with full semantic processing #16074
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
src/macros.cr
Outdated
getter({{property}}) | ||
{% else %} | ||
getter :{{property.id}} | ||
getter(:{{property.id}}) |
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.
Only line 78 needed the parenthesis; I added them to the other methods for consistency.
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.
Great catch! 🚀
We should probably add a spec. I'm not sure what's the best way to do that... Maybe an adaptation of assert_expand
with wants_doc= true
?
It should go into record_spec.cr
.
I'm also wondering if there's anything we can do about this problem more generally 🤔
But I suppose not? Macro expansions can't know whether they are in a location where doc comments are allowed or would break semantics.
We might want to comb through macro usage in stdlib and see if there are similar issues with other expansions. And document this somewhere.
Btw. it would be nice if we could retain the actual doc comment so that |
I'll see if I can get a spec to cover it, or update an existing one by applying a comment to one already being tested 👍 Yeah, with macros it's tricky. Part of the problem I think is that I think the fix would be to include the |
Regarding the documentation for |
Got a spec written that fails without the parenthesis, passes with them. Needed to go through semantic as Unfortunately I couldn't get the I'll create another issue regarding the lack of doc_comments surviving the record macro for documentation purposes, but this PR unblocks a semantic exception being thrown, at least :) |
This is a very subtle bug discovered during trying to introduce
:nodoc:
filtering into the cr-source-typer tool as initially suggested here. My apologies for the long winded PR description; this consumed about 2 days of my time to track down and I want to document it for posterity.Semi Minimal Reproduction
After constructing a
Program
andParser
, add the.wants_docs = true
configuration to both of them. Then have the Parser parsetest.cr
below and then run fullsemantic
on the resulting parsed node. This is left as an exercise for the reader (this is a decent example within the compiler itself)my_record.cr:
test.cr:
Resulting exception:
This error goes away if any of the following happen:
my_record.cr
is removedwants_docs
is set tofalse
record
macroMyRecord
is defined intest.cr
itself instead of being required (I didn't figure out why)Following the Macro Expansions
Trial and error eventually got me to the macro evaluation as the culprit (prior thoughts were on the lexer / parser being overly aggressive somehow, as those were the only places where
wants_docs
,docs_enabled
, or thedoc
type variable were really being used). It turns out if a type node has adoc
variable set on it, then macro{{node}}
will expand that part of it first as a comment, followed by a newline (here for the doc writing in macro expansion, here for the source of theemit_doc
property). This resulted in the below macro expansion(s).The followup macro expansion of the
getter
macro would result in nothing being generated (empty*properties
list). The danglinghello : String
is technically valid but represents a private (protected?) field of the MyRecord struct now. Adding parens on thegetter
macro generation now captures thehello : String
as part of that*properties
list in thegetter
macro and now generates thedef
for it as theTypeDeclaration
it is.How did you find this?
The above minimal reproduction represents the
src/compiler/crystal/interpreter/interpreter.cr
->CallFrame
record. Running the cr-source-typer tool with full semantic on theprelude
node withwants_docs
found that and started complaining about a lack ofreal_frame_index
method being defined.Why doesn't this show up during doc generation?
Running
crystal docs
only runs thetop_level_semantic
on the AST, which doesn't open up methods, follow calls, and then discover methods don't exist. The impact instead is that these methods generated by thegetter
macro wouldn't be generated and the resulting docs wouldn't include them 🤷