GATs and lifetimes (and more lifetimes)

so we already found out that closures and GATs don't play well together, so much so that we use this beautiful workaround: OperateIn in selfref - Rust

now we're running into this:

error[E0309]: the parameter type `T` may not live long enough
   --> src/mock/mod.rs:484:12
    |
484 |           if plug.as_ref().operate_in(MockPluginInit::<T> {
    |  ____________^
485 | |             arg,
486 | |             _p: PhantomData,
487 | |         }) {
    | |__________^ ...so that the type `T` will meet its required lifetime bounds
    |
help: consider adding an explicit lifetime bound...
    |
387 |     where for<'k> T: crate::Plugin<'k> + 'env, T: Default {
    |                                        ++++++

where we have this code:

impl<'ph, 'env> MockPlugin<'ph, 'env> {
    pub fn new<T>(
        env: Pin<&'env PluginEnvironment<'env>>,
        filename: CString,
        arg: Option<&CStr>,
    ) -> Option<Pin<Rc<Holder<'env, MockPluginK<'env>>>>>
    where for<'k> T: crate::Plugin<'k>, T: Default {
        struct MockPluginNewWith<'env> {
            filename: CString,
            env: Pin<&'env PluginEnvironment<'env>>
        }
        impl<'k, 'env> NewWith<'k, MockPluginK<'env>>
        for MockPluginNewWith<'env>
        where 'env: 'k {
            fn new_with<'ph>(self) -> UnsafeCell<MockPlugin<'ph, 'env>>
            where 'k: 'ph {
                let filename = self.filename;
                let env = self.env;
                UnsafeCell::new(MockPlugin {
                    methods: crate::internals::Ph {
                        hexchat_hook_command,
                        hexchat_hook_server,
                        hexchat_hook_print,
                        hexchat_hook_timer,
                        hexchat_hook_fd,
                        hexchat_unhook,
                        hexchat_print,
                        userdata: hexchat_printf as *mut _,
                        hexchat_command,
                        hexchat_commandf_do_not_use: hexchat_commandf,
                        hexchat_nickcmp,
                        hexchat_set_context,
                        hexchat_find_context,
                        hexchat_get_context,
                        hexchat_get_info,
                        hexchat_get_prefs,
                        hexchat_list_get,
                        hexchat_list_free,
                        hexchat_list_fields,
                        hexchat_list_next,
                        hexchat_list_str,
                        hexchat_list_int,
                        hexchat_plugingui_add,
                        hexchat_plugingui_remove,
                        hexchat_emit_print,
                        hexchat_read_fd,
                        hexchat_list_time,
                        hexchat_gettext,
                        hexchat_send_modes,
                        hexchat_strip,
                        hexchat_free,
                        hexchat_pluginpref_set_str,
                        hexchat_pluginpref_get_str,
                        hexchat_pluginpref_set_int,
                        hexchat_pluginpref_get_int,
                        hexchat_pluginpref_delete,
                        hexchat_pluginpref_list,
                        hexchat_hook_server_attrs,
                        hexchat_hook_print_attrs,
                        hexchat_emit_print_attrs,
                        hexchat_event_attrs_create,
                        hexchat_event_attrs_free,
                    },
                    filename: filename,
                    plugin_name: ptr::null(), // not initialized yet!
                    plugin_desc: ptr::null(),
                    plugin_vers: ptr::null(),
                    free_strings: false,
                    env: env,
                })
            }
        }
        let plug = Rc::pin(Holder::new_with(MockPluginNewWith {
            filename,
            env,
        }));
        struct MockPluginInit<'arg, T> {
            arg: Option<&'arg CStr>,
            _p: PhantomData<T>
        }
        impl<'k, 'env: 'k, 'arg, T> OperateIn<'k, MockPluginK<'env>>
        for MockPluginInit<'arg, T>
        where for<'l> T: crate::Plugin<'l> + Default, T: 'k {
            type Out = bool;
            fn operate_in<'ph>(
                self,
                ph: Pin<&'ph UnsafeCell<MockPlugin<'ph, 'env>>>,
            ) -> bool where 'k: 'ph {
                let ptr = ph.get();
                let arg = self.arg;
                unsafe {
                    // initialize plugin_name from filename(!)
                    (*ptr).plugin_name = (*ptr).filename.as_ptr();
                    crate::hexchat_plugin_init::<'ph, T>(
                        MutLtPtr::from_raw(ptr as *mut _),
                        ptr::addr_of_mut!((*ptr).plugin_name),
                        ptr::addr_of_mut!((*ptr).plugin_desc),
                        ptr::addr_of_mut!((*ptr).plugin_vers),
                        arg.map(|arg| arg.as_ptr()).unwrap_or(ptr::null()),
                    ) != 0
                }
            }
        }
        if plug.as_ref().operate_in(MockPluginInit::<T> {
            arg,
            _p: PhantomData,
        }) {
            Some(plug)
        } else {
            None
        }
    }
}

but rustc's suggestion here is, honestly, very wrong. we don't want T: 'env. if anything we want 'env: T. that's because 'env: 'k, 'k: 'ph but 'ph is artifical and T: Plugin<'ph> + 'ph (which is always smaller than 'k).

the problem with unstable features is that you get to run into all the issues and there's no help because it's all still being worked on. anyway, any ideas what we can do here aside from throwing more trait Workaround at the problem?

oh yeah you do need to use GATs everywhere for GATs to work...

hmm that's a pain and a half...

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.