-
Notifications
You must be signed in to change notification settings - Fork 348
ppx: add test for inference regression in keys #752
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
c9acf14 to
06402e8
Compare
|
Check the difference in generated code. Before: let render author =
ReactDOMRe.createDOMElementVariadic "tr"
~props:(ReactDOMRe.domProps ~key:author.Author.name ())
[|
ReactDOMRe.createDOMElementVariadic "td"
[|
ReactDOMRe.createDOMElementVariadic "img"
~props:(ReactDOMRe.domProps ~src:author.imageUrl ())
[||];
|];
|]After: let render author =
ReactDOM.jsxKeyed "tr"
((ReactDOM.domProps [@merlin.hide])
~children:
(ReactDOM.jsx "td"
((ReactDOM.domProps [@merlin.hide])
~children:
(ReactDOM.jsx "img"
((ReactDOM.domProps [@merlin.hide]) ~src:author.imageUrl ()))
()))
())
~key:author.Author.name ()I tried this too, but it doesn't fix it: let render author =
ReactDOM.jsxKeyed ~key:author.Author.name "tr"
((ReactDOM.domProps [@merlin.hide])
~children:
(ReactDOM.jsx "td"
((ReactDOM.domProps [@merlin.hide])
~children:
(ReactDOM.jsx "img"
((ReactDOM.domProps [@merlin.hide]) ~src:author.imageUrl ()))
()))
())
() |
|
Thanks for sharing the ppx expanded. With React jsx-runtime API, Line 2139 in c9acf14
(side note: should it be a So, because what matters for inference is the ordering of arguments at the definition, there is not much we can do. Here is a simpler example, note how the call to Funny enough (but understandably) this works fine: let render = author =>
<tr key={author.name}>
<td>
<img src=author.Author.imageUrl />
</td>
</tr>;The only solution I can think of is to redefine the args order by doing something like: [@bs.module "react/jsx-runtime"]
external jsxKeyed: (string, domProps, string) => React.element = "jsx";
let jsxKeyed(element, key, props) = jsxKeyed(element, props, key);But I personally don't think it's worth it. Wdyt? |
|
went ahead and implemented the suggestion above in 8425467. |
|
That’s a good idea, we don’t need the let though. We should be able to keep it an external, or didn’t that work? |
I don't know how to have both things with a single external:
Do you have any ideas? |
|
Ah you’re right, of course. I think this creates an extra function call for every JSX call though, which I don’t think is desirable. |
|
@jchavarri I pushed a different version of your fix that generates: let render author =
let reason_react_ppx_key_arg___x = author.Author.name in
ReactDOM.jsxKeyed ~key:reason_react_ppx_key_arg___x "tr"
(((ReactDOM.domProps)[@merlin.hide ])
~children:(ReactDOM.jsx "td"
(((ReactDOM.domProps)[@merlin.hide ])
~children:(ReactDOM.jsx "img"
(((ReactDOM.domProps)[@merlin.hide ])
~src:(author.imageUrl) ())) ())) ())
()we introduce a let binding that matches the expected flow of type inference. What do you think? |
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.
Your approach looks good as well! It is very creative :) I left a comment about locations that I think should be tackled before merging.
In general, all other things equal, I tend to prefer solving issues elsewhere than into a ppx, just because it has so much inherent complexity... but it is not a strong opinion, happy to go with this solution.
Do you know which one would be more optimal in terms of resulting size of the generated JavaScript code? I understand the extra let in the bindings is just added once in the bindings, but the ppx will add an extra let for every usage of key?
ppx/src/reactjs_jsx_ppx.ml
Outdated
| pvb_loc = loc; | ||
| }; | ||
| ] | ||
| (Exp.apply ~loc:parentExpLoc ~attrs jsxExpr |
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 kind of breaks the rules for "well-formed" locations, because the apply will have a larger range (parentExpLoc) than the parent let expression (which has loc). I am afraid that our for now limited tests are not catching a potential regression here.
I think we should at least rename loc to callerLoc or something else, to prevent this kind of issues in the future.
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.
The rename make sense, but I don't understand the issue here. I belive the location is pointed to the right place no?
(li ~key:e.path [@JSX]) (* <-- parentExpLoc *)
let reason_react_ppx_key_arg___x = e.path in
ReactDOM.jsxKeyed ~key:reason_react_ppx_key_arg___x "li" (* <-- parentExpLoc *)
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.
After pressing "Send", I realised that the let reason_react_ppx_key_arg___x use the location of the identifier, and this is the reason why when you hover a lowercase component it says "string"
I wonder now, what would be the right location for this case.
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.
In my experience, it doesn't matter that much which is the right location for each node. As long as they are well formed (parents have larger scope than children), things kind of work. One might need to hide some nodes to prioritize others, but the fundamental first step is that the ranges are well formed. When that fails, merlin will fail in most cases.
…-test-for-inference-regression * 'main' of github.com:/reasonml/reason-react: Allow memoCustomCompareProps on ppx (#766) Fix rules for reason under with-test (#762) fix opam formula (#763) depexts: expand to react 17 (#761) add npm depexts (#760) Create a blog entry for 0.11 and Melange (#743) Install melange 1.0 (#757) (#758)
|
I updated this branch with latest |
48cb585 to
151c89b
Compare
…ional-props-in-makeProps * 'main' of github.com:/reasonml/reason-react: ppx: add test for inference regression in keys (#752)
This test shows some regression where the type checker is not able to infer the type of a prop for a value which type has been inferred before in a
keyprop.The compilation fails with:
When before, it would infer that
authorhas typeAuthor.t, as it is namespaced in line 603:reason-react/test/React__test.re
Line 603 in c9acf14
I bisected the test, and this used to work before #714 was merged (tested with commit 2b8819b and it builds fine)