Clean up and extend support for ocaml.warning/ocaml.warnerror/ocaml.ppwarning attributes#1248
Conversation
|
Ok, the work done to support ocaml.warning is all attribute contexts also made it easy to reimplement support for ocaml.ppwarning in a way which respect the scopes of ocaml.warning attributes. Now ready for reviews. Volunteers are welcome! (@aantron : hint hint) |
|
Hi, I like the general idea of this PR (i.e. adding support for such attributes in all contexts), as well as the new However, the new |
| File "w03.ml", line 19, characters 9-12: | ||
| Warning 3: deprecated: X.t | ||
| File "w03.ml", line 21, characters 15-17: | ||
| Warning 3: deprecated: t7 |
There was a problem hiding this comment.
I don't think you meant to commit this file.
There was a problem hiding this comment.
Well spotted, thanks!
To be checked, but there is probably already an Env.t available everywhere we need it, and we could use it to thread the warnings information as well. I agree this would be a nice cleanup. However, I think the PR in its current state adds useful features and also remove existing drawbacks. The worse that can happen if I forgot to deal with a lazy is a scoping problem for some ocaml.warning attribute which is not the end of the world (and not even a regression, since those attributes were ignored in most contexts). I checked all the lazy in Typeclass, and I don't believe lazyness is used in other places. Moreover, I've provided a rather extensive test (which did catch the problem with lazy, initially). So unless someone plans to work on the suggested cleanup in the short term, I think it is better to record it for future work and accept this PR. |
Actually, it's not the case. We'd need to have access to the warning configuration everywhere a warning can be raised, which would create a rather invasive change. Note that even the lexer can raise warnings (although they are currently not controlled by ocaml.warning). |
To be fair the flow of I do agree the change is invasive yes, but it does still feel beneficial to me.
I do not quite agree with the reasoning here. Here if a bug creeps in it doesn't seem unrealistic that we would turn off some warning in a place where we're not supposed to do so, that seems bad. My personal feeling is that this PR is adding an easy way to write bogus code and it seems like we could prevent that with some effort. Depending on your definition of short-term ("before the 4.06 freeze"?) I wouldn't mind waiting to see if a kind soul is willing to at least experiment with threading the warnings context explicitly. |
I don't think it's a fair statement. The type-checker is already full of global state, and even before this PR, we already used the same technique to support ocaml.warning. It is just that the PR extends the support for ocaml.warning to classes, where the type-checker uses lazyiness (in a relatively well controlled place). If this PR covered all cases except for class fields, would you still consider that its inclusion is conditioned to the big refactoring? |
No one is denying that :)
That's a fair point, indeed as you already noted this PR doesn't introduce any regression. It simply increases the number of places where errors can be made.
Oh, I'd rather we merged the whole thing rather than omitting support for classes. Omitting class fields in this PR wouldn't make the implementation fundamentally safer, just less complete. I still think it'd be good if the cleanup was done in the not too distant future though. |
Can you elaborate on that? What I had in mind was changing from val warning_attribute: Parsetree.attribute -> unit
val warning_scope: Parsetree.attributes -> (unit -> 'a) -> 'ato val warning_attribute: Env.t -> Parsetree.attribute -> Env.t
val warning_scope: Env.t -> Parsetree.attributes -> (Env.t -> 'a) -> 'aAdapting call sites for these function to these new signature should be easy. Then we only need to ensure that the env is passed in all contexts where a warning can be raised. Anyway, I think this is for later. ===== @garrigue Do you have an opinion on the proposal? |
|
Wouldn't |
|
Yes, with a fold (warning_scope takes multiple attributes). |
Well, the general vague idea is that warnings should flow down to subtrees only, while the environment might sometimes pass from one branch to the next. I'm not that familiar with the typechecker (so I have probably missed something when trying to follow the code) but, after a quick look inside typecore.ml, I wonder if the following could be problematic: in That being said, storing the warnings in the environment has the nice side effect that they would be available at a later stage when translating from typedtree to lambda. I imagine this could prove useful. |
typing/typemod.ml
Outdated
| making them abstract otherwise. *) | ||
|
|
||
| let rec approx_modtype env smty = | ||
| (* Need to process warning attributes here ?? *) |
There was a problem hiding this comment.
Should warnings rather be disabled when computing approximative module types (i.e. in approx_* functions) since those approximation are only used to initialize the typing of recursive module types and warnings can be emitted once the full module types have been computed?
There was a problem hiding this comment.
Yes, indeed. This would fall in the scope of #1191 I think.
There was a problem hiding this comment.
Well, in #1191, the call to approx_* function is not protected against warnings, but it should probably be if the current PR is merged before.
3114320 to
8eb5fc4
Compare
|
Rebased, and fixed the test. @Octachron Since you started to comment on the PR, would you like to review it? |
|
Certainly, I would try to find the time for a full review this week. |
|
Gentle ping to @Octachron. |
trefis
left a comment
There was a problem hiding this comment.
Stylistic disagreement aside, the code looks correct to me.
Octachron
left a comment
There was a problem hiding this comment.
The PR looks good but I had some suggestions for minor potential tweaks.
One more potential tweak might be the Typetexp.transl_type_param function that does not take in account the attributes on the type parameters. Even, it is currently not possible to emit a warning here, I wonder if it may not be better to enclose it in a warning scope already?
| (such as an expression, or a type expression) | ||
| in which case its scope is limited to that item. | ||
| Note that it is not well-defined which scope is used for a specific | ||
| warning. This is implementation dependant and can change between versions. |
There was a problem hiding this comment.
I think it would be a good idea to mention here that some warnings are not affected by such attributes. In particular, lexical warnings (latin 1 identifiers, comment end and start, illegal backslash, and unattached documentation comment) are not affected. Maybe more problematic, the flambda warning 59 is simultaneously not affected and can yield false positive.
| end; | ||
| let exp = | ||
| Builtin_attributes.with_warning_attribute pvb_attributes | ||
| Builtin_attributes.warning_scope pvb_attributes |
There was a problem hiding this comment.
I would argue that pattern typing should also be done in this warning scope for let binding, in order to be able to write for instance
let[@warning "-8"] [] = []i.e. update
let (pat_list, new_env, force, unpacks) =
type_pattern_list env spatl scope nvs allow in
at line 4012 to take in account the warning attributes on the let binding.
There was a problem hiding this comment.
Well spotted! However, note that warning 8 is not processed when type-checking the pattern, but a bit later. I've thus added two warning scopes, and made sure that ppwarning attributes are not processed several times because of that.
| let (trem, rem, final_env) = transl_sig (Env.in_signature true env) sg in | ||
| let rem = simplify_signature rem in | ||
| let sg = { sig_items = trem; sig_type = rem; sig_final_env = final_env } in | ||
| Cmt_format.set_saved_types |
There was a problem hiding this comment.
Would it not be better to put Cmt_format.set_saved_types outside of the warning scope since it does not emit warning, and even if it would I am not sure that the warning scope should be shared here.
There was a problem hiding this comment.
Other calls to Cmt_format.set_saved_types (for Partial_structure_item and Partial_structure) are also under a warning scope (cf end of type_structure, inner run function). I think this harmless: set_saved_types is really just a reference assignment.
typing/typemod.ml
Outdated
| md_attributes = pmd.pmd_attributes; | ||
| md_loc = pmd.pmd_loc; | ||
| } | ||
| Builtin_attributes.warning_scope pmd.pmd_attributes |
There was a problem hiding this comment.
I think it would be better to remove the warning scope here: the only entry point of the approx_* function is the approx_modtype function, and we agreed before that there should be no warnings here.
typing/typemod.ml
Outdated
| (extract_sig env smty.pmty_loc mty) in | ||
| let newenv = Env.add_signature sg env in | ||
| sg @ approx_sig newenv srem | ||
| Builtin_attributes.warning_scope sincl.pincl_attributes |
There was a problem hiding this comment.
Same thing as above: approx functions should probably not concern themselves with warnings .
Actually, it is currently impossible to attach attributes to type parameters (it's really a hack to encode them as type expressions in the Parsetree -- and the type checker should report a proper error for unsupported cases instead of a failed assertion). Still, I've added some code to dead with such attributes, to be more future proof (it would probably be quite useful for ppx to allow attributes there, btw). Note that warnings could be raised by |
|
Thanks @trefis and @Octachron! @Octachron : if you are ok with my recent changes following you observations, can you approve the PR so that I can merge it? |
Previously, there was a dedicated traversal of the Parsetree to collect and report all ocaml.ppwarning attributes. This approach has the drawback that ocaml.warning settings for the current scope around the ocaml.ppwarnign attribute were not taken into account. Thanks to previous commits, we have a specific place in the code were all attributes go through. So we re-use it to detect ocaml.ppwarning attributes, completely avoiding the dedicated traversal and the drawback mentioned above.
c717733 to
893c2bb
Compare
|
Rebased to trunk. |
Octachron
left a comment
There was a problem hiding this comment.
LGTM (once the typing-deprecated test is fixed).
| [%%expect{| | ||
| Line _, characters 26-29: | ||
| Warning 3: deprecated: X.t | ||
| Line _, characters 26-29: |
There was a problem hiding this comment.
This repeated warning message is no longer here.
This commit includes the following changes:
Some internal cleanup in the implementation of ocaml.warning/ocaml.warnerror.
Extend the support for those attributes in all attribute contexts. For instance, with this PR,
[@ocaml.warning "-3"]can be used on a type expression. See Avoid "internal" deprecation warnings #1237 for a discussion on the need for this feature.Re-implement the support for ocaml.ppwarning so that the warning raised by this attribute
are properly scoped by surrounding ocaml.warning/ocaml.warnerror attribute. This benefits from the machinery put in place for the bullet above, and the new implementation is simpler and more efficient than the previous one (dedicated traversal over the AST). Fixes https://caml.inria.fr/mantis/view.php?id=7361
This is now ready for review.