Commit Graph

230 Commits

Author SHA1 Message Date
arferreira 407e421f7f Unify same-span labels in move error diagnostics 2026-03-10 09:35:03 -04:00
mu001999 0436634084 Remove unused features in tests 2026-03-04 08:06:45 +08:00
Guillaume Gomez bca1cb4c2f Replace emit_span_lint with emit_span_diag_lint in rustc_lint 2026-02-26 09:32:23 +01:00
bors e0cb264b81 Auto merge of #141295 - Kivooeo:if-let-guard-stable, r=fee1-dead,est31
Stabilize `if let` guards (`feature(if_let_guard)`)



## Summary

This proposes the stabilization of `if let` guards (tracking issue: rust-lang/rust#51114, RFC: rust-lang/rfcs#2294). This feature allows `if let` expressions to be used directly within match arm guards, enabling conditional pattern matching within guard clauses.

## What is being stabilized

The ability to use `if let` expressions within match arm guards.

Example:

```rust
enum Command {
    Run(String),
    Stop,
    Pause,
}

fn process_command(cmd: Command, state: &mut String) {
    match cmd {
        Command::Run(name) if let Some(first_char) = name.chars().next() && first_char.is_ascii_alphabetic() => {
            // Both `name` and `first_char` are available here
            println!("Running command: {} (starts with '{}')", name, first_char);
            state.push_str(&format!("Running {}", name));
        }
        Command::Run(name) => {
            println!("Cannot run command '{}'. Invalid name.", name);
        }
        Command::Stop if state.contains("running") => {
            println!("Stopping current process.");
            state.clear();
        }
        _ => {
            println!("Unhandled command or state.");
        }
    }
}
```

## Motivation

The primary motivation for `if let` guards is to reduce nesting and improve readability when conditional logic depends on pattern matching. Without this feature, such logic requires nested `if let` statements within match arms:

```rust
// Without if let guards
match value {
    Some(x) => {
        if let Ok(y) = compute(x) {
            // Both `x` and `y` are available here
            println!("{}, {}", x, y);
        }
    }
    _ => {}
}

// With if let guards
match value {
    Some(x) if let Ok(y) = compute(x) => {
        // Both `x` and `y` are available here
        println!("{}, {}", x, y);
    }
    _ => {}
}
```

## Implementation and Testing

The feature has been implemented and tested comprehensively across different scenarios:

### Core Functionality Tests

**Scoping and variable binding:**
- [`scope.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/scope.rs) - Verifies that bindings created in `if let` guards are properly scoped and available in match arms
- [`shadowing.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs) - Tests that variable shadowing works correctly within guards
- [`scoping-consistency.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/scoping-consistency.rs) - Ensures temporaries in guards remain valid for the duration of their match arms

**Type system integration:**
- [`type-inference.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/type-inference.rs) - Confirms type inference works correctly in `if let` guards  
- [`typeck.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/typeck.rs) - Verifies type mismatches are caught appropriately

**Pattern matching semantics:**
- [`exhaustive.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/exhaustive.rs) - Validates that `if let` guards are correctly handled in exhaustiveness analysis
- [`move-guard-if-let.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let.rs) and [`move-guard-if-let-chain.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs) - Test that conditional moves in guards are tracked correctly by the borrow checker

### Error Handling and Diagnostics

- [`warns.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/warns.rs) - Tests warnings for irrefutable patterns and unreachable code in guards
- [`parens.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs) - Ensures parentheses around `let` expressions are properly rejected
- [`macro-expanded.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs) - Verifies macro expansions that produce invalid constructs are caught
- [`guard-mutability-2.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/guard-mutability-2.rs) - Tests mutability and ownership violations in guards
- [`ast-validate-guards.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs) - Validates AST-level syntax restrictions

### Drop Order and Temporaries

**Key insight:** Unlike `let_chains` in regular `if` expressions, `if let` guards do not have drop order inconsistencies because:
1. Match guards are clearly scoped to their arms
2. There is no "else block" equivalent that could cause temporal confusion

- [`drop-order.rs`](https://github.com/rust-lang/rust/blob/5796073c134eaac30475f9a19462c4e716c9119c/tests/ui/rfcs/rfc-2294-if-let-guard/drop-order.rs) - Check drop order of temporaries create in match guards
- [`compare-drop-order.rs`](https://github.com/rust-lang/rust/blob/aef3f5fdf052fbbc16e174aef5da6d50832ca316/tests/ui/rfcs/rfc-2294-if-let-guard/compare-drop-order.rs) - Compares drop order between `if let` guards and nested `if let` in match arms, confirming they behave identically across all editions
- rust-lang/rust#140981 - A complicated drop order test involved `let chain` was made by @est31
- [`drop-order-comparisons-let-chains.rs`](https://github.com/rust-lang/rust/blob/902b4d28783e03e231d8513082cc30c4fcce5d95/tests/ui/drop/drop-order-comparisons-let-chains.rs) - Compares drop order between `let chains` in `if let guard` and regular `if` expressions
- [`if-let-guards.rs`](https://github.com/rust-lang/rust/blob/5650d716e0589e2e145ce9027f35bd534e5f862a/tests/ui/drop/if-let-guards.rs) - Test correctness of drop order for bindings and temporaries
- [`if-let-guards-2`](https://github.com/rust-lang/rust/blob/3a6c8c8f3d7ae654fdb6ce1255182bda21680655/tests/ui/drop/if-let-guards-2.rs) - The same test as above but more comprehensive and tests more interactions between different features and their drop order, checking that drop order is correct, created by @traviscross 

## Edition Compatibility

This feature stabilizes on all editions, unlike `let chains` which was limited to edition 2024. This is safe because:

1. `if let` guards don't suffer from the drop order issues that affected `let chains` in regular `if` expressions
2. The scoping is unambiguous - guards are clearly tied to their match arms
3. Extensive testing confirms identical behavior across all editions

## Interactions with Future Features

The lang team has reviewed potential interactions with planned "guard patterns" and determined that stabilizing `if let` guards now does not create obstacles for future work. The scoping and evaluation semantics established here align with what guard patterns will need.

## Unresolved Issues

- [x] - rust-lang/rust#140981
- [x] - added tests description by @jieyouxu request
- [x] - Concers from @scottmcm about stabilizing this across all editions
- [x] - check if drop order in all edition when using `let chains` inside `if let` guard is the same
- [x] - interactions with guard patters
- [x] - pattern bindings drops before guard bindings https://github.com/rust-lang/rust/pull/143376
- [x] - documentaion (https://github.com/rust-lang/reference/pull/1957)
- [ ] (non-blocking) add tests for [this](https://github.com/rust-lang/rust/issues/145237) and [this](https://github.com/rust-lang/rust/pull/141295#issuecomment-3173059821)

---

**Related:**
- Tracking Issue: rust-lang/rust#51114  
- RFC: rust-lang/rfcs#2294
- Documentation PR: https://github.com/rust-lang/reference/pull/1957
2026-02-18 20:49:50 +00:00
Ralf Jung 5e65109f21 add write_box_via_move intrinsic and use it for vec!
This allows us to get rid of box_new entirely
2026-02-16 17:27:40 +01:00
Kivooeo 964b63f42e if let guard stabilize 2026-02-16 12:24:15 +00:00
bors 3f808f29e6 Auto merge of #152602 - jhpratt:rollup-uaxGseW, r=jhpratt
Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#151998 (Set hidden visibility on naked functions in compiler-builtins)
 - rust-lang/rust#149460 (rustdoc: sort stable items first)
 - rust-lang/rust#152076 (Feed `ErrorGuaranteed` from late lifetime resolution errors through to bound variable resolution)
 - rust-lang/rust#152471 (improve associated-type suggestions from bounds)
 - rust-lang/rust#152573 (move `escape_symbol_name` to `cg_ssa`)
 - rust-lang/rust#152594 (c-variadic: implement `va_arg` for `wasm64`)
 - rust-lang/rust#151386 (rustdoc: more js cleanup)
 - rust-lang/rust#152567 (nix-dev-shell: fix a typo)
 - rust-lang/rust#152568 (Port `#[lang]` and `#[panic_handler]` to the new attribute parsers)
 - rust-lang/rust#152575 (layout_of unexpected rigid alias delayed bug)
 - rust-lang/rust#152587 (A couple of tiny polonius things)
2026-02-14 06:23:09 +00:00
Rémy Rakic 65eb2e709d add another NLL problem case 3 variant 2026-02-13 17:29:49 +00:00
Shoyu Vanilla f5a8b86695 WF check lifetime bounds for locals with type params 2026-02-13 00:33:47 +09:00
Stuart Cook b4f8dc726f Rollup merge of #148718 - estebank:macro-spans, r=nnethercote
Do not mention `-Zmacro-backtrace` for std macros that are a wrapper around a compiler intrinsic
2026-01-27 12:50:50 +11:00
Esteban Küber 4a27be6972 Do not mention -Zmacro-backtrace for std macros that are a wrapper around a compiler intrinsic 2026-01-26 17:34:31 +00:00
Boxy dab7c0923e Misc cleanups to borrowck crate 2026-01-26 10:24:15 +00:00
Matthias Krüger b6c2dab72b Rollup merge of #150216 - reddevilmidzy:t13, r=Kivooeo
Tidying up tests/ui/issues 15 tests [6/N]

> [!NOTE]
> Intermediate commits are intended to help review, but will be squashed add comment commit prior to merge.

part of rust-lang/rust#133895

r? Kivooeo
2025-12-24 00:54:36 +01:00
reddevilmidzy 4578082361 Cleaned up some tests
add comment to closure-move-use-after-move-diagnostic.rs

add comment to missing-operator-after-float.rs

add comment to closure-array-break-length.rs

add comment to box-lifetime-argument-not-allowed.rs

add comment to const-return-outside-fn.rs

add comment to drop-conflicting-impls.rs

add comment to unbalanced-doublequote-2.rs

add comment to borrow-immutable-deref-box.rs

add comment to for-in-const-eval.rs

add comment to borrowck-annotated-static-lifetime.rs

cleaned up cast-rfc0401.rs

add comment to nll-anon-to-static.rs

add comment to cast-to-dyn-any.rs

add comment to missing-associated-items.rs

add comment to enum-discriminant-missing-variant.rs
2025-12-23 21:13:24 +09:00
reddevilmidzy 7ca2eb9c6f moved test 2025-12-23 20:33:37 +09:00
bors cb79c42008 Auto merge of #148329 - LorrensP-2158466:closure-prop, r=lcnr
Better closure requirement propagation.

Fixes rust-lang/rust#148289
Fixes rust-lang/rust#104477
Should unblock rust-lang/rust#148187

When propagating closure requirements we:
- no longer try to find a post dominiting region for the list of non-local lower bounds of `longer_fr`.
- we filter the list of `longer_fr-: shorter_fr+` to only these constraints between external regions which are required regardless. If no such constraint exists, we fall back to propagating all of them.

See the [FCP](https://github.com/rust-lang/rust/pull/148329#issuecomment-3581019253) for more information.

r? `@lcnr`
2025-12-20 21:05:32 +00:00
LorrensP-2158466 0627df9151 Propagate region error for every non-local lower bound 2025-12-10 18:05:30 +01:00
Christian Poveda 7ae2823bc6 Gate 2018 UI tests 2025-11-27 14:13:58 -05:00
Esteban Küber 71b0755a98 Provide more context when mutably borrowing an imutable borrow
Point at statics and consts being mutable borrowed or written to:

```
error[E0594]: cannot assign to immutable static item `NUM`
  --> $DIR/E0594.rs:4:5
   |
LL | static NUM: i32 = 18;
   | --------------- this `static` cannot be written to
...
LL |     NUM = 20;
   |     ^^^^^^^^ cannot assign
```

Point at the expression that couldn't be mutably borrowed from a pattern:

```
error[E0596]: cannot borrow data in a `&` reference as mutable
  --> $DIR/mut-pattern-of-immutable-borrow.rs:19:14
   |
LL |     match &arg.field {
   |           ---------- this cannot be borrowed as mutable
LL |         Some(ref mut s) => s.push('a'),
   |              ^^^^^^^^^ cannot borrow as mutable
```
2025-11-09 22:14:48 +00:00
Stuart Cook ea4e037dd7 Rollup merge of #133149 - estebank:niko-rustnation, r=wesleywiser
Provide more context on `Fn` closure modifying binding

When modifying a binding from inside of an `Fn` closure, point at the binding definition and suggest using an `std::sync` type that would allow the code to compile.

```
error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure
 --> f703.rs:6:9
  |
4 |     let mut counter = 0;
  |         ----------- `counter` declared here, outside the closure
5 |     let x: Box<dyn Fn()> = Box::new(|| {
  |                                     -- in this closure
6 |         counter += 1;
  |         ^^^^^^^^^^^^ cannot assign
  |
  = help: consider using `std::sync::atomic::AtomicI32` instead, which allows for multiple threads to access and modify the value
```

This provides more context on where the binding being modified was declared, and more importantly, guides newcomers towards `std::sync` when encountering cases like these.

When the requirement comes from an argument of a local function, we already tell the user that they might want to change from `Fn` to `FnMut`:

```
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
  --> $DIR/borrow-immutable-upvar-mutation.rs:21:27
   |
LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
   |                                              - change this to accept `FnMut` instead of `Fn`
...
LL |         let mut x = 0;
   |             ----- `x` declared here, outside the closure
LL |         let _f = to_fn(|| x = 42);
   |                  ----- -- ^^^^^^ cannot assign
   |                  |     |
   |                  |     in this closure
   |                  expects `Fn` instead of `FnMut`
   |
   = help: consider using `std::sync::atomic::AtomicI32` instead, which allows for multiple threads to access and modify the value
```

We might want to avoid the `help` in this case.

_Inspired by a [part of Niko's keynote at RustNation UK 2024](https://youtu.be/04gTQmLETFI?si=dgJL2OJRtuShkxdD&t=600)._
2025-11-04 13:44:47 +11:00
Esteban Küber 4ab1fc5127 Provide more context on Fn closure modifying binding
When modifying a binding from inside of an `Fn` closure, point at the binding definition and suggest using an `std::sync` type that would allow the code to compile.

```
error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure
 --> f703.rs:6:9
  |
4 |     let mut counter = 0;
  |         ----------- `counter` declared here, outside the closure
5 |     let x: Box<dyn Fn()> = Box::new(|| {
  |                                     -- in this closure
6 |         counter += 1;
  |         ^^^^^^^^^^^^ cannot assign
```
2025-11-03 20:26:18 +00:00
Matthias Krüger 549846e857 Rollup merge of #147141 - estebank:issue-81059, r=jackh726
Suggest making binding `mut` on `&mut` reborrow

When a binding needs to be mutably reborrowed multiple times, suggesting removing `&mut` will lead to follow up errors. Instead suggest both making the binding mutable and removing the reborrow.

```
error[E0596]: cannot borrow `outer` as mutable, as it is not declared as mutable
 --> f14.rs:2:12
  |
2 |     match (&mut outer, 23) {
  |            ^^^^^^^^^^ cannot borrow as mutable
  |
note: the binding is already a mutable borrow
 --> f14.rs:1:16
  |
1 | fn test(outer: &mut Option<i32>) {
  |                ^^^^^^^^^^^^^^^^
help: consider making the binding mutable if you need to reborrow multiple times
  |
1 | fn test(mut outer: &mut Option<i32>) {
  |         +++
help: if there is only one mutable reborrow, remove the `&mut`
  |
2 -     match (&mut outer, 23) {
2 +     match (outer, 23) {
  |
```

Address rust-lang/rust#81059.
2025-11-03 21:20:20 +01:00
Esteban Küber 75bb675f96 Do not suggest introducing lifetime in impl assoc type
```
error[E0261]: use of undeclared lifetime name `'a`
  --> $DIR/missing-lifetime-in-assoc-type-2.rs:7:57
   |
LL | impl IntoIterator for &S {
   |     - help: consider introducing lifetime `'a` here: `<'a>`
...
LL |     type IntoIter = std::collections::btree_map::Values<'a, i32, T>;
   |                                                         ^^ undeclared lifetime
```

```
error[E0106]: missing lifetime specifier
  --> $DIR/issue-74918-missing-lifetime.rs:9:30
   |
LL |     type Item = IteratorChunk<T, S>;
   |                              ^ expected named lifetime parameter
   |
help: consider introducing a named lifetime parameter
   |
LL ~ impl<'a, T, S: Iterator<Item = T>> Iterator for ChunkingIterator<T, S> {
LL ~     type Item = IteratorChunk<'a, T, S>;
   |
```
2025-10-31 20:45:33 +00:00
Esteban Küber 516a273144 Suggest making binding mut on &mut reborrow
When a binding needs to be mutably reborrowed multiple times, suggesting removing `&mut` will lead to follow up errors. Instead suggest both making the binding mutable and removing the reborrow.

```
error[E0596]: cannot borrow `outer` as mutable, as it is not declared as mutable
 --> f14.rs:2:12
  |
2 |     match (&mut outer, 23) {
  |            ^^^^^^^^^^ cannot borrow as mutable
  |
note: the binding is already a mutable borrow
 --> f14.rs:1:16
  |
1 | fn test(outer: &mut Option<i32>) {
  |                ^^^^^^^^^^^^^^^^
help: consider making the binding mutable if you need to reborrow multiple times
  |
1 | fn test(mut outer: &mut Option<i32>) {
  |         +++
help: if there is only one mutable reborrow, remove the `&mut`
  |
2 -     match (&mut outer, 23) {
2 +     match (outer, 23) {
  |
```
2025-10-31 19:23:33 +00:00
Rémy Rakic 68080de4e3 ignore boring locals when explaining borrow due to drop
Polonius liveness has to contain boring locals, and we ignore them in
diagnostics to match NLL diagnostics, since they doesn't contain boring locals.

We ignored these when explaining why a loan contained a point due to
a use of a live var, but not when it contained a point due to a drop of
a live var.
2025-10-15 15:47:44 +00:00
Boxy Uwu 30bedc74d4 in opaque type handling lift region vars to static if they outlive placeholders 2025-10-13 15:26:22 +01:00
bors 4b9c62b4da Auto merge of #147138 - jackh726:split-canonical-bound, r=lcnr
Split Bound index into Canonical and Bound

See [#t-types/trait-system-refactor > perf &#96;async-closures/post-mono-higher-ranked-hang.rs&#96;](https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/perf.20.60async-closures.2Fpost-mono-higher-ranked-hang.2Ers.60/with/541535613) for context

Things compile and tests pass, but not sure if this actually solves the perf issue (edit: it does). Opening up this to do a perf (and maybe crater) run.

r? lcnr
2025-10-02 08:09:33 +00:00
jackh726 d1bbd39c59 Split Bound into Canonical and Bound 2025-09-30 12:58:28 -04:00
Esteban Küber 4973903cd2 reword note 2025-09-28 20:55:35 +00:00
Esteban Küber 7a0319f01d Point at lifetime requirement origin in more cases 2025-09-28 20:55:34 +00:00
Esteban Küber c3e0b29e79 Point at fn bound that introduced lifetime obligation
```
error[E0597]: `c` does not live long enough
  --> $DIR/without-precise-captures-we-are-powerless.rs:19:20
   |
LL | fn simple<'a>(x: &'a i32) {
   |           -- lifetime `'a` defined here
...
LL |     let c = async move || { println!("{}", *x); };
   |         - binding `c` declared here
LL |     outlives::<'a>(c());
   |     ---------------^---
   |     |              |
   |     |              borrowed value does not live long enough
   |     argument requires that `c` is borrowed for `'a`
LL |     outlives::<'a>(call_once(c));
LL | }
   | - `c` dropped here while still borrowed
   |
note: requirement that `c` is borrowed for `'a` introduced here
  --> $DIR/without-precise-captures-we-are-powerless.rs:7:33
   |
LL | fn outlives<'a>(_: impl Sized + 'a) {}
   |                                 ^^
```

When encountering a `ConstraintCategory::Predicate` in a funtion call, point at the `Span` for that `Predicate` to explain where the lifetime obligation originates from.
2025-09-28 20:55:34 +00:00
Amanda Stjerna 7dd56b10ad Region inference: Use outlives-static constraints in constraint search
Revise the extra `r: 'static` constraints added upon universe issues
to add an explanation, and use that explanation during constraint blame
search. This greatly simplifies the region inference logic, which
now does not need to reverse-engineer the event that caused a region
to outlive 'static.
2025-08-22 13:38:22 +02:00
Karol Zwolak d14b83e378 bless tests with new lint messages 2025-08-19 21:27:10 +02:00
Stuart Cook f3f1847e40 Rollup merge of #145041 - lcnr:borrowck-limitations-error, r=BoxyUwU
rework GAT borrowck limitation error

The old one depends on the `ConstraintCategory` of the constraint which meant we did not emit this note if we had to prove the higher ranked trait bound due to e.g. normalization.

This made it annoying brittle and caused MIR borrowck errors to be order dependent, fixes the issue in https://github.com/rust-lang/rust/pull/140737#discussion_r2259592651.

r? types cc ```@amandasystems```
2025-08-19 14:18:22 +10:00
bors cd7cbe818e Auto merge of #142071 - lcnr:revealing-use, r=compiler-errors
`apply_member_constraints`: fix placeholder check

Checking whether the member region is *an existential region from a higher universe* is just wrong and I am pretty sure we've added that check by accident as the naming was just horribly confusing before rust-lang/rust#140466.

I've encountered this issue separately while working on rust-lang/rust#139587, but feel like it's probably easier to separately FCP this change. This allows the following code to compile
```rust
trait Proj<'a> {
    type Assoc;
}
impl<'a, 'b, F: FnOnce() -> &'b ()> Proj<'a> for F {
    type Assoc = ();
}

fn is_proj<F: for<'a> Proj<'a>>(f: F) {}
fn define<'a>() -> impl Sized + use<'a> {
    // This adds a use of `opaque::<'a>` with hidden type `&'unconstrained_b ()`.
    // 'unconstrained_b is an inference variable from a higher universe as it gets
    // created inside of the binder of `F: for<'a> Proj<'a>`. This previously
    // caused us to not apply member constraints. We now do, constraining
    // it to `'a`.
    is_proj(define::<'a>);
    &()
}

fn main() {}
```

This should not be breaking change, even in theory. Applying member constraints is incomplete in rare circumstances which means that applying them in more cases can cause spurious errors, cc rust-lang/rust#140569/rust-lang/rust#142073. However, as we always skipped these member regions in `apply_member_constraints` the skipped region is guaranteed to cause an error in `check_member_constraints` later on.
2025-08-15 18:52:12 +00:00
Jake Goulding 65d329d189 Adjust error message grammar to be less awkward 2025-08-14 12:50:07 -04:00
lcnr 3ebf611005 it's not a borrow checker limitation :< 2025-08-14 17:43:39 +02:00
lcnr a95a2ac476 rework add_placeholder_from_predicate_note 2025-08-13 14:03:26 +02:00
Esteban Küber 1aa5668d20 Point at the Fn() or FnMut() bound that coerced a closure, which caused a move error
When encountering a move error involving a closure because the captured value isn't `Copy`, and the obligation comes from a bound on a type parameter that requires `Fn` or `FnMut`, we point at it and explain that an `FnOnce` wouldn't cause the move error.

```
error[E0507]: cannot move out of `foo`, a captured variable in an `Fn` closure
  --> f111.rs:15:25
   |
14 | fn do_stuff(foo: Option<Foo>) {
   |             ---  ----------- move occurs because `foo` has type `Option<Foo>`, which does not implement the `Copy` trait
   |             |
   |             captured outer variable
15 |     require_fn_trait(|| async {
   |                      -- ^^^^^ `foo` is moved here
   |                      |
   |                      captured by this `Fn` closure
16 |         if foo.map_or(false, |f| f.foo()) {
   |            --- variable moved due to use in coroutine
   |
help: `Fn` and `FnMut` closures require captured values to be able to be consumed multiple times, but an `FnOnce` consume them only once
  --> f111.rs:12:53
   |
12 | fn require_fn_trait<F: Future<Output = ()>>(_: impl Fn() -> F) {}
   |                                                     ^^^^^^^^^
help: consider cloning the value if the performance cost is acceptable
   |
16 |         if foo.clone().map_or(false, |f| f.foo()) {
   |               ++++++++
```
2025-08-10 19:22:49 +00:00
Stuart Cook e5b98a9c21 Rollup merge of #143093 - lqd:polonius-pre-alpha, r=jackh726
Simplify polonius location-sensitive analysis

This PR reworks the location-sensitive analysis into what we think is a worthwhile subset of the datalog analysis. A sort of polonius alpha analysis that handles NLL problem case 3 and more, but is still using the faster "reachability as an approximation of liveness", as well as the same loans-in-scope computation as NLLs -- and thus doesn't handle full flow-sensitivity like the datalog implementation.

In the last few months, we've identified this subset as being actionable:
- we believe we can make a stabilizable version of this analysis
- it is an improvement over the status quo
- it can also be modeled in a-mir-formality, or some other formalism, for assurances about soundness, and I believe ````````@nikomatsakis```````` is interested in looking into this during H2.
- and we've identified the areas of work we wish to explore later to gradually expand the supported cases: the differences between reachability and liveness, support of kills, and considerations of time-traveling, for example.

The approach in this PR is to try less to have the graph only represent live paths, by checking whether we reach a live region during traversal and recording the loan as live there, instead of equating traversal with liveness like today because it has subtleties with the typeck edges in statements (that could forward loans to the successor point without ensuring their liveness). We can then also simplify these typeck stmt edges. And we also can simplify traversal by removing looking at kills, because that's enough to handle a bunch of NLL problem 3 cases -- and we can gradually support them more and more in traversal in the future, to reduce the approximation of liveness.

There's still some in-progress pieces of work w/r/t opaque types that I'm expecting [lcnr's opaque types rework](https://github.com/rust-lang/rust/pull/139587), and [amanda's SCCs rework](https://github.com/rust-lang/rust/pull/130227) to handle. That didn't seem to show up in tests until I rebased today (and shows lack of test coverage once again) when https://github.com/rust-lang/rust/pull/142255 introduced a couple of test failures with the new captures rules from edition 2024. It's not unexpected since we know more work is needed with member constraints (and we're not even using SCCs in this prototype yet)

I'll look into these anyways, both for future work, and checking how these other 2 PRs would change things.

---

I'm not sure the following means a lot until we have some formalism in-place, but:
- I've changed the polonius compare-mode to use this analysis: the tests pass with it, except 2 cases with minor diagnostics differences, and the 2 edition 2024 opaque types one I mentioned above and need to investigate
- things that are expected to work still do work: it bootstraps, can run our rustc-perf benchmarks (and the results are not even that bad), and a crater run didn't find any regressions (forgetting that crater currently fails to test around a quarter of all crates 👼)
- I've added tests with improvements, like the NLL problem case 3 and others, as well as some that behave the same as NLLs today and are thus worse than the datalog implementation

r? ````````@jackh726````````

(no rush I know you're deep in phd work and "implmentating" the new trait solver for r-a :p <3)

This also fixes rust-lang/rust#135646, a diagnostics ICE from the previous implementation.
2025-08-10 19:45:46 +10:00
Stuart Cook 50ad4c8b44 Rollup merge of #145050 - lcnr:add-opaque-type-tests, r=lqd
add member constraints tests

taken from rust-lang/rust#139587.
2025-08-09 13:58:48 +10:00
Rémy Rakic b99fe2b720 mark polonius=next's NLL imprecisions as known-bugs
- linked-list cursor-like patterns
- issue-46589

These are known-bugs for the polonius alpha, where they show the same
imprecision as NLLs, but are supported by the old datalog
implementation.
2025-08-08 15:15:09 +00:00
Rémy Rakic 9badbdf5f9 add cursor-like example that works
This is an example similar to the linked-list cursor examples
where the alpha shows the same imprecision as NLLs, but that can work due to
the loans not being live after the loop, or the constraint graph being
simple enough that the cfg/subset relationships are the same for
reachability and liveness.
2025-08-08 15:14:51 +00:00
Rémy Rakic 48ebae9cef add NLL-like imprecision example
This test showcases the same imprecision as NLLs, unlike the datalog
implementation, when using reachability as a liveness approximation.
2025-08-08 15:14:51 +00:00
Rémy Rakic b172980d5c add some test cases for overlapping yielded items
These are just some sanity checks to ensure NLLs, the polonius alpha
analysis, and the datalog implementation behave the same on these common
examples.
2025-08-08 15:14:51 +00:00
Rémy Rakic 13308988b0 new impl fixes crash test 2025-08-08 15:14:51 +00:00
lcnr cde14e65bf apply_member_constraints: fix placeholder check 2025-08-08 14:32:35 +02:00
Rémy Rakic 202963f221 add multiple known-bugs for the linked-list cursor-like pattern of 46859/48001
these are fixed by polonius=legacy, are currently accepted by
polonius=next but won't be by the alpha analysis
2025-08-07 13:33:35 +00:00
Rémy Rakic e3aae6162e add filtering lending iterator known-bug 2025-08-07 13:06:35 +00:00
Rémy Rakic d6dc3634db add multiple known-bugs for NLL problem case 3
these are fixed by polonius=next and polonius=legacy
2025-08-07 13:05:27 +00:00