link to code - https://github.com/starduv/lil-schemy/blob/ea8ac2e8049f3b8bcf069374e7cd2e0c40c79508/native/src/open_api/generate_schema.rs#L54
diagnostic error
error[E0597]: `node` does not live long enough
--> src/open_api/generate_schema.rs:54:18
|
45 | fn find_paths<'m, 'n : 'm>(
| -- lifetime `'m` defined here
46 | open_api: &mut OpenApi,
47 | node: SchemyNode<'n>,
| ---- binding `node` declared here
...
54 | for child in node.children() {
| ^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
70 | _ => find_paths(open_api, child.clone(), file_path, deferred_schemas, symbol_tables),
| ------------------------------------------------------------------------------- argument requires that `node` is borrowed for `'m`
...
73 | }
| - `node` dropped here while still borrowed
The link to github shows different code than the snippet here. Which one is correct?
The permalink goes to line 54. The snippet is the diagnostic that also highlights line 54. Oh, in the diagnostic i see the additional lifetime. Either way, i get the same error and it doesn't work.
The root issue is likely the data structure
pub enum SchemyNode<'m> {
BlockStmt {
node: &'m BlockStmt,
parent: Option<Box<&'m SchemyNode<'m>>>,
},
/* and more similar variants… */
}
Then your children
function creates values with back-pointers to the parents, so it requires a &'m self
borrow; but your use-site, the find_paths
function, violates this requirements in that it owns the node
argument, yet is expected to be able to return (indirectly, via the symbol_tables
argument) references to it. To complete the issue, this applies not only to node
, but via the recursive calls also to the child
ren, so there’s very clearly newly generated SchemyNode
values that nobody can own after the find_paths
function terminates.
Back-pointers in Rust are uncommon in general, mostly we avoid them. If we don’t, references are commonly not the right tool for representing pointers in nested data structures, in particular if you aren’t very certain who else is going to own all those nodes. Migrating to some usage of Arc
is a potential alternative candidate solution, if avoiding them isn’t an option. In any case, data structures without any lifetime parameters are infinitely easier to work with, and generally the recommended path, especially at a beginner level of Rust usage. (On that node, it’s a pity that the compiler so easily suggests you to add them, if you ever write a &T
type into any field).
For any more concrete tips on the best approach for your code I’d need to dig deeper than the preliminary glance at the code that I’m doing at the moment.
i wanted to avoid cloning up a tree of nodes. now i see why i need Arc. thanks!