Skip to content

On "pattern in arg for fn def without body" emit structured suggestion #78927

Closed
@estebank

Description

@estebank

Taken from #35203 (comment)

error: patterns aren't allowed in functions without bodies
  --> src/lib.rs:11:45
   |
11 |     fn partition_dedup_by_new<F>(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T])
   |                                             ^^^^^^^^^^^^^^^
   |
   = note: `#[deny(patterns_in_fns_without_body)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>

error: aborting due to previous error

error: could not compile `alt-dedup-rs`

To learn more, run the command again with --verbose.

Looks rust is giving me this error without suggestion, I didn't know the fix was just simply removing mut which does not seemed related to this issue. CC @estebank

code
use std::mem;

pub trait NewDedup<T> {
    fn partition_dedup_new(&mut self) -> (&mut [T], &mut [T])
    where
        T: PartialEq<T>,
    {
        self.partition_dedup_by_new(|a, b| a == b)
    }

    fn partition_dedup_by_new<F>(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T])
    where
        F: FnMut(&mut T, &mut T) -> bool;
}

impl<T> NewDedup<T> for &mut [T] {
    fn partition_dedup_by_new<F>(&mut self, mut same_bucket: F) -> (&mut [T], &mut [T])
    where
        F: FnMut(&mut T, &mut T) -> bool,
    {
        let len = self.len();
        if len <= 1 {
            return (self, &mut []);
        }

        let ptr = self.as_mut_ptr();
        let mut next_read: usize = 1;
        let mut next_write: usize = 1;

        // SAFETY: the `while` condition guarantees `next_read` and `next_write`
        // are less than `len`, thus are inside `self`. `prev_ptr_write` points to
        // one element before `ptr_write`, but `next_write` starts at 1, so
        // `prev_ptr_write` is never less than 0 and is inside the slice.
        // This fulfils the requirements for dereferencing `ptr_read`, `prev_ptr_write`
        // and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)`
        // and `prev_ptr_write.offset(1)`.
        //
        // `next_write` is also incremented at most once per loop at most meaning
        // no element is skipped when it may need to be swapped.
        //
        // `ptr_read` and `prev_ptr_write` never point to the same element. This
        // is required for `&mut *ptr_read`, `&mut *prev_ptr_write` to be safe.
        // The explanation is simply that `next_read >= next_write` is always true,
        // thus `next_read > next_write - 1` is too.
        unsafe {
            // Avoid bounds checks by using raw pointers.
            while next_read < len {
                let ptr_read = ptr.add(next_read);
                let prev_ptr_write = ptr.add(next_write - 1);
                if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) {
                    next_write += 1;
                    next_read += 1;
                    // Avoid checking next_write != next_read once it is not in the same bucket,
                    // always swap memory if it is not in the same bucket.
                    while next_read < len {
                        let ptr_read = ptr.add(next_read);
                        let prev_ptr_write = ptr.add(next_write - 1);
                        if !same_bucket(&mut *ptr_read, &mut *prev_ptr_write) {
                            let ptr_write = prev_ptr_write.offset(1);
                            mem::swap(&mut *ptr_read, &mut *ptr_write);
                            next_write += 1;
                        }
                        next_read += 1;
                    }
                    return self.split_at_mut(next_write);
                }
                next_read += 1;
            }
        }

        self.split_at_mut(next_write)
    }
}

We should suggest to use an identifier. When possible take that identifier from the pattern, otherwise _ should work just as well.

CC @pickfire

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsA-suggestion-diagnosticsArea: Suggestions generated by the compiler applied by `cargo fix`D-papercutDiagnostics: An error or lint that needs small tweaks.D-terseDiagnostics: An error or lint that doesn't give enough information about the problem at hand.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions