Initial implementation of #![feature(move_ref_pattern)] by Centril · Pull Request #68376 · rust-lang/rust (original) (raw)

@Centril

estebank

matthewjasper

Centril

@Centril

@Centril

bindings_after_at: harden tests

@Centril

@Centril Centril added S-waiting-on-author

Status: This is awaiting some action (such as code changes or more information) from the author.

and removed S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

labels

Feb 2, 2020

@Centril Centril added S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

and removed S-waiting-on-author

Status: This is awaiting some action (such as code changes or more information) from the author.

labels

Feb 2, 2020

@bors bors added the S-waiting-on-bors

Status: Waiting on bors to run and complete tests. Bors will change the label on completion.

label

Feb 8, 2020

bors added a commit that referenced this pull request

Feb 9, 2020

@bors

Initial implementation of #![feature(move_ref_pattern)]

Following up on #45600, under the gate #![feature(move_ref_pattern)], (ref x, mut y) is allowed subject to restrictions necessary for soundness. The match checking implementation and tests for #![feature(bindings_after_at)] is also adjusted as necessary.

Closes #45600. Tracking issue: #68354.

r? @matthewjasper

JohnTitor added a commit to JohnTitor/rust that referenced this pull request

Oct 15, 2020

@JohnTitor

…n, r=nikomatsakis

Stabilize move_ref_pattern

Implementation

Tracking issue: rust-lang#68354.

Description

This PR is to stabilize the feature move_ref_pattern, which allows patterns containing both by-ref and by-move bindings at the same time.

For example: Foo(ref x, y), where x is by-ref, and y is by-move.

The rules of moving a variable also apply here when moving part of a variable, such as it can't be referenced or moved before.

If this pattern is used, it would result in partial move, which means that part of the variable is moved. The variable that was partially moved from cannot be used as a whole in this case, only the parts that are still not moved can be used.

Documentation

Tests

There are many tests, but I think one of the comperhensive ones:

Examples

#[derive(PartialEq, Eq)]
struct Finished {}

#[derive(PartialEq, Eq)]
struct Processing {
    status: ProcessStatus,
}

#[derive(PartialEq, Eq)]
enum ProcessStatus {
    One,
    Two,
    Three,
}

#[derive(PartialEq, Eq)]
enum Status {
    Finished(Finished),
    Processing(Processing),
}

fn check_result(_url: &str) -> Status {
    // fetch status from some server
    Status::Processing(Processing {
        status: ProcessStatus::One,
    })
}

fn wait_for_result(url: &str) -> Finished {
    let mut previous_status = None;
    loop {
        match check_result(url) {
            Status::Finished(f) => return f,
            Status::Processing(p) => {
                match (&mut previous_status, p.status) {
                    (None, status) => previous_status = Some(status), // first status
                    (Some(previous), status) if *previous == status => {} // no change, ignore
                    (Some(previous), status) => { // Now it can be used
                        // new status
                        *previous = status;
                    }
                }
            }
        }
    }
}

Before, we would have used:

                match (&previous_status, p.status) {
                    (Some(previous), status) if *previous == status => {} // no change, ignore
                    (_, status) => {
                        // new status
                        previous_status = Some(status);
                    }
                }

Demonstrating partial move

fn main() {
    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }

    let person = Person {
        name: String::from("Alice"),
        age: 20,
    };

    // `name` is moved out of person, but `age` is referenced
    let Person { name, ref age } = person;

    println!("The person's age is {}", age);

    println!("The person's name is {}", name);

    // Error! borrow of partially moved value: `person` partial move occurs
    //println!("The person struct is {:?}", person);

    // `person` cannot be used but `person.age` can be used as it is not moved
    println!("The person's age from person struct is {}", person.age);
}

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request

Oct 15, 2020

@Dylan-DPC

…n, r=nikomatsakis

Stabilize move_ref_pattern

Implementation

Tracking issue: rust-lang#68354.

Description

This PR is to stabilize the feature move_ref_pattern, which allows patterns containing both by-ref and by-move bindings at the same time.

For example: Foo(ref x, y), where x is by-ref, and y is by-move.

The rules of moving a variable also apply here when moving part of a variable, such as it can't be referenced or moved before.

If this pattern is used, it would result in partial move, which means that part of the variable is moved. The variable that was partially moved from cannot be used as a whole in this case, only the parts that are still not moved can be used.

