Skip to content

Fix: pure function body lost in modular verification#74

Open
pawinkler wants to merge 9 commits intomainfrom
paul/pure-functions-body-bug
Open

Fix: pure function body lost in modular verification#74
pawinkler wants to merge 9 commits intomainfrom
paul/pure-functions-body-bug

Conversation

@pawinkler
Copy link
Copy Markdown
Collaborator

Description:

When a @pure function B is called from within another function A that is being verified, its Viper function body was missing from the generated program. The verifier could only reason about B via its pre- and postconditions, which limited the usage of pure functions.

Suspected Cause:

The PureUserFunctionEmbedding can be generated in two different ways, either by calling registerForVerification (triggered when the function itself was verified; generated the body) or by calling embedPureFunction (triggered when the function was called in the specifications or body of another function/method; did not generate the body).

Without the body, Viper's function inlining did not work, leading to the verification limitations.

Fix:

Changes in ProgramConverter.kt:

  • New convertAndSetPureBody helper: converts and registers the body of a pure function
  • embedPureFunction: triggers the new helper function
  • registerForVerification: also triggers the new helper function

Note: I am not entirely sure if the implementation of the helper function satisfies our code requirements, please verify this.

@pawinkler pawinkler requested a review from jesyspa March 17, 2026 10:28
…aligned branches for pure and non-pure functions
}
embedPureUserFunction(declaration.symbol, signature)
} else {
val returnTarget = returnTargetProducer.getFresh(signature.callableType.returnType)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code fragment looks duplicated, am I missing something?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've merged your PR and resolved it.

pawinkler and others added 3 commits March 23, 2026 09:47
## Summary
- Extracts `createBodyConversionContext` helper to eliminate duplicated
creation of `ReturnTarget`, `RootParameterResolver`, and
`StmtConversionContext` between `registerForVerification` (non-pure
branch) and `embedPureUserFunction`.
- Net reduction of ~10 lines; both call sites now delegate to the shared
helper.

## Test plan
- [x] `./gradlew :formver.compiler-plugin:compileKotlin` passes
- [x] `./gradlew :formver.compiler-plugin:test --tests "*Pure*"` passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@pawinkler pawinkler requested a review from jesyspa March 25, 2026 15:05
symbol: FirFunctionSymbol<*>,
signature: FullNamedFunctionSignature
): PureUserFunctionEmbedding {
// Return if already registered
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is not helpful, please remove it.

val new = PureUserFunctionEmbedding(processCallable(symbol, signature))
// Insert into the map before processing the body, so recursive calls can find the embedding.
functions[signature.name] = new
val declaration = symbol.fir as? FirSimpleFunction
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the desired behaviour if this cast fails?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cast would fail when symbol is not a FirSimpleFunction, but we allow the @Pure annotation only on normal functions. So if I understand correctly, this should never occur, but it could fail silently. Should I throw an error here for safety?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if the case cannot happen please throw an exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants