-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Unclear compiler error when impl Trait
return value captures non-'static argument
#82171
Comments
This seems similar to #79415. |
That might be reasonable, it'll just be tricky to identify the specific cases where this action would be appropriate to try and avoid a diagnostic that is too verbose for uncommon cases.
Good catch! It is a similar case, but will likely need to be handled independently. Let's not close either :) |
There's no way currently to express that an |
A friend of mine just encountered something similar, and I found this workaround from #34511, which seems to fit your problem here. (However, I haven't personally figured out why this works... Any help will be appreciated!) I tried to fix your code using this method: fn foo<T>(a: T) -> impl Iterator<Item = String> + 'static
where
T: std::fmt::Display,
{
std::iter::once(a.to_string())
}
// What are those?
trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}
fn bar1<'a>(a: &'a str) -> impl Iterator<Item = String> + 'static + Captures<'a> {
foo(a)
} Update: Now this workaround can be automatically applied via the fix_hidden_lifetime_bug.rs library. Update: This could be resolved in language edition 2024 which will, as currently planned, allow you to use TAIT to avoid over-capturing: #115822, HackMD |
I'm having a similar issue here: I can't seem to force the returned trait Animal {}
struct Horse;
impl Animal for Horse {}
// Using `impl Trait` here to avoid unnecessary heap allocation if `k < 10`
fn make_animal(set: impl FnOnce(u32)) -> impl Animal {
set(3);
Horse // alternatively, return value of complex/unnamed type that impls Animal
}
fn expand_zoo(zoo: &mut Vec<Box<dyn Animal>>) {
let mut k = 0;
let x = make_animal(|r| k = r);
if k >= 10 {
zoo.push(Box::new(x));
}
} |
@gh2o Given what you're trying to do, you might have to resort to leveraging interior mutability and runtime reference counting. |
Triage, the current output for the original report is
|
I also ran into this issue, my use case is a function that takes an iterator, reads it to build & send a request, and returns an iterator on the response. Something like: fn lifetime_issue() {
let v = Vec::new();
let _foo = foo(&v);
drop(v); // do something with v
}
fn foo<'output, 'input_item, 'input_iter>(_: impl IntoIterator<Item = &'input_item String> + 'input_iter) -> impl Iterator<Item = String> + 'output
{
std::iter::empty()
}
A minimal version of the issue: struct NotCopy;
trait Marker {}
impl<'a> Marker for &'a NotCopy {}
impl Marker for () {}
fn lifetime_issue() {
let nc = NotCopy;
let _foo = foo(&nc);
drop(nc); // do something with nc
}
fn foo(_: impl Marker) -> impl Marker {}
Rustc version: $ rustc --version --verbose
rustc 1.67.1 (d5a82bbd2 2023-02-07)
binary: rustc
commit-hash: d5a82bbd26e1ad8b7401f6a718a9c57c96905483
commit-date: 2023-02-07
host: x86_64-unknown-linux-gnu
release: 1.67.1
LLVM version: 15.0.6 |
@estebank Regarding your reply (#82171 (comment)):
I still can't understand how TAIT could help convey the idea that in the original example (#82171 (comment)), trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}
fn bar1<'a>(a: &'a str) -> impl Iterator<Item = String> + 'static + Captures<'a> {
foo(a)
} If I understand correctly, it seems to me that, with TAIT: type Bar<'a> = impl Iterator<Item = String> + 'a;
fn bar2(a: &str) -> Bar {
foo(a)
} ... should be equivalent to: fn bar3<'a>(a: &'a str) -> impl Iterator<Item = String> + 'a {
foo(a)
} ... which has a weaker bound in the return type. Could you please elaborate a bit? Many thanks! |
TAIT can be used to indicate that the return type of #![feature(type_alias_impl_trait)]
mod mod_foo {
pub type ReturnTy = impl Iterator<Item = String> + 'static;
pub fn foo<T>(a: T) -> ReturnTy
where
T: std::fmt::Display,
{
std::iter::once(a.to_string())
}
}
fn bar(a: &str) -> impl Iterator<Item = String> + 'static {
mod_foo::foo(a)
} The need for a separate mod is unfortunate, but hopefully it shouldn't be necessary when TAIT is stabilized. The default behavior for impl-trait in return position is to be generic over all type parameters in scope. Desugared to TAIT, it is like: pub type ReturnTy<T> = impl Iterator<Item = String> + 'static;
pub fn foo<T>(a: T) -> ReturnTy<T>
// ... |
@aliemjay Wow, that's somehow surprising to me. Apart from having to add a new module (which seems more like a current limitation), I was also surprised by having to change the callee rather than the caller, since the compile time error is usually found on the caller's side: 13 | fn bar(a: &str) -> impl Iterator<Item = String> + 'static {
| ---- hidden type `impl Iterator<Item = String> + 'static` captures the anonymous lifetime defined here ... and since the "wrong" callee code compiles alright in isolation, this incorrectness might never be exposed to a lib author if (s)he hasn't included the right kind of test cases. It seems to me that it has always been the API consumers' responsibility to perform the Anyway, thanks a lot for your detailed explanation! |
(cc @estebank)
I tried this code (the explicit
'static
lifetime is unnecessary but emphasizes the implicit'static
requirement ofimpl Trait
):See playground.
I expected to see this happen:
Successful compilation or a clear error message suggesting that
impl Trait
can't be used in this way due to the non-'static
lifetime offoo
's argumenta
.Instead, this happened:
foo
's return value isn't dependent ona
's lifetime sinceto_string
converts it to an ownedString
. ReturningBox<dyn Iterator<Item = String>>
instead of usingimpl Trait
fixes the error.Neither of the compiler's suggestions are the "right" fix here, since I'd like the return value to have a
'static
lifetime but don't want to requirea
to have one.I think the ideal fix (to the error message) would be something along the lines of:
impl Trait
doesn't allow the return value not to depend on the lifetime ofa
(maybe with a tracking issue if this limitation is being addressed)Box<dyn Trait>
and/or a concrete typeMeta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: