Skip to content

Borrowck deduces empty lifetime #74429

Closed
@dingxiangfei2009

Description

@dingxiangfei2009

I tried this code:

use std::ops::{DivAssign, SubAssign};

use ndarray::{s, Array2, ArrayView1, Axis, Zip};
use num::{Zero, One};
use rayon::prelude::*;

pub fn gaussian_elimination<T>(mut a: Array2<T>) -> Array2<T>
where
    T: One + Zero + Clone + Send + Sync + DivAssign + SubAssign,
{
    let (n, m) = a.dim();
    assert!(n > 0);
    let mut pivots = vec![];
    let mut pivot = 0;
    for i in 0..n {
        if a[[i, pivot]].is_zero() {
            if let Some((new_pivot, row)) = (pivot..m)
                .into_par_iter()
                .flat_map(|pivot| {
                    let a: ArrayView1<_> = a.slice(s![i.., pivot]);
                    a.axis_iter(Axis(0))
                        .into_par_iter()
                        .enumerate()
                        .flat_map(|(j, x)| {
                            if x.into_scalar().is_zero() {
                                None
                            } else {
                                Some(j)
                            }
                        })
                        .find_any(|_| true)
                        .map(|row| (pivot, row))
                })
                .find_first(|_| true)
            {
                pivot = new_pivot;
                if row > 0 {
                    let mut a = a.slice_mut(s![i..; row, ..]);
                    let mut it = a.axis_iter_mut(Axis(0));
                    let this_row = it.next().expect("this row exists");
                    let that_row = it.next().expect("that row exists");
                    Zip::from(this_row).and(that_row).par_apply(std::mem::swap);
                }
            } else {
                break;
            }
        }
        pivots.push((i, pivot));
        let (mut this_equation, mut rest_equations) = a.slice_mut(s![i.., ..]).split_at(Axis(0), 1);
        let mut this_equation = this_equation.index_axis_mut(Axis(0), 0);
        let scale = this_equation[pivot].clone();
        assert!(!scale.is_zero());
        this_equation.iter_mut().for_each(|a| {
            *a /= scale.clone();
        });

        rest_equations
            .axis_iter_mut(Axis(0))
            .into_par_iter()
            .for_each(|mut eqn| {
                let scale = eqn[pivot].clone();
                if !scale.is_zero() {
                    eqn.iter_mut()
                        .zip(this_equation.iter())
                        .for_each(|(e, e_)| *e -= e_.clone() * scale.clone());
                }
            });
        pivot += 1;
        if pivot >= m {
            break;
        }
    }

    // a is in row echelon form now
    if pivots.len() > 1 {
        for (i, pivot) in pivots[1..].iter().rev() {
            let (mut rest_equations, this_equation) =
                a.slice_mut(s![..=*i, ..]).split_at(Axis(0), *i);
            let this_equation = this_equation.index_axis(Axis(0), 0);
            rest_equations.axis_iter_mut(Axis(0)).for_each(|eqn| {
                if eqn[*pivot].is_zero() {
                    return;
                }
                let scale = eqn[*pivot].clone();
                Zip::from(eqn)
                    .and(this_equation)
                    .par_apply(|e, e_| *e -= e_.clone() * scale.clone());
            });
        }
    }

    a
}

I expected to see this happen:
On Rust 1.44.0, this compiles.

Instead, this happened:

error[E0311]: the parameter type `T` may not live long enough
  --> src/lib.rs:85:17
   |
85 | /                 Zip::from(eqn)
86 | |                     .and(this_equation)
   | |_______________________________________^
   |
   = note: the parameter type `T` must be valid for the empty lifetime...
   = note: ...so that the reference type `&T` does not outlive the data it points at

error: aborting due to previous error

Meta

rustc --version --verbose:

rustc 1.46.0-nightly (346aec9b0 2020-07-11)
binary: rustc
commit-hash: 346aec9b02f3c74f3fce97fd6bda24709d220e49
commit-date: 2020-07-11
host: x86_64-unknown-linux-gnu
release: 1.46.0-nightly
LLVM version: 10.0

Metadata

Metadata

Assignees

Labels

A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.E-needs-mcveCall for participation: This issue has a repro, but needs a Minimal Complete and Verifiable ExampleICEBreaker-Cleanup-CrewHelping to "clean up" bugs with minimal examples and bisectionsP-criticalCritical priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions