Closed
Description
I tried this code:
#![warn(rust_2021_incompatible_closure_captures)]
#![feature(capture_disjoint_fields)]
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
pub struct GameMode {}
struct GameStateManager<'a> {
gamestate_stack: Vec<Box<dyn GameState<'a> + 'a>>,
}
pub trait GameState<'a> {}
async fn construct_gamestate_replay<'a>(
_gamemode: &GameMode,
_factory: &mut GameStateManager<'a>,
) -> Box<dyn GameState<'a> + 'a> {
unimplemented!()
}
type FutureGameState<'a, 'b> = Pin<Box<dyn Future<Output = Box<dyn GameState<'a> + 'a>> + 'b>>;
struct MenuOption<'a> {
command: Box<dyn for<'b> Fn(&'b mut GameStateManager<'a>) -> FutureGameState<'a, 'b> + 'a>,
}
impl<'a> MenuOption<'a> {
fn new(
_command: impl for<'b> Fn(&'b mut GameStateManager<'a>) -> FutureGameState<'a, 'b> + 'a,
) -> Self {
unimplemented!()
}
}
struct MenuState<'a> {
options: Vec<MenuOption<'a>>,
}
impl<'a> GameState<'a> for MenuState<'a> {}
pub async fn get_replay_menu<'a>(
gamemodes: &'a HashMap<&str, GameMode>,
) -> Box<dyn GameState<'a> + 'a> {
let recordings: Vec<String> = vec![];
let _ = recordings
.into_iter()
.map(|entry| {
MenuOption::new(move |f| {
Box::pin(construct_gamestate_replay(&gamemodes[entry.as_str()], f))
})
})
.collect::<Vec<_>>();
todo!()
}
fn main() {}
This compiles successfully without disjoint captures, but with them enable gives a lifetime error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:42:5
|
42 | gamemodes: &'a HashMap<&str, GameMode>,
| ^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 41:30...
--> src/main.rs:41:30
|
41 | pub async fn get_replay_menu<'a>(
| ^^
note: ...so that the expression is assignable
--> src/main.rs:42:5
|
42 | gamemodes: &'a HashMap<&str, GameMode>,
| ^^^^^^^^^
= note: expected `&HashMap<&str, GameMode>`
found `&'a HashMap<&str, GameMode>`
note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the body at 48:29...
--> src/main.rs:48:29
|
48 | MenuOption::new(move |f| {
| _____________________________^
49 | | Box::pin(construct_gamestate_replay(&gamemodes[entry.as_str()], f))
50 | | })
| |_____________^
note: ...so that the expression is assignable
--> src/main.rs:49:17
|
49 | Box::pin(construct_gamestate_replay(&gamemodes[entry.as_str()], f))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `Pin<Box<dyn Future<Output = Box<dyn GameState<'_>>>>>`
found `Pin<Box<dyn Future<Output = Box<dyn GameState<'_>>>>>`
I would expect either it to compile successfully, or the rust_2021_incompatible_closure_captures
lint to provide a suggestion to make it compile successfully.
Found in the 2021 crater run for https://crater-reports.s3.amazonaws.com/pr-87190-3/try%23a7a572ce3edd6d476191fbfe92c9c1986e009b34/gh/stefan-blair.tetrust/log.txt
(Sorry, didn't narrow the example down further, or if this is a duplicate.)
Meta
rustc --version --verbose
:
rustc 1.56.0-nightly (ac50a5335 2021-08-27)
binary: rustc
commit-hash: ac50a53359328a5d7f2f558833e63d59d372e4f7
commit-date: 2021-08-27
host: x86_64-apple-darwin
release: 1.56.0-nightly
LLVM version: 13.0.0
cc @rust-lang/wg-rfc-2229