One of the things I don't like about C++ is that signatures often end up being complex. Sadly, D2's signatures are even more complex (D1 had an edge on C++ there).
Why not simply move "linting" information to a separate line and keep the "first line" of function definitions clean.
E.g. to require the return value, and c.x to have the same lifetime:
int myfunc(A a, ref T c)
lifetime(return,c.x)
{
body
}
Or introduce a new operator £ that takes the lifetime of an object, which I think is even better:
int myfunc(A a, B b, ref T c)
require(£return==£a.x)
{
body
}
This would also allow specifying destruction order
require(£b < £a.x)
Or are there things that needs to be expressed about life times that cannot work with such a scheme?
I also think a scheme like this should allow library authors to give names to individual requirements and invariants.
That would allow better error messages, maybe even custom error handlers, e.g.:
…
invariant outofbounds { tests }
…
require lifetimes (…)
…
__interpret_compilation_error outofbounds (context) {
if (context.xyz such and such)
return "This failed because..."
}