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

Suggest turning if let into irrefutable let if appropriate #120479

Merged
merged 1 commit into from
Feb 7, 2024

Conversation

estebank
Copy link
Contributor

When encountering an if let tail expression without an else arm for an enum with a single variant, suggest writing an irrefutable let binding instead.

error[E0317]: `if` may be missing an `else` clause
  --> $DIR/irrefutable-if-let-without-else.rs:8:5
   |
LL |   fn foo(x: Enum) -> i32 {
   |                      --- expected `i32` because of this return type
LL | /     if let Enum::Variant(value) = x {
LL | |         value
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
   = note: `if` expressions without `else` evaluate to `()`
   = help: consider adding an `else` block that evaluates to the expected type
help: consider using an irrefutable `let` binding instead
   |
LL ~     let Enum::Variant(value) = x;
LL ~         value
   |

Fix #61788.

@rustbot
Copy link
Collaborator

rustbot commented Jan 29, 2024

r? @wesleywiser

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 29, 2024
@estebank
Copy link
Contributor Author

If this is too much logic for little gain, we can still close #61788, as the help and note that weren't present in the original report can also be claimed to fix the issue.

@workingjubilee workingjubilee changed the title Suggest turnging if let into irrefutable let if appropriate Suggest turning if let into irrefutable let if appropriate Jan 30, 2024
Comment on lines 340 to 345
let padding = self
.tcx
.sess
.source_map()
.indentation_before(first.span)
.unwrap_or_else(|| String::new());
Copy link
Member

Choose a reason for hiding this comment

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

Just an idle thought but I wonder if we should have an extension trait specifically for use in diagnostics that can provide some of this boilerplate functionality? As another example of a similar thing, the idiom used to test if a type implements a specific trait that sometimes appears in diagnostics is also a bit cryptic and would be neater if factored behind a well named function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@wesleywiser yeah. There are a couple of methods to check for "type implements trait?", but they are not always available in all stages. We should probably audit all cases and unify functionality behind a handful of easier to use methods. It is a bit complicated by the needs of diagnostics, where sometimes we want to be maximally inclusive (accepting things that could implement, but we don't know for sure) or maximally exclusive (accepting only things that we know for sure implement, to avoid invalid suggestions).

compiler/rustc_hir_typeck/src/_match.rs Outdated Show resolved Hide resolved
When encountering an `if let` tail expression without an `else` arm for an
enum with a single variant, suggest writing an irrefutable `let` binding
instead.

```
error[E0317]: `if` may be missing an `else` clause
  --> $DIR/irrefutable-if-let-without-else.rs:8:5
   |
LL |   fn foo(x: Enum) -> i32 {
   |                      --- expected `i32` because of this return type
LL | /     if let Enum::Variant(value) = x {
LL | |         value
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
   = note: `if` expressions without `else` evaluate to `()`
   = help: consider adding an `else` block that evaluates to the expected type
help: consider using an irrefutable `let` binding instead
   |
LL ~     let Enum::Variant(value) = x;
LL ~         value
   |
```

Fix rust-lang#61788.
@wesleywiser
Copy link
Member

Thanks @estebank 💯

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Feb 7, 2024

📌 Commit a939bad has been approved by wesleywiser

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 Feb 7, 2024
Nadrieril added a commit to Nadrieril/rust that referenced this pull request Feb 7, 2024
Suggest turning `if let` into irrefutable `let` if appropriate

When encountering an `if let` tail expression without an `else` arm for an enum with a single variant, suggest writing an irrefutable `let` binding instead.

```
error[E0317]: `if` may be missing an `else` clause
  --> $DIR/irrefutable-if-let-without-else.rs:8:5
   |
LL |   fn foo(x: Enum) -> i32 {
   |                      --- expected `i32` because of this return type
LL | /     if let Enum::Variant(value) = x {
LL | |         value
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
   = note: `if` expressions without `else` evaluate to `()`
   = help: consider adding an `else` block that evaluates to the expected type
help: consider using an irrefutable `let` binding instead
   |
LL ~     let Enum::Variant(value) = x;
LL ~         value
   |
```

Fix rust-lang#61788.
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 7, 2024
Rollup of 13 pull requests

Successful merges:

 - rust-lang#110482 (Add armv8r-none-eabihf target for the Cortex-R52.)
 - rust-lang#119162 (Add unstable `-Z direct-access-external-data` cmdline flag for `rustc`)
 - rust-lang#120302 (various const interning cleanups)
 - rust-lang#120455 ( Add FileCheck annotations to MIR-opt SROA tests)
 - rust-lang#120470 (Mark "unused binding" suggestion as maybe incorrect)
 - rust-lang#120479 (Suggest turning `if let` into irrefutable `let` if appropriate)
 - rust-lang#120564 (coverage: Split out counter increment sites from BCB node/edge counters)
 - rust-lang#120633 (pattern_analysis: gather up place-relevant info)
 - rust-lang#120664 (Add parallel rustc ui tests)
 - rust-lang#120721 (fix `llvm_out` to use the correct LLVM root)
 - rust-lang#120726 (Don't use bashism in checktools.sh)
 - rust-lang#120733 (MirPass: make name more const)
 - rust-lang#120735 (Remove some `unchecked_claim_error_was_emitted` calls)

Failed merges:

 - rust-lang#120727 (exhaustiveness: Prefer "`0..MAX` not covered" to "`_` not covered")

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 7, 2024
Rollup of 13 pull requests

Successful merges:

 - rust-lang#110482 (Add armv8r-none-eabihf target for the Cortex-R52.)
 - rust-lang#119162 (Add unstable `-Z direct-access-external-data` cmdline flag for `rustc`)
 - rust-lang#120302 (various const interning cleanups)
 - rust-lang#120455 ( Add FileCheck annotations to MIR-opt SROA tests)
 - rust-lang#120470 (Mark "unused binding" suggestion as maybe incorrect)
 - rust-lang#120479 (Suggest turning `if let` into irrefutable `let` if appropriate)
 - rust-lang#120564 (coverage: Split out counter increment sites from BCB node/edge counters)
 - rust-lang#120633 (pattern_analysis: gather up place-relevant info)
 - rust-lang#120664 (Add parallel rustc ui tests)
 - rust-lang#120726 (Don't use bashism in checktools.sh)
 - rust-lang#120733 (MirPass: make name more const)
 - rust-lang#120735 (Remove some `unchecked_claim_error_was_emitted` calls)
 - rust-lang#120746 (Record coroutine kind in coroutine generics)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit cc7edbc into rust-lang:master Feb 7, 2024
11 checks passed
@rustbot rustbot added this to the 1.78.0 milestone Feb 7, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Feb 7, 2024
Rollup merge of rust-lang#120479 - estebank:issue-61788, r=wesleywiser

Suggest turning `if let` into irrefutable `let` if appropriate

When encountering an `if let` tail expression without an `else` arm for an enum with a single variant, suggest writing an irrefutable `let` binding instead.

```
error[E0317]: `if` may be missing an `else` clause
  --> $DIR/irrefutable-if-let-without-else.rs:8:5
   |
LL |   fn foo(x: Enum) -> i32 {
   |                      --- expected `i32` because of this return type
LL | /     if let Enum::Variant(value) = x {
LL | |         value
LL | |     }
   | |_____^ expected `i32`, found `()`
   |
   = note: `if` expressions without `else` evaluate to `()`
   = help: consider adding an `else` block that evaluates to the expected type
help: consider using an irrefutable `let` binding instead
   |
LL ~     let Enum::Variant(value) = x;
LL ~         value
   |
```

Fix rust-lang#61788.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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
Development

Successfully merging this pull request may close these issues.

Irrefutable if let on a single-variant enum only produces () value
4 participants