[Bug Fix] Allow wants_docs=true to be used with full semantic processing#16074
[Bug Fix] Allow wants_docs=true to be used with full semantic processing#16074Vici37 wants to merge 9 commits intocrystal-lang:masterfrom
Conversation
src/macros.cr
Outdated
| getter({{property}}) | ||
| {% else %} | ||
| getter :{{property.id}} | ||
| getter(:{{property.id}}) |
There was a problem hiding this comment.
Only line 78 needed the parenthesis; I added them to the other methods for consistency.
There was a problem hiding this comment.
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
ProgramandParser, add the.wants_docs = trueconfiguration to both of them. Then have the Parser parsetest.crbelow and then run fullsemanticon 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.cris removedwants_docsis set tofalserecordmacroMyRecordis defined intest.critself 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 thedoctype variable were really being used). It turns out if a type node has adocvariable 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_docproperty). This resulted in the below macro expansion(s).The followup macro expansion of the
gettermacro would result in nothing being generated (empty*propertieslist). The danglinghello : Stringis technically valid but represents a private (protected?) field of the MyRecord struct now. Adding parens on thegettermacro generation now captures thehello : Stringas part of that*propertieslist in thegettermacro and now generates thedeffor it as theTypeDeclarationit is.How did you find this?
The above minimal reproduction represents the
src/compiler/crystal/interpreter/interpreter.cr->CallFramerecord. Running the cr-source-typer tool with full semantic on thepreludenode withwants_docsfound that and started complaining about a lack ofreal_frame_indexmethod being defined.Why doesn't this show up during doc generation?
Running
crystal docsonly runs thetop_level_semanticon 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 thegettermacro wouldn't be generated and the resulting docs wouldn't include them 🤷