Open Manishearth opened 3 years ago
cc @estebank
also cc @ehuss for thinking about what the UX would be like from cargo's perspective
Is there something on the rustc
side that needs to be done? We could add a new variant with a degree of confidence between MachineApplicable
and MaybeIncorrect
. We could have LikelyIncorrect
for things we have little confidence in and start applying MaybeIncorrect
on rustfix
's side.
@estebank no, I don't think that'll help. MaybeIncorrect already is that variant: there's another one for when you're absolutely sure it's incorrect. MaybeIncorrect is just when it's a bad idea to auto apply the fix without checking; because the fix may introduce semantic change (etc)
At least the way it's used in clippy, most MaybeIncorrects are not supposed to be blindly applied.
cc @rust-lang/clippy in case folks have opinions on whether we need additional suggestion applicability types
This should be entirely on the rustfix/cargo side I think.
I think to some extent rustfix already tries to skip applying lint results where the resulting code does not compile. I would love to be able to just throw everything at it and let rustc and rustfix figure it out by themselves. :D
The problem is that MaybeIncorrect is often not stuff that is incorrect because it won't compile, it's incorrect because it changed the semantics of the program in a way clippy thinks is according to intention but might not be
The problem is that MaybeIncorrect is often not stuff that is incorrect because it won't compile, it's incorrect because it changed the semantics of the program in a way clippy thinks is according to intention but might not be
In Clippy MaybeIncorrect
is used interchangeable for both cases. Sometimes we use it, if the suggestion might result in new errors (e.g. the borrow checker might complain or an additional (trait) import is needed). And sometimes, because it's a semantic change (e.g. removes a possibly panicking expression). At least, that's how I use it and recommend it in reviews.
So maybe splitting it up in MayIntroduceNewError
and SemanticChange
(with possibly better names) would make sense.
Both reasons might apply. That may be reason enough not to split it. Unless we say, "if it is maybe incorrect for multiple reasons, prefer X." Is the motivation for splitting to offer an explanation to the user? Maybe instead we could add a "incorrect reason" field. In fact, in reviews I've picked up the habit of making sure there is a code comment explaining MaybeIncorrect
.
Maybe instead we could add a "incorrect reason" field.
That also sounds reasonable to me. (Edit: no pun intended)
or apply them using a "pick and choose" mode
Especially this reason could be used in such a pick and choose prompt.
This suggestion was not automatically applied, because <reason>
Do you want to apply this suggestion anyway? (y/N)
For what it's worth, I think "may introduce error" can also be described as "maybe incomplete" - additional changes are necessary to "complete" the intended suggestion, like adding an import.
Ideally, we should provide a mode where you can apply them anyway (cargo clippy --fix --apply-all-suggestions?),
This exists today as __CARGO_FIX_YOLO=1
. It would be great to make that more discoverable with a CLI option.
@jyn514 what does the YOLO stand for ?
I think it tries to apply suggestions no matter what...? https://github.com/rust-lang/cargo/blob/50a0af4bfd47294f53cf3000e1a7e076162280c6/src/cargo/ops/fix.rs#L581
@jyn514 what does the YOLO stand for ?
Proabably “you only live once”, which is
a call to live life to its fullest extent, even embracing behavior which carries inherent risk
All the kids are saying it
@NikosEfthias sample usage:
I was supposed to check if I accidentally commited tax crimes today via armchair lawyering but we can just yolo that
@estebank @rust-lang/clippy it's been a while since it's been filed and there's some interest in exposing applicability levels to users. Before we do so, do y'all think it's worth splitting MaybeIncorrect into SemanticChange and MayIntroduceNewError?
Ideally the applicability exposition lets you choose how far you want to go.
I think it does make sense to split that. In Clippy, we use this level for both of those use cases interchangeably.
EDIT: Wait, I suggested that above. I couldn't remember that I did that 😅
In Clippy
MaybeIncorrect
is used interchangeable for both cases. Sometimes we use it, if the suggestion might result in new errors (e.g. the borrow checker might complain or an additional (trait) import is needed). And sometimes, because it's a semantic change (e.g. removes a possibly panicking expression). At least, that's how I use it and recommend it in reviews.So maybe splitting it up in
MayIntroduceNewError
andSemanticChange
(with possibly better names) would make sense.
Maybe we can do a nice audit to clippy to see which goes where. I wonder if that's something @3tilley is interested in looking in to
The way I see it is that there are three somewhat independent work items here:
Yeah, having that split makes sense to me. Migration is going to be annoying though.
Hello, I've been following this conversation but haven't had a chance to dig in properly. I YOLO'd this evening to help me with some module refactoring and it certainly did what it said on the tin. Just recording four and a half potential bugs here while I've got them in front of me. This is git bash running on regular Windows 10 for reference:
The u
from use
got dropped somehow:
Where use was required in multiple places, it was added multiple times:
This could have been because of poor code quality initially with non-standard imports, but it seems like use
sometimes reexports types from the module and sometimes takes them from the original crate? I'm not good enough at Rust to know exactly what's happening here, and what should happen:
Do macro import suggestions count as MaybeIncorrect
? YOLO wouldn't implement those suggestions, which perhaps means it doesn't?
I don't know if this is really a bug, but the format that was used for the use
lines seems a bit odd - lots of blank lines added between statements. Are fixes supposed to be rustfmt compatible?
I also agree with splitting MaybeIncorrect
. Perhaps MayFailToCompile
, MayChangeBehavior
and MayBeCounterproductive
(for things that might compile and keep behavior, but not help readability or perf).
How does splitting applicability improve UX? Or what problem does it solve?
We may use the split values for reporting. Users would likely be interested what they should expect. Also if we had a "might not compile, but if it does, it's OK" category, rustfix could try to auto-fix and back out on errors.
@camsteffen It lets users set some minimum applicability level with rustfix, instead of going with the default.
The way I see it, the applicabilities go in order of least to most applicable:
For example, quite often with the latter two I'm actually comfortable running rustfix on my codebase, with the former two I kinda want to review them case by case.
As a clippy user I would also be interested in a better handling of MaybeIncorrect
options. clippy::semicolon_if_nothing_returned
is the canonical example of the lint that if failing sometimes automatically is not an issue, and on a large codebase it's much easier to dealt with only the corner cases manually than all the occurrences.
The split of MaybeIncorrect
is probably worth being nominated in a clippy meeting?
Just chiming in, being able to say something like --try-anyway
even if it results in syntax errors etc. is still better than having to refactor 10,000 instances of something tedious (e.g. adding a generic to a deeply-coupled type).
This would also be useful for rustc tests. It's not always the case that a MaybeIncorrect
suggestion is incorrect, and you might want to add rustfix based tests for the cases where it is right, to ensure that there is no regression. e.g. I've filed https://github.com/rust-lang/rust/issues/105227 about an incorrect suggestion and the PR to fix it would benefit from a rustfix option to apply the suggestion.
@est31 compiletest applies all suggestions regardless of applicability with the run-rustfix
header. Only when using rustfix-only-machine-applicable
will it limit it to machine-applicable.
@ehuss oh it seems compiletest seems to use rustfix
as a crate and there you can tell it to apply MaybeIncorrect
suggestions. Thanks for the pointer!
Here's the current plan:
@veykril does this look OK to you from a rust-analyzer perspective? are these categories useful?
I'm not sure I understand "remove MachineApplicable". Isn't that the variant that is most useful? Did you maybe mean MaybeIncorrect?
Can you define exactly what these two categories mean? MaybeIncorrect
is often used for suggestions that are known to be outright buggy. I'm not sure that really fits PotentialCompileError
, which reads to me that rustc
is unable to provide a better suggestion.
Er, sorry, meant MaybeIncorrect
Can you define exactly what these two categories mean?
MaybeIncorrect
is often used for suggestions that are known to be outright buggy. I'm not sure that really fitsPotentialCompileError
, which reads to me thatrustc
is unable to provide a better suggestion.
It's an interesting point about suggestions that are outright buggy. Perhaps we should add a Nursery/Buggy category? Not sure. I kinda feel BehaviorChange covers that okayishly. Right now, MaybeIncorrect covers a lot of different types of incorrectness with lots of different implications on how people use the tooling. I'm not sure if Buggy and PotentialBehaviorChange have different implications on tooling use
We might want to have an explicit Applicability::Buggy
category. That would help rustfix to ignore them and is to audit them.
We might want to have an explicit
Applicability::Buggy
category. That would help rustfix to ignore them and is to audit them.
That's Unspecified
, no?
https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html
Here's the current plan:
* add PotentialBehaviorChange and PotentialCompileError. Keep MaybeIncorrect around for now. * PotentialCompileError is considered more machine applicable than PotentialBehaviorChange since the latter means both * do a campaign to migrate everyone * remove MaybeIncorrect * work with rustfix and RA for better UI
@Veykril does this look OK to you from a rust-analyzer perspective? are these categories useful?
I don't think rust-analyzer cares too much about this, I can't think of a direct use case for us here aside from maybe grouping quickfixes of these two kinds differently (r-a is doing a terrible job at categorizing quick fixes currently), as for both we'd want to show the user a quickfix in the UI (as we do with MaybeIncorrect
in general right now).
@jyn514 it could be, I'm not sure if we are using it that way though.
That's
Unspecified
, no?
I think Unspecified was for diagnostics that have not been vetted as to whether or not they work correctly. I believe that was used when the applicability system was put in, and there was a huge list of diagnostics to update, so Unspecified was the default until a more appropriate category could be determined.
The idea behind splitting is that MayNotCompile
suggestions may compile, and guarantee not to change behavior if they do. So a tool like rust fix could apply them, check compiling the result and roll them back on failure. On the other hand MayChangeBehavior
have no such guarantee.
Changing the names will help us keep track of which suggestions have been vetted.
I don't think rust-analyzer cares too much about this, I can't think of a direct use case for us here aside from maybe grouping quickfixes of these two kinds differently (r-a is doing a terrible job at categorizing quick fixes currently), as for both we'd want to show the user a quickfix in the UI (as we do with
MaybeIncorrect
in general right now).
Yeah I guess that r-a isn't batching things the way rustfix
does so it's all user-driven anyway.
The idea behind splitting is that
MayNotCompile
suggestions may compile, and guarantee not to change behavior if they do. So a tool like rust fix could apply them, check compiling the result and roll them back on failure. On the other handMayChangeBehavior
have no such guarantee.
It also means that the user workflow can be "run rustfix with PotentialCompileError
, and then manually fix any errors they see".
Whereas for PotentialBehaviorChange
the workflow will probably be to review them one by one, and ideally put them in a separate commit for cleaner review (as a reviewer I'd want the direct rustfix fixes in one commit, PotentialCompileError
fixups in another, and PotentialBehaviorChange
ones in a third)
We might want to have an explicit
Applicability::Buggy
category.
Unspecified
in Clippy is pretty much a shrug :shrug: for suggestions right now: no one spent time looking at the suggestion to categorize it.
That said, I don't think a Buggy
category would add much value here. I think, that every (potentially) "buggy" suggestion could be categorized into one of PotentialCompileError
, PotentialBehaviorChange
, or HasPlaceholder
. And if it is really impossible to tell where it should go, I think Unspecified
describes that pretty well.
cc @Muscraft
When the compiler or clippy produce suggestions, some of them are marked as MaybeIncorrect; i.e. the suggestion should probably not be automatically applied. rustfix currently doesn't touch these.
This leads to confusion like in https://github.com/rust-lang/cargo/issues/8806, and is somewhat frustrating. We should at the very least be clear that such suggestions were not applied.
Ideally, we should provide a mode where you can apply them anyway (
cargo clippy --fix --apply-all-suggestions
?), or apply them using a "pick and choose" mode. We can then mention it when people have suggestions that were not applied.See also: https://github.com/rust-lang/cargo/issues/13023