Proposal
Allow functions to be declared as inline fn
, which would require them to be inlined into the callee. This makes it easy to do two key things: return unsized types, and return references to the stack.
Here's an example of both capabilities at the same time. I'm using the 'super
reserved keyword for the special "callee" reference:
impl<T: ?Sized> Pin<T> {
pub inline const fn value(mut value: T) -> Pin<&'super mut T> {
// SAFETY: value is on a fixed position in the stack
// and is inaccessible except via Pin wrapper
unsafe { Pin::new_unsafe(&mut value) }
}
}
Example usage:
fn main() {
let generator = Pin::value(|| {
let mut i = 0;
loop {
yield i + 1;
i += 1;
}
});
// do stuff with the generator
}
Similarly, this would allow wrapper types like ManuallyDrop
to take and return unsized values:
impl<T: ?Sized> ManuallyDrop<T> {
pub inline const fn new(inner: T) -> Self {
ManuallyDrop { inner }
}
}
...and could be used to allow alloca
to be implemented:
pub unsafe inline fn alloca(layout: Layout) -> &'super [u8] {
// platform specific stack manipulation asm goes here
}
Semantics
And inline
function would be syntactical sugar for effectively cutting-and-pasting the body of the function into the callee, similar to the way macros work right now.
The key difference between inline fn
and #[inline(always)]
is the latter is just a (strong) hint that may still be ignored by the compiler, eg in the case of a function that recurses. An inline
function would not be allowed to to have call graph with recursion and would never show up in stack frames. (how it should interact with #[track_caller]
etc is an interesting question!).
I'm frankly not a compiler expert, so I'm sure someone can chime in on how that simple model wouldn't quite work with unsized function arguments and unsized return values. But the 'super
lifetime by itself seems valuable to me on its own.
Implementation
Again, I'll defer to actual experts on the viability of this.