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

Do not trigger unused_braces for while let #75083

Merged
merged 1 commit into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,10 @@ trait UnusedDelimLint {
(cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
}

While(ref cond, ref block, ..) => {
// Do not lint `unused_braces` in `while let` expressions.
While(ref cond, ref block, ..)
if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
{
let left = e.span.lo() + rustc_span::BytePos(5);
let right = block.span.lo();
(cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right))
Expand Down
11 changes: 2 additions & 9 deletions src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,8 @@ fn main() {
while let Some(_) = ((yield)) {} //~ ERROR: unnecessary parentheses
{{yield}}; //~ ERROR: unnecessary braces
{( yield )}; //~ ERROR: unnecessary parentheses

// FIXME: Reduce duplicate warnings.
// Perhaps we should tweak checks in `BlockRetValue`?
while let Some(_) = {(yield)} {}
//~^ ERROR: unnecessary braces
//~| ERROR: unnecessary parentheses
while let Some(_) = {{yield}} {}
//~^ ERROR: unnecessary braces
//~| ERROR: unnecessary braces
while let Some(_) = {(yield)} {} //~ ERROR: unnecessary parentheses
while let Some(_) = {{yield}} {} //~ ERROR: unnecessary braces

// FIXME: It'd be great if we could also warn them.
((yield));
Expand Down
18 changes: 3 additions & 15 deletions src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,17 @@ error: unnecessary parentheses around block return value
LL | {( yield )};
| ^^^^^^^^^ help: remove these parentheses

error: unnecessary braces around `let` scrutinee expression
--> $DIR/issue-74883-unused-paren-baren-yield.rs:21:29
|
LL | while let Some(_) = {(yield)} {}
| ^^^^^^^^^ help: remove these braces

error: unnecessary parentheses around block return value
--> $DIR/issue-74883-unused-paren-baren-yield.rs:21:30
--> $DIR/issue-74883-unused-paren-baren-yield.rs:18:30
|
LL | while let Some(_) = {(yield)} {}
| ^^^^^^^ help: remove these parentheses

error: unnecessary braces around `let` scrutinee expression
--> $DIR/issue-74883-unused-paren-baren-yield.rs:24:29
|
LL | while let Some(_) = {{yield}} {}
| ^^^^^^^^^ help: remove these braces

error: unnecessary braces around block return value
--> $DIR/issue-74883-unused-paren-baren-yield.rs:24:30
--> $DIR/issue-74883-unused-paren-baren-yield.rs:19:30
|
LL | while let Some(_) = {{yield}} {}
| ^^^^^^^ help: remove these braces

error: aborting due to 8 previous errors
error: aborting due to 6 previous errors

12 changes: 12 additions & 0 deletions src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// check-pass

#![deny(unused_braces)]

fn main() {
let mut a = Some(3);
// Shouldn't warn below `a`.
while let Some(ref mut v) = {a} {
Copy link
Contributor

Choose a reason for hiding this comment

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

So it is not linted for unnamed struct literal in the future?

Copy link
Contributor

Choose a reason for hiding this comment

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

not quite sure what you mean here, we can't warn for { a } if it's used in patterns because it can
actually change the behavior there. From the docs

    /// Due to `ref` pattern, there can be a difference between using
    /// `{ expr }` and `expr` in pattern-matching contexts. This means
    /// that we should only lint `unused_parens` and not `unused_braces`
    /// in this case.
    ///
    /// ```rust
    /// let mut a = 7;
    /// let ref b = { a }; // We actually borrow a copy of `a` here.
    /// a += 1; // By mutating `a` we invalidate any borrows of `a`.
    /// assert_eq!(b + 1, a); // `b` does not borrow `a`, so we can still use it here.
    /// ```

Copy link
Contributor

@tesuji tesuji Aug 3, 2020

Choose a reason for hiding this comment

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

Playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d28588845e2466227a28572bb6929b30

What I trying to say is that currently we don't allow struct literals in if, while-let.

struct Foo {
     a: u32
}

fn foo() {
     while let Foo { a } = Foo { a: 42} {
          ()
     }
}

By enabling around { a }, unnamed structs in the future might be hard to be used/migrate.
I am not against this changes, also am not authorative.
What I want is improving the precision of the lint around {( yield )}.

Copy link
Contributor

Choose a reason for hiding this comment

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

So you want forbid while let pat = { a }?

I still can't completely follow you here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I think it kind of ambiguous in parsing. But I'm not authoritative here.
so let's cc parser devs like @petrochenkov @estebank

I'm sorry for causing this noise.

Copy link
Contributor

Choose a reason for hiding this comment

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

We already allow while let pat = { a } { /**/ } so I don't really think we can change that now

Copy link
Contributor

Choose a reason for hiding this comment

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

But with the unused braces warning people will feel discouraged to use it.

Copy link
Contributor

Choose a reason for hiding this comment

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

while let pat = { a } also doesn't cause ambiguity here as while let _ = expects expr { so the { of { a } must be part of expr here

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm kinda get it your point. Does it mean parsing unnamed structs at expr is unambiguous and allowed?
Even though struct literals are forbidden.

Copy link
Contributor

@lcnr lcnr Aug 3, 2020

Choose a reason for hiding this comment

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

But with the unused braces warning people will feel discouraged to use it.

The unused braces warning can break code here and imo rustc should try quite hard to not emit potentially incorrect warnings

a.as_mut().map(|a| std::mem::swap(a, v));
break;
}
}