Two similar code snippets but only one triggers a lifetime error - rust

#![feature(rustc_private)]
extern crate rustc;
use rustc::hir::intravisit as hir_visit;
use rustc::hir;
use std::marker::PhantomData;
// ----------------------------------------------------------------------------
// Why does this compile?
// ----------------------------------------------------------------------------
pub struct Map<'a> {
pub _m: PhantomData<&'a ()>,
}
pub struct SomeVisitor<'a, 'tcx: 'a> {
pub map: &'a Map<'tcx>,
}
pub enum NestedVisitorMap<'this, 'tcx: 'this> {
None,
OnlyBodies(&'this Map<'tcx>),
All(&'this Map<'tcx>),
}
pub trait Visitor<'v>: Sized {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
}
impl<'v, 'tcx> Visitor<'v> for SomeVisitor<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::All(self.map)
}
}
// ----------------------------------------------------------------------------
// Why does this *not* compile?
// ----------------------------------------------------------------------------
pub struct SomeVisitor2<'a, 'tcx: 'a> {
pub map: &'a hir::map::Map<'tcx>,
}
impl<'v, 'tcx> hir_visit::Visitor<'v> for SomeVisitor2<'v, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
hir_visit::NestedVisitorMap::All(self.map)
}
}
fn main() {}
playground
NestedVisitorMap and Visitor
I recently ran into a lifetime issue and I decided to recreate it without any dependencies. The odd thing is that I can not recreate the lifetime error. To me both implementations look the same from the outside, but only one compiles successfully. Why is that?
rustc 1.21.0-nightly (e26688824 2017-08-27)
Update:
The problem seems to be the RefCell inside Map.
#[derive(Clone)]
pub struct Map<'hir> {
inlined_bodies: RefCell<rustc::util::nodemap::DefIdMap<&'hir hir::Body>>,
}
If there is a RefCell with a inner lifetime, it will trigger an error.
playground
Update2:
It turns out that I just mixed up lifetime subtyping. playground
I still don't know why only RefCell causes the error.

Related

Access a composition field of a struct from Trait

In the following example, is there any way to access the comp_field within the implementation of BaseTrait for MyStruct?
pub trait CompositionTrait {
//methods
}
pub trait BaseTrait {
fn get_comp_field(&self) -> Box<dyn CompositionTrait>;
}
pub struct MyStruct {
pub comp_field: Box<dyn CompositionTrait>
}
impl MyStruct {
pub fn new(config: Config) -> Result<Self, Error> {
// here based on config, comp_field is assigned with different structs, all of which implements CompositionTrait.
}
}
impl BaseTrait for MyStruct {
fn get_comp_field(&self) -> Box<dyn CompositionTrait> {
self.comp_field // Error
}
}
The following error is presented for the current implementation:
cannot move out of `self.comp_field` which is behind a shared reference
move occurs because `self.comp_field` has type `std::boxed::Box<dyn BaseTrait::CompositionTrait>`, which does not implement the `Copy` trait
The eventual need for such implementation would be accessing the methods of comp_field in the functions which are based on BaseTrait.
The error occurs because you're trying to move the box out of the struct, but the struct is not mutable (and even if it was you would need to put something else in place of the box you're removing). Instead you should return a reference to the CompositionTrait:
pub trait CompositionTrait {
//methods
}
pub trait BaseTrait {
fn get_comp_field(&self) -> &dyn CompositionTrait;
}
pub struct MyStruct {
pub comp_field: Box<dyn CompositionTrait>
}
impl BaseTrait for MyStruct {
fn get_comp_field(&self) -> &dyn CompositionTrait {
&*self.comp_field // Or self.comp_field.as_ref()
}
}
Playground

Lifetimes for traits

Let there is some struct:
struct ResourceData { }
We can create its list:
pub struct ResourceList
{
pub v: Vec<ResourceData>,
}
but if I add a level of indirection:
pub trait Resource<'a> {
fn data(&self) -> &'a ResourceData;
fn data_mut(&mut self) -> &'a mut ResourceData;
}
then I am messed:
pub struct ResourceList2<R: Resource<'a>> // What should be 'a?
{
pub v: Vec<R>,
}
What should be 'a?
'a could be the lifetime of the vector, but if an element is removed, the lifetime of the references shorten, because references break. So, accordingly my understanding, 'a isn't the lifetime of the vector.
Resource should not have a lifetime argument, but instead just use elided lifetimes:
pub trait Resource {
fn position(&self) -> &ResourceData;
fn position_mut(&mut self) -> &mut ResourceData;
}
After understanding this, the question disappears, just:
pub struct ResourceList2<R: Resource> // What should be 'a?
{
pub v: Vec<R>,
}

Is it possible to change generic lifetime of a struct?

I have an existing library which exposes a necessary data via reference to a struct with lifetime parameter. The problem is that I need to expose it using wasm_bindgen. For that I've created a separate struct in my wasm module:
#[wasm_bindgen]
struct Event {
// doesn't compile - passed from another lib
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
Now, the problem is that 'a and 'b are lifetimes that are passed from an outer library, but wasm-bindgen limitations doesn't allow for a Rust struct that's about to be accessible via WebAssembly to contain any generic params on its own - therefore Event cannot define any references to 'a or 'b.
While I can get rid of 'a by using raw pointers, I cannot do the same with 'b. Technically I can mock it with 'static, however I'm unable to change struct's generic lifetime param from 'a to 'static.
How can I keep reference to an &'a InnerEvent<'b> in a way that doesn't collide with wasm-bindgen restrictions?
EDIT:
My particular use case looks like follows - I'm writing a wrapper over a library, that enables a pub/sub for custom user data:
pub struct Transaction<'txn> {
// .. omitted fields
}
pub struct SomeStruct {
pub fn subscribe<F>(&mut self, f: F) -> Subscription
where F: Fn(&Transaction, &Event) -> () + 'static {
// .. method body
}
}
Now I need to expose SomeStruct over to WebAssembly. For this I'm creating a wasm-bingen wrapper, and I need it to be able to expose its subscribe capabilities over to a JavaScript side:
#[wasm_bindgen]
pub struct SomeStructWrapper(SomeStruct);
#[wasm_bindgen]
impl SomeStructWrapper {
#[wasm_bindgen]
pub fn observe(&mut self, f: js_sys::Function) -> SubscriptionWrapper {
let sub = self.0.observe(move |transaction, event| {
// transaction is: &'a Transaction<'txn> and event: &'a Event
let e = EventWrapper::new(e, txn);
let arg: JsValue = e.into();
f.call1(&JsValue::UNDEFINED, &arg);
});
SubscriptionWrapper(sub)
}
}
#[wasm_bindgen]
pub struct SubscriptionWrapper(Subscription);
Now the problem is that I need to references to both of the rust callback parameters (transaction and event) inside of JavaScript callback. This means that EventWrapper needs to store them as fields:
// code below won't compile because
// wasm_bindgen doesn't allow its structs to declare lifecycle parameters
#[wasm_bindgen]
pub struct EventWrapper {
transaction: &'a Transaction<'txn>,
inner_event: &'a Event,
}
// we can get rid of 'a by casting references to raw pointers
// but this won't fix issue with 'txn lifecycle
#[wasm_bindgen]
pub struct EventWrapper {
transaction: *const Transaction<'txn>,
inner_event: *const Event,
}
In the below code, it get error `error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently?
use wasm_bindgen::prelude::*;
struct InnerEvent<'a> {
_a: &'a str
}
#[wasm_bindgen]
struct Event<'a,'b> where 'a: 'b {
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event<'a,'b> {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
Output
error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently
--> src\lib.rs:8:13
|
8 | struct Event<'a,'b> where 'a: 'b {
| ^^^^^^^
You can get around like that
use wasm_bindgen::prelude::*;
struct InnerEvent<'a> {
_a: &'a str
}
struct Event<'a,'b> where 'a: 'b {
inner: &'a InnerEvent<'b>
}
impl<'a,'b> From<&'a InnerEvent<'b>> for Event<'a,'b> {
fn from(e: &'a InnerEvent<'b>) -> Self {
Event { inner: e }
}
}
#[wasm_bindgen]
struct WrapEvent
{
i: Event<'static, 'static>
}
But this meet your requierement?
This issue is also discussed here How to get rid of lifetime in wrapper struct for wasm_bindgen

How to properly solve lifetime inferences in struct?

The Rust playground code is here.
I have a struct of Token which has lifetime 'tok, and a scanner has lifetime 'lexer. I'm using both of them in another struct Parser, then I had a problem:
pub struct Token<'tok> {
pub value: Cow<'tok, str>,
pub line: usize,
}
pub struct Scanner {
pub source: Vec<char>,
pub current: usize,
pub line: usize,
}
pub struct Parser<'lexer> {
pub curr: &'lexer Token<'lexer>,
pub prev: &'lexer Token<'lexer>,
scanner: &'lexer mut Scanner,
}
impl <'lexer> Parser<'lexer> {
pub fn advance(&mut self) {
self.prev = self.curr;
self.curr = &self.scanner.next(); // cannot inference lifetime
}
}
I think the problem is Token has lifetime 'tok, and the borrow checker doesn't know the relation between 'tok and 'lexer so it can't inference proper lifetime.
However, I can avoid the problem by modifying it into the updated code:
pub struct Parser<'lexer> {
pub curr: Token<'lexer>,
pub prev: Token<'lexer>,
scanner: &'lexer mut Scanner,
}
impl <'lexer> Parser<'lexer> {
pub fn advance(&mut self) {
let prev = std::mem::replace(&mut self.curr, self.scanner.next());
self.prev = prev;
}
}
And with Token produced by next() is static:
impl Scanner {
pub fn next(&mut self) -> Token<'static> {
Token {
value: Cow::from(""),
line: 0,
}
}
}
It does compile but I think it's not ideal because all tokens are cloned from scanner into parser(they are not references anymore) and living until end of Parser's life. So memory usage is doubled. Is there a more proper way to deal with this?
Actualy your code structure is not ideal to deal with the borrow checker here why:
Token struct should be owned, the struct itself do not require any allocations (as the token is owned some indrection are required to allow prev <-> next switching)
None of the Parser or Lexer should own the base data so it will be easy to bound proper lifetime
In our case Vec<Char> is not a friendly type to work with (we do not need to own the data and this will be harder to make the comipler understand lifetimes), instead we're going to use an &'str but you could reproduce the exact behaviours with an &[char])
Here is an example that compile just fine
pub struct Token<'source> {
pub value: Cow<'source, str>,
pub line: usize,
}
pub struct Scanner<'source> {
pub source: &'source str,
pub current: usize,
pub line: usize,
}
pub struct Parser<'source> {
pub curr: Option<Token<'source>>,
pub prev: Option<Token<'source>>,
scanner: Scanner<'source>,
}
impl <'source>Scanner<'source> {
pub fn next(&'source /* DONT Forget to bound 'source to `self` */ self) -> Token<'source> {
Token {
value: Cow::from(self.source), /* `self.source` is bound to `'source` so the compiler understand that the token lifetime is the same than the source's one */
line: 0,
}
}
}
impl <'lexer> Parser<'lexer> {
pub fn advance(&'lexer mut self) {
self.prev = self.curr.take();
self.curr = Some(self.scanner.next());
}
}

Source trait is inaccessible

The situation is (severely simplified) this (playpen):
mod tokentree {
pub struct TokenTree;
mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
I get the following error (both on nightly and beta):
<anon>:20:22: 20:47 error: source trait is inaccessible
<anon>:20 println!("{:?}", [TokenTree].intern_strs());
^~~~~~~~~~~~~~~~~~~~~~~~~
My problem is that I don't even know what this is supposed to mean.
It needs a pub declaration. Also your declarations are all over the place. Recommended form is to stick your pub mod declarations first, then, use.
Here is the working example.
mod tokentree {
pub struct TokenTree;
pub mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
pub use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
(playpen)
What happened here is that you stumbled upon following glitches:
https://github.com/rust-lang/rust/issues/18241
https://github.com/rust-lang/rust/issues/16264
You can't export your traits from a private module. That's why you need to change mod serialize into pub mod serialize. For example this playpen example demonstrates that exporting struct Export works, but un-commenting the println! will make it stop compiling, because we used a trait.
Tip: One thing that helps me with the visibility rules is to generate doc files and see which doc files are visible.

Resources