diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 980a61ef0..cbee8c018 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -63,7 +63,7 @@
- [Closure expressions](expressions/closure-expr.md)
- [Loop expressions](expressions/loop-expr.md)
- [Range expressions](expressions/range-expr.md)
- - [If and if let expressions](expressions/if-expr.md)
+ - [If expressions](expressions/if-expr.md)
- [Match expressions](expressions/match-expr.md)
- [Return expressions](expressions/return-expr.md)
- [Await expressions](expressions/await-expr.md)
diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md
index a6f05d788..0a3d4f15f 100644
--- a/src/attributes/type_system.md
+++ b/src/attributes/type_system.md
@@ -206,7 +206,6 @@ let _ = EnumWithNonExhaustiveVariants::First as u8;
Non-exhaustive types are always considered inhabited in downstream crates.
-[`if let`]: ../expressions/if-expr.md#if-let-expressions
[`match`]: ../expressions/match-expr.md
[attributes]: ../attributes.md
[enum]: ../items/enumerations.md
diff --git a/src/const_eval.md b/src/const_eval.md
index 07f704512..33d562e22 100644
--- a/src/const_eval.md
+++ b/src/const_eval.md
@@ -102,10 +102,10 @@ r[const-eval.const-expr.const-fn]
* Calls of [const functions] and const methods.
r[const-eval.const-expr.loop]
-* [loop], [while] and [`while let`] expressions.
+* [loop] and [while] expressions.
r[const-eval.const-expr.if-match]
-* [if], [`if let`] and [match] expressions.
+* [if] and [match] expressions.
r[const-eval.const-context]
## Const context
@@ -185,7 +185,6 @@ of whether you are building on a `64` bit or a `32` bit system.
[grouped]: expressions/grouped-expr.md
[interior mutability]: interior-mutability.md
[if]: expressions/if-expr.md#if-expressions
-[`if let`]: expressions/if-expr.md#if-let-expressions
[lazy boolean]: expressions/operator-expr.md#lazy-boolean-operators
[let statements]: statements.md#let-statements
[literals]: expressions/literal-expr.md
@@ -202,4 +201,3 @@ of whether you are building on a `64` bit or a `32` bit system.
[struct]: expressions/struct-expr.md
[tuple expressions]: expressions/tuple-expr.md
[while]: expressions/loop-expr.md#predicate-loops
-[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
diff --git a/src/destructors.md b/src/destructors.md
index 2f4711815..dbf1dcd1d 100644
--- a/src/destructors.md
+++ b/src/destructors.md
@@ -67,8 +67,9 @@ leaves a drop scope all variables associated to that scope are dropped in
reverse order of declaration (for variables) or creation (for temporaries).
r[destructors.scope.desugaring]
-Drop scopes are determined after replacing [`for`], [`if let`], and
-[`while let`] expressions with the equivalent expressions using [`match`].
+Drop scopes can be determined by replacing [`for`], [`if`], and [`while`]
+expressions with equivalent expressions using [`match`], [`loop`] and
+`break`.
r[destructors.scope.operators]
Overloaded operators are not distinguished from built-in operators and [binding
@@ -203,11 +204,11 @@ smallest scope that contains the expression and is one of the following:
* A statement.
* The body of an [`if`], [`while`] or [`loop`] expression.
* The `else` block of an `if` expression.
-* The condition expression of an `if` or `while` expression, or a `match`
- guard.
+* The non-pattern matching condition expression of an `if` or `while` expression,
+ or a `match` guard.
* The body expression for a match arm.
* Each operand of a [lazy boolean expression].
-* The pattern-matching condition and consequent body of [`if let`] ([destructors.scope.temporary.edition2024]).
+* The pattern-matching condition(s) and consequent body of [`if`] ([destructors.scope.temporary.edition2024]).
* The entirety of the tail expression of a block ([destructors.scope.temporary.edition2024]).
> [!NOTE]
@@ -479,10 +480,10 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
[tuple indexing expression]: expressions/tuple-expr.md#tuple-indexing-expressions
[`for`]: expressions/loop-expr.md#iterator-loops
-[`if let`]: expressions/if-expr.md#if-let-expressions
+[`if let`]: expressions/if-expr.md#if-let-patterns
[`if`]: expressions/if-expr.md#if-expressions
[`let` statement]: statements.md#let-statements
[`loop`]: expressions/loop-expr.md#infinite-loops
[`match`]: expressions/match-expr.md
-[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
+[`while let`]: expressions/loop-expr.md#while-let-patterns
[`while`]: expressions/loop-expr.md#predicate-loops
diff --git a/src/expressions.md b/src/expressions.md
index b82f3b52e..eacf005e9 100644
--- a/src/expressions.md
+++ b/src/expressions.md
@@ -41,7 +41,6 @@ ExpressionWithBlock ->
| UnsafeBlockExpression
| LoopExpression
| IfExpression
- | IfLetExpression
| MatchExpression
)
```
@@ -311,9 +310,9 @@ They are never allowed before:
[`Copy`]: special-types-and-traits.md#copy
[`Drop`]: special-types-and-traits.md#drop
-[`if let`]: expressions/if-expr.md#if-let-expressions
+[`if let`]: expressions/if-expr.md#if-let-patterns
[`Sized`]: special-types-and-traits.md#sized
-[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
+[`while let`]: expressions/loop-expr.md#while-let-patterns
[array expressions]: expressions/array-expr.md
[array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions
[assign]: expressions/operator-expr.md#assignment-expressions
diff --git a/src/expressions/block-expr.md b/src/expressions/block-expr.md
index 0a63e7272..da0f93b36 100644
--- a/src/expressions/block-expr.md
+++ b/src/expressions/block-expr.md
@@ -258,7 +258,7 @@ r[expr.block.attributes.inner-attributes]
[Inner attributes] are allowed directly after the opening brace of a block expression in the following situations:
* [Function] and [method] bodies.
-* Loop bodies ([`loop`], [`while`], [`while let`], and [`for`]).
+* Loop bodies ([`loop`], [`while`], and [`for`]).
* Block expressions used as a [statement].
* Block expressions as elements of [array expressions], [tuple expressions],
[call expressions], and tuple-style [struct] expressions.
@@ -282,7 +282,6 @@ fn is_unix_platform() -> bool {
[`for`]: loop-expr.md#iterator-loops
[`loop`]: loop-expr.md#infinite-loops
[`unsafe` blocks]: ../unsafe-keyword.md#unsafe-blocks-unsafe-
-[`while let`]: loop-expr.md#predicate-pattern-loops
[`while`]: loop-expr.md#predicate-loops
[array expressions]: array-expr.md
[call expressions]: call-expr.md
diff --git a/src/expressions/if-expr.md b/src/expressions/if-expr.md
index dca3538d8..37e7d707c 100644
--- a/src/expressions/if-expr.md
+++ b/src/expressions/if-expr.md
@@ -1,34 +1,55 @@
r[expr.if]
-# `if` and `if let` expressions
-
-## `if` expressions
+# `if` expressions
r[expr.if.syntax]
```grammar,expressions
IfExpression ->
- `if` Expression _except [StructExpression]_ BlockExpression
- (`else` ( BlockExpression | IfExpression | IfLetExpression ) )?
+ `if` Conditions BlockExpression
+ (`else` ( BlockExpression | IfExpression ) )?
+
+Conditions ->
+ Expression _except [StructExpression]_
+ | LetChain
+
+LetChain -> LetChainCondition ( `&&` LetChainCondition )*
+
+LetChainCondition ->
+ Expression _except [ExcludedConditions]_
+ | OuterAttribute* `let` Pattern `=` Scrutinee _except [ExcludedConditions]_
+
+@root ExcludedConditions ->
+ StructExpression
+ | LazyBooleanExpression
+ | RangeExpr
+ | RangeFromExpr
+ | RangeInclusiveExpr
+ | AssignmentExpression
+ | CompoundAssignmentExpression
```
-
+
r[expr.if.intro]
-An `if` expression is a conditional branch in program control.
-The syntax of an `if` expression is a condition operand, followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block.
+The syntax of an `if` expression is a sequence of one or more condition operands separated by `&&`,
+followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block.
-r[expr.if.condition-bool]
-The condition operands must have the [boolean type].
+r[expr.if.condition]
+Condition operands must be either an [_Expression_] with a [boolean type] or a conditional `let` match.
r[expr.if.condition-true]
-If a condition operand evaluates to `true`, the consequent block is executed and any subsequent `else if` or `else` block is skipped.
+If all of the condition operands evaluate to `true` and all of the `let` patterns successfully match their [scrutinee]s,
+the consequent block is executed and any subsequent `else if` or `else` block is skipped.
r[expr.if.else-if]
-If a condition operand evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated.
+If any condition operand evaluates to `false` or any `let` pattern does not match its scrutinee,
+the consequent block is skipped and any subsequent `else if` condition is evaluated.
r[expr.if.else]
If all `if` and `else if` conditions evaluate to `false` then any `else` block is executed.
r[expr.if.result]
-An if expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
+An `if` expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
r[expr.if.type]
An `if` expression must have the same type in all situations.
@@ -43,6 +64,7 @@ if x == 4 {
println!("x is something else");
}
+// `if` can be used as an expression.
let y = if 12 * 15 > 150 {
"Bigger"
} else {
@@ -52,31 +74,17 @@ assert_eq!(y, "Bigger");
```
r[expr.if.let]
-## `if let` expressions
-
-r[expr.if.let.syntax]
-```grammar,expressions
-IfLetExpression ->
- `if` `let` Pattern `=` Scrutinee _except [LazyBooleanExpression]_ BlockExpression
- (`else` ( BlockExpression | IfExpression | IfLetExpression ) )?
-```
+## `if let` patterns
r[expr.if.let.intro]
-An `if let` expression is semantically similar to an `if` expression but in place of a condition operand it expects the keyword `let` followed by a pattern, an `=` and a [scrutinee] operand.
-
-r[expr.if.let.pattern]
-If the value of the scrutinee matches the pattern, the corresponding block will execute.
+`let` patterns in an `if` condition allow binding new variables into scope when the pattern matches successfully.
-r[expr.if.let.else]
-Otherwise, flow proceeds to the following `else` block if it exists.
-
-r[expr.if.let.result]
-Like `if` expressions, `if let` expressions have a value determined by the block that is evaluated.
+The following examples illustrate bindings using `let` patterns:
```rust
let dish = ("Ham", "Eggs");
-// this body will be skipped because the pattern is refuted
+// This body will be skipped because the pattern is refuted.
if let ("Bacon", b) = dish {
println!("Bacon is served with {}", b);
} else {
@@ -84,7 +92,7 @@ if let ("Bacon", b) = dish {
println!("No bacon will be served");
}
-// this body will execute
+// This body will execute.
if let ("Ham", b) = dish {
println!("Ham is served with {}", b);
}
@@ -94,47 +102,9 @@ if let _ = 5 {
}
```
-r[expr.if.let.else-if]
-`if` and `if let` expressions can be intermixed:
-
-```rust
-let x = Some(3);
-let a = if let Some(1) = x {
- 1
-} else if x == Some(2) {
- 2
-} else if let Some(y) = x {
- y
-} else {
- -1
-};
-assert_eq!(a, 3);
-```
-
-r[expr.if.let.desugaring]
-An `if let` expression is equivalent to a [`match` expression] as follows:
-
-
-```rust,ignore
-if let PATS = EXPR {
- /* body */
-} else {
- /*else */
-}
-```
-
-is equivalent to
-
-
-```rust,ignore
-match EXPR {
- PATS => { /* body */ },
- _ => { /* else */ }, // () if there is no else
-}
-```
-
r[expr.if.let.or-pattern]
-Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
+Multiple patterns may be specified with the `|` operator.
+This has the same semantics as with `|` in [`match` expressions]:
```rust
enum E {
@@ -148,27 +118,85 @@ if let E::X(n) | E::Y(n) = v {
}
```
-r[expr.if.let.lazy-bool]
-The expression cannot be a [lazy boolean operator expression][expr.bool-logic].
-Use of a lazy boolean operator is ambiguous with a planned feature change of the language (the implementation of if-let chains - see [eRFC 2947][_eRFCIfLetChain_]).
-When lazy boolean operator expression is desired, this can be achieved by using parenthesis as below:
+r[expr.if.chains]
+## Chains of conditions
-
-```rust,ignore
-// Before...
-if let PAT = EXPR && EXPR { .. }
+r[expr.if.chains.intro]
+Multiple condition operands can be separated with `&&`.
-// After...
-if let PAT = ( EXPR && EXPR ) { .. }
+r[expr.if.chains.order]
+Similar to a `&&` [_LazyBooleanOperatorExpression_], each operand is evaluated from left-to-right until an operand evaluates as `false` or a `let` match fails,
+in which case the subsequent operands are not evaluated.
-// Before...
-if let PAT = EXPR || EXPR { .. }
+r[expr.if.chains.bindings]
+The bindings of each pattern are put into scope to be available for the next condition operand and the consequent block.
-// After...
-if let PAT = ( EXPR || EXPR ) { .. }
+The following is an example of chaining multiple expressions, mixing `let` bindings and boolean expressions, and with expressions able to reference pattern bindings from previous expressions:
+
+```rust
+fn single() {
+ let outer_opt = Some(Some(1i32));
+
+ if let Some(inner_opt) = outer_opt
+ && let Some(number) = inner_opt
+ && number == 1
+ {
+ println!("Peek a boo");
+ }
+}
```
-[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
-[`match` expression]: match-expr.md
+The above is equivalent to the following without using chains of conditions:
+
+```rust
+fn nested() {
+ let outer_opt = Some(Some(1i32));
+
+ if let Some(inner_opt) = outer_opt {
+ if let Some(number) = inner_opt {
+ if number == 1 {
+ println!("Peek a boo");
+ }
+ }
+ }
+}
+```
+
+r[expr.if.chains.or]
+If any condition operand is a `let` pattern, then none of the condition operands can be a `||` [lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with the `let` scrutinee.
+If a `||` expression is needed, then parentheses can be used. For example:
+
+```rust
+# let foo = Some(123);
+# let condition1 = true;
+# let condition2 = false;
+// Parentheses are required here.
+if let Some(x) = foo && (condition1 || condition2) { /*...*/ }
+```
+
+r[expr.if.edition2024]
+> [!EDITION-2024]
+> Before the 2024 edition, let chains are not supported. That is, the [LetChain] grammar is not allowed in an `if` expression.
+
+[_BlockExpression_]: block-expr.md
+[_Expression_]: ../expressions.md
+[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
+[_Pattern_]: ../patterns.md
+[_Scrutinee_]: match-expr.md
+[`match` expressions]: match-expr.md
[boolean type]: ../types/boolean.md
[scrutinee]: ../glossary.md#scrutinee
+
+
diff --git a/src/expressions/loop-expr.md b/src/expressions/loop-expr.md
index 310b3ad4d..ab15da5e2 100644
--- a/src/expressions/loop-expr.md
+++ b/src/expressions/loop-expr.md
@@ -7,23 +7,21 @@ LoopExpression ->
LoopLabel? (
InfiniteLoopExpression
| PredicateLoopExpression
- | PredicatePatternLoopExpression
| IteratorLoopExpression
| LabelBlockExpression
)
```
r[expr.loop.intro]
-Rust supports five loop expressions:
+Rust supports four loop expressions:
* A [`loop` expression](#infinite-loops) denotes an infinite loop.
* A [`while` expression](#predicate-loops) loops until a predicate is false.
-* A [`while let` expression](#predicate-pattern-loops) tests a pattern.
* A [`for` expression](#iterator-loops) extracts values from an iterator, looping until the iterator is empty.
* A [labelled block expression](#labelled-block-expressions) runs a loop exactly once, but allows exiting the loop early with `break`.
r[expr.loop.break-label]
-All five types of loop support [`break` expressions](#break-expressions), and [labels](#loop-labels).
+All four types of loop support [`break` expressions](#break-expressions), and [labels](#loop-labels).
r[expr.loop.continue-label]
All except labelled block expressions support [`continue` expressions](#continue-expressions).
@@ -52,18 +50,32 @@ A `loop` expression containing associated [`break` expression(s)](#break-express
r[expr.loop.while]
## Predicate loops
-r[expr.loop.while.syntax]
+r[expr.loop.while.grammar]
```grammar,expressions
-PredicateLoopExpression -> `while` Expression _except [StructExpression]_ BlockExpression
+PredicateLoopExpression -> `while` Conditions BlockExpression
```
-
r[expr.loop.while.intro]
-A `while` loop begins by evaluating the [boolean] loop conditional operand.
+A `while` loop expression allows repeating the evaluation of a block while a set of conditions remain true.
+
+r[expr.loop.while.syntax]
+The syntax of a `while` expression is a sequence of one or more condition operands separated by `&&`,
+followed by a [_BlockExpression_].
r[expr.loop.while.condition]
-If the loop conditional operand evaluates to `true`, the loop body block executes, then control returns to the loop conditional operand.
-If the loop conditional expression evaluates to `false`, the `while` expression completes.
+Condition operands must be either an [_Expression_] with a [boolean type] or a conditional `let` match.
+If all of the condition operands evaluate to `true` and all of the `let` patterns successfully match their [scrutinee]s,
+then the loop body block executes.
+
+r[expr.loop.while.repeat]
+After the loop body successfully executes, the condition operands are re-evaluated to determine if the body should be executed again.
+
+r[expr.loop.while.exit]
+If any condition operand evaluates to `false` or any `let` pattern does not match its scrutinee,
+the body is not executed and execution continues after the `while` expression.
+
+r[expr.loop.while.eval]
+A `while` expression evaluates to `()`.
An example:
@@ -77,20 +89,11 @@ while i < 10 {
```
r[expr.loop.while.let]
-## Predicate pattern loops
-
-r[expr.loop.while.let.syntax]
-```grammar,expressions
-PredicatePatternLoopExpression ->
- `while` `let` Pattern `=` Scrutinee _except [LazyBooleanExpression]_ BlockExpression
-```
+### `while let` patterns
r[expr.loop.while.let.intro]
-A `while let` loop is semantically similar to a `while` loop but in place of a condition expression it expects the keyword `let` followed by a pattern, an `=`, a [scrutinee] expression and a block expression.
-
-r[expr.loop.while.let.condition]
-If the value of the scrutinee matches the pattern, the loop body block executes then control returns to the pattern matching statement.
-Otherwise, the while expression completes.
+`let` patterns in a `while` condition allow binding new variables into scope when the pattern matches successfully.
+The following examples illustrate bindings using `let` patterns:
```rust
let mut x = vec![1, 2, 3];
@@ -139,8 +142,28 @@ while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
}
```
-r[expr.loop.while.let.lazy-bool]
-As is the case in [`if let` expressions], the scrutinee cannot be a [lazy boolean operator expression][expr.bool-logic].
+r[expr.loop.while.chains]
+### `while` condition chains
+
+r[expr.loop.while.chains.intro]
+Multiple condition operands can be separated with `&&`.
+These have the same semantics and restrictions as [`if` condition chains].
+
+The following is an example of chaining multiple expressions, mixing `let` bindings and boolean expressions, and with expressions able to reference pattern bindings from previous expressions:
+
+```rust
+fn main() {
+ let outer_opt = Some(Some(1i32));
+
+ while let Some(inner_opt) = outer_opt
+ && let Some(number) = inner_opt
+ && number == 1
+ {
+ println!("Peek a boo");
+ break;
+ }
+}
+```
r[expr.loop.for]
## Iterator loops
@@ -333,7 +356,7 @@ r[expr.loop.continue.intro]
When `continue` is encountered, the current iteration of the associated loop body is immediately terminated, returning control to the loop *head*.
r[expr.loop.continue.while]
-In the case of a `while` loop, the head is the conditional expression controlling the loop.
+In the case of a `while` loop, the head is the conditional operands controlling the loop.
r[expr.loop.continue.for]
In the case of a `for` loop, the head is the call-expression controlling the loop.
@@ -369,8 +392,25 @@ r[expr.loop.break-value.loop]
In the case a `loop` has an associated `break`, it is not considered diverging, and the `loop` must have a type compatible with each `break` expression.
`break` without an expression is considered identical to `break` with expression `()`.
+[_BlockExpression_]: block-expr.md
+[_Expression_]: ../expressions.md
+[`if` condition chains]: if-expr.md#chains-of-conditions
+[`if` expressions]: if-expr.md
[`match` expression]: match-expr.md
-[boolean]: ../types/boolean.md
+[boolean type]: ../types/boolean.md
[scrutinee]: ../glossary.md#scrutinee
[temporary values]: ../expressions.md#temporaries
-[`if let` expressions]: if-expr.md#if-let-expressions
+
+
diff --git a/src/expressions/struct-expr.md b/src/expressions/struct-expr.md
index 3c3dd15d4..afb555dc4 100644
--- a/src/expressions/struct-expr.md
+++ b/src/expressions/struct-expr.md
@@ -146,7 +146,7 @@ Point3d { x, y: y_value, z };
```
[enum variant]: ../items/enumerations.md
-[if let]: if-expr.md#if-let-expressions
+[if let]: if-expr.md#if-let-patterns
[if]: if-expr.md#if-expressions
[loop]: loop-expr.md
[match]: match-expr.md
diff --git a/src/names.md b/src/names.md
index 92d2cd82c..b9af0e535 100644
--- a/src/names.md
+++ b/src/names.md
@@ -135,13 +135,13 @@ to with certain [path qualifiers] or aliases.
[*visibility*]: visibility-and-privacy.md
[`'static`]: keywords.md#weak-keywords
[`for`]: expressions/loop-expr.md#iterator-loops
-[`if let`]: expressions/if-expr.md#if-let-expressions
+[`if let`]: expressions/if-expr.md#if-let-patterns
[`let` statement]: statements.md#let-statements
[`macro_export` attribute]: macros-by-example.md#path-based-scope
[`macro_rules` declarations]: macros-by-example.md
[`macro_use` attribute]: macros-by-example.md#the-macro_use-attribute
[`match`]: expressions/match-expr.md
-[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
+[`while let`]: expressions/loop-expr.md#while-let-patterns
[associated items]: items/associated-items.md
[attributes]: attributes.md
[Boolean type]: types/boolean.md
diff --git a/src/names/namespaces.md b/src/names/namespaces.md
index afe48a2e5..feb0e9771 100644
--- a/src/names/namespaces.md
+++ b/src/names/namespaces.md
@@ -123,14 +123,14 @@ It is still an error for a [`use` import] to shadow another macro, regardless of
[`cfg` attribute]: ../conditional-compilation.md#the-cfg-attribute
[`cfg` macro]: ../conditional-compilation.md#the-cfg-macro
[`for`]: ../expressions/loop-expr.md#iterator-loops
-[`if let`]: ../expressions/if-expr.md#if-let-expressions
+[`if let`]: ../expressions/if-expr.md#if-let-patterns
[`let`]: ../statements.md#let-statements
[`macro_rules` declarations]: ../macros-by-example.md
[`match`]: ../expressions/match-expr.md
[`Self` constructors]: ../paths.md#self-1
[`Self` type]: ../paths.md#self-1
[`use` import]: ../items/use-declarations.md
-[`while let`]: ../expressions/loop-expr.md#predicate-pattern-loops
+[`while let`]: ../expressions/loop-expr.md#while-let-patterns
[Associated const declarations]: ../items/associated-items.md#associated-constants
[Associated function declarations]: ../items/associated-items.md#associated-functions-and-methods
[Associated type declarations]: ../items/associated-items.md#associated-types
diff --git a/src/names/scopes.md b/src/names/scopes.md
index cfc5ffd30..0a7240512 100644
--- a/src/names/scopes.md
+++ b/src/names/scopes.md
@@ -49,9 +49,9 @@ r[names.scopes.pattern-bindings.parameter]
r[names.scopes.pattern-bindings.closure]
* [Closure parameter] bindings are within the closure body.
r[names.scopes.pattern-bindings.loop]
-* [`for`] and [`while let`] bindings are within the loop body.
-r[names.scopes.pattern-bindings.if-let]
-* [`if let`] bindings are within the consequent block.
+* [`for`] bindings are within the loop body.
+r[names.scopes.pattern-bindings.let-chains]
+* [`if let`] and [`while let`] bindings are valid in the following conditions as well as the consequent block.
r[names.scopes.pattern-bindings.match-arm]
* [`match` arms] bindings are within the [match guard] and the match arm expression.
@@ -340,14 +340,14 @@ impl ImplExample {
[`derive` attribute]: ../attributes/derive.md
[`for` loop]: ../expressions/loop-expr.md#iterator-loops
[`for`]: ../expressions/loop-expr.md#iterator-loops
-[`if let`]: ../expressions/if-expr.md#if-let-expressions
+[`if let`]: ../expressions/if-expr.md#if-let-patterns
+[`while let`]: ../expressions/loop-expr.md#while-let-patterns
[`let` statement]: ../statements.md#let-statements
[`macro_export`]: ../macros-by-example.md#path-based-scope
[`macro_use` prelude]: preludes.md#macro_use-prelude
[`macro_use`]: ../macros-by-example.md#the-macro_use-attribute
[`match` arms]: ../expressions/match-expr.md
[`Self`]: ../paths.md#self-1
-[`while let`]: ../expressions/loop-expr.md#predicate-pattern-loops
[Associated consts]: ../items/associated-items.md#associated-constants
[associated items]: ../items/associated-items.md
[Asterisk glob imports]: ../items/use-declarations.md
diff --git a/src/patterns.md b/src/patterns.md
index cda82076e..2d9ddb5ac 100644
--- a/src/patterns.md
+++ b/src/patterns.md
@@ -79,7 +79,7 @@ r[patterns.if-let]
* [`if let` expressions](expressions/if-expr.md)
r[patterns.while-let]
-* [`while let` expressions](expressions/loop-expr.md#predicate-pattern-loops)
+* [`while let` expressions](expressions/loop-expr.md#while-let-patterns)
r[patterns.for]
* [`for` expressions](expressions/loop-expr.md#iterator-loops)
diff --git a/src/tokens.md b/src/tokens.md
index 7dffe9f51..294753e69 100644
--- a/src/tokens.md
+++ b/src/tokens.md
@@ -1049,7 +1049,7 @@ r[lex.token.reserved-guards.edition2024]
[functions]: items/functions.md
[generics]: items/generics.md
[identifier]: identifiers.md
-[if let]: expressions/if-expr.md#if-let-expressions
+[if let]: expressions/if-expr.md#if-let-patterns
[Integer literal expressions]: expressions/literal-expr.md#integer-literal-expressions
[keywords]: keywords.md
[lazy-bool]: expressions/operator-expr.md#lazy-boolean-operators
@@ -1080,4 +1080,4 @@ r[lex.token.reserved-guards.edition2024]
[unary minus operator]: expressions/operator-expr.md#negation-operators
[use declarations]: items/use-declarations.md
[use wildcards]: items/use-declarations.md
-[while let]: expressions/loop-expr.md#predicate-pattern-loops
+[while let]: expressions/loop-expr.md#while-let-patterns