Documentation

Tests

There are many tests, but I think one of the comperhensive ones:

Examples

#[derive(PartialEq, Eq)]
struct Finished {}

#[derive(PartialEq, Eq)]
struct Processing {
    status: ProcessStatus,
}

#[derive(PartialEq, Eq)]
enum ProcessStatus {
    One,
    Two,
    Three,
}

#[derive(PartialEq, Eq)]
enum Status {
    Finished(Finished),
    Processing(Processing),
}

fn check_result(_url: &str) -> Status {
    // fetch status from some server
    Status::Processing(Processing {
        status: ProcessStatus::One,
    })
}

fn wait_for_result(url: &str) -> Finished {
    let mut previous_status = None;
    loop {
        match check_result(url) {
            Status::Finished(f) => return f,
            Status::Processing(p) => {
                match (&mut previous_status, p.status) {
                    (None, status) => previous_status = Some(status), // first status
                    (Some(previous), status) if *previous == status => {} // no change, ignore
                    (Some(previous), status) => { // Now it can be used
                        // new status
                        *previous = status;
                    }
                }
            }
        }
    }
}

Before, we would have used:

                match (&previous_status, p.status) {
                    (Some(previous), status) if *previous == status => {} // no change, ignore
                    (_, status) => {
                        // new status
                        previous_status = Some(status);
                    }
                }

Demonstrating partial move

fn main() {
    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }

    let person = Person {
        name: String::from("Alice"),
        age: 20,
    };

    // `name` is moved out of person, but `age` is referenced
    let Person { name, ref age } = person;

    println!("The person's age is {}", age);

    println!("The person's name is {}", name);

    // Error! borrow of partially moved value: `person` partial move occurs
    //println!("The person struct is {:?}", person);

    // `person` cannot be used but `person.age` can be used as it is not moved
    println!("The person's age from person struct is {}", person.age);
}

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this pull request

Oct 16, 2020

@Dylan-DPC

…n, r=nikomatsakis

Stabilize move_ref_pattern

Implementation

Tracking issue: rust-lang#68354.

Description

This PR is to stabilize the feature move_ref_pattern, which allows patterns containing both by-ref and by-move bindings at the same time.

For example: Foo(ref x, y), where x is by-ref, and y is by-move.

The rules of moving a variable also apply here when moving part of a variable, such as it can't be referenced or moved before.

If this pattern is used, it would result in partial move, which means that part of the variable is moved. The variable that was partially moved from cannot be used as a whole in this case, only the parts that are still not moved can be used.

Documentation

Tests

There are many tests, but I think one of the comperhensive ones:

Examples

#[derive(PartialEq, Eq)]
struct Finished {}

#[derive(PartialEq, Eq)]
struct Processing {
    status: ProcessStatus,
}

#[derive(PartialEq, Eq)]
enum ProcessStatus {
    One,
    Two,
    Three,
}

#[derive(PartialEq, Eq)]
enum Status {
    Finished(Finished),
    Processing(Processing),
}

fn check_result(_url: &str) -> Status {
    // fetch status from some server
    Status::Processing(Processing {
        status: ProcessStatus::One,
    })
}

fn wait_for_result(url: &str) -> Finished {
    let mut previous_status = None;
    loop {
        match check_result(url) {
            Status::Finished(f) => return f,
            Status::Processing(p) => {
                match (&mut previous_status, p.status) {
                    (None, status) => previous_status = Some(status), // first status
                    (Some(previous), status) if *previous == status => {} // no change, ignore
                    (Some(previous), status) => { // Now it can be used
                        // new status
                        *previous = status;
                    }
                }
            }
        }
    }
}

Before, we would have used:

                match (&previous_status, p.status) {
                    (Some(previous), status) if *previous == status => {} // no change, ignore
                    (_, status) => {
                        // new status
                        previous_status = Some(status);
                    }
                }

Demonstrating partial move

fn main() {
    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }

    let person = Person {
        name: String::from("Alice"),
        age: 20,
    };

    // `name` is moved out of person, but `age` is referenced
    let Person { name, ref age } = person;

    println!("The person's age is {}", age);

    println!("The person's name is {}", name);

    // Error! borrow of partially moved value: `person` partial move occurs
    //println!("The person struct is {:?}", person);

    // `person` cannot be used but `person.age` can be used as it is not moved
    println!("The person's age from person struct is {}", person.age);
}