Skip to content

Upcasts for access-permissions on strict supertypes#106

Draft
pawinkler wants to merge 2 commits intopaul/interface-permissionsfrom
paul/upcasts
Draft

Upcasts for access-permissions on strict supertypes#106
pawinkler wants to merge 2 commits intopaul/interface-permissionsfrom
paul/upcasts

Conversation

@pawinkler
Copy link
Copy Markdown
Collaborator

Summary

This PR was extracted from #92 and is based on #105. It concerns the implementation of a new Upcast embedding. It allows us to detect an implicit upcast from a subtype to a strict supertype at the conversion level. The upcasts can then be used in the linearizers to unfold the access-permissions accordingly, so that the the supertype and its fields can be accessed. This is necessary in certain situations, such as when a functions expects a strict supertype of an argument's type. Without the additional unfolds, the held permissions would only include the subtype, not the supertype. Creating a new embedding allows us to split concerns nicely between the conversion and the encoding layer.

Draft — changes are not verified to be theoretically correct and some language concepts are missing.

Changes

  • Introduces an Upcast expression embedding (TypeOp.kt) that, when linearized, unfolds
    the shared-predicate hierarchy between a concrete subtype and an expected supertype.
  • Replaces the old ad-hoc call-site unfold statements (previously injected at method/function
    call sites and assignments) with a uniform expression-level mechanism driven by withUpcast.
  • Adds applyUnfolding to LinearizationContext with specialized implementations in
    Linearizer (emits Stmt.Unfold) and PureFunBodyLinearizer (registers predicates on an
    SSA variable for SsaConverter); PureExpLinearizer throws since SSA is required.

Special Considerations

Nullability

  • Non-nullable subtype → non-nullable supertype — direct unfold
  • Non-nullable subtype → nullable supertype — treated as non-nullable (value is guaranteed non-null)
  • Nullable subtype → nullable supertype — null-guarded unfold (Stmt.If / ternary)

Type cast operators

  • Unsafe cast (as) — produces a Cast embedding; type is already the target, no upcast needed
  • (Not yet supported) Safe cast (as?) — the then-branch stores the receiver (supertype) into the cast result
    (subtype), which is the wrong direction for Upcast; unfolding is missing

Specification contexts

  • (Not yet supported) @Pure function preconditions / postconditions — PureExpLinearizer.applyUnfolding
    throws; requires SSA support that this linearizer does not have

pawinkler and others added 2 commits April 9, 2026 18:09
Add an `Upcast` expression embedding (TypeOp.kt) that, when linearized,
unfolds the shared-predicate hierarchy between a concrete subtype and an
expected supertype. Replace the old `withType` calls at return/branch sites
in `Linearizer` with `withUpcast`, and implement `applyUnfolding` on
`LinearizationContext` (with specialized overrides in `Linearizer`,
`PureFunBodyLinearizer`, and a throwing override in `PureExpLinearizer`).
`NonInlineNamedFunction.insertCall` wraps each argument with `withUpcast`
before the call.

Add tests: `conditional_subtype_passing` (verification/classes) and
`pure_upcast` (verification/pure_functions).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
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.

1 participant