+1, I think this is very nice to have. I knew about inlining, but not the details of the mechanism, so it's nice to see when I should expect it to happen.
I have some minor wording feedback: + And if an extension has hooked function entry/exit, + then inlining must be skipped. Maybe "And if any extension has hooked function entry/exit, then inlining will be skipped." for clarity? + It must return a type that matches the function declaration. I think this could also be clearer: maybe "It must return a type that matches the function declaration exactly (without an implicit cast)"? Maybe that's overkill, but when reading the original version, it wasn't clear to me why a function would return a type that does not match the declaration: wouldn't that be an error? Then I figured out you're probably talking about implicit casts. + references to tables or table-like objects, <literal>DISTINCT</literal>, Maybe we should say "...to tables, views, and other table-like objects" or otherwise expand on this. In ddl.sgml, we have "Allows <command>SELECT</command> from any column, or specific column(s), of a table, view, materialized view, or other table-like object." + The hypothetical inlined expression must be no more volatile than the original function + (so an <literal>IMMUTABLE</literal> function must inline to an <literal>IMMUTABLE</literal> + expression, and a <literal>STABLE</literal> function must inline to <literal>STABLE</literal> or <literal>IMMUTABLE</literal>). This makes sense, but I don't know how to reason about the volatility of an inlined expression. I don't think most users will be able to either. Is there a way to clarify that? Otherwise, this looks great. Thanks, Maciek