This is a little different than other examples of such issues that I've seen. See the playground I put together for the actual code and compiler error I'm running into.
You'll notice that the error has to do with a set of chained passes which take as input a mutable reference to a Function
struct, and return the same reference when done with it. If you modify those same passes to instead take a Function
by-value, everything compiles and works happily, so the error seems to be related to an inability of the compiler to match the lifetime of the actual reference to that expected by the passes. Interestingly, this only seems to come up when chaining more than two passes, a single chain
'd pass works fine, it just becomes an issue when further passes are chained.
For context, what I was trying to accomplish was a trait that could represent compiler passes in different stages of my compiler, with the following properties:
- Can represent passes which operate on by-value or by-reference inputs/outputs. In the latter case, the lifetime of the inputs/outputs would all be the same (i.e. you aren't changing the lifetime across passes, but rather chaining together passes which will be given a reference to some value and every pass will operate on that one reference, or alternatively taking a value by-reference and returning a new type by-value).
- Can represent passes whose input/output is the same type or different types (e.g. when lowering to another representation, you might take
AstType
as input, and returnIrType
as output.) - Can be chained together to form pipelines of passes where the output of a pass is passed as the input to the next. This would allow you to represent a compiler as a series of passes which successively transform the input to some final output form.
I've worked around the issue by defining a secondary trait that specifically represents passes that take a mutable reference to some input, since I don't have any cases where I'm chaining those kind of passes with others that operate by-value, but nevertheless, I'd really like to better understand why I can't represent those types of passes using the same trait. As far as I can tell, the compiler should be able to infer that the passes all expect a reference of the same lifetime, but after banging my head against it for days, I think I've lost the ability to reason about it further.
I suspect this is related to #30472, but I'm not 100% sure on that, and it isn't clear to me if what I was aiming for is something the Rust compiler is intended to support or not. Anyway, hope some of you all may have more insight into this than me!
Paul