Shared CFG: add callableExitStep hook for routing epilogue tails to exit nodes

This commit is contained in:
Owen Mansel-Chan
2026-06-16 14:44:47 +01:00
parent db8b2cff07
commit 28afda1726

View File

@@ -1189,6 +1189,23 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
none()
}
/**
* Holds if `n` steps directly to the normal exit node (`normal = true`)
* or the exceptional exit node (`normal = false`) of callable `c`.
*
* By default the only node that reaches a callable's normal exit is the
* "after" node of its body. This predicate lets a language route the tail
* of a function epilogue (such as Go's result-read or deferred-call nodes)
* to the appropriate exit node, which is useful when the body cannot
* terminate normally (e.g. it always ends in a `return`) and therefore has
* no "after" node to anchor the epilogue on.
*
* The default implementation adds no such steps.
*/
default predicate callableExitStep(PreControlFlowNode n, Callable c, boolean normal) {
none()
}
/**
* Holds if there is a local non-abrupt step from `n1` to `n2`.
*
@@ -1464,6 +1481,12 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
n1.isAfter(getBodyExit(c)) and
n2.(NormalExitNodeImpl).getEnclosingCallable() = c
or
Input2::callableExitStep(n1, c, true) and
n2.(NormalExitNodeImpl).getEnclosingCallable() = c
or
Input2::callableExitStep(n1, c, false) and
n2.(ExceptionalExitNodeImpl).getEnclosingCallable() = c
or
n1.(AnnotatedExitNodeImpl).getEnclosingCallable() = c and
n2.(ExitNodeImpl).getEnclosingCallable() = c
)