Open
Description
This is either a borrow checker bug, a library bug, or a diagnostics bug. I don't know which one.
I tried this code:
use std::collections::HashMap;
use std::collections::BTreeSet;
struct DataRoot {
entries: Vec<Entry>
}
impl DataRoot {
pub fn columns<'this>(&'this self) -> impl Iterator<Item = &'this str> {
let mut dynamic_columns = BTreeSet::new();
for entry in &self.entries {
dynamic_columns.extend(entry.dynamic_coluimns());
}
// This combines 'this and 'static, and I want the result to be 'this
// (which is *shorter*)
// This doesn't work for some reason, why? And what can be done about it?
Entry::leading_columns()
.chain(dynamic_columns.into_iter())
.chain(Entry::trailing_columns())
}
pub fn columns2<'this>(&'this self) -> impl Iterator<Item = &'this str> {
let mut dynamic_columns = BTreeSet::new();
for entry in &self.entries {
dynamic_columns.extend(entry.dynamic_coluimns());
}
// This doesn't work either!
let mut values = vec![];
values.extend(Entry::leading_columns());
values.extend(dynamic_columns.into_iter());
values.extend(Entry::trailing_columns());
values.into_iter()
}
pub fn columns3(&self) -> impl Iterator<Item = String> {
let mut dynamic_columns = BTreeSet::new();
for entry in &self.entries {
dynamic_columns.extend(entry.dynamic_coluimns());
}
// Okay, it makes no sense that this doesn't work.
// * I turned it into String, so it is owned
// * I collected into a vec and then returned that (which normally works)
let v: Vec<_> = Entry::leading_columns()
.chain(dynamic_columns.into_iter())
.chain(Entry::trailing_columns())
.map(|v| v.to_string()).collect();
v.into_iter()
}
}
struct Entry {
// Various fixed fields here...
// Other fields that are specific to this case, capture them dynamically
// #[serde(flatten)]
other: HashMap<String, String>
}
impl Entry {
fn leading_columns() -> impl Iterator<Item = &'static str> {
["Crate name", "URL", "Maintained", "License", "Std"].into_iter()
}
fn dynamic_coluimns(&self) -> impl Iterator<Item = &str> {
self.other.keys().map(|s| s.as_str())
}
fn trailing_columns() -> impl Iterator<Item = &'static str> {
["Notes"].into_iter()
}
}
I expected to see this happen: One of the following:
- All three cases works, and
'static
is shortened to'this
- The compiler errors nudge you towards a solution to the issue rather than suggesting incorrect things like adding
+ 'this
Ideally (if this can't be fixed so that it works) the compiler error should nudge you in the direction that jendrikw suggested on URLO:
Entry::leading_columns().map(|s: &'static str| -> &'this str {s})
.chain(dynamic_columns.into_iter())
.chain(Entry::trailing_columns().map(|s: &'static str| -> &'this str {s}))
Instead, this happened:
Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
--> src/lib.rs:19:9
|
9 | pub fn columns<'this>(&'this self) -> impl Iterator<Item = &'this str> {
| ----- lifetime `'this` defined here
...
19 | / Entry::leading_columns()
20 | | .chain(dynamic_columns.into_iter())
21 | | .chain(Entry::trailing_columns())
| |_____________________________________________^ returning this value requires that `'this` must outlive `'static`
|
help: to declare that `impl Iterator<Item = &'this str>` captures data from argument `self`, you can add an explicit `'this` lifetime bound
|
9 | pub fn columns<'this>(&'this self) -> impl Iterator<Item = &'this str> + 'this {
| +++++++
error[E0521]: borrowed data escapes outside of method
--> src/lib.rs:27:22
|
24 | pub fn columns2<'this>(&'this self) -> impl Iterator<Item = &'this str> {
| ----- ----------- `self` is a reference that is only valid in the method body
| |
| lifetime `'this` defined here
...
27 | for entry in &self.entries {
| ^^^^^^^^^^^^^
| |
| `self` escapes the method body here
| argument requires that `'this` must outlive `'static`
error[E0521]: borrowed data escapes outside of method
--> src/lib.rs:43:22
|
40 | pub fn columns3(&self) -> impl Iterator<Item = String> {
| -----
| |
| `self` is a reference that is only valid in the method body
| let's call the lifetime of this reference `'1`
...
43 | for entry in &self.entries {
| ^^^^^^^^^^^^^
| |
| `self` escapes the method body here
| argument requires that `'1` must outlive `'static`
For more information about this error, try `rustc --explain E0521`.
error: could not compile `playground` (lib) due to 3 previous errors
Meta
rustc --version --verbose
:
rustc 1.82.0 (f6e511eec 2024-10-15)
binary: rustc
commit-hash: f6e511eec7342f59a25f7c0534f1dbea00d01b14
commit-date: 2024-10-15
host: x86_64-unknown-linux-gnu
release: 1.82.0
LLVM version: 19.1.1
Backtrace
No crash, so not applicable?