Skip to content

Handle regions equivalent to 'static in non_local_bounds #139668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ impl UniversalRegionRelations<'_> {
assert!(self.universal_regions.is_universal_region(fr0));

let mut external_parents = vec![];
let mut queue = vec![fr0];

let mut queue = vec![relation.minimal_scc_representative(fr0)];

// Keep expanding `fr` into its parents until we reach
// non-local regions.
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_data_structures/src/transitive_relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,20 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> {
.collect()
}

/// Given an element A, elements B with the lowest index such that `A R B`
/// and `B R A`, or `A` if no such element exists.
pub fn minimal_scc_representative(&self, a: T) -> T {
match self.index(a) {
Some(a_i) => self.with_closure(|closure| {
closure
.iter(a_i.0)
.find(|i| closure.contains(*i, a_i.0))
.map_or(a, |i| self.elements[i])
Copy link
Member

@compiler-errors compiler-errors Apr 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we not find such an element? In other words, what's the justification for the map_or, over an unwrap? Shouldn't all free regions be represented in TransitiveRelations?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Borrowck will always have this as a reflexive relation, but the data structure doesn't require that (maybe it should though).

}),
None => a,
}
}

fn with_closure<OP, R>(&self, op: OP) -> R
where
OP: FnOnce(&BitMatrix<usize, usize>) -> R,
Expand Down
41 changes: 41 additions & 0 deletions compiler/rustc_data_structures/src/transitive_relation/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,44 @@ fn parent() {
let p = relation.postdom_parent(3);
assert_eq!(p, Some(0));
}

#[test]
fn minimal_scc_representative_1() {
// +---------+
// v |
// a -> c -> d -> e
// ^ ^
// | |
// b ---+

// "digraph { a -> c -> d -> e -> c; b -> d; b -> e; }",
let mut relation = TransitiveRelationBuilder::default();
relation.add("a", "c");
relation.add("c", "d");
relation.add("d", "e");
relation.add("e", "c");
relation.add("b", "d");
relation.add("b", "e");
let relation = relation.freeze();

assert_eq!(relation.minimal_scc_representative("a"), "a");
assert_eq!(relation.minimal_scc_representative("b"), "b");
assert_eq!(relation.minimal_scc_representative("c"), "c");
assert_eq!(relation.minimal_scc_representative("d"), "c");
assert_eq!(relation.minimal_scc_representative("e"), "c");
}

#[test]
fn minimal_scc_representative_2() {
// "digraph { a -> b; a -> a; b -> a; c -> c}",
let mut relation = TransitiveRelationBuilder::default();
relation.add("a", "b");
relation.add("b", "a");
relation.add("a", "a");
relation.add("c", "c");
let relation = relation.freeze();

assert_eq!(relation.minimal_scc_representative("a"), "a");
assert_eq!(relation.minimal_scc_representative("b"), "a");
assert_eq!(relation.minimal_scc_representative("c"), "c");
}
14 changes: 0 additions & 14 deletions tests/crashes/122704.rs

This file was deleted.

22 changes: 22 additions & 0 deletions tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Regression test for #122704
use std::any::Any;

pub struct Foo {
bar: Box<dyn for<'a> Fn(&'a usize) -> Box<dyn Any + 'a>>,
}

impl Foo {
pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
self.bar = Box::new(|baz| Box::new(f(baz)));
//~^ ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
//~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
//~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
//~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
//~| ERROR the parameter type `I` may not live long enough
//~| ERROR the parameter type `I` may not live long enough
//~| ERROR the parameter type `I` may not live long enough
//~| ERROR `f` does not live long enough
}
}

fn main() {}
119 changes: 119 additions & 0 deletions tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:9
|
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| ^^^^^^^^
| |
| the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
| ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
| +++++++++

error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:9
|
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| ^^^^^^^^
| |
| the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
| ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding an explicit lifetime bound
|
LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
| +++++++++

error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:20
|
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| ^^^^^^^^
| |
| the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
| ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
| +++++++++

error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:20
|
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime...
| ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) {
| +++++++++

error[E0310]: the parameter type `I` may not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:35
|
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| ^^^^^^^^^^^^^^^^
| |
| the parameter type `I` must be valid for the static lifetime...
| ...so that the type `I` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | pub fn ack<I: 'static>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
| +++++++++

error[E0310]: the parameter type `I` may not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:35
|
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| ^^^^^^^^^^^^^^^^
| |
| the parameter type `I` must be valid for the static lifetime...
| ...so that the type `I` will meet its required lifetime bounds
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider adding an explicit lifetime bound
|
LL | pub fn ack<I: 'static>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
| +++++++++

error[E0311]: the parameter type `I` may not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:35
|
LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
| --------- the parameter type `I` must be valid for the anonymous lifetime defined here...
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| ^^^^^^^^^^^^^^^^ ...so that the type `I` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | pub fn ack<'a, I: 'a>(&'a mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
| +++ ++++ ++

error[E0597]: `f` does not live long enough
--> $DIR/unconstrained-closure-lifetime-generic.rs:10:44
|
LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) {
| - binding `f` declared here
LL | self.bar = Box::new(|baz| Box::new(f(baz)));
| -------- ----- ^ borrowed value does not live long enough
| | |
| | value captured here
| coercion requires that `f` is borrowed for `'static`
...
LL | }
| - `f` dropped here while still borrowed
|
= note: due to object lifetime defaults, `Box<dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)>>` actually means `Box<(dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)> + 'static)>`

error: aborting due to 8 previous errors

Some errors have detailed explanations: E0310, E0311, E0597.
For more information about an error, try `rustc --explain E0310`.
11 changes: 11 additions & 0 deletions tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Regression test for #139004
use std::any::Any;

type B = Box<dyn for<'a> Fn(&(dyn Any + 'a)) -> Box<dyn Any + 'a>>;

fn foo<E>() -> B {
Box::new(|e| Box::new(e.is::<E>()))
//~^ ERROR the parameter type `E` may not live long enough
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
error[E0310]: the parameter type `E` may not live long enough
--> $DIR/unconstrained-closure-lifetime-trait-object.rs:7:29
|
LL | Box::new(|e| Box::new(e.is::<E>()))
| ^^
| |
| the parameter type `E` must be valid for the static lifetime...
| ...so that the type `E` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound
|
LL | fn foo<E: 'static>() -> B {
| +++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0310`.
Loading