Skip to content
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

Generate correct suggestion with named arguments used positionally #99660

Merged
merged 3 commits into from
Jul 29, 2022

Conversation

PrestonFrom
Copy link
Contributor

Address issue #99265 by checking each positionally used argument
to see if the argument is named and adding a lint to use the name
instead. This way, when named arguments are used positionally in a
different order than their argument order, the suggested lint is
correct.

For example:

println!("{b} {}", a=1, b=2);

This will now generate the suggestion:

println!("{b} {a}", a=1, b=2);

Additionally, this check now also correctly replaces or inserts
only where the positional argument is (or would be if implicit).
Also, width and precision are replaced with their argument names
when they exists.

Since the issues were so closely related, this fix for issue #99265
also fixes issue #99266.

Fixes #99265
Fixes #99266

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jul 24, 2022
@rust-highfive
Copy link
Collaborator

r? @compiler-errors

(rust-highfive has picked a reviewer for you, use r? to override)

@rustbot
Copy link
Collaborator

rustbot commented Jul 24, 2022

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 24, 2022
@rust-log-analyzer

This comment has been minimized.

@PrestonFrom
Copy link
Contributor Author

@compiler-errors I just found a bug in how I'm getting the span for width and precision. Please hold off on reviewing!

@rust-log-analyzer

This comment has been minimized.

Address issue rust-lang#99265 by checking each positionally used argument
to see if the argument is named and adding a lint to use the name
instead. This way, when named arguments are used positionally in a
different order than their argument order, the suggested lint is
correct.

For example:
```
println!("{b} {}", a=1, b=2);
```
This will now generate the suggestion:
```
println!("{b} {a}", a=1, b=2);
```

Additionally, this check now also correctly replaces or inserts
only where the positional argument is (or would be if implicit).
Also, width and precision are replaced with their argument names
when they exists.

Since the issues were so closely related, this fix for issue rust-lang#99265
also fixes issue rust-lang#99266.

Fixes rust-lang#99265
Fixes rust-lang#99266
@PrestonFrom
Copy link
Contributor Author

@compiler-errors Figured out my bug! I think this is ready for a look now.

I am wondering if I should do a crater run to make avoid any issues like last time. Is there a way to do that in GitHub or do I need to do it locally?

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of initial nits, I am still reading thru this to make sure all the logic is correct.

compiler/rustc_builtin_macros/src/format.rs Outdated Show resolved Hide resolved
compiler/rustc_builtin_macros/src/format.rs Outdated Show resolved Hide resolved
@PrestonFrom
Copy link
Contributor Author

@compiler-errors thanks for the initial comments! Great idea on both of them.

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few more nits, still trying to wrap my head around all the logic here haha

) {
let named_arg = names
.iter()
.find(|name| name.deref().1.0 == format_argument_index)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why is this deref call needed? can you destructure things here, e.g.

.find(|(_, (idx, _))| idx == format_arg_idx)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

return Some(Span::new(
arg_span.lo() + BytePos(1),
arg_span.lo() + BytePos(1),
self.positional_named_arg_span.ctxt(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you using the ctxt and parent from self.positional_named_arg_span?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also probably just do arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First bit was a copy-and-paste error, I think, but the suggested replacement is much better!

// In the case of a named argument whose position is implicit, there will not be a span
// to replace. Instead, we insert the name after the `{`, which is the first character
// of arg_span.
if let Some(arg_span) = cx.arg_spans.get(self.cur_piece).copied() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
if let Some(arg_span) = cx.arg_spans.get(self.cur_piece).copied() {
if let Some(arg_span) = cx.arg_spans.get(self.cur_piece) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

// the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
// `Precision`.
if ty == PositionalNamedArgType::Precision {
inner_span_to_replace = inner_span_to_replace.map(|mut is| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny microscopic nit: can we do this without mutating, lol

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

cur_piece,
inner_span_to_replace,
replacement: named_arg.0.clone(),
positional_named_arg_span: named_arg.1.1.clone(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here re: destructuring

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

i,
named_arg_type,
self.curpiece,
inner_span.clone(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is inner_span not Copy? If not, then it probably can be.

Suggested change
inner_span.clone(),
*inner_span,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it is indeed copy!

@@ -1316,11 +1442,10 @@ pub fn expand_preparsed_format_args(
}

diag.emit();
} else if cx.invalid_refs.is_empty() && !named_arguments.is_empty() {
} else if cx.invalid_refs.is_empty() && cx.ecx.sess.err_count() == 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we suppress lints if we have errors? Can you describe what case(s) this prevents erroneous lints from being fired?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't know one way or another if lints are suppressed when there are errors -- it would make sense if that were the case. However, I had a test fail because it output this lint in addition to the error for positional arguments cannot follow named arguments. (This was in src/test/ui/macros/format-parse-errors.rs.)

@PrestonFrom
Copy link
Contributor Author

@compiler-errors Thank you for the comments! I think I go them all. I also added a new method with comment on the logic behind how it determines when a lint should be emitted. If the logic is still not making sense, please let me know!

@compiler-errors
Copy link
Member

Thanks, this looks good for now. rollup=never so it's easier to bisect later just in case we have more ICEs, though from the look of this code we probably shouldn't have more errors.

@bors r+ rollup=never

@bors
Copy link
Contributor

bors commented Jul 28, 2022

📌 Commit 1b2e05e has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 28, 2022
@bors
Copy link
Contributor

bors commented Jul 29, 2022

⌛ Testing commit 1b2e05e with merge ea6ab1b...

@bors
Copy link
Contributor

bors commented Jul 29, 2022

☀️ Test successful - checks-actions
Approved by: compiler-errors
Pushing ea6ab1b to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jul 29, 2022
@bors bors merged commit ea6ab1b into rust-lang:master Jul 29, 2022
@rustbot rustbot added this to the 1.64.0 milestone Jul 29, 2022
| -- ^^ this named argument is only referred to by position in formatting string
| |
| this formatting argument uses named argument `_x` by position
| - ^^ this named argument is only referred to by position in formatting string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the span change only underlining the closing } expected ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lqd
Basically yes, because that's where the named argument gets inserted. But now that you've commented on it, I think it should probably underline both.

I think I will have time to fix this today.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took a little longer than I expected!
#99958

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (ea6ab1b): comparison url.

Instruction count

  • Primary benchmarks: no relevant changes found
  • Secondary benchmarks: 😿 relevant regression found
mean1 max count2
Regressions 😿
(primary)
N/A N/A 0
Regressions 😿
(secondary)
0.2% 0.2% 1
Improvements 🎉
(primary)
N/A N/A 0
Improvements 🎉
(secondary)
N/A N/A 0
All 😿🎉 (primary) N/A N/A 0

Max RSS (memory usage)

Results
  • Primary benchmarks: 😿 relevant regression found
  • Secondary benchmarks: 😿 relevant regression found
mean1 max count2
Regressions 😿
(primary)
2.9% 2.9% 1
Regressions 😿
(secondary)
2.1% 2.1% 1
Improvements 🎉
(primary)
N/A N/A 0
Improvements 🎉
(secondary)
N/A N/A 0
All 😿🎉 (primary) 2.9% 2.9% 1

Cycles

Results
  • Primary benchmarks: mixed results
  • Secondary benchmarks: no relevant changes found
mean1 max count2
Regressions 😿
(primary)
2.1% 2.1% 1
Regressions 😿
(secondary)
N/A N/A 0
Improvements 🎉
(primary)
-9.3% -9.3% 1
Improvements 🎉
(secondary)
N/A N/A 0
All 😿🎉 (primary) -3.6% -9.3% 2

If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf.

@rustbot label: -perf-regression

Footnotes

  1. the arithmetic mean of the percent change 2 3

  2. number of relevant changes 2 3

flip1995 pushed a commit to flip1995/rust that referenced this pull request Aug 11, 2022
…rrors

Generate correct suggestion with named arguments used positionally

Address issue rust-lang#99265 by checking each positionally used argument
to see if the argument is named and adding a lint to use the name
instead. This way, when named arguments are used positionally in a
different order than their argument order, the suggested lint is
correct.

For example:
```
println!("{b} {}", a=1, b=2);
```
This will now generate the suggestion:
```
println!("{b} {a}", a=1, b=2);
```

Additionally, this check now also correctly replaces or inserts
only where the positional argument is (or would be if implicit).
Also, width and precision are replaced with their argument names
when they exists.

Since the issues were so closely related, this fix for issue rust-lang#99265
also fixes issue rust-lang#99266.

Fixes rust-lang#99265
Fixes rust-lang#99266
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
8 participants