avoid propagating outlives obligations on locals if we can
This commit is contained in:
parent
db169e53e5
commit
43e758798c
2 changed files with 63 additions and 0 deletions
|
@ -701,6 +701,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||||
// `ClosureOutlivesRequirement`.
|
// `ClosureOutlivesRequirement`.
|
||||||
let r_scc = self.constraint_sccs.scc(*lower_bound);
|
let r_scc = self.constraint_sccs.scc(*lower_bound);
|
||||||
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
|
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
|
||||||
|
// Check whether we can already prove that the "subject" outlives `ur`.
|
||||||
|
// If so, we don't have to propagate this requirement to our caller.
|
||||||
|
//
|
||||||
|
// To continue the example from the function, if we are trying to promote
|
||||||
|
// a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union
|
||||||
|
// `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here
|
||||||
|
// we check whether `T: '1` is something we *can* prove. If so, no need
|
||||||
|
// to propagate that requirement.
|
||||||
|
//
|
||||||
|
// This is needed because -- particularly in the case
|
||||||
|
// where `ur` is a local bound -- we are sometimes in a
|
||||||
|
// position to prove things that our caller cannot. See
|
||||||
|
// #53570 for an example.
|
||||||
|
if self.eval_region_test(mir, ur, &type_test.test) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
debug!("try_promote_type_test: ur={:?}", ur);
|
debug!("try_promote_type_test: ur={:?}", ur);
|
||||||
|
|
||||||
let non_local_ub = self.universal_region_relations.non_local_upper_bound(ur);
|
let non_local_ub = self.universal_region_relations.non_local_upper_bound(ur);
|
||||||
|
|
46
src/test/ui/nll/issue-53570.rs
Normal file
46
src/test/ui/nll/issue-53570.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Regression test for #53570. Here, we need to propagate that `T: 'a`
|
||||||
|
// but in some versions of NLL we were propagating a stronger
|
||||||
|
// requirement that `T: 'static`. This arose because we actually had
|
||||||
|
// to propagate both that `T: 'a` but also `T: 'b` where `'b` is the
|
||||||
|
// higher-ranked lifetime that appears in the type of the closure
|
||||||
|
// parameter `x` -- since `'b` cannot be expressed in the caller's
|
||||||
|
// space, that got promoted th `'static`.
|
||||||
|
//
|
||||||
|
// compile-pass
|
||||||
|
|
||||||
|
#![feature(nll)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::cell::{RefCell, Ref};
|
||||||
|
|
||||||
|
trait AnyVec<'a> {
|
||||||
|
}
|
||||||
|
|
||||||
|
trait GenericVec<T> {
|
||||||
|
fn unwrap<'a, 'b>(vec: &'b AnyVec<'a>) -> &'b [T] where T: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Scratchpad<'a> {
|
||||||
|
buffers: RefCell<Box<AnyVec<'a>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Scratchpad<'a> {
|
||||||
|
fn get<T: GenericVec<T>>(&self) -> Ref<[T]>
|
||||||
|
where T: 'a
|
||||||
|
{
|
||||||
|
Ref::map(self.buffers.borrow(), |x| T::unwrap(x.as_ref()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
Loading…
Add table
Add a link
Reference in a new issue