Skip to content

Commit cd25567

Browse files
authored
Fortran assumed-type arguments (#73)
Add Fortran assumed-type argument support * add `AnyNative` contracts for `TYPE(*)` scalar, assumed-size, assumed-shape, and assumed-rank dummies * lower assumed-type arguments through raw-address or C descriptor ABI according to the Fortran dummy declaration * support NumPy scalars, arrays, native derived objects, and module-backed native storage * preserve read-only, contiguous, optional, and asynchronous source semantics * add runtime type discovery, descriptor validation, and derived-type identity metadata * support generated, hand-authored, and edited `.pyi` contracts * add end-to-end coverage across compilers, platforms, module variables, and derived types * document assumed-type support and current limitations
1 parent f63f396 commit cd25567

38 files changed

Lines changed: 1918 additions & 132 deletions

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Ignore:
3838
Do not spend context window or analysis on those files unless explicitly requested.
3939
When asked to change or move an API, import path, command, feature, or behavior, do not add or keep compatibility layers, aliases, shims, fallback paths, or legacy entrypoints unless explicitly requested. A requested change means the old behavior should be removed.
4040
When updating tests, remove obsolete tests that only assert removed/old implementation behavior does not exist. Do not preserve rejection or absence checks for API/features that were intentionally removed unless explicitly requested.
41+
Do not add tests whose purpose is only to prove that removed or nonexistent features are rejected. Test supported behavior and meaningful validation boundaries instead. For example, if `ArrayCategory` is removed, delete its tests; do not add a test asserting that `ArrayCategory` now fails.
4142

4243
Treat tests as evidence for a named invariant, not as specifications merely
4344
because they already exist. Add or retain automated tests when they protect at

‎CHANGELOG.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ release tags add a leading `v` to the package version.
77

88
## Unreleased
99

10+
- Contributor test guidance focuses on supported behavior and meaningful
11+
validation boundaries after a feature is removed.
12+
13+
- Fortran `TYPE(*)` dummies accept native NumPy scalars and arrays through the
14+
declaration's address or C-descriptor ABI. Direct `BIND(C)` entries remain
15+
direct. Editable contracts use `AnyNative` with direct shape subscripts and
16+
`ReadOnly` for immutable scalar inputs; source intent and asynchronous facts
17+
remain internal. Descriptor dtypes cover a documented subset, and callers
18+
retain buffers for nonblocking operations.
19+
1020
- `--export-symbols` and `build_fortran_extension(export_symbols=...)` accept
1121
module-qualified Fortran procedure identities. Generated contracts and
1222
source builds publish only that reviewed function surface while retaining

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ code generation with a diagnostic naming the boundary and the reason.
235235

236236
**Types and arrays**
237237

238-
- arrays of derived types, and assumed-type `type(*)` arrays;
238+
- arrays of derived types and higher-rank assumed-size `type(*)` arrays;
239239
- parameterized derived types such as `type :: buffer_type(k, n)`;
240240
- character arrays that cannot be represented as a fixed-width NumPy bytes
241241
dtype, and `allocatable` and `pointer` character *fields*.

‎docs/developer/packages/codegen.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ _prik_ops_state_t = {}
216216
class State:
217217
'Opaque native state.'
218218
__slots__ = ('_prik_capsule', '_prik_owner', '_prik_ops', '_prik_origin')
219+
_prik_type_info = _prik_state_t_type_info()
219220
def __new__(cls, *args, **kwargs):
220221
'Construction is disabled.'
221222
raise TypeError('State objects come from native code.')

‎docs/user/guide/arrays.md‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,65 @@ This checks the final Python axis and flattens the leading axes.
477477

478478
---
479479

480+
## Pass Values To `TYPE(*)` Dummies
481+
482+
Use `TYPE(*)` when a Fortran procedure accepts native values of more than one
483+
type. Pass a NumPy scalar for a read-only dummy, or an ndarray with the intended
484+
native dtype:
485+
486+
```python
487+
from prik.contracts import Annotated, AnyNative, Flat, ReadOnly
488+
489+
def scalar(value: AnyNative) -> None: ...
490+
def read_scalar(value: Annotated[AnyNative, ReadOnly]) -> None: ...
491+
def raw_buffer(values: AnyNative[Flat]) -> None: ...
492+
def vector(values: AnyNative[:]) -> None: ...
493+
def matrix(values: AnyNative[:, :]) -> None: ...
494+
def arbitrary_rank(values: AnyNative[...]) -> None: ...
495+
```
496+
497+
`AnyNative` accepts values with PRIK-recognized native storage, including NumPy
498+
scalars and arrays and supported PRIK native objects. It does not accept an
499+
arbitrary Python object. `Flat` marks assumed-size storage; `...` marks assumed
500+
rank. Bare `AnyNative` permits native writes, so pass writable storage. When a
501+
procedure only reads its argument, use `Annotated[AnyNative, ReadOnly]` to also
502+
accept NumPy scalars; generated contracts use this marker for read-only dummies.
503+
504+
```fortran
505+
subroutine consume(buf) bind(C)
506+
type(*), dimension(..), intent(in) :: buf
507+
end subroutine
508+
```
509+
510+
```python
511+
consume(np.int64(7))
512+
consume(np.array([1.0, 2.0], dtype=np.float64))
513+
```
514+
515+
`type(*) :: x` passes the storage address. The supported assumed-size form,
516+
`type(*), dimension(*) :: x`, accepts contiguous array storage and passes its
517+
first element's address. Higher-rank assumed-size declarations are not yet
518+
supported.
519+
`dimension(:)`, higher-rank assumed shape, and `dimension(..)` pass a C
520+
descriptor containing the actual dtype, element size, rank, shape, and strides.
521+
Assumed rank also accepts a NumPy scalar, a rank-zero ndarray, or a PRIK native
522+
derived object. A PRIK native derived object can also be passed to a scalar
523+
`TYPE(*)` dummy. An arbitrary Python object has no native storage and is
524+
rejected. A writable dummy requires a writable ndarray when the actual is a
525+
NumPy value; NumPy scalars use call-local storage and are accepted only for
526+
read-only dummies.
527+
528+
Descriptor dummies accept NumPy `bool`, signed integer dtypes from `int8`
529+
through `int64`, `float32`, `float64`, `complex64`, and `complex128`.
530+
Raw-address dummies can also receive other NumPy dtypes with native storage,
531+
including unsigned integers and fixed-width bytes. Dtypes containing Python
532+
object references are rejected. Arrays must be aligned and use native byte
533+
order.
534+
535+
`ASYNCHRONOUS` is preserved in the generated Fortran declaration. For a
536+
nonblocking native operation, keep the Python buffer alive through its request
537+
completion; PRIK currently retains it only until the wrapper call returns.
538+
480539
## Strided Views
481540

482541
Use `::` for an assumed-shape axis that accepts F-contiguous arrays and

‎docs/user/language-support/feature-matrix.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ where they apply.
6363
| Pointer scalar projections and array handles | Partially supported | [Pointers](../guide/pointers.md) | [Pointer handle tests](../../../tests/fortran/pointers/end_to_end/test_pointer_handles.py), [pointer policy tests](../../../tests/fortran/pointers/policy/test_pointer_ownership_policy.py), [scalar-derived matrix tests](../../../tests/fortran/derived_types/end_to_end/test_scalar_actual_dummy_matrix.py) | Descriptor arguments, module and field handles, strided views, and returned array handles are supported. Deferred-width character views require contiguous storage and a compatible compiler. |
6464
| Array-valued function results | Supported | [Array results](../guide/arrays.md#mutation-and-results) | [Array result tests](../../../tests/fortran/arrays/end_to_end/test_array_results.py) | Ownership and dtype/shape behavior are limited to documented array result forms. |
6565
| NumPy array argument contracts | Supported | [Arrays](../guide/arrays.md) | [Array contract tests](../../../tests/fortran/arrays/end_to_end/test_array_contract_validation.py), [multidimensional tests](../../../tests/fortran/arrays/end_to_end/test_layout_and_strided_arrays.py) | Wrong dtype, rank, shape, contiguity, alignment, or mutability is rejected. |
66+
| Assumed-type native arguments | Partially supported | [Arrays](../guide/arrays.md#pass-values-to-type-dummies) | [Assumed-type source and edited-contract tests](../../../tests/fortran/assumed_types/end_to_end/test_assumed_type_calls.py) | `AnyNative` accepts PRIK-native NumPy and derived actuals. Descriptor dtypes have a documented subset; assumed-size is rank one, and nonblocking buffer lifetime remains caller-owned. |
6667
| Derived-type scalar boundaries and methods | Supported | [Derived types](../guide/wrapping-derived-types.md) | [Derived boundary tests](../../../tests/fortran/derived_types/end_to_end/test_derived_boundaries.py), [method tests](../../../tests/fortran/derived_types/end_to_end/test_type_bound_methods.py) | Derived-type arrays and some polymorphic forms are not included. |
6768
| Default and keyword constructors with finalizers | Supported | [Constructors and finalizers](../guide/wrapping-derived-types.md#key-concepts) | [Constructor/finalizer tests](../../../tests/fortran/derived_types/end_to_end/test_default_constructors_and_finalizers.py), [borrowed finalizer tests](../../../tests/fortran/derived_types/end_to_end/test_borrowed_components.py) | Construction commits ownership only after initialization; borrowed wrappers never run an owning finalizer. |
6869
| Generic constructor interfaces and overloaded runtime initialization | Supported | [Constructors](../guide/wrapping-derived-types.md#custom-constructor) | [Edited class surface tests](../../../tests/fortran/infrastructure/semantic_pyi/contracts/functions_and_classes/end_to_end/test_edited_class_surfaces.py), [class policy tests](../../../tests/fortran/infrastructure/semantic_pyi/contracts/functions_and_classes/policy/test_class_surface_policy.py) | Candidates require distinguishable completed Python signatures; incomplete or ambiguous sets are blocked before emission. |
@@ -99,7 +100,7 @@ where they apply.
99100
| Fortran parse, semantic IR, and `.pyi` inspection | Supported | [CLI commands](../reference/cli-commands.md#parse-and-semantics) | [Fortran parser fixtures](../../../tests/fortran/infrastructure/parsing/test_fortran_fixture_suite.py), [Fortran semantic tests](../../../tests/fortran/infrastructure/semantic_ir/semantics/) | Inspection support does not by itself prove runtime wrapper support. |
100101
| Semantic `.pyi` wrapper builds from explicit native artifacts | Partially supported | [Editing `.pyi` contracts](../reference/pyi-contracts/index.md) | [format and authoritative-input tests](../../../tests/fortran/infrastructure/semantic_pyi/), [multi-source contract tests](../../../tests/fortran/infrastructure/building/end_to_end/test_multi_source_builds.py), [native build plan tests](../../../tests/fortran/infrastructure/building/end_to_end/test_source_build_modes.py) | Source/generated/modified multi-source package parity is covered. Support is limited to contract forms with linked build evidence; no general parity claim is made for every source-supported Fortran feature. |
101102
| Scalar inheritance and polymorphic dispatch | Partially supported | [Inheritance and polymorphic input](../guide/wrapping-derived-types.md#inheritance-and-polymorphic-input-dispatch) | [Inheritance tests](../../../tests/fortran/derived_types/end_to_end/test_inheritance_and_polymorphism.py) | Abstract types wrap as non-instantiable Python base classes and deferred bindings resolve through the caller's concrete type. Polymorphic results, mutable dummies, arrays, allocatable/pointer scalars, and `class(*)` are blocked. |
102-
| Assumed-size, assumed-rank, and lower-bound array contracts | Partially supported | [Arrays](../guide/arrays.md) | [Assumed-rank tests](../../../tests/fortran/arrays/end_to_end/test_assumed_rank_arrays.py) | Assumed type and derived-type arrays remain blocked. Character arrays require fixed-width NumPy bytes dtype. |
103+
| Assumed-size, assumed-rank, and lower-bound array contracts | Partially supported | [Arrays](../guide/arrays.md) | [Assumed-rank tests](../../../tests/fortran/arrays/end_to_end/test_assumed_rank_arrays.py), [assumed-type tests](../../../tests/fortran/assumed_types/end_to_end/test_assumed_type_calls.py) | `TYPE(*)` uses `AnyNative` contracts. Arrays of concrete derived types remain blocked. Character arrays require fixed-width NumPy bytes dtype. |
103104

104105
### C
105106

@@ -127,7 +128,7 @@ documented diagnostic-stage exception below.
127128
| Unproved pointer lifetime and ownership-changing operations | Unsupported | [Pointer safety](../guide/pointers.md#safety-checklist) | [Pointer policy tests](../../../tests/fortran/pointers/policy/test_pointer_ownership_policy.py), [pointer runtime tests](../../../tests/fortran/pointers/runtime/test_pointer_handle_protocol.py) | Native targets must outlive every handle use; allocation, target deallocation, resize, and writable reassociation require explicit completed policy. |
128129
| Persistent callbacks and procedure pointers | Unsupported | [Callback limitations](../guide/callbacks.md#important-limitations) | [Callback policy tests](../../../tests/fortran/callbacks/policy/test_callback_policy.py), [scalar callback tests](../../../tests/fortran/callbacks/end_to_end/test_scalar_callbacks.py) | Callbacks are valid only during the wrapped call. |
129130
| Advanced multi-source dependency discovery and external-library integration | Unsupported | [Multiple source files](../guide/building-shared-library.md#multiple-source-files) | [Multi-source tests](../../../tests/fortran/infrastructure/building/end_to_end/test_multi_source_builds.py) | PRIK does not discover sources you did not name, prebuilt module search paths, or external libraries. Dependency ordering among the sources it parses is supported. |
130-
| Blocked array forms | Unsupported | [Arrays](../guide/arrays.md) | [Array semantic tests](../../../tests/fortran/arrays/semantics/test_array_semantics.py), [diagnostics](../reference/diagnostic-codes.md) | Assumed type `type(*)`, arrays of derived types, and character arrays not representable as fixed-width bytes need missing runtime contracts. |
131+
| Blocked array forms | Unsupported | [Arrays](../guide/arrays.md) | [Array semantic tests](../../../tests/fortran/arrays/semantics/test_array_semantics.py), [diagnostics](../reference/diagnostic-codes.md) | Arrays of derived types and character arrays not representable as fixed-width bytes need missing runtime contracts. |
131132
| Unsupported polymorphic forms | Unsupported | [Inheritance limits](../guide/wrapping-derived-types.md#inheritance-and-polymorphic-input-dispatch) | [Inheritance tests](../../../tests/fortran/derived_types/codegen/test_class_surfaces.py) | Results, mutable dummies, arrays, polymorphic allocatable/pointer scalars, and `class(*)` are blocked. Abstract types and deferred bindings are supported. |
132133
| Ambiguous or incomplete constructor overload sets | Unsupported | [Constructor limitations](../guide/wrapping-derived-types.md#custom-constructor) | [Constructor semantic tests](../../../tests/fortran/infrastructure/semantic_pyi/contracts/functions_and_classes/semantics/test_method_and_constructor_contracts.py), [class-plan validation tests](../../../tests/fortran/infrastructure/semantic_pyi/contracts/functions_and_classes/policy/test_class_surface_policy.py) | Candidates must have distinguishable exact runtime signatures and compatible native-owner lifecycles. A Fortran `interface <typename>` is wrapped as the type's overloaded constructor. |
133134
| Parameterized derived types | Unsupported | [Fortran support boundaries](fortran-support.md#important-boundaries) | [Parameterized-declaration parsing](../../../tests/fortran/derived_types/parsing/test_parameterized_derived_types.py) | The parser preserves the declaration and its parameter expressions, but wrapper semantics do not model type parameters. A build can currently reach compiler probing and surface a raw compiler diagnostic instead of a PRIK diagnostic. |

‎docs/user/reference/pyi-format.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -921,12 +921,12 @@ type. Metadata falls into four groups.
921921
| `Contiguous` | Storage is contiguous. | Loaded source-provenance/compatibility fact; on `T[...]` it narrows stride-agnostic runtime-rank storage to the language's contiguous order. |
922922
| `Aliased` | Native storage is addressable or may be exposed as an alias. | Fortran `target` and borrowed native objects. |
923923
| `Immutable` | Python-visible value is replace-only, not mutated in place. | Requires a compatible replacement/copy policy for writable native storage. |
924+
| `ReadOnly` | Native code reads an `AnyNative` actual without writing it. | Use when an immutable NumPy scalar should be accepted. |
924925
| `Polymorphic` | Fortran native declaration is `class(T)`. | Fortran. |
925-
| `AssumedType` | Fortran native declaration is assumed type. | Accepted/generated where source semantics require it; wrapper support is limited. |
926926
| `MaybeUnallocated` | Direct allocatable array function result can be unallocated. | Valid only on that result form. |
927927
| `PointerAssociation("runtime")` | Pointer association is runtime state. | Fortran pointer facts. |
928928
| `SourceName("native-name")` | Preserve a native name that the Python identifier cannot represent. | Shared. |
929-
| `ArrayCategory("...")`, `FortranAllocatable` | Older source-provenance spellings. | Loaded compatibility; use active storage syntax for authored contracts. |
929+
| `FortranAllocatable` | Fortran allocatable source provenance. | Loaded source contracts. |
930930
| `CAnonymousMember` | Field is the containing member for a nested anonymous C aggregate. | C inspection contracts. |
931931

932932
### Constraints
@@ -1090,12 +1090,12 @@ valid and whether it is buildable.
10901090
| Group | Public names |
10911091
| --- | --- |
10921092
| Typing forms | `Annotated`, `Any`, `Final` |
1093-
| Scalar types | `Bool`, `Bool8`, `Bool16`, `Bool32`, `Bool64`, `Byte`, `CEnum`, `Char`, `Complex64`, `Complex128`, `Complex256`, `Float16`, `Float32`, `Float64`, `Float128`, `Int`, `Int8`, `Int16`, `Int32`, `Int64`, `SizeT`, `String`, `UInt`, `UInt8`, `UInt16`, `UInt32`, `UInt64`, `Void` |
1093+
| Scalar types | `AnyNative`, `Bool`, `Bool8`, `Bool16`, `Bool32`, `Bool64`, `Byte`, `CEnum`, `Char`, `Complex64`, `Complex128`, `Complex256`, `Float16`, `Float32`, `Float64`, `Float128`, `Int`, `Int8`, `Int16`, `Int32`, `Int64`, `SizeT`, `String`, `UInt`, `UInt8`, `UInt16`, `UInt32`, `UInt64`, `Void` |
10941094
| Storage and result types | `Addr`, `Allocatable`, `Pointer`, `Returns`, `private` |
10951095
| Compatibility/category types | `Matrix`, `Vector`, `OpaqueHandle`, `WrappedType` |
10961096
| Class and C inspection markers | `CAnonymous`, `CAnonymousMember`, `CStruct`, `CUnion`, `Opaque` |
10971097
| Shape and layout markers | `Contiguous`, `COPY_F`, `Flat`, `ORDER_ANY`, `ORDER_C`, `ORDER_F` |
1098-
| General metadata | `Aliased`, `ArrayCategory`, `AssumedType`, `FortranAllocatable`, `Immutable`, `MaybeUnallocated`, `Polymorphic`, `SourceName` |
1098+
| General metadata | `Aliased`, `FortranAllocatable`, `Immutable`, `MaybeUnallocated`, `Polymorphic`, `ReadOnly`, `SourceName` |
10991099
| Constraints and ownership | `Bounded`, `Finite`, `Range`, `Ownership`, `Transfer`, `Destruction`, `PointerAssociation`, `PointerPolicy` |
11001100
| Prototype direction | `In`, `Out`, `InOut` |
11011101
| Native-call helpers | `Arg`, `Hidden`, `IsPresent`, `Len`, `Pass`, `Return`, `Value`, `Work` |

0 commit comments

Comments
 (0)