Open
Description
The following code:
use std::{borrow::Cow, collections::HashMap};
#[derive(Debug)]
struct Message(String);
impl Message {
fn interface(&self) -> &str {
&self.0
}
}
#[derive(Debug)]
struct Proxy<'p>(Cow<'p, str>);
impl<'p> Proxy<'p> {
fn interface(&self) -> &str {
&self.0
}
}
#[derive(Hash, Eq, PartialEq)]
struct ProxyKey<'key>(Cow<'key, str>);
impl From<&Proxy<'_>> for ProxyKey<'_> {
fn from(proxy: &Proxy<'_>) -> Self {
ProxyKey(Cow::from(proxy.interface().to_owned()))
}
}
impl<'key> From<&'key Message> for ProxyKey<'key> {
fn from(msg: &'key Message) -> Self {
ProxyKey(Cow::from(msg.interface()))
}
}
struct ProxyGroup<'p> {
proxies: HashMap<ProxyKey<'static>, Proxy<'p>>,
}
impl<'p> ProxyGroup<'p> {
pub fn new() -> Self {
Self {
proxies: HashMap::new(),
}
}
pub fn add<'a: 'p>(&mut self, proxy: Proxy<'a>) {
let key = ProxyKey::from(&proxy);
self.proxies.insert(key, proxy);
}
pub fn handle_next_signal(&self) {
let msg = Message(String::from("some.interface"));
match self.get_proxy_for_msg(&msg) {
Some(_) => Self::consume_msg(msg),,
None => (),
}
}
fn get_proxy_for_msg<'a, 'b>(&'a self, msg: &'b Message) -> Option<&'a Proxy<'p>>
where
'p: 'a,
{
let key = ProxyKey::from(msg);
self.proxies.get(&key)
}
fn consume_msg(_msg: Message) {}
}
Which I (and devs I consulted on the Discord and IRC) think should compile. However, it doesn't and you get the following error:
error[E0623]: lifetime mismatch
--> src/main.rs:67:9
|
61 | fn get_proxy_for_msg<'a, 'b>(&'a self, msg: &'b Message) -> Option<&'a Proxy<'p>>
| -------- ----------- these two types are declared with different lifetimes...
...
67 | self.proxies.get(&key)
| ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `msg` flows into `self` here
error: aborting due to previous error
i-e for some reason the lifetime of the key
get associated with lifetime of the Proxy
value we get from the HashMap::get
call. I think it's likely a compiler bug. Even it is not, it'd be great to get better diagnostics/error message from the compiler for this so I can tell what exactly is going wrong here.
Here is the playground link for trying this out conveniently.
NB: If I change the code to make use of iterator, it works:
fn get_proxy_for_msg<'a, 'b>(&'a self, msg: &'b Message) -> Option<&'a Proxy<'p>>
where
'p: 'a,
{
let key = ProxyKey::from(msg);
self.proxies
.iter()
.find(|&(k, _)| &key == k)
.map(|(_, v)| v)
}
Meta
rustc --version --verbose
:
rustc 1.48.0 (7eac88abb 2020-11-16)
binary: rustc
commit-hash: 7eac88abb2e57e752f3302f02be5f3ce3d7adfb4
commit-date: 2020-11-16
host: x86_64-unknown-linux-gnu
release: 1.48.0
LLVM version: 11.0
Reproducible on nightly (bb17823 2020-12-25) as well.