diff --git a/README.md b/README.md index f9edd4952..d7257eee0 100644 --- a/README.md +++ b/README.md @@ -430,10 +430,10 @@ File: tests/data/fortran/general/modern_pyi_example.f90 class particle: id: Int32 mass: Float64 - position: Float64[Shape('3'), ORDER_F] + position: Float64[3] class vector3: - values: Float64[Shape('3'), ORDER_F] + values: Float64[3] @private class hidden_state: @@ -443,46 +443,47 @@ counter: Int32 hidden_scale: private[Float64] -@native_call([Return(0), Arg(0), Arg(1), Arg(2), Arg(3), Arg(4)]) def init_particle( - pid: Int32, - mass: Float64, - x: Float64, - y: Float64, - z: Float64 -) -> particle: ... + p: Annotated[Ptr(particle), Intent('out')], + pid: Ptr(Const(Int32)), + mass: Ptr(Const(Float64)), + x: Ptr(Const(Float64)), + y: Ptr(Const(Float64)), + z: Ptr(Const(Float64)) +) -> None: ... def kinetic_energy( - p: particle, - vx: Float64, - vy: Float64, - vz: Float64 + p: Ptr(Const(particle)), + vx: Ptr(Const(Float64)), + vy: Ptr(Const(Float64)), + vz: Ptr(Const(Float64)) ) -> Float64: ... def scale_vector( - v: Float64[Shape(':'), ORDER_F], - alpha: Float64 -) -> Returns["v", Float64[Shape(':'), ORDER_F]]: ... + v: Float64[::Strided], + alpha: Ptr(Const(Float64)) +) -> None: ... def dot3( - a: Float64[Shape('3'), ORDER_F], - b: Float64[Shape('3'), ORDER_F] + a: Const(Float64[3]), + b: Const(Float64[3]) ) -> Float64: ... -@native_call([Return(0)]) -def fill_identity3() -> Float64[Shape('3', '3'), ORDER_F]: ... +def fill_identity3( + a: Annotated[Float64[3, 3], ORDER_F, Intent('out')] +) -> None: ... def normalize_particle( - p: particle -) -> Returns["p", particle]: ... + p: Ptr(particle) +) -> None: ... @private def hidden_proc( - x: Int32 + x: Ptr(Const(Int32)) ) -> None: ... ``` -This snapshot is also verified in `tests/pyi/test_pyi_printer_modern_example.py`. +This snapshot is also verified in `tests/semantics/test_pyi_printer_modern_example.py`. Parse output for the same fixture now includes the derived type definition and field list: diff --git a/docs/architecture/semantic_multilanguage_wrapper_runtime_architecture.md b/docs/architecture/semantic_multilanguage_wrapper_runtime_architecture.md index ada0ce919..c3167f52a 100644 --- a/docs/architecture/semantic_multilanguage_wrapper_runtime_architecture.md +++ b/docs/architecture/semantic_multilanguage_wrapper_runtime_architecture.md @@ -327,13 +327,13 @@ def solve( From(np.ndarray), ORDER_F, Writable, - Shape("N", "N"), + "N", "N", ], b: Float64Vector[ From(np.ndarray), - Shape("N"), + "N", ], -) -> Float64Vector[Shape("N")]: ... +) -> Float64Vector["N"]: ... ``` This means: @@ -366,7 +366,7 @@ Examples: * `ORDER_F` * `ORDER_C` * `CPUResident` -* `Shape(N, N)` +* shape subscriptions such as `Float64["N", "N"]` * `Aligned(64)` * `Finite` * `NonNull` diff --git a/docs/c_parser/c_parser_architecture.md b/docs/c_parser/c_parser_architecture.md index 3ba6b84b8..2fba5e7e3 100644 --- a/docs/c_parser/c_parser_architecture.md +++ b/docs/c_parser/c_parser_architecture.md @@ -683,7 +683,8 @@ Planned mapping: - C parameter -> `SemanticArgument` - C primitive -> `SemanticType` - C pointer -> constraints and ownership metadata -- C array -> `Shape(...)`, `ORDER_C`, and pointer/extent metadata +- C array -> subscription shape notation such as `T[n]`, order metadata such as + `ORDER_C`, and pointer/extent metadata - `const` -> read-only ownership/constraint metadata - `restrict` -> aliasing metadata - structs/unions -> `SemanticClass` or named opaque semantic type @@ -712,10 +713,11 @@ Likely stub patterns: - plain scalar functions: - `def f(x: Int32) -> Float64: ...` - pointer arguments: - - use semantic constraints such as `Pointer`, `Writable`, `Const`, `Shape` - only after the IR supports them cleanly + - use storage/calling contracts such as `Ptr(...)`, `Const(...)`, writable + metadata, and explicit extent metadata only after the IR supports them + cleanly - arrays: - - `Float64[Shape("n"), ORDER_C]` + - `Annotated[Float64[n], ORDER_C]` - opaque handles: - classes or named semantic types with ownership constraints - structs: @@ -727,9 +729,9 @@ Likely stub patterns: - `Final[...]` The existing `.pyi` parser already supports `Final`, `private`, `native_call`, -imports, classes, functions, shapes, and native projection entries. C-specific -work should extend the semantic model intentionally before changing `.pyi` -syntax. +imports, classes, functions, shape subscriptions, storage contracts, metadata, +and native projection entries. C-specific work should extend the semantic model +intentionally before changing `.pyi` syntax. For function pointers and callbacks, parser extraction and later wrappability are separate decisions. The parser should extract the function pointer type into diff --git a/docs/semantics/c_pyi_self_contained_specification.md b/docs/semantics/c_pyi_self_contained_specification.md index 3db9fb6fb..3d00795f0 100644 --- a/docs/semantics/c_pyi_self_contained_specification.md +++ b/docs/semantics/c_pyi_self_contained_specification.md @@ -188,9 +188,16 @@ runnable C Phase 1 wrapper requires the corresponding native routine to accept that storage layout directly. For a rank-one array, `ORDER_C` and `ORDER_F` do not distinguish storage, contiguous or strided, so no order constraint is written. -For a multidimensional strided annotation, `ORDER_F` is orientation metadata, -not a requirement that NumPy report `F_CONTIGUOUS`; non-unit strides remain -part of the contract. + For a multidimensional strided annotation, `ORDER_F` is orientation metadata, + not a requirement that NumPy report `F_CONTIGUOUS`; non-unit strides remain + part of the contract. + Source frontends may retain original declaration dimensions, source bounds + or native dummy categories as internal provenance. Those source facts are + not part of the canonical public array annotation unless they produce an + actual storage constraint. In particular, Fortran dummy bounds are + established by native association rather than supplied as Python array + metadata. This does not add C semantic conversion support; C conversion + remains deferred. Stride-aware dimensions use a slice step marker: diff --git a/docs/semantics/pyi_format.md b/docs/semantics/pyi_format.md index 289ecabdb..f8e830050 100644 --- a/docs/semantics/pyi_format.md +++ b/docs/semantics/pyi_format.md @@ -1,749 +1,431 @@ # Wrapper `.pyi` Format -The `.pyi` format is a Python-valid view of the semantic IR. It is meant to be -easy to read and edit first, with extra metadata added only when the wrapper -needs information that normal Python annotations cannot express. +The semantic `.pyi` format is a Python-valid view of x2py semantic IR. It is +language-neutral: Fortran and future C inputs use the same type, storage, +pointer, array, layout and metadata notation. Source language differences are +represented by contracts and metadata, not by separate syntax families. -The target canonical editable form uses NumPy-style array subscriptions and -keeps non-dimensional semantic constraints in `Annotated[...]` metadata. For -example, an ordinary Fortran array accepted from Python is a NumPy array: +This document describes the behavior implemented for the current Fortran path +and the shared notation it establishes for later C semantic conversion. C +semantic conversion and C `.pyi` generation remain deferred. -```python -def norm2( - x: Const(Float64[:]) -) -> Float64: ... -``` +## Canonical Type And Storage Contract -Unqualified array notation has one meaning independent of source language: -`Float64[:, :]` implies `ORDER_C`, matching ordinary NumPy notation and -allocation defaults. A generator translating an ordinary Fortran-contiguous -multidimensional array contract emits -`Annotated[Float64[:, :], ORDER_F]`; it does not rely on the fact that the -stub originated from Fortran. A contiguous rank-one array needs no order -metadata because C- and Fortran-contiguous vector storage is the same. -For rank two or higher, stride capability and order are separate constraints: -bare `Float64[::Strided, ::Strided]` is strided with implicit `ORDER_C`, -while `Annotated[Float64[::Strided, ::Strided], ORDER_F]` is a strided -Fortran-oriented contract. A fully orientation-independent contract is written -`Annotated[Float64[::Strided, ::Strided], ORDER_ANY]`. -On a strided form, `ORDER_F` is not a requirement that NumPy report the view -as `F_CONTIGUOUS`; it preserves the required native orientation while -non-unit strides remain allowed. - -NumPy normally creates a new multidimensional array in C order. A caller of a -dense `Annotated[T[:, :], ORDER_F]` signature supplies F-contiguous storage, -for example using `np.empty(shape, order="F")` or -`np.asfortranarray(value)`, unless an explicit wrapper conversion policy is -later introduced. An `ORDER_F` form containing `::Strided` instead supplies -Fortran-oriented storage satisfying its stated stride constraints; it is not -required to be contiguous. - -The current parser and printer still emit and consume the earlier -`Float64[Shape(':'), ORDER_F]` representation and existing Python-facing -output projections. They must migrate before this exact native target notation -is accepted as a runnable or round-trippable stub. - -Emit currently supported stubs from semantic IR with `emit_module`: +Bare scalar types represent direct semantic values: ```python -from semantics.pyi_printer import emit_module - -pyi = emit_module(module) +def dot_value(a: Float64, b: Float64) -> Float64: ... ``` -## Default: Exact Native Interface - -The default semantic `.pyi` represents the direct C callable interface and the -exact Fortran dummy-argument contract. It does not use `@native_call`: - -- Every target argument remains a visible Python argument in target order. -- A direct native return is the only value placed in the return annotation. -- A scalar passed through writable native storage is written `Ptr(T)`. -- A scalar passed through read-only native storage is written `Ptr(Const(T))`. -- A Fortran array accepted from Python is represented by a NumPy array - annotation, together with any source-level properties the wrapper must - preserve, such as rank, shape, `ORDER_F`, `Allocatable` or - `Pointer`. -- A C pointer uses an array annotation only when an array storage contract is - known; an otherwise unrefined `T *` remains `Ptr(T)`. - -For a primitive scalar argument, `Ptr(T)` means that Python supplies writable -zero-dimensional NumPy storage of the matching dtype. `Ptr(Const(T))` means -the corresponding read-only native reference contract. A plain Python scalar -does not satisfy either exact reference form because creating temporary storage -would already be a Pythonic adaptation. - -### Fortran Direct Form - -For Fortran, "exact" means that the semantic stub preserves the target -procedure's dummy-argument contract. The wrapper backend may emit an -intermediary Fortran procedure that accepts C/Python-provided storage and -calls the desired Fortran procedure. Creating the compiler-required -descriptor, temporary or association inside that intermediary is native -lowering; it is not an `@native_call` Pythonic projection, provided the -visible semantic arguments and results are unchanged. - -Fortran scalar dummy arguments that are passed by reference remain reference -arguments in the exact interface. `intent(out)` and `intent(inout)` differ in -source-language intent, but both require writable caller-supplied storage and -do not become Python results in this form: - -```fortran -subroutine update(scale, value, result) bind(c) - use iso_c_binding - real(c_double), value, intent(in) :: scale - real(c_double), intent(inout) :: value - real(c_double), intent(out) :: result -end subroutine -``` - -```python -def update( - scale: Float64, - value: Ptr(Float64), - result: Ptr(Float64), -) -> None: ... -``` - -A read-only Fortran reference is represented without permitting mutation: - -```fortran -subroutine inspect(value) bind(c) - use iso_c_binding - integer(c_int), intent(in) :: value -end subroutine -``` +Native reference and pointer-backed storage is explicit: ```python def inspect(value: Ptr(Const(Int32))) -> None: ... +def update(value: Ptr(Float64)) -> None: ... ``` -Fortran array lowering is determined by the dummy declaration, not simply by -whether the source is modern or legacy: - -| Fortran dummy array form or property | Exact semantic annotation | Backend obligation | -| --- | --- | --- | -| explicit-shape or adjustable, such as `x(n, m)` | `Annotated[Float64[n, m], ORDER_F]` | Validate extents and pass first-element Fortran-contiguous storage. | -| assumed-size, such as `x(*)` or `x(n, *)` | `Float64[:]` for rank one; `Annotated[Float64[:, :], ORDER_F]` or the known-rank equivalent for multidimensional contiguous storage | Preserve known rank/bounds; no final extent is supplied by the dummy. | -| assumed-shape, such as `x(:)` or `x(:, :)`, without `contiguous` | `Float64[::Strided]` for a vector; `Annotated[Float64[::Strided, ::Strided], ORDER_ANY]` for an unrestricted rank-two contract | Construct the Fortran call representation from NumPy shape and strides. Use `ORDER_C` (implicit) or `ORDER_F` instead when the contract deliberately restricts orientation. | -| assumed-rank, `x(..)`, without `contiguous` | stride-aware rank-polymorphic notation with `ORDER_ANY` once defined | Pass runtime rank, shape and strides as required by the generated adapter. | -| `contiguous` dummy property | `Float64[:]` for rank one; `Annotated[Float64[:, :], ORDER_F]` or the corresponding form for rank two or higher | Reject or explicitly convert incompatible layout according to policy. | -| `allocatable` dummy property | `Annotated[Float64[:], Allocatable]` for a vector; add `ORDER_F` only for a multidimensional Fortran-contiguous contract | Provide allocatable semantics and preserve allocation changes if permitted. | -| `pointer` dummy property | `Annotated[Float64[:], Pointer]` for a contiguous vector, or a stride-aware form when permitted; combine with `ORDER_F` or `ORDER_ANY` for multidimensional storage as required | Provide pointer association semantics and preserve association changes if permitted. | - -No additional annotation is needed for the compiler's internal array -transport. The target is already known to be Fortran, and the backend's -intermediary Fortran procedure can prepare the compiler-specific argument -representation. The `.pyi` must say whether the target contract is -sufficiently known: element type, rank or allowed ranks, required -extents/bounds, mutability, contiguity requirements and attributes such as -`Allocatable` or `Pointer`. - -This design assumes that the intermediary is compiled against an available -Fortran interface, for example by `use`-associating a module procedure or by -using retained source/semantic information sufficient to declare that -interface. If a wrapper must call an arbitrary precompiled non-interoperable -Fortran symbol using only a `.pyi` file and a binary library, compiler ABI and -dummy-category information must be retained separately; NumPy shape -annotations alone cannot discover that call convention. - -`Float64[...]` is not a placeholder for missing information: it represents a -target procedure that accepts runtime rank, such as an assumed-rank dummy. If -a fixed-rank target's required rank, dimensions or attributes are unknown, -the interface is incomplete and should fail readiness rather than silently -be generalized. - -Plain dense array notation means C-contiguous storage. Multidimensional -Fortran-contiguous contracts are emitted with explicit `ORDER_F`; rank-one -contiguous arrays need no order marker. For multidimensional strided storage, -the order annotation is retained independently: a bare strided form is -C-oriented, an `ORDER_F` strided form is Fortran-oriented, and `ORDER_ANY` -states that neither orientation is required. An ordinary assumed-shape dummy -without `contiguous` can accept a non-contiguous actual argument in any -orientation when the adapter passes its shape and strides correctly. These -are distinct contracts: +Array storage uses NumPy-style subscriptions. The dimensions inside `T[...]` +are the storage contract: ```python -# Explicit-shape Fortran-contiguous storage. -def explicit_shape( - n: Ptr(Const(Int32)), - m: Ptr(Const(Int32)), - x: Annotated[Float64[n, m], ORDER_F], -) -> None: ... - -# Assumed-shape with a stated contiguous Fortran storage requirement. -def assumed_shape( - x: Annotated[Float64[:, :], ORDER_F], -) -> None: ... - -# Strided storage with the default C orientation. -def c_oriented_strided( - x: Float64[::Strided, ::Strided], -) -> None: ... - -# Strided storage with a required Fortran orientation. -def f_oriented_strided( - x: Annotated[Float64[::Strided, ::Strided], ORDER_F], -) -> None: ... - -# Assumed-shape exposing the unrestricted non-contiguous contract. -def any_order_assumed_shape( - x: Annotated[Float64[::Strided, ::Strided], ORDER_ANY], -) -> None: ... -``` - -At the Python boundary, each of these array arguments is still a NumPy array. -For an ordinary assumed-shape or assumed-rank dummy, NumPy already provides -the storage facts an adapter needs: data address, element dtype/length, rank, -extents and strides. The properties that change semantics beyond those array -facts must remain in the annotation: - -| Fortran property | Representation | Observable consequence | -| --- | --- | --- | -| Required dense Fortran-contiguous multidimensional storage | `Annotated[T[:, :], ORDER_F]` or shaped equivalent | May reject a C-order or strided input or require an explicit conversion policy. | -| C-oriented multidimensional strided storage | `T[::Strided, ::Strided]` | Strides are admitted while the default order remains `ORDER_C`. | -| Fortran-oriented multidimensional strided storage | `Annotated[T[::Strided, ::Strided], ORDER_F]` | Strides are admitted while retaining Fortran orientation. | -| Orientation-independent multidimensional strided storage | `Annotated[T[::Strided, ::Strided], ORDER_ANY]` | Suitable for an unrestricted assumed-shape dummy. | -| Rank-one contiguous storage | `T[:]` or `T[n]` without an order marker | C- and Fortran-contiguous storage are equivalent for a vector. | -| Rank-one non-contiguous storage | `T[::Strided]` or a bounded/exact-step equivalent | Stride, not C/F order, distinguishes the view. | -| Allocation semantics | `Allocatable` | A target may allocate, deallocate or reallocate; replacing storage cannot be observed merely by mutating the original NumPy array. | -| Pointer association semantics | `Pointer` | A target may change association; reassociation cannot be expressed by element updates on the original NumPy array. | -| Required explicit bounds not recoverable from NumPy shape | retained bound metadata | The adapter constructs matching Fortran bounds rather than assuming Python's zero-based view is the complete contract. | - -For ordinary Fortran-contiguous array dummies, element mutation is observed -through the supplied NumPy storage: - -```python -def axpy( - n: Ptr(Const(Int32)), - a: Ptr(Const(Float64)), - x: Const(Float64[n]), - y: Float64[n], -) -> None: ... +def scale(n: Ptr(Const(Int32)), x: Float64[n]) -> None: ... +def matrix(a: Annotated[Const(Float64[n, m]), ORDER_F]) -> None: ... +def assumed(x: Annotated[Float64[::Strided, ::Strided], ORDER_F]) -> None: ... ``` -A legacy Fortran 77 style explicit-shape or assumed-size array is lowered -through its first element address, not through a descriptor. Its dimensions -still belong in the semantic annotation when they are known, because the -wrapper can validate NumPy storage before passing that address: - -```fortran - SUBROUTINE SCALE(N, X) - INTEGER N - DOUBLE PRECISION X(N) -``` - -```python -def scale( - n: Ptr(Const(Int32)), - x: Float64[n], -) -> None: ... -``` +There is no separate dimension helper in canonical type syntax. A dimension +entry without colons is an extent (`Float64[n]`, `Float64[n, m]`). Slice-like +entries express range or stride contracts (`Float64[1:n]`, +`Float64[::Strided]`, `Float64[:, 0:n:m]`). `Strided` means the runtime stride +is part of the accepted storage contract. -The same first-element-address rule also applies to modern explicit-shape and -assumed-size dummy arrays. By contrast, modern assumed-shape, assumed-rank, -`Pointer` and `Allocatable` dummies require their richer Fortran call -representation internally; the generated intermediary handles that transport. -For a first-element-address interface, a non-contiguous NumPy view cannot be -passed directly because the target procedure receives no stride information. -For rank greater than one, explicit `ORDER_F` also makes NumPy element order -match Fortran column-major indexing. Accepting other layouts for these -interfaces requires an explicit pack/copy-back policy. - -For an allocatable or pointer dummy, using a NumPy argument is still the -desired Python-facing API, but state-changing operations need an explicit -policy. Reading data or changing elements can be adapted directly. Allocating -a replacement, deallocating storage or changing pointer association must later -define whether the wrapper rejects the operation, copies data back, or -returns/manages new storage: +`Annotated[...]` carries non-dimensional metadata: -```python -def maybe_resize( - x: Annotated[Float64[:], Allocatable], -) -> None: ... +- `ORDER_F` for a Fortran-oriented multidimensional contract. +- `ORDER_ANY` for an orientation-independent multidimensional strided + contract chosen explicitly by an edited interface or later projection. +- `Allocatable` for a Fortran allocatable array. +- `Pointer` for a Fortran pointer array. +- `Intent("out")` when a visible exact-native argument has source intent + `out`; `intent(inout)` is the default writable reference/array spelling and + does not need metadata. -def maybe_reassociate( - x: Annotated[Float64[:], Pointer], -) -> None: ... +Plain multidimensional array notation is C-oriented (`ORDER_C`) by default. +Under the current Fortran generation policy, every multidimensional Fortran +array contract emits `ORDER_F`, including stride-aware assumed-shape arrays. +Rank-one storage has no C-versus-Fortran order distinction, so no order marker +is emitted for vectors. -# Pointer dummy permitted to associate with a non-contiguous section. -def pointer_section( - x: Annotated[Float64[::Strided], Pointer], -) -> None: ... +`ArrayCategory(...)`, `SourceDims(...)`, `LowerBounds(...)` and `Contiguous` +are not part of newly generated canonical array annotations. They described +native declaration provenance rather than additional requirements on the +Python-visible array. The loader continues to accept existing edited stubs +that contain these metadata forms. Fortran source category, original bounds +and declaration dimensions may remain available as internal source provenance +when converting source; they are not required for the public storage contract +or for ordinary Python-to-Fortran array argument association. -def pointer_matrix_section( - x: Annotated[Float64[::Strided, ::Strided], ORDER_F, Pointer], -) -> None: ... -``` +## Implemented Fortran Exact Form -Until that policy exists, mutable `Allocatable` or `Pointer` dummies whose -allocation or association can change are wrap-readiness blockers; they must -not be silently treated as ordinary borrowed arrays. +Generated Fortran `.pyi` currently represents the exact native dummy-argument +interface. It does not synthesize, reorder or hide arguments and it does not +turn `intent(out)` or `intent(inout)` dummy arguments into Python return +values. -`Pointer` may be combined with `::Strided` when the target permits -association with a non-contiguous section. `Allocatable` is not the general -strided-view spelling: allocated array storage is contiguous, while its -distinct issue is allocation ownership and possible replacement. +Fortran scalar dummy arguments are represented as follows: -### C Direct Form +- Scalar dummy without `value`, `intent(in)`: `Ptr(Const(T))`. +- Scalar dummy without `value`, `intent(out)` or `intent(inout)`: `Ptr(T)`. +- Scalar dummy with `value`: direct `T`. +- Function result: direct return annotation. -C by-value parameters and direct returns use bare types. C scalar pointers use -the same reference notation as Fortran: +Example: -```c -int add(int a, int b); -void increment(int *value); -void read_count(const int *value); +```fortran +subroutine update(scale, value, result) + real(8), value, intent(in) :: scale + real(8), intent(inout) :: value + real(8), intent(out) :: result +end subroutine ``` ```python -def add(a: Int, b: Int) -> Int: ... -def increment(value: Ptr(Int)) -> None: ... -def read_count(value: Ptr(Const(Int))) -> None: ... +def update( + scale: Float64, + value: Ptr(Float64), + result: Annotated[Ptr(Float64), Intent("out")] +) -> None: ... ``` -For `increment`, a caller supplies scalar storage rather than a Python `int`: +Fortran module variables and derived-type fields are data declarations, not +procedure dummy arguments. Scalar fields and variables therefore remain direct +types: ```python -value = np.array(7, dtype=np.intc) -increment(value) -updated = value.item() -``` - -C has no generated Fortran adapter for an ordinary pointer parameter. A bare -C pointer with no known scalar or array storage contract is kept as a raw -pointer: +answer: Final[Int32] -```c -void consume(double *values); -double sum_values(size_t n, const double *values); +class particle: + id: Int32 + position: Float64[3] ``` -```python -def consume(values: Ptr(Float64)) -> None: ... -def sum_values(n: SizeT, values: Const(Float64[n])) -> Float64: ... -``` - -`Float64[n]` in the second signature records an API/semantic shape contract -and still lowers to one `double *`; it does not claim C passes rank or shape -metadata inside `values`. - -### Direct Returns +## Implemented Fortran Arrays -Native returns remain returns: +Explicit-shape and adjustable arrays use shaped storage. Multidimensional +Fortran-contiguous storage carries `ORDER_F`; vectors omit order metadata: ```python -def value() -> Float64: ... -def raw_values() -> Ptr(Float64): ... -``` - -An output parameter is not a native return. For example, a Fortran subroutine -`make_vector(n, x)` with an output array and a C function -`void get_count(int *out)` remain: +def scale(n: Ptr(Const(Int32)), x: Float64[n]) -> None: ... -```python -def make_vector( +def apply( n: Ptr(Const(Int32)), - x: Float64[n], + m: Ptr(Const(Int32)), + a: Annotated[Const(Float64[n, m]), ORDER_F], ) -> None: ... -def get_count(out: Ptr(Int)) -> None: ... -``` - -## Pythonic Projection (Later) - -A later optional generation mode, for example `--pythonic`, may expose a -friendlier Python interface that differs from the native argument list. Only -that projected view uses `@native_call`. - -For a mutable scalar reference, the exact form is: - -```python -def increment(value: Ptr(Int)) -> None: ... -``` - -A generated Pythonic form may accept and return an ordinary scalar while the -decorator records the native reference and readback: - -```python -@native_call([Ptr(Arg(0))]) -def increment(value: Int) -> Returns["value", Int]: ... -``` - -The same transformation applies to a Fortran scalar `intent(inout)` argument: - -```python -# Exact Fortran interface -def advance(value: Ptr(Float64)) -> None: ... - -# Optional Pythonic generated view -@native_call([Ptr(Arg(0))]) -def advance(value: Float64) -> Returns["value", Float64]: ... ``` -For a native output argument, a Pythonic view may allocate and return storage: +Assumed-size arrays preserve their fixed rank and any dimensions constrained by +the visible storage contract. A rank-one `x(*)` is emitted as `T[:]`; for +`x(n, *)`, the second dimension has an unconstrained runtime extent, not an +unknown rank: ```python -# Exact native interface -def get_count(out: Ptr(Int)) -> None: ... - -# Optional Pythonic generated view -@native_call([Ptr(Return(0))]) -def get_count() -> Int: ... -``` - -Pythonic generation can also derive array metadata using NumPy attributes: +def legacy(values: Float64[:]) -> None: ... -```python -# Exact native interface: C size argument remains visible. -def sum_values(n: SizeT, values: Const(Float64[n])) -> Float64: ... - -# Optional Pythonic generated view. -@native_call([As[SizeT](Arg(0).shape[0]), Arg(0)]) -def sum_values(values: Const(Float64[:])) -> Float64: ... -``` - -`Arg(i).shape[dim]` selects a zero-based axis extent. -`Arg(i).strides[dim]` selects NumPy's byte stride for one axis: - -```python -@native_call([Arg(0), Arg(0).shape[1], Arg(0).strides[1]]) -def process_columns(values: Const(Float64[:, ::Strided])) -> None: ... -``` - -Annotation steps such as `::m` are element steps, while -`Arg(i).strides[dim]` is measured in bytes. A native function expecting an -element stride requires an explicit conversion using `Arg(i).itemsize`. - -This projected syntax is a design target, not behavior currently implemented -by the parser or printer. - -## Type Constraints - -Array dimensions use NumPy-style subscriptions. `Annotated[...]` holds layout -or Fortran dummy-argument properties that do not describe dimensions: - -```python -# Plain array notation is always C-order; generated C stubs use it directly. -Float64[:, :] - -# Generated dense Fortran-contiguous contracts explicitly state ORDER_F. -Annotated[Float64[:, :], ORDER_F] - -# Rank-one order is not emitted: ORDER_C and ORDER_F are equivalent. -Annotated[Int32[n], Allocatable] -Annotated[Float64[:], Pointer] - -# For rank >= 2, stride capability and orientation are independent. -# Bare strided storage keeps the default ORDER_C interpretation. -Float64[::Strided, ::Strided] -Annotated[Float64[::Strided, ::Strided], ORDER_F] -Annotated[Float64[::Strided, ::Strided], ORDER_ANY] - -# For rank one, stride is relevant but C/F order is not. -Float64[::Strided] +def legacy_matrix( + n: Ptr(Const(Int32)), + a: Annotated[Float64[n, :], ORDER_F] +) -> None: ... ``` -Dimension forms include: - -- `T[:]` for a rank-one array of unspecified extent. -- `T[:, :]` for a rank-two array of unspecified extents. -- `T[n]` for a rank-one array whose size is `n`; this is an extent, not an - element selection or index. -- `T[n, m]` or `T[3, 4]` for a rank-two array whose axis sizes are given by - the respective symbolic or literal extents. -- `T[0:n]` or `T[start:stop]` for an explicit half-open range contract rather - than a size-only contract. -- `T[:, ::Strided]` for a rank-two array whose second axis carries a runtime - stride rather than an assumed contiguous step. -- `T[::Strided, ::Strided]` for a rank-two array that exposes arbitrary - runtime strides on both axes while retaining the default `ORDER_C` - orientation. -- `T[:, ::2]` for a rank-two array whose second-axis step is exactly two. -- `T[:, 0:n:Strided]` for a bounded second axis with an arbitrary runtime - stride. -- `T[:, 0:n:m]` for a bounded second axis whose step is the semantic value - `m`. - -`T[:, ::]` is valid Python syntax, but it has the same meaning as `T[:, :]`; -it does not declare stride-aware storage. Use `::Strided` when an axis stride -must be represented and validated. - -An axis entry without colons is an extent: `T[n]` has size `n`, and -`T[n, m]` has shape `(n, m)`. An axis slice follows the NumPy/Python-style -half-open `lower:upper:step` shape. Each bound or explicit step may be a -literal or a symbol resolved from a visible scalar argument or a declared -semantic constant such as `Final[Int32]`. For example, in -`def sample(n: Int32, m: Int32, x: T[:, 0:n:m]) -> None: ...`, `n` -constrains the selected upper bound and `m` constrains the exact step. -`Strided` is the sentinel for any runtime step when its exact value is not -part of the semantic contract. Future expression support can extend symbols -to resolvable arithmetic such as `2*n` without changing this notation. Steps -are measured in elements, following NumPy slicing; conversion to native byte -strides, when required, belongs to the native-call mapping. - -For a Fortran assumed-shape or assumed-rank target lowered through a generated -Fortran intermediary, `Strided` can be satisfied directly from NumPy stride -metadata: it does not introduce another public function argument. For a C -function, or for a Fortran first-element-address interface, stride-aware -storage is direct only when the target call has the necessary visible stride -metadata; otherwise it requires packing/copy-back. - -Rank-polymorphic arrays use `...`, optionally followed by an allowed-rank -selector: - -| Annotation | Meaning | -| --- | --- | -| `Float64[...]` | `Float64` array with any rank (any number of dimensions). | -| `Float64[...][1:4]` | `Float64` array with rank 1, 2, or 3; the stop value is exclusive. | -| `Float64[...][1, 2, 5]` | `Float64` array with rank 1, 2, or 5. | - -Layout and ownership constraints can follow a dimension form: - -- Unqualified array forms imply `ORDER_C`, including multidimensional forms - with `::Strided`, regardless of whether a stub was generated from C, - Fortran, or written by hand. Generated C stubs omit redundant `ORDER_C`; - for rank one this same bare form is also the canonical Fortran spelling - because C/F order is not distinct. -- A Fortran generator emits `Annotated[Float64[:, :], ORDER_F]` for a - Fortran-contiguous rank-two or higher array contract rather than relying on - language provenance. -- `Annotated[Float64[...][1:4], ORDER_F]` writes a Fortran-oriented - contract for ranks 1, 2 or 3; concrete dense axis forms state - contiguity where required. -- `Annotated[Float64[::Strided, ::Strided], ORDER_F]` combines permitted - runtime strides with a required Fortran orientation. -- `Annotated[Float64[::Strided, ::Strided], ORDER_ANY]` combines permitted - runtime strides with no C/F orientation restriction, for example for a - fully general Fortran assumed-shape dummy. -- `ORDER_F` for a required Fortran orientation; with dense axis forms it - expresses Fortran-contiguous storage, while with `::Strided` it does not - prohibit non-contiguous storage. -- `ORDER_ANY` for a multidimensional contract that imposes no C/F - orientation requirement. -- `ORDER_C` is redundant in the canonical format: use the bare array form - because it already means the C orientation; a bare dense form is - C-contiguous, while a bare strided form is C-oriented and non-contiguous - where its stride constraints permit it. -- `Allocatable` for a Fortran allocatable dummy or value. -- `Pointer` for a Fortran pointer dummy; this is not the same as `Ptr(T)`, - which expresses a scalar or unrefined native address parameter. -- `Const(...)` for read-only pointee or array-storage contracts. -- `Ptr(T)` and `Ptr(Const(T))` for one-level scalar/native reference - arguments, rather than array dimensions. - -For a Fortran target, array notation describes the NumPy value accepted at -the Python boundary and the Fortran array contract the adapter must satisfy. -It does not expose whether the compiler-level call uses an address or a -descriptor. For a C target, dimensioned array notation records a known -storage contract and lowers to one native data pointer. Bare array forms -always imply `ORDER_C`. For rank one, a contiguous Fortran array uses the -same bare form because `ORDER_C == ORDER_F` for vectors. For rank two or -higher, Fortran-oriented contracts retain `ORDER_F` explicitly in generated -Fortran stubs, whether dense or strided. When a Fortran assumed-shape/rank -procedure accepts non-contiguous storage in any multidimensional orientation, -use a form such as -`Annotated[T[::Strided, ::Strided], ORDER_ANY]`; use `T[::Strided]` for a -rank-one form because rank-one C/F order is not distinct. -A Fortran adapter intentionally designed around C-contiguous multidimensional -storage may use the plain array form because that contract is genuinely -`ORDER_C`. - -`Strided` is an axis constraint, while `ORDER_C`, `ORDER_F`, and `ORDER_ANY` -describe multidimensional orientation independently. Consequently, -`T[::Strided, ::Strided]` inherits `ORDER_C`, -`Annotated[T[::Strided, ::Strided], ORDER_F]` admits strides under a Fortran -orientation, and `Annotated[T[::Strided, ::Strided], ORDER_ANY]` makes no -orientation restriction. An implementation must not reduce `ORDER_F` on a -strided form to the NumPy `F_CONTIGUOUS` flag. Wrappers must either pass the -required native stride metadata or apply an explicit packing/copy-back policy. -A Fortran adapter can prepare the target array argument from NumPy shape and -strides; a direct C call needs any required native extent or stride scalar -arguments preserved in the exact signature. - -The alternative spelling `T[:, :][ORDER_F]` is deliberately not canonical: -it can be confused with the second subscription used for permitted-rank -selectors such as `T[...][1:4]`. Use -`Annotated[T[:, :], ORDER_F]` for layout properties. - -`Arg(i).shape[dim]` and `Arg(i).strides[dim]` are native-call projection -expressions for obtaining metadata from a visible array argument; they are not -array annotation syntax. - -## Constants - -Fortran `parameter` declarations are constants. The printer emits them with -`Final[...]` instead of a generic type constraint: +Assumed-shape arrays are stride-aware. A rank-one assumed-shape dummy is +emitted as a strided vector. Under the current generated-wrapper policy, a +rank-two or higher assumed-shape dummy retains Fortran orientation while +permitting strides: ```python -answer: Final[Int32] -scale: Final[Float64] -``` - -When a constant is private, `private[...]` remains the outer visibility marker: +def vector(x: Float64[::Strided]) -> None: ... -```python -hidden_answer: private[Final[Int32]] +def matrix( + a: Annotated[ + Const(Float64[::Strided, ::Strided]), + ORDER_F, + ] +) -> None: ... ``` -The `.pyi` parser accepts `Final[...]` and restores it to the semantic IR as a -`Constant` constraint, so edited stubs still round-trip through the existing IR -model. +The Fortran declaration itself may permit an actual argument with another +orientation. The generated semantic interface deliberately chooses +Fortran-oriented storage by default. An edited interface or future projection +may choose `ORDER_ANY` only with corresponding backend and validation policy. +`contiguous` assumed-shape arrays use dense dimensions instead of +`::Strided`; their multidimensional forms also carry `ORDER_F`. -## Visibility +Explicit bounds are expressed through storage extents, not source-dimension +metadata. For example, `x(1:n)` has storage extent `n`; `x(0:n-1)` also has +extent `n` (the implementation currently retains the equivalent arithmetic +expression when it is not simplified). Python arrays present zero-based +storage; the compiled Fortran call associates that storage with the dummy +argument and supplies the lower and upper bounds declared by the procedure. +Those Fortran bounds affect indexing within the procedure, not what bound +metadata Python must pass. The public contract therefore needs the required +extent, layout and mutability, not `LowerBounds(...)`. -Private procedures and classes use decorators: +Allocatable and pointer arrays preserve their source storage property: ```python -@private -def hidden(x: Int32) -> None: ... -``` +class workspace: + values: Annotated[Float64[:], Allocatable] -Private module variables and fields use `private[...]`: - -```python -hidden_scale: private[Float64] +def section( + x: Annotated[Float64[:], Pointer] +) -> None: ... ``` -## Imports +Allocation or association replacement policy is not implemented. The semantic +IR preserves the facts needed for readiness and lowering decisions; a backend +must not silently treat replacement-capable allocatable or pointer dummies as +ordinary borrowed arrays. -Plain module imports are emitted for bare Fortran `use` statements: +## Preserved Metadata -```python -import iso_c_binding -``` +The shared semantic model separates: -For explicit `use ... only:` lists, the printer emits Python `from` imports so -the imported symbols remain visible in the stub: +- value type (`Float64`, `Int32`, derived type names); +- storage/calling contract (`value`, `reference`, `pointer`, `array`); +- public array contract (rank, required extents or admitted strides, order, + contiguity, allocatable and pointer semantics); +- source origin metadata (source language, native name, native scope, + source-level type/category information and lowering-relevant facts). -```python -from iso_c_binding import c_int, c_double -``` +The Fortran converter currently preserves public storage dimensions, order, +`intent`, optionality, `value`, constants, `allocatable` and `pointer` in the +visible semantic contract. It retains source declaration dimensions, bounds, +dummy category and `contiguous` provenance internally where the parser +supplies those facts for diagnostics or native-interface provenance; those +facts do not add visible array requirements. -For renamed Fortran imports, both sides are preserved with Python alias syntax: +## Loading And Round Trips -```fortran -use list_input, delete_input => delete_input_list -``` +`parse_pyi_text`, `load_pyi_file` and `convert_pyi_to_ir` load canonical +array subscriptions and `Annotated[...]` metadata into the same public +storage contracts emitted by the Fortran semantic pipeline. Native +source-provenance details not emitted into the public type are intentionally +excluded from public contract equality. Focused round-trip tests cover: -```python -from list_input import delete_input_list as delete_input +```text +Fortran parser model -> semantic IR -> .pyi -> semantic IR ``` -The `.pyi` parser accepts both `import module` and -`from module import source as target`. In semantic IR, `source` is the -provider-side name and `target` is the local alias; when there is no alias, -`target` is `None`. - -## Fortran Names That Are Not Python Identifiers +The loader rejects removed dimension helper syntax in type annotations. Use +array subscriptions such as `Float64[n]`, `Float64[:, :]` or +`Float64[::Strided]` instead. -If a parameter name is not usable as Python syntax, the printer uses a safe -Python name and preserves the original name with `Annotated[..., Name(...)]`: +## Pythonic Projection (Later) -```python -def call( - class_: Annotated[Int32, Name("class")] -) -> None: ... +The implemented Fortran generator emits the exact form described above. A +later optional generation or editing mode, for example `--pythonic`, may +expose a friendlier Python API whose arguments or results differ from that +native contract. Such a projected interface must retain a mapping back to the +exact semantic/native interface; it must not discard source origin, storage, +intent, shape, ownership or lowering facts needed to issue the call. + +A projection is allowed to be more restrictive or more expressive than the +exact native interface, according to the Python API the user wants to expose. +It may add accepted-input coercions, local constraints, cross-argument checks, +result checks, mutation policy or ownership policy. It need not expose every +use that the native routine could technically accept. At the native-call +boundary, however, the mapped native values must still satisfy the +requirements encoded by the exact native contract. + +The Fortran converter does not automatically generate a projected interface. +The loader and printer retain explicit projection mappings for edited semantic +stubs, including `@native_call` entries formed from `Arg`, `Return`, `Const`, +`Len`, `IsPresent`, `Work` and `.shape[...]`, plus `Returns[...]`. The +pointer/reference adaptation examples below (`Ptr(Arg(...))` and +`Ptr(Return(...))`), `As[...]`, `.strides[...]`, coercion policy and +validation contracts describe extensions required for the fuller Pythonic +projection; they are not currently accepted or emitted by this path. + +### Native Argument Projection + +Only a projected interface uses `@native_call`. The decorator records how +visible Python arguments and projected results supply the exact native +arguments. + +For a mutable scalar reference, the implemented exact Fortran form keeps +caller-supplied storage: + +```python +# Implemented exact form. +def advance(value: Ptr(Float64)) -> None: ... ``` -Module variables and derived-type fields can use `var[...]`: +A future Pythonic form may create writable temporary storage, perform the +native call and read the updated value back as a Python result: ```python -var["operator-name"]: Float64 +# Projected form, not currently implemented. +@native_call([Ptr(Arg(0))]) +def advance(value: Float64) -> Returns["value", Float64]: ... ``` -Both forms are valid Python syntax and are understood by the `.pyi` parser. - -## Loading Edited Stubs - -Use these entrypoints to recover semantic IR from a stub: +Similarly, an `intent(out)` scalar currently remains an explicit writable +reference with its preserved source intent: ```python -from semantics.pyi_parser import convert_pyi_to_ir, load_pyi_file, parse_pyi_text +# Implemented exact form. +def get_count(result: Annotated[Ptr(Int32), Intent("out")]) -> None: ... -module = load_pyi_file("mymodule.pyi") -module = parse_pyi_text(source, module_name="mymodule") -module = convert_pyi_to_ir(source, module_name="mymodule") +# Projected form, not currently implemented. +@native_call([Ptr(Return(0))]) +def get_count() -> Int32: ... ``` -To compare an edited `.pyi` file with an existing semantic IR module: +A projection may derive hidden native metadata from a visible array. For a +future native interface with a by-value length parameter, for example: ```python -from semantics.pyi_parser import load_pyi_file - -edited_ir = load_pyi_file("mymodule.pyi", module_name=existing_ir.name) -assert edited_ir == existing_ir -``` - -An exact semantic stub preserves every visible target argument required to -issue the call. For C this is the direct native argument list; for Fortran it -is the target dummy-argument contract lowered through the generated adapter. -A plain return type means a direct target return. `Returns[...]` and -`@native_call` belong to a later Pythonic projected stub, where a generated -wrapper intentionally turns caller-supplied storage into Python return values. - -Function and method argument names are placeholders during IR comparison. For -example, `def f(a: Int32) -> None: ...` and -`def f(b: Int32) -> None: ...` compare equal as functions. The same positional -renaming is applied inside dimension expressions such as `Float64[n]`. Names -outside function and method argument lists, including module variables and class -fields, remain significant. - -## Semantic Wrap-Readiness - -Readiness is assessed from semantic IR, not from parser internals. The same CLI -flag works for either source path: +# Exact contract for a future supported native frontend. +def sum_values(n: SizeT, values: Const(Float64[n])) -> Float64: ... -```bash -python -m x2py solver.f90 --wrap-readiness -python -m x2py solver.pyi --wrap-readiness +# Projected form, not currently implemented. +@native_call([As[SizeT](Arg(0).shape[0]), Arg(0)]) +def sum_values(values: Const(Float64[:])) -> Float64: ... ``` -For Fortran input, x2py parses the source, converts it to semantic IR, then -checks that semantic interface. For `.pyi` input, x2py parses the edited stub -directly to semantic IR and checks that interface. The edited `.pyi` is the -source of truth when the user needs to provide information the source parser -cannot infer. - -The flag can be requested alone for a concise readiness report or combined with -other stages. For example, `--semantics --wrap-readiness` emits semantic IR with -the readiness payload attached. - -The target readiness check consumes these `.pyi` facts: - -- `class name:` declares a wrapper-visible derived type or handle. -- `name: Final[Int32] = 8` declares a literal compile-time constant value that - can satisfy shape and size metadata. -- `Callable[[ArgType, ...], ReturnType]` declares the full callback signature - for a procedure/function-pointer argument. -- Array annotations and `Annotated[...]` properties provide required rank, - shape, layout, `Allocatable` and `Pointer` facts for a Fortran adapter. - -Mutable `Allocatable` or `Pointer` array dummies that may replace allocation -or pointer association remain not ready until a return, ownership or -copy-back policy specifies how that changed state is exposed to Python. - -Example: +`Arg(i).shape[dim]` denotes a zero-based array extent. +`Arg(i).strides[dim]` denotes a NumPy byte stride: ```python -from typing import Callable, Final - -rk: Final[Int32] = 8 - -class sim_state: - n: Int32 - values: Float64[n] - -def step( - state: Ptr(sim_state), - t: Ptr(Const(Float64)), - objective: Callable[[Ptr(sim_state), Ptr(Const(Float64))], Float64], - score: Ptr(Float64), -) -> None: ... +@native_call([Arg(0), Arg(0).shape[1], Arg(0).strides[1]]) +def process_columns(values: Const(Float64[:, ::Strided])) -> None: ... ``` -This can clear readiness blockers for a Fortran routine that imports -`sim_state`, uses `real(kind=rk)`, accepts `objective` as a callback, and -mutates caller-supplied `state`/`score` storage. A `Final[...]` declaration -without a literal value is intentionally not enough for compile-time shape or -size resolution, and `Callable[..., ReturnType]` is not enough for callbacks -because the wrapper still needs argument order and argument types. +Dimension steps such as `::m` are expressed in elements; deriving a native +element stride from a byte stride must include the item-size conversion in +the native mapping. + +### Coercions And Constraints + +A Pythonic projection may accept values that are not already in the exact +storage form, but only through explicit allowed coercions. For example, a +projected API could allow a NumPy C-order matrix to be copied into an +`ORDER_F` value required by a Fortran-oriented exact contract. It may instead +reject that input when no copying coercion is declared. + +Coercions and constraints serve different purposes: + +- A coercion states how an accepted Python object becomes the required + semantic runtime value, potentially allocating storage or changing layout. +- A constraint states what must be true of the adapted value before native + lowering, such as dtype, rank, shape, stride capability, `ORDER_F`, + mutability, device residence, alignment or ownership. + +The exact notation already records native-facing local constraints, including +`Ptr(Const(T))`, `Const(T[...])`, dimensions, `ORDER_F`, `ORDER_ANY`, +`Allocatable` and `Pointer`. A projected API may add allowed conversion +policy, for example a future `From(np.ndarray, copy=True)` spelling, but it +cannot silently weaken the exact native contract. + +The exact native contract is therefore a minimum obligation for a projection. +A projected API may require additional properties, such as finite values, +non-aliasing arguments, a square matrix or a no-copy policy. A declared +coercion may convert a projected input so that it satisfies a native +requirement, such as packing C-oriented input into `ORDER_F` storage. But the +mapped value sent to native lowering must satisfy the encoded native element +type, reference/read-write contract, rank, extent, layout, stride, +allocation/association and other calling-relevant requirements. + +This document does not currently define a hard-versus-soft classification for +exact-contract constraints. Until such a classification and override policy +exist, constraints encoded in the exact native interface are mandatory at the +native-call boundary. A later design may classify advisory requirements, such +as a preferred layout or zero-copy preference, as relaxable by an explicit +projection policy. ABI, memory-safety and semantic-correctness requirements +cannot be treated as advisory. + +In particular, conversion and copy-back policies are required before a +projection can: + +- accept C-order or non-contiguous storage for a target requiring dense + Fortran-oriented storage; +- expose mutable scalar references as ordinary scalar inputs and returns; +- return changes to output arrays through allocated temporary storage; +- expose replacement-capable `Allocatable` or `Pointer` dummies; or +- preserve ownership, lifetime and aliasing behavior through a temporary. + +### Validation Contracts + +Local constraints are not sufficient for relationships between multiple +arguments or for promises about projected results. A future projected +interface may add a validation contract, whether or not the exact native +interface already contains local constraints, for: + +- preconditions, such as matching extents or non-aliasing inputs; +- postconditions, such as the returned shape or dtype; +- invariants on projected objects after mutation; +- mutation and aliasing rules; and +- ownership and lifetime rules for borrowed, owned, viewed or temporary + storage. + +For example, this is an illustrative later projected interface, not currently +accepted projection syntax: + +```python +@contract( + pre=[ + lambda ctx: ctx.args.a.shape[0] == ctx.args.a.shape[1], + lambda ctx: ctx.args.b.shape == (ctx.args.a.shape[0],), + ], + post=[lambda ctx: ctx.result.shape == ctx.args.b.shape], + invariants=[lambda ctx: not ctx.result.aliases(ctx.args.a)], +) +def solve( + a: Annotated[Float64[:, :], ORDER_F], + b: Float64[:], +) -> Float64[:]: ... +``` + +A constraint can require that `a` is `ORDER_F`; a contract can require that +`a` is square, that `b` agrees with its extent and that the result does not +alias mutable input storage. These checks occur at distinct levels and must +remain distinct in a later semantic model. Projection-level checks supplement +the exact native contract; they do not replace its mandatory native-call +checks. + +A projected call therefore has the following conceptual sequence: + +```text +visible Python values + -> projected allowed coercions + -> projected local constraints and contract preconditions + -> exact native argument mapping + -> mandatory exact-native constraint validation + -> backend lowering + -> native call + -> contract postconditions and invariants + -> projected Python results +``` + +The projection mechanism is language-neutral. It can later adapt exact +Fortran or C contracts through the same notation and runtime concepts, but +this milestone does not implement automatic Pythonic generation, current +exact-reference adaptation, coercion/contract execution or C semantic +conversion/output. + +## Deferred C Work + +The shared model is capable of representing future C functions, variables, +fields, constants, scalar references, pointers, arrays with known contracts, +origin metadata, mutability and ownership facts. This task does not implement: + +- `semantics/c2ir.py`; +- C semantic conversion; +- C `.pyi` generation; +- C wrapper lowering; +- C ownership, callback or pointer policy inference. + +Future C conversion should use the same notation: by-value scalars as bare +types, unrefined pointers as `Ptr(T)` or `Ptr(Const(T))`, and array notation +only when a real array storage contract is known. diff --git a/docs/x2py_checklist.md b/docs/x2py_checklist.md index e1fc438e5..827761c98 100644 --- a/docs/x2py_checklist.md +++ b/docs/x2py_checklist.md @@ -49,39 +49,41 @@ Language scope is stated in each section or subsection heading: ## Step 3: Shared Semantic Model Foundation (Fortran And C) -- [ ] Treat the semantic model as language-neutral: Fortran and C parser output +- [x] Treat the semantic model as language-neutral: Fortran and C parser output should converge into the same IR shapes wherever the native contract is equivalent. -- [ ] Decide whether `SemanticArgument` remains the common model for variables, +- [x] Decide whether `SemanticArgument` remains the common model for variables, function arguments, fields, and returned argument projections, or whether `semantics/models.py` should introduce a clearer `SemanticVariable` model and use it consistently. -- [ ] Make the chosen variable model represent C function parameters, C globals, +- [x] Make the chosen variable model represent C function parameters, C globals, C struct/union fields, Fortran dummy arguments, Fortran module variables, Fortran derived-type components, and projected return values. -- [ ] Keep language-specific origin facts as metadata, for example +- [x] Keep language-specific origin facts as metadata, for example `source_language`, `native_name`, `native_scope`, source location, parser node kind, and backend lowering hints. -- [ ] Split the semantic value type from the storage and calling contract where +- [x] Split the semantic value type from the storage and calling contract where needed, so `Float64`, `Ptr(Float64)`, `Const(Float64[n])`, and a Fortran descriptor-backed array are not confused. -- [ ] Define one array/storage contract that can represent known C array +- [x] Define one array/storage contract that can represent known C array contracts and Fortran array dummies using element type, rank, shape, bounds, strides, order, contiguity, mutability, and ownership. -- [ ] Decide whether that array/storage contract is represented as a dedicated +- [x] Decide whether that array/storage contract is represented as a dedicated semantic model, a derived semantic type, or structured metadata on `SemanticType`; the chosen design must be readable from both generated and edited `.pyi` files. -- [ ] For Fortran arrays, record the dummy category and properties needed by - lowering: explicit-shape, assumed-size, assumed-shape, assumed-rank, - deferred-shape, `contiguous`, `allocatable`, `pointer`, rank, shape, - lower bounds, and whether replacement or reassociation is possible. +- [x] For Fortran arrays, retain native declaration provenance where available: + explicit-shape, assumed-size, assumed-shape, assumed-rank, + deferred-shape, `contiguous`, `allocatable`, `pointer`, rank and source + bounds. Canonical `.pyi` exposes only storage constraints; Fortran dummy + bounds are established by native argument association, not passed as + Python array metadata. - [ ] For C arrays, use the same array/storage contract only when a real storage contract is known; leave unrefined pointers as pointer types instead of inventing array shapes. -- [ ] Preserve scalar by-reference contracts for both languages with the same +- [x] Preserve scalar by-reference contracts for both languages with the same reference representation, including `Ptr(T)` and `Ptr(Const(T))`. -- [ ] Make `intent`, mutability, ownership, aliasing, optionality, defaults, +- [x] Make `intent`, mutability, ownership, aliasing, optionality, defaults, constraints, coercions, and contracts work on the shared variable model rather than in language-specific side channels. - [ ] Define how future constraints and coercions attach to variables and @@ -91,17 +93,18 @@ Language scope is stated in each section or subsection heading: Fortran array rank, unknown array category, unsupported allocatable or pointer reassociation, unresolved C pointer ownership, and unsupported callbacks. -- [ ] Keep backend lowering metadata separate from the Python-facing `.pyi` +- [x] Keep backend lowering metadata separate from the Python-facing `.pyi` contract; generated stubs should describe the visible semantic interface, not compiler-private transport details. - [ ] Add equality and round-trip tests that prove equivalent C and Fortran variables compare by semantic contract, not by parser-specific metadata. -- [ ] Add model tests for Fortran arrays represented as semantic array/storage - contracts with shape, rank, `ORDER_F` or `ORDER_ANY`, `Allocatable`, and - `Pointer`. +- [x] Add model tests for Fortran arrays represented as semantic array/storage + contracts with shape, rank, generated `ORDER_F`, `Allocatable`, and + `Pointer`; keep `ORDER_ANY` available for an explicitly edited or + projected interface. - [ ] Add model tests for C pointer/array contracts using the same array/storage representation when shape and storage facts are known. -- [ ] Document the shared variable, array, pointer, ownership, constraint, and +- [x] Document the shared variable, array, pointer, ownership, constraint, and coercion model before enabling new generator behavior. ## Step 4: C Semantic Readiness @@ -222,32 +225,38 @@ Language scope is stated in each section or subsection heading: ### Fortran Conversion -- [ ] Update `FortranToIRConverter` to emit the exact native interface described +- [x] Update `FortranToIRConverter` to emit the exact native interface described in `docs/semantics/pyi_format.md`, not the older placeholder shape representation. -- [ ] Map Fortran scalar dummy arguments by reference to shared pointer +- [x] Map Fortran scalar dummy arguments by reference to shared pointer contracts: writable storage as `Ptr(T)` and read-only storage as `Ptr(Const(T))`. -- [ ] Map Fortran `value` scalar dummy arguments and function returns to direct +- [x] Map Fortran `value` scalar dummy arguments and function returns to direct semantic scalar values. -- [ ] Map Fortran explicit-shape and adjustable arrays to shaped NumPy storage +- [x] Map Fortran explicit-shape and adjustable arrays to shaped NumPy storage contracts with `ORDER_F` where rank and orientation require it. -- [ ] Map Fortran assumed-size arrays to known-rank storage contracts while - preserving the missing final extent boundary. -- [ ] Map Fortran assumed-shape arrays to strided contracts with `ORDER_ANY` - unless `contiguous` or another source fact restricts orientation. +- [x] Map Fortran assumed-size arrays to known-rank storage contracts with an + unconstrained final runtime extent where the native declaration uses + `*`. +- [x] Map Fortran assumed-shape arrays to strided contracts with generated + `ORDER_F` orientation under the current Fortran-default layout policy; + an edited interface or later projection may explicitly select + `ORDER_ANY`. - [ ] Map Fortran assumed-rank arrays only after the semantic model can represent rank-polymorphic array contracts explicitly. - [ ] Map Fortran `allocatable` and `pointer` dummy arrays to shared array - contracts with `Allocatable` or `Pointer` constraints and readiness + contracts with `Allocatable` or `Pointer` metadata and readiness blockers for allocation or association changes until policy exists. -- [ ] Preserve Fortran lower bounds and source-level dimension expressions when - they affect wrapper validation or lowering. -- [ ] Convert Fortran module variables and derived-type components through the + Contracts are represented in IR and `.pyi`; readiness blockers for + allocation or association changes remain open. +- [x] Convert Fortran bound declarations to required public storage extents; + retain original source bounds only as internal provenance, since the + compiled Fortran interface establishes dummy bounds on association. +- [x] Convert Fortran module variables and derived-type components through the same variable model used for C variables and fields. -- [ ] Ensure language-to-IR conversion retains enough origin metadata for +- [x] Ensure language-to-IR conversion retains enough origin metadata for backend lowering without making `.pyi` syntax language-specific. -- [ ] Add Fortran semantic IR tests for scalar references, explicit-shape +- [x] Add Fortran semantic IR tests for scalar references, explicit-shape arrays, assumed-size arrays, assumed-shape arrays, allocatable arrays, pointer arrays, derived-type components, and module variables. @@ -262,58 +271,61 @@ Language scope is stated in each section or subsection heading: ### Shared Generation Contract (Fortran And C) -- [ ] Make `.pyi` generation consume semantic IR only; language-specific +- [x] Make `.pyi` generation consume semantic IR only; language-specific differences should already be encoded as semantic contracts and metadata. -- [ ] Update the `.pyi` printer to emit the canonical target notation from +- [x] Update the `.pyi` printer to emit the canonical target notation from `docs/semantics/pyi_format.md`, including `T[n, m]`, `T[:, :]`, `T[::Strided]`, `Annotated[..., ORDER_F]`, `Annotated[..., ORDER_ANY]`, `Allocatable`, and `Pointer`. ### Fortran Stub Generation -- [ ] Update Fortran `.pyi` generation to emit exact native interface stubs: +- [x] Update Fortran `.pyi` generation to emit exact native interface stubs: scalar references as `Ptr(...)`, array dummies as NumPy array annotations, explicit `ORDER_F` only when rank and orientation require it, and no `@native_call` for the exact interface. -- [ ] Ensure Fortran `.pyi` generation preserves source facts that affect - validation or lowering, including rank, shape expressions, lower bounds, - assumed-shape or assumed-size category, contiguity, `allocatable`, - `pointer`, `intent`, optionality, and constants. -- [ ] Ensure generated Fortran stubs do not generalize missing fixed-rank array +- [x] Ensure Fortran `.pyi` generation preserves source facts that affect + the visible contract, including rank, storage extent expressions, + stride/layout policy, `allocatable`, `pointer`, `intent`, optionality, + and constants. Retain native dummy category and original bound facts + internally as source provenance rather than emitting + `ArrayCategory(...)` or `SourceDims(...)` in canonical stubs. +- [x] Ensure generated Fortran stubs do not generalize missing fixed-rank array information into rank-polymorphic notation. -- [ ] Add Fortran `.pyi` generation tests for exact scalar references, +- [x] Add Fortran `.pyi` generation tests for exact scalar references, explicit-shape arrays, assumed-size arrays, assumed-shape strided arrays, contiguous arrays, allocatable arrays, pointer arrays, constants, derived type fields, and module variables. ### Shared Loading And Round Trips (Fortran And C) -- [ ] Extend `load_pyi_file`, `parse_pyi_text`, and `convert_pyi_to_ir` to load +- [x] Extend `load_pyi_file`, `parse_pyi_text`, and `convert_pyi_to_ir` to load the accepted `.pyi` target notation into semantic IR, not just parse a subset for readiness. -- [ ] Teach the `.pyi` loader to parse `Annotated[...]` metadata into semantic - constraints and metadata without losing order, ownership, array category, - or source-name information. -- [ ] Teach the `.pyi` loader to parse NumPy-style array subscriptions into the +- [x] Teach the `.pyi` loader to parse canonical `Annotated[...]` metadata into + semantic storage metadata without losing order, ownership, or + source-name information; it continues to accept legacy + `ArrayCategory(...)` and `SourceDims(...)` annotations. +- [x] Teach the `.pyi` loader to parse NumPy-style array subscriptions into the shared array/storage contract, including symbolic dimensions, `:`, `::Strided`, known rank, rank-polymorphic forms when supported, and order metadata. -- [ ] Teach the `.pyi` loader to parse `Ptr(...)`, `Const(...)`, `Final[...]`, +- [x] Teach the `.pyi` loader to parse `Ptr(...)`, `Const(...)`, `Final[...]`, `private[...]`, `Name(...)`, `native_call(...)`, and projected returns into the same semantic IR emitted by language converters. - [ ] Add parser errors for `.pyi` constructs that look valid but cannot be converted to complete semantic IR, such as unknown fixed-rank shape, unsupported rank-polymorphic arrays, or unsafe allocatable/pointer replacement policy. -- [ ] Add round-trip tests for Fortran parser output: +- [x] Add round-trip tests for Fortran parser output: parser model -> semantic IR -> `.pyi` -> semantic IR. -- [ ] Add round-trip tests for edited Fortran `.pyi` files loaded directly into +- [x] Add round-trip tests for edited Fortran `.pyi` files loaded directly into semantic IR. - [ ] Add round-trip tests for C parser output: parser model -> semantic IR -> `.pyi` -> semantic IR. - [ ] Add mixed-language semantic fixture tests where C and Fortran stubs load through the same `.pyi` loader and readiness checker. -- [ ] Keep `.pyi` syntax language-neutral; Fortran and C should differ by +- [x] Keep `.pyi` syntax language-neutral; Fortran and C should differ by semantic contract, not by separate annotation families. ### C Stub Generation And Policy diff --git a/fortran_parser/models.py b/fortran_parser/models.py index af4bdb8f0..4e2cd3420 100644 --- a/fortran_parser/models.py +++ b/fortran_parser/models.py @@ -262,6 +262,14 @@ class FortranArgument(FortranVariable): allocatable: bool = False pointer: bool = False + @property + def contiguous(self) -> bool: + return bool(getattr(self, "_contiguous", False)) + + @contiguous.setter + def contiguous(self, value: bool) -> None: + self._contiguous = bool(value) + @dataclass(eq=False) class FortranUseMapping: diff --git a/fortran_parser/parser.py b/fortran_parser/parser.py index d57ae8336..d56cd7280 100644 --- a/fortran_parser/parser.py +++ b/fortran_parser/parser.py @@ -2611,6 +2611,7 @@ def _new_decl_meta(base_type: str, kind: str | None) -> dict: "value": False, "allocatable": False, "pointer": False, + "contiguous": False, "external": False, "parameter": False, } @@ -2629,6 +2630,8 @@ def _apply_decl_attrs(meta: dict, attrs: list[str], *, include_intent: bool = Fa meta["allocatable"] = True elif la == "pointer": meta["pointer"] = True + elif la == "contiguous": + meta["contiguous"] = True elif la == "external": meta["external"] = True elif la == "parameter": @@ -2679,6 +2682,7 @@ def _apply(arg: FortranArgument, meta: dict, shape: list[str]): arg.pass_by_value = meta["value"] arg.allocatable = meta["allocatable"] arg.pointer = meta["pointer"] + arg.contiguous = meta["contiguous"] arg.is_parameter = meta["parameter"] if shape: arg.shape = shape diff --git a/semantics/fortran2ir.py b/semantics/fortran2ir.py index 27843a8d8..c751e2a32 100644 --- a/semantics/fortran2ir.py +++ b/semantics/fortran2ir.py @@ -1,5 +1,6 @@ from __future__ import annotations +import ast from copy import deepcopy import re from pathlib import Path @@ -18,6 +19,7 @@ from .models import ( SemanticArgument, + SemanticArrayContract, SemanticClass, SemanticConstraint, SemanticFunction, @@ -25,6 +27,8 @@ SemanticImportItem, SemanticMethod, SemanticModule, + SemanticOrigin, + SemanticStorageContract, SemanticType, ProjectionMapping, ) @@ -177,13 +181,16 @@ def visit_file(self, parsed_file: FortranFile) -> SemanticModule: def visit_variable(self, var: FortranVariable) -> SemanticType: semantic_name = self._semantic_type_name(var) + shape = [self._resolve_compile_time_text(dim) for dim in var.shape] + storage = self._array_storage_contract(var, shape) if var.rank > 0 else None semantic_type = SemanticType( name=semantic_name, rank=var.rank, dtype=semantic_name, - shape=[self._resolve_compile_time_text(dim) for dim in var.shape], + shape=list(storage.array.shape if storage is not None and storage.array is not None else shape), + storage=storage, + origin=self._variable_origin(var), ) - self._add_shape_constraints(semantic_type) self._add_variable_constraints(semantic_type, var) return semantic_type @@ -194,11 +201,14 @@ def visit_argument( intent: str | None = None, ) -> SemanticArgument: semantic_type = self.visit_variable(arg) - self._add_argument_constraints(semantic_type, arg) resolved_intent = intent if intent is not None else getattr(arg, "intent", "in") resolved_intent = str(resolved_intent).lower().replace(" ", "") if resolved_intent == "unknown": resolved_intent = "inout" + if semantic_type.rank > 0: + self._apply_array_argument_contract(semantic_type, arg, resolved_intent) + elif not getattr(arg, "pass_by_value", False): + semantic_type.storage = self._reference_storage_contract(resolved_intent) self._apply_argument_ownership(semantic_type, resolved_intent) return SemanticArgument( @@ -207,6 +217,26 @@ def visit_argument( intent=resolved_intent, optional=getattr(arg, "optional", False), visibility=getattr(arg, "visibility", "public"), + origin=self._argument_origin(arg), + ) + + def visit_data_member( + self, + var: FortranArgument | FortranVariable, + *, + intent: str = "in", + ) -> SemanticArgument: + semantic_type = self.visit_variable(var) + if semantic_type.storage is not None and semantic_type.storage.array is not None: + semantic_type.storage.array.allocatable = getattr(var, "allocatable", False) + semantic_type.storage.array.pointer = getattr(var, "pointer", False) + return SemanticArgument( + name=var.name, + semantic_type=semantic_type, + intent=intent, + optional=getattr(var, "optional", False), + visibility=getattr(var, "visibility", "public"), + origin=self._argument_origin(var), ) def visit_procedure( @@ -214,7 +244,7 @@ def visit_procedure( proc: FortranProcedureSignature, visibility: str = "public", ) -> SemanticFunction: - arguments = [self.visit_argument(arg) for arg in self._projected_procedure_arguments(proc)] + arguments = [self.visit_argument(arg) for arg in proc.arguments] return SemanticFunction( name=proc.name, native_name=proc.name, @@ -222,6 +252,12 @@ def visit_procedure( return_type=self.visit_variable(proc.result) if proc.result else None, projection=self._procedure_projection(proc, arguments), visibility=visibility, + origin=SemanticOrigin( + source_language="fortran", + native_name=proc.name, + native_scope=proc.module, + source_kind=proc.kind, + ), ) def visit_derived_type( @@ -233,10 +269,16 @@ def visit_derived_type( return SemanticClass( name=dtype.name, native_name=dtype.name, - fields=[self.visit_argument(field, intent="in") for field in dtype.fields], + fields=[self.visit_data_member(field, intent="in") for field in dtype.fields], methods=self._bound_methods(dtype, lookup), base_classes=self._base_classes(dtype), visibility=getattr(dtype, "visibility", "public"), + origin=SemanticOrigin( + source_language="fortran", + native_name=dtype.name, + native_scope=dtype.module, + source_kind="derived_type", + ), ) def visit_module(self, module: FortranModule) -> SemanticModule: @@ -260,8 +302,14 @@ def visit_module(self, module: FortranModule) -> SemanticModule: name=module.name, functions=semantic_functions, classes=semantic_classes, - variables=[self.visit_argument(var, intent="in") for var in getattr(module, "variables", [])], + variables=[self.visit_data_member(var, intent="in") for var in getattr(module, "variables", [])], imports=self._module_imports(module), + origin=SemanticOrigin( + source_language="fortran", + native_name=module.name, + native_scope=module.name, + source_kind="module", + ), ) def visit_file_modules( @@ -391,29 +439,219 @@ def _resolve_compile_time_text(self, text: str) -> str: return _resolve_compile_time_text(text, self.compile_time_values) @staticmethod - def _add_shape_constraints(semantic_type: SemanticType) -> None: - if semantic_type.rank <= 0: - return - semantic_type.constraints.append( - SemanticConstraint( - name="Shape", - arguments=list(semantic_type.shape), + def _variable_origin(var: FortranVariable) -> SemanticOrigin: + return SemanticOrigin( + source_language="fortran", + native_name=var.name, + source_kind="variable", + source_type=FortranToIRConverter._fortran_source_type(var), + metadata=FortranToIRConverter._fortran_variable_metadata(var), + ) + + @staticmethod + def _argument_origin(arg: FortranArgument | FortranVariable) -> SemanticOrigin: + return SemanticOrigin( + source_language="fortran", + native_name=arg.name, + native_scope=getattr(arg, "procedure", None), + source_kind="argument" if isinstance(arg, FortranArgument) else "variable", + source_type=FortranToIRConverter._fortran_source_type(arg), + metadata=FortranToIRConverter._fortran_variable_metadata(arg), + ) + + @staticmethod + def _fortran_source_type(var: FortranVariable) -> str: + if var.kind: + return f"{var.base_type}(kind={var.kind})" + return var.base_type + + @staticmethod + def _fortran_variable_metadata(var: FortranVariable) -> dict[str, object]: + metadata: dict[str, object] = { + "rank": var.rank, + "shape": list(var.shape), + "lower_bounds": list(getattr(var, "lbound", []) or []), + "upper_bounds": list(getattr(var, "ubound", []) or []), + } + if isinstance(var, FortranArgument): + metadata.update( + { + "intent": var.intent, + "optional": var.optional, + "value": var.pass_by_value, + "allocatable": var.allocatable, + "pointer": var.pointer, + "contiguous": getattr(var, "contiguous", False), + } ) + if getattr(var, "is_parameter", False): + metadata["constant"] = True + return metadata + + def _array_storage_contract( + self, + var: FortranVariable, + shape: list[str], + ) -> SemanticStorageContract: + category = self._array_category(var, shape) + axes = self._array_axes(shape, category, contiguous=getattr(var, "contiguous", False)) + rank = var.rank + order = self._array_order(rank, category, contiguous=getattr(var, "contiguous", False)) + lower_bounds, upper_bounds = self._array_bound_metadata(shape) + array = SemanticArrayContract( + rank=rank, + shape=list(axes), + lower_bounds=lower_bounds, + upper_bounds=upper_bounds, + source_shape=list(shape), + category=category, + order=order, + axes=["strided" if self._is_strided_axis(axis) else "dense" for axis in axes], + contiguous=self._array_contiguous(category, contiguous=getattr(var, "contiguous", False)), + allocatable=getattr(var, "allocatable", False), + pointer=getattr(var, "pointer", False), + ) + return SemanticStorageContract( + kind="array", + mutable=False, + array=array, ) - semantic_type.constraints.append(SemanticConstraint(name="ORDER_F")) + + def _resolve_optional_compile_time_text(self, text: str | None) -> str | None: + if text is None: + return None + return self._resolve_compile_time_text(text) + + def _array_bound_metadata(self, shape: list[str]) -> tuple[list[str | None], list[str | None]]: + lower_bounds: list[str | None] = [] + upper_bounds: list[str | None] = [] + for dim in shape: + token = dim.strip() + if ":" not in token: + lower_bounds.append(None) + upper_bounds.append("*" if token == "*" else None) + continue + lower, upper = self._dimension_bounds(token) + lower_bounds.append(None if lower in {None, "1"} else self._resolve_compile_time_text(lower)) + upper_bounds.append(self._resolve_optional_compile_time_text(upper)) + if all(value is None for value in lower_bounds): + lower_bounds = [] + if all(value is None for value in upper_bounds): + upper_bounds = [] + return lower_bounds, upper_bounds + + @staticmethod + def _array_category(var: FortranVariable, shape: list[str]) -> str: + cleaned = [dim.strip() for dim in shape] + if cleaned == [".."]: + return "assumed_rank" + if cleaned and cleaned[-1] == "*": + return "assumed_size" + if any(dim.endswith(":*") for dim in cleaned): + return "assumed_size" + if isinstance(var, FortranArgument) and (getattr(var, "allocatable", False) or getattr(var, "pointer", False)): + return "deferred_shape" if any(FortranToIRConverter._has_omitted_upper_bound(dim) for dim in cleaned) else "explicit_shape" + if any(FortranToIRConverter._has_omitted_upper_bound(dim) for dim in cleaned): + return "assumed_shape" + return "explicit_shape" + + @classmethod + def _array_axes(cls, shape: list[str], category: str, *, contiguous: bool) -> list[str]: + if category == "assumed_rank": + return ["..."] + if category == "assumed_shape" and not contiguous: + return ["::Strided" for _dim in shape] + + axes: list[str] = [] + for dim in shape: + token = dim.strip() + if token == "*": + axes.append(":") + continue + if token.endswith(":*"): + axes.append(":") + continue + lower, upper = cls._dimension_bounds(token) + if lower in {None, "1"} and upper: + axes.append(cls._canonical_dimension_expression(upper)) + elif lower is not None and upper is not None: + axes.append(cls._canonical_dimension_expression(f"({upper}) - ({lower}) + 1")) + elif ":" in token: + axes.append(":") + else: + axes.append(cls._canonical_dimension_expression(token)) + return axes + + @staticmethod + def _dimension_bounds(token: str) -> tuple[str | None, str | None]: + if ":" not in token: + return "1", token + lower, upper = token.split(":", 1) + return lower.strip() or None, upper.strip() or None + + @staticmethod + def _has_omitted_upper_bound(token: str) -> bool: + return ":" in token and token.split(":", 1)[1].strip() == "" + + @staticmethod + def _canonical_dimension_expression(expression: str) -> str: + try: + return ast.unparse(ast.parse(expression, mode="eval").body) + except SyntaxError: + return expression + + @staticmethod + def _array_order(rank: int, category: str, *, contiguous: bool) -> str | None: + if rank <= 1: + return None + return "ORDER_F" + + @staticmethod + def _array_contiguous(category: str, *, contiguous: bool) -> bool | None: + if contiguous: + return True + if category in {"explicit_shape", "assumed_size", "deferred_shape"}: + return True + if category == "assumed_shape": + return False + return None + + @staticmethod + def _is_strided_axis(axis: str) -> bool: + return "Strided" in axis + + @staticmethod + def _reference_storage_contract(intent: str) -> SemanticStorageContract: + read_only = str(intent).lower() == "in" + return SemanticStorageContract( + kind="reference", + read_only=read_only, + mutable=not read_only, + pointer_depth=1, + ) + + @staticmethod + def _apply_array_argument_contract( + semantic_type: SemanticType, + arg: FortranArgument | FortranVariable, + intent: str, + ) -> None: + if semantic_type.storage is None: + return + read_only = str(intent).lower() == "in" + semantic_type.storage.read_only = read_only + semantic_type.storage.mutable = not read_only + if semantic_type.storage.array is not None: + semantic_type.storage.array.allocatable = getattr(arg, "allocatable", False) + semantic_type.storage.array.pointer = getattr(arg, "pointer", False) + if getattr(arg, "contiguous", False): + semantic_type.storage.array.contiguous = True @staticmethod def _add_variable_constraints(semantic_type: SemanticType, var: FortranVariable) -> None: if getattr(var, "is_parameter", False): semantic_type.constraints.append(SemanticConstraint("Constant")) - @staticmethod - def _add_argument_constraints(semantic_type: SemanticType, arg: FortranArgument | FortranVariable) -> None: - if getattr(arg, "allocatable", False): - semantic_type.constraints.append(SemanticConstraint("Allocatable")) - if getattr(arg, "pointer", False): - semantic_type.constraints.append(SemanticConstraint("Pointer")) - @staticmethod def _apply_argument_ownership(semantic_type: SemanticType, intent: str) -> None: semantic_type.ownership.mutable = str(intent).lower() != "in" @@ -435,7 +673,9 @@ def _bound_methods( arguments=proc.arguments, return_type=proc.return_type, contracts=proc.contracts, + projection=proc.projection, visibility=proc.visibility, + origin=proc.origin, ) ) return methods @@ -463,15 +703,6 @@ def _procedure_projection( arguments: list[SemanticArgument], ) -> list[ProjectionMapping]: by_name = {arg.name: arg for arg in arguments} - call_positions = { - arg.name: index - for index, arg in enumerate(arg for arg in arguments if getattr(arg, "intent", "in") != "out") - } - result_offset = 1 if proc.result is not None else 0 - result_positions = { - arg.name: result_offset + index - for index, arg in enumerate(arg for arg in arguments if getattr(arg, "intent", "in") in {"out", "inout"}) - } projection: list[ProjectionMapping] = [] for native_position, native_arg in enumerate(proc.arguments): @@ -479,11 +710,10 @@ def _procedure_projection( intent = getattr(arg, "intent", "in") projection.append( ProjectionMapping( - python_name=arg.name if intent != "out" else None, + python_name=arg.name, native_name=native_arg.name, native_position=native_position, - python_position=call_positions.get(arg.name), - result_position=result_positions.get(arg.name), + python_position=native_position, intent=intent, ) ) @@ -759,6 +989,30 @@ def _resolve_semantic_type_compile_time_values( for constraint in semantic_type.constraints: constraint.arguments = _resolve_semantic_value(constraint.arguments, compile_time_values) semantic_type.metadata = _resolve_semantic_value(semantic_type.metadata, compile_time_values) + if semantic_type.storage is not None: + semantic_type.storage.metadata = _resolve_semantic_value( + semantic_type.storage.metadata, + compile_time_values, + ) + if semantic_type.storage.array is not None: + array = semantic_type.storage.array + array.shape = [ + _resolve_compile_time_text(dim, compile_time_values) + for dim in array.shape + ] + array.source_shape = [ + _resolve_compile_time_text(dim, compile_time_values) + for dim in array.source_shape + ] + array.lower_bounds = [ + None if dim is None else _resolve_compile_time_text(dim, compile_time_values) + for dim in array.lower_bounds + ] + array.upper_bounds = [ + None if dim is None else _resolve_compile_time_text(dim, compile_time_values) + for dim in array.upper_bounds + ] + array.metadata = _resolve_semantic_value(array.metadata, compile_time_values) def _resolve_semantic_argument_compile_time_values( diff --git a/semantics/models.py b/semantics/models.py index bcf3d0dec..4084b492d 100644 --- a/semantics/models.py +++ b/semantics/models.py @@ -39,10 +39,54 @@ class OwnershipPolicy: # ============================================================ -# Semantic Types +# Origin And Storage Contracts # ============================================================ @dataclass +class SemanticOrigin: + source_language: Optional[str] = None + native_name: Optional[str] = None + native_scope: Optional[str] = None + source_kind: Optional[str] = None + source_type: Optional[str] = None + source_location: dict[str, Any] = field(default_factory=dict) + metadata: dict[str, Any] = field(default_factory=dict) + + +@dataclass +class SemanticArrayContract: + rank: Optional[int] = None + shape: list[str] = field(default_factory=list) + # Native-source provenance, excluded from public contract equality. + lower_bounds: list[Optional[str]] = field(default_factory=list) + upper_bounds: list[Optional[str]] = field(default_factory=list) + source_shape: list[str] = field(default_factory=list) + category: Optional[str] = None + order: Optional[str] = None + axes: list[str] = field(default_factory=list) + contiguous: Optional[bool] = None + allocatable: bool = False + pointer: bool = False + metadata: dict[str, Any] = field(default_factory=dict) + + +@dataclass +class SemanticStorageContract: + kind: str = "value" + read_only: bool = False + mutable: bool = False + pointer_depth: int = 0 + ownership: str = "borrowed" + array: Optional[SemanticArrayContract] = None + calling_convention: Optional[str] = None + metadata: dict[str, Any] = field(default_factory=dict) + + +# ============================================================ +# Semantic Types +# ============================================================ + +@dataclass(eq=False) class SemanticType: name: str @@ -60,6 +104,15 @@ class SemanticType: metadata: dict[str, Any] = field(default_factory=dict) + storage: Optional[SemanticStorageContract] = None + + origin: SemanticOrigin = field(default_factory=SemanticOrigin, compare=False) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SemanticType): + return False + return _semantic_type_key(self, {}) == _semantic_type_key(other, {}) + # ============================================================ # Semantic Arguments @@ -80,6 +133,8 @@ class SemanticArgument: metadata: dict[str, Any] = field(default_factory=dict) + origin: SemanticOrigin = field(default_factory=SemanticOrigin, compare=False) + # ============================================================ # Semantic Contracts @@ -132,6 +187,7 @@ class SemanticFunction: metadata: dict[str, Any] = field(default_factory=dict) visibility: str = "public" + origin: SemanticOrigin = field(default_factory=SemanticOrigin, compare=False) def __eq__(self, other: object) -> bool: if type(self) is not type(other): @@ -176,7 +232,7 @@ class SemanticMethod(SemanticFunction): def _call_arguments(func: SemanticFunction) -> list[SemanticArgument]: - return [arg for arg in func.arguments if getattr(arg, "intent", "in") != "out"] + return list(func.arguments) def _argument_name_map(arguments: list[SemanticArgument]) -> dict[str, str]: @@ -212,15 +268,77 @@ def _semantic_type_key( ) -> tuple[Any, ...] | None: if semantic_type is None: return None + shape = ( + semantic_type.storage.array.shape + if semantic_type.storage is not None and semantic_type.storage.array is not None + else semantic_type.shape + ) return ( semantic_type.name, semantic_type.rank, semantic_type.dtype, - tuple(_canonical_expression(item, name_map) for item in semantic_type.shape), - tuple(_constraint_key(c, name_map) for c in semantic_type.constraints), + tuple(_canonical_expression(item, name_map) for item in shape), + tuple( + _constraint_key(c, name_map) + for c in _semantic_contract_constraints(semantic_type) + ), tuple(semantic_type.coercions), semantic_type.ownership if include_ownership else None, semantic_type.metadata, + _storage_contract_key(semantic_type.storage, name_map), + ) + + +def _semantic_contract_constraints(semantic_type: SemanticType) -> list[SemanticConstraint]: + if semantic_type.storage is None: + return semantic_type.constraints + storage_constraint_names = { + "Allocatable", + "ORDER_ANY", + "ORDER_C", + "ORDER_F", + "Pointer", + } + return [ + constraint + for constraint in semantic_type.constraints + if constraint.name not in storage_constraint_names + ] + + +def _storage_contract_key( + storage: SemanticStorageContract | None, + name_map: dict[str, str], +) -> tuple[Any, ...] | None: + if storage is None: + return None + return ( + storage.kind, + storage.read_only, + storage.mutable, + storage.pointer_depth, + storage.ownership, + _array_contract_key(storage.array, name_map), + storage.calling_convention, + _canonical_expression(storage.metadata, name_map), + ) + + +def _array_contract_key( + array: SemanticArrayContract | None, + name_map: dict[str, str], +) -> tuple[Any, ...] | None: + if array is None: + return None + return ( + array.rank, + tuple(_canonical_expression(item, name_map) for item in array.shape), + array.order, + tuple(array.axes), + array.contiguous, + array.allocatable, + array.pointer, + _canonical_expression(array.metadata, name_map), ) @@ -231,11 +349,6 @@ def _return_projection_key( returns: list[tuple[Any, ...]] = [] if func.return_type is not None: returns.append((_semantic_type_key(func.return_type, name_map, include_ownership=False),)) - returns.extend( - (_semantic_type_key(arg.semantic_type, name_map, include_ownership=False),) - for arg in func.arguments - if getattr(arg, "intent", "in") in {"out", "inout"} - ) return tuple(returns) @@ -338,6 +451,7 @@ class SemanticClass: metadata: dict[str, Any] = field(default_factory=dict) visibility: str = "public" + origin: SemanticOrigin = field(default_factory=SemanticOrigin, compare=False) # ============================================================ @@ -368,3 +482,5 @@ class SemanticModule: imports: list[str | SemanticImport] = field(default_factory=list) metadata: dict[str, Any] = field(default_factory=dict) + + origin: SemanticOrigin = field(default_factory=SemanticOrigin, compare=False) diff --git a/semantics/pyi_parser.py b/semantics/pyi_parser.py index d39ddd7c0..b4d00b70d 100644 --- a/semantics/pyi_parser.py +++ b/semantics/pyi_parser.py @@ -7,6 +7,7 @@ from .models import ( ProjectionMapping, SemanticArgument, + SemanticArrayContract, SemanticClass, SemanticConstraint, SemanticFunction, @@ -14,6 +15,7 @@ SemanticImportItem, SemanticMethod, SemanticModule, + SemanticStorageContract, SemanticType, ) @@ -122,11 +124,14 @@ def ann_assign(self, node: ast.AnnAssign, *, default_intent: str) -> SemanticArg visibility, semantic_type, original_name = self.visible_type(node.annotation) if original_name is not None: name = original_name - semantic_type.ownership.mutable = default_intent.lower() != "in" + intent = self._pop_intent_metadata(semantic_type, default_intent) + semantic_type.ownership.mutable = intent.lower() != "in" + if semantic_type.storage is not None: + semantic_type.storage.mutable = intent.lower() != "in" return SemanticArgument( name=name, semantic_type=semantic_type, - intent=default_intent, + intent=intent, optional=self.default_marks_optional(node.value), visibility=visibility, default_value=self.literal_default_value(node.value), @@ -157,6 +162,9 @@ def native_call(self, node: ast.Call) -> list[ProjectionMapping]: ] def native_projection_entry(self, node: ast.AST, native_position: int) -> ProjectionMapping: + shape_mapping = self.native_shape_projection_entry(node, native_position) + if shape_mapping is not None: + return shape_mapping if not isinstance(node, ast.Call): raise ValueError("native_call expects projection entry calls") if node.keywords: @@ -194,14 +202,6 @@ def native_projection_entry(self, node: ast.AST, native_position: int) -> Projec value_kind="len", value=self.native_value_ref(node.args[0]), ) - if helper == "Shape": - if len(node.args) != 2: - raise ValueError("Shape expects a value reference and dimension") - return ProjectionMapping( - native_position=native_position, - value_kind="shape", - value={"value": self.native_value_ref(node.args[0]), "dim": int(ast.literal_eval(node.args[1]))}, - ) if helper == "IsPresent": if len(node.args) != 1: raise ValueError("IsPresent expects one value reference") @@ -221,6 +221,25 @@ def native_projection_entry(self, node: ast.AST, native_position: int) -> Projec raise ValueError(f"Unsupported native_call projection entry: {helper}") + def native_shape_projection_entry( + self, + node: ast.AST, + native_position: int, + ) -> ProjectionMapping | None: + if not isinstance(node, ast.Subscript) or not isinstance(node.value, ast.Attribute): + return None + attribute = node.value.attr + if attribute != "shape": + return None + return ProjectionMapping( + native_position=native_position, + value_kind="shape", + value={ + "value": self.native_value_ref(node.value.value), + "dim": int(ast.literal_eval(node.slice)), + }, + ) + def native_value_ref(self, node: ast.AST) -> dict[str, int | str]: if not isinstance(node, ast.Call): raise ValueError("Expected Arg(...), Return(...), or Work(...) value reference") @@ -251,11 +270,14 @@ def semantic_type_annotation(self, node: ast.expr) -> tuple[SemanticType, str | raise ValueError(f"Annotated type is empty: {ast.unparse(node)!r}") original_name = None + semantic_type = self.semantic_type(items[0]) for item in items[1:]: parsed_name = self.name_metadata(item) if parsed_name is not None: original_name = parsed_name - return self.semantic_type(items[0]), original_name + continue + self.apply_annotation_metadata(semantic_type, item) + return semantic_type, original_name def semantic_type(self, node: ast.expr) -> SemanticType: if self.is_subscript_of(node, "Annotated"): @@ -271,6 +293,26 @@ def semantic_type(self, node: ast.expr) -> SemanticType: return semantic_type if self.matches_name(node, "Callable") or self.is_subscript_of(node, "Callable"): return self.callable_type(node) + if isinstance(node, ast.Call) and self.matches_name(node.func, "Const"): + if len(node.args) != 1 or node.keywords: + raise ValueError(f"Const type expects one argument: {ast.unparse(node)!r}") + semantic_type = self.semantic_type(node.args[0]) + self._mark_storage_read_only(semantic_type) + return semantic_type + if isinstance(node, ast.Call) and self._is_ptr_call(node): + if len(node.args) != 1 or node.keywords: + raise ValueError(f"Ptr type expects one argument: {ast.unparse(node)!r}") + pointer_depth = self._ptr_depth(node.func) + pointee = self.semantic_type(node.args[0]) + read_only = pointee.storage.read_only if pointee.storage is not None else False + pointee.storage = SemanticStorageContract( + kind="reference" if pointer_depth == 1 else "pointer", + read_only=read_only, + mutable=not read_only, + pointer_depth=pointer_depth, + ) + pointee.ownership.mutable = not read_only + return pointee name = self.type_name(node) if name == "Unknown": @@ -278,24 +320,229 @@ def semantic_type(self, node: ast.expr) -> SemanticType: if not isinstance(node, ast.Subscript): return SemanticType(name=name, dtype=name) + if self._is_array_subscript(node): + return self.array_type(node) + constraints = [self.constraint(item) for item in self.subscript_items(node)] - shape = [] - for constraint in constraints: - if constraint.name == "Shape": - shape = [str(arg) for arg in constraint.arguments] - break return SemanticType( name=name, - rank=len(shape), + rank=0, dtype=name, - shape=shape, + shape=[], constraints=constraints, ) + def array_type(self, node: ast.Subscript) -> SemanticType: + if isinstance(node.value, ast.Subscript): + semantic_type = self.array_type(node.value) + selector = ", ".join(self.dimension_text(item) for item in self.subscript_items(node)) + semantic_type.metadata["rank_selector"] = selector + if semantic_type.storage and semantic_type.storage.array: + semantic_type.storage.array.metadata["rank_selector"] = selector + return semantic_type + + name = self.type_name(node) + dims = [self.dimension_text(item) for item in self.subscript_items(node)] + rank = None if "..." in dims else len(dims) + array = SemanticArrayContract( + rank=rank, + shape=list(dims), + order="ORDER_C" if rank is not None and rank > 1 else None, + axes=["strided" if "Strided" in dim else "dense" for dim in dims], + contiguous=False if any("Strided" in dim for dim in dims) else True, + ) + storage = SemanticStorageContract(kind="array", array=array) + return SemanticType( + name=name, + rank=rank or 0, + dtype=name, + shape=list(dims) if rank is not None else [], + constraints=[], + storage=storage, + ) + + def apply_annotation_metadata(self, semantic_type: SemanticType, node: ast.expr) -> None: + if isinstance(node, ast.Name): + self._apply_metadata_name(semantic_type, node.id) + return + if isinstance(node, ast.Call): + helper = self.required_name(node.func) + if helper == "Intent": + if len(node.args) != 1: + raise ValueError(f"Intent metadata expects one argument: {ast.unparse(node)!r}") + semantic_type.metadata["_pyi_intent"] = str(ast.literal_eval(node.args[0])) + return + if helper == "ArrayCategory": + self._require_array_storage(semantic_type).category = str(ast.literal_eval(node.args[0])) + return + if helper == "SourceDims": + values = [str(ast.literal_eval(arg)) for arg in node.args] + array = self._require_array_storage(semantic_type) + array.source_shape = values + array.lower_bounds, array.upper_bounds = self._bounds_from_source_shape(values) + return + if helper == "SourceShape": + raise ValueError("SourceShape metadata is not supported; use SourceDims") + if helper == "LowerBounds": + self._require_array_storage(semantic_type).lower_bounds = [ + None if isinstance(arg, ast.Constant) and arg.value is None else str(ast.literal_eval(arg)) + for arg in node.args + ] + return + if helper == "UpperBounds": + self._require_array_storage(semantic_type).upper_bounds = [ + None if isinstance(arg, ast.Constant) and arg.value is None else str(ast.literal_eval(arg)) + for arg in node.args + ] + return + return + + def _apply_metadata_name(self, semantic_type: SemanticType, name: str) -> None: + if name in {"ORDER_C", "ORDER_F", "ORDER_ANY"}: + array = self._require_array_storage(semantic_type) + array.order = name + return + if name == "Allocatable": + array = self._require_array_storage(semantic_type) + array.allocatable = True + return + if name == "Pointer": + array = self._require_array_storage(semantic_type) + array.pointer = True + return + if name == "Contiguous": + self._require_array_storage(semantic_type).contiguous = True + + @staticmethod + def _replace_constraint(semantic_type: SemanticType, name: str) -> None: + semantic_type.constraints = [ + constraint for constraint in semantic_type.constraints if constraint.name != name + ] + semantic_type.constraints.append(SemanticConstraint(name)) + + @staticmethod + def _require_array_storage(semantic_type: SemanticType) -> SemanticArrayContract: + if semantic_type.storage is None: + semantic_type.storage = SemanticStorageContract(kind="array") + if semantic_type.storage.array is None: + semantic_type.storage.array = SemanticArrayContract( + rank=semantic_type.rank, + shape=list(semantic_type.shape), + ) + return semantic_type.storage.array + + @staticmethod + def _bounds_from_source_shape(shape: list[str]) -> tuple[list[str | None], list[str | None]]: + lower_bounds: list[str | None] = [] + upper_bounds: list[str | None] = [] + for dim in shape: + token = str(dim).strip() + if ":" in token: + lower, upper = token.split(":", 1) + lower_text = lower.strip() or None + lower_bounds.append(None if lower_text == "1" else lower_text) + upper_bounds.append(upper.strip() or None) + elif token == "*": + lower_bounds.append(None) + upper_bounds.append("*") + else: + lower_bounds.append(None) + upper_bounds.append(None) + return lower_bounds, upper_bounds + + @staticmethod + def _mark_storage_read_only(semantic_type: SemanticType) -> None: + if semantic_type.storage is None: + semantic_type.storage = SemanticStorageContract(kind="value") + semantic_type.storage.read_only = True + semantic_type.storage.mutable = False + semantic_type.ownership.mutable = False + + @staticmethod + def _inferred_argument_intent(semantic_type: SemanticType) -> str: + storage = semantic_type.storage + if storage is None: + return "in" + if storage.kind in {"reference", "array", "pointer"} and not storage.read_only: + return "inout" + return "in" + + @staticmethod + def _pop_intent_metadata(semantic_type: SemanticType, default: str) -> str: + value = semantic_type.metadata.pop("_pyi_intent", None) + return str(value).lower() if value is not None else default + + @staticmethod + def _is_ptr_call(node: ast.Call) -> bool: + return _PyiAstParser.matches_name(node.func, "Ptr") or ( + isinstance(node.func, ast.Subscript) + and _PyiAstParser.matches_name(node.func.value, "Ptr") + ) + + @staticmethod + def _ptr_depth(node: ast.AST) -> int: + if isinstance(node, ast.Subscript): + depth = int(ast.literal_eval(node.slice)) + if depth <= 1: + raise ValueError("Ptr[1](...) is invalid; use Ptr(...)") + return depth + return 1 + + def _is_array_subscript(self, node: ast.Subscript) -> bool: + if isinstance(node.value, ast.Subscript): + return self._is_array_subscript(node.value) + items = self.subscript_items(node) + if not items: + return False + if any(isinstance(item, (ast.Slice, ast.Constant)) for item in items): + return True + if any(isinstance(item, ast.Name) and item.id not in self._legacy_constraint_names() for item in items): + return True + if any(isinstance(item, ast.Call) and self.required_name(item.func) not in self._legacy_constraint_names() for item in items): + return True + if any(isinstance(item, (ast.BinOp, ast.UnaryOp)) for item in items): + return True + return False + + @staticmethod + def _legacy_constraint_names() -> set[str]: + return { + "Allocatable", + "Constant", + "Optional", + "ORDER_ANY", + "ORDER_C", + "ORDER_F", + "Pointer", + } + + def dimension_text(self, node: ast.expr) -> str: + if isinstance(node, ast.Constant) and node.value is Ellipsis: + return "..." + if isinstance(node, ast.Slice): + return self.slice_text(node) + if isinstance(node, ast.Constant): + return str(node.value) + if isinstance(node, ast.Call) and self.required_name(node.func) == "Shape": + raise ValueError("Shape dimensions are not supported; use T[n, m] array subscriptions") + return ast.unparse(node) + + def slice_text(self, node: ast.Slice) -> str: + lower = "" if node.lower is None else ast.unparse(node.lower) + upper = "" if node.upper is None else ast.unparse(node.upper) + step = "" if node.step is None else ast.unparse(node.step) + if step: + return f"{lower}:{upper}:{step}" + return f"{lower}:{upper}" + def constraint(self, node: ast.expr) -> SemanticConstraint: if isinstance(node, ast.Name): + if node.id == "Shape": + raise ValueError("Shape constraints are not supported; use T[n, m] array subscriptions") return SemanticConstraint(node.id) if isinstance(node, ast.Call): + if self.required_name(node.func) == "Shape": + raise ValueError("Shape constraints are not supported; use T[n, m] array subscriptions") return SemanticConstraint( name=self.required_name(node.func), arguments=[ast.literal_eval(arg) for arg in node.args], @@ -478,11 +725,14 @@ def _callable_argument(self, arg: ast.arg, default: ast.expr | None) -> Semantic if arg.annotation is None: raise ValueError(f"Expected typed argument: {arg.arg!r}") visibility, semantic_type, original_name = self.visible_type(arg.annotation) - semantic_type.ownership.mutable = False + intent = self._pop_intent_metadata(semantic_type, self._inferred_argument_intent(semantic_type)) + semantic_type.ownership.mutable = intent.lower() != "in" + if semantic_type.storage is not None: + semantic_type.storage.mutable = intent.lower() != "in" return SemanticArgument( name=original_name or arg.arg, semantic_type=semantic_type, - intent="in", + intent=intent, optional=self.default_marks_optional(default), visibility=visibility, ) diff --git a/semantics/pyi_printer.py b/semantics/pyi_printer.py index 6d9d48cb8..51a719fc7 100644 --- a/semantics/pyi_printer.py +++ b/semantics/pyi_printer.py @@ -4,7 +4,9 @@ import re from .models import ( + ProjectionMapping, SemanticArgument, + SemanticArrayContract, SemanticClass, SemanticConstraint, SemanticFunction, @@ -13,7 +15,6 @@ SemanticMethod, SemanticModule, SemanticType, - ProjectionMapping, ) @@ -42,6 +43,8 @@ def emit(self, node) -> str: raise TypeError(f"Unsupported semantic model for .pyi emission: {type(node)!r}") def emit_constraint(self, constraint: SemanticConstraint) -> str: + if constraint.name == "Shape": + raise ValueError("Shape constraints are not supported; use T[n, m] array subscriptions") if not constraint.arguments: return constraint.name args = ", ".join(map(repr, constraint.arguments)) @@ -52,12 +55,69 @@ def emit_semantic_type(self, semantic_type: SemanticType) -> str: raise ValueError("Cannot emit .pyi with unresolved semantic type 'Unknown'") if semantic_type.name == "Callable": return self._emit_callable_type(semantic_type) + if semantic_type.storage is not None: + return self._emit_storage_type(semantic_type) text = semantic_type.name annotations = [self.emit_constraint(c) for c in semantic_type.constraints] if annotations: text += "[" + ", ".join(annotations) + "]" return text + def _emit_storage_type(self, semantic_type: SemanticType) -> str: + storage = semantic_type.storage + if storage is None: + return semantic_type.name + if storage.kind == "value": + if storage.read_only: + return f"Const({semantic_type.name})" + return semantic_type.name + if storage.kind in {"reference", "pointer"}: + target = semantic_type.name + if storage.read_only: + target = f"Const({target})" + if storage.pointer_depth > 1: + return f"Ptr[{storage.pointer_depth}]({target})" + return f"Ptr({target})" + if storage.kind == "array": + return self._emit_array_type(semantic_type) + return semantic_type.name + + def _emit_array_type(self, semantic_type: SemanticType) -> str: + storage = semantic_type.storage + array = storage.array if storage is not None else None + dimensions = self._array_dimensions(semantic_type, array) + base = f"{semantic_type.name}[{', '.join(dimensions)}]" + if storage is not None and storage.read_only: + base = f"Const({base})" + + metadata = self._array_annotation_metadata(array) + if metadata: + return f"Annotated[{base}, {', '.join(metadata)}]" + return base + + @staticmethod + def _array_dimensions( + semantic_type: SemanticType, + array: SemanticArrayContract | None, + ) -> list[str]: + shape = list(array.shape if array is not None and array.shape else semantic_type.shape) + if not shape and semantic_type.rank > 0: + shape = [":" for _ in range(semantic_type.rank)] + return [str(dim) for dim in shape] + + @staticmethod + def _array_annotation_metadata(array: SemanticArrayContract | None) -> list[str]: + if array is None: + return [] + metadata: list[str] = [] + if array.order in {"ORDER_F", "ORDER_ANY"}: + metadata.append(array.order) + if array.allocatable: + metadata.append("Allocatable") + if array.pointer: + metadata.append("Pointer") + return metadata + def _emit_callable_type(self, semantic_type: SemanticType) -> str: arguments = semantic_type.metadata.get("arguments") return_type = semantic_type.metadata.get("return") @@ -88,8 +148,13 @@ def _emit_typed_name( ) -> str: semantic_type = self._without_constant_constraint(arg.semantic_type) type_text = self.emit_semantic_type(semantic_type) + annotation_metadata = [] if original_name is not None: - type_text = f'Annotated[{type_text}, Name("{original_name}")]' + annotation_metadata.append(f'Name("{original_name}")') + if self._requires_intent_metadata(arg): + annotation_metadata.append(f"Intent({arg.intent!r})") + if annotation_metadata: + type_text = self._annotated_type_text(type_text, annotation_metadata) if self._is_constant(arg.semantic_type): type_text = f"Final[{type_text}]" if getattr(arg, "visibility", "public") == "private": @@ -100,6 +165,13 @@ def _emit_typed_name( text += " = ..." return text + @staticmethod + def _annotated_type_text(type_text: str, metadata: list[str]) -> str: + suffix = ", ".join(metadata) + if type_text.startswith("Annotated[") and type_text.endswith("]"): + return f"{type_text[:-1]}, {suffix}]" + return f"Annotated[{type_text}, {suffix}]" + @staticmethod def _is_constant(semantic_type: SemanticType) -> bool: return any(constraint.name == "Constant" for constraint in semantic_type.constraints) @@ -121,6 +193,8 @@ def _without_constant_constraint(semantic_type: SemanticType) -> SemanticType: coercions=list(semantic_type.coercions), ownership=semantic_type.ownership, metadata=dict(semantic_type.metadata), + storage=semantic_type.storage, + origin=semantic_type.origin, ) def emit_function(self, func: SemanticFunction) -> str: @@ -231,25 +305,9 @@ def _append_items(self, sections: list[str], items: list, emit_item) -> None: sections.append("") def _projected_return_annotation(self, func: SemanticFunction) -> str: - returns = [] if func.return_type: - returns.append(self.emit_semantic_type(func.return_type)) - - returned_args = [ - arg - for arg in func.arguments - if getattr(arg, "intent", "in") in {"out", "inout"} - ] - returns.extend( - self._projected_argument_return(arg) - for arg in returned_args - ) - - if not returns: - return "None" - if len(returns) == 1: - return returns[0] - return "tuple[" + ", ".join(returns) + "]" + return self.emit_semantic_type(func.return_type) + return "None" def _projected_argument_return(self, arg: SemanticArgument) -> str: if self._requires_named_return(arg): @@ -297,7 +355,7 @@ def _native_projection_value(mapping: ProjectionMapping) -> str: if mapping.value_kind == "len": return f"Len({PyiPrinter._native_value_ref(mapping.value)})" if mapping.value_kind == "shape": - return f"Shape({PyiPrinter._native_value_ref(mapping.value['value'])}, {mapping.value['dim']})" + return f"{PyiPrinter._native_value_ref(mapping.value['value'])}.shape[{mapping.value['dim']}]" if mapping.value_kind == "is_present": return f"IsPresent({PyiPrinter._native_value_ref(mapping.value)})" if mapping.value_kind == "work": @@ -333,11 +391,11 @@ def _requires_explicit_projection_mapping(mapping: ProjectionMapping) -> bool: @staticmethod def _call_arguments(func: SemanticFunction) -> list[SemanticArgument]: - return [ - arg - for arg in func.arguments - if getattr(arg, "intent", "in") != "out" - ] + return list(func.arguments) + + @staticmethod + def _requires_intent_metadata(arg: SemanticArgument) -> bool: + return getattr(arg, "intent", "in") == "out" @classmethod def _method_call_arguments(cls, method: SemanticMethod) -> list[SemanticArgument]: diff --git a/semantics/readiness.py b/semantics/readiness.py index 8cd3decad..5c2d5fb64 100644 --- a/semantics/readiness.py +++ b/semantics/readiness.py @@ -510,9 +510,9 @@ def _is_constant(semantic_type: SemanticType) -> bool: def _shape_expressions(semantic_type: SemanticType) -> list[str]: expressions = list(semantic_type.shape) - for constraint in semantic_type.constraints: - if constraint.name == "Shape": - expressions.extend(str(value) for value in _iter_expression_values(constraint.arguments)) + storage = semantic_type.storage + if storage is not None and storage.array is not None: + expressions.extend(storage.array.shape) return expressions diff --git a/tests/parser/test_cli.py b/tests/parser/test_cli.py index bcb44d92a..8e21fa4f4 100644 --- a/tests/parser/test_cli.py +++ b/tests/parser/test_cli.py @@ -355,7 +355,9 @@ def test_cli_pyi_out_writes_explicit_file_from_inline_code(tmp_path: Path): assert res.stdout == "" assert out.exists() text = out.read_text(encoding="utf-8") - assert "def set_value() -> Float64: ..." in text + assert "def set_value(" in text + assert "x: Annotated[Ptr(Float64), Intent('out')]" in text + assert "-> None: ..." in text def test_cli_rejects_conflicting_json_and_pyi_out_from_inline_code(tmp_path: Path): @@ -476,7 +478,8 @@ def test_fortran_parser_cli_semantics_pyi_and_empty_module_report_from_inline_co pyi_cmd = [sys.executable, "-m", "fortran_parser", str(module_source), "--pyi"] pyi_res = subprocess.run(pyi_cmd, capture_output=True, text=True, check=True) - assert "@native_call([Arg(0), Return(0), Arg(1)])" in pyi_res.stdout + assert "@native_call" not in pyi_res.stdout + assert "x: Annotated[Ptr(Float64), Intent('out')]" in pyi_res.stdout assert "def solve(" in pyi_res.stdout empty_pyi_cmd = [sys.executable, "-m", "fortran_parser", str(program_source), "--pyi"] diff --git a/tests/pyi/fixtures/general/basic_subroutine.pyi b/tests/pyi/fixtures/general/basic_subroutine.pyi index 18c322cc0..a37cfed1f 100644 --- a/tests/pyi/fixtures/general/basic_subroutine.pyi +++ b/tests/pyi/fixtures/general/basic_subroutine.pyi @@ -1,4 +1,4 @@ def add1( - n: Int32, - x: Float64[Shape('n'), ORDER_F] -) -> Returns["x", Float64[Shape('n'), ORDER_F]]: ... + n: Ptr(Const(Int32)), + x: Float64[n] +) -> None: ... diff --git a/tests/pyi/fixtures/general/compile_time_all_exprs.pyi b/tests/pyi/fixtures/general/compile_time_all_exprs.pyi index 749a4c623..1a5850e8d 100644 --- a/tests/pyi/fixtures/general/compile_time_all_exprs.pyi +++ b/tests/pyi/fixtures/general/compile_time_all_exprs.pyi @@ -17,13 +17,13 @@ p_pow: Final[Int32] p_mix: Final[Int32] def all_exprs( - x1: Int32[Shape('1:p_add'), ORDER_F], - x2: Int32[Shape('1:p_sub'), ORDER_F], - x3: Int32[Shape('1:p_mul'), ORDER_F], - x4: Int32[Shape('1:p_div'), ORDER_F], - x5: Int32[Shape('1:p_pow'), ORDER_F], - x6: Int32[Shape('0:p_mix'), ORDER_F], - x7: Int32[Shape('1:-(-a + b)'), ORDER_F], - x8: Int32[Shape('1:(a+b)*(c+1)-1'), ORDER_F], - x9: Int32[Shape('1:(a-b)*(a-c)'), ORDER_F] -) -> tuple[Returns["x1", Int32[Shape('1:p_add'), ORDER_F]], Returns["x2", Int32[Shape('1:p_sub'), ORDER_F]], Returns["x3", Int32[Shape('1:p_mul'), ORDER_F]], Returns["x4", Int32[Shape('1:p_div'), ORDER_F]], Returns["x5", Int32[Shape('1:p_pow'), ORDER_F]], Returns["x6", Int32[Shape('0:p_mix'), ORDER_F]], Returns["x7", Int32[Shape('1:-(-a + b)'), ORDER_F]], Returns["x8", Int32[Shape('1:(a+b)*(c+1)-1'), ORDER_F]], Returns["x9", Int32[Shape('1:(a-b)*(a-c)'), ORDER_F]]]: ... + x1: Int32[p_add], + x2: Int32[p_sub], + x3: Int32[p_mul], + x4: Int32[p_div], + x5: Int32[p_pow], + x6: Int32[p_mix - 0 + 1], + x7: Int32[-(-a + b)], + x8: Int32[(a + b) * (c + 1) - 1], + x9: Int32[(a - b) * (a - c)] +) -> None: ... diff --git a/tests/pyi/fixtures/general/compile_time_shape_exprs.pyi b/tests/pyi/fixtures/general/compile_time_shape_exprs.pyi index e1bddb7dc..ab2e8eecc 100644 --- a/tests/pyi/fixtures/general/compile_time_shape_exprs.pyi +++ b/tests/pyi/fixtures/general/compile_time_shape_exprs.pyi @@ -3,6 +3,6 @@ n0: Final[Int32] n1: Final[Int32] def use_expr( - x: Int32[Shape('0:n1-1'), ORDER_F], - y: Float64[Shape('1:n0*2'), ORDER_F] -) -> tuple[Returns["x", Int32[Shape('0:n1-1'), ORDER_F]], Returns["y", Float64[Shape('1:n0*2'), ORDER_F]]]: ... + x: Int32[n1 - 1 - 0 + 1], + y: Float64[n0 * 2] +) -> None: ... diff --git a/tests/pyi/fixtures/general/derived_type.pyi b/tests/pyi/fixtures/general/derived_type.pyi index 8825f8344..52485c8cb 100644 --- a/tests/pyi/fixtures/general/derived_type.pyi +++ b/tests/pyi/fixtures/general/derived_type.pyi @@ -1,7 +1,7 @@ class particle: id: Int32 - x: Float64[Shape('3'), ORDER_F] + x: Float64[3] def touch( - p: particle -) -> Returns["p", particle]: ... + p: Ptr(particle) +) -> None: ... diff --git a/tests/pyi/fixtures/general/derived_types_and_methods.pyi b/tests/pyi/fixtures/general/derived_types_and_methods.pyi index 03595dc50..681759c30 100644 --- a/tests/pyi/fixtures/general/derived_types_and_methods.pyi +++ b/tests/pyi/fixtures/general/derived_types_and_methods.pyi @@ -1,7 +1,7 @@ class node: id: Int32 - xyz: Float64[Shape('3'), ORDER_F] + xyz: Float64[3] class mesh: nnodes: Int32 - nodes: node[Shape(':'), ORDER_F, Allocatable] + nodes: Annotated[node[:], Allocatable] diff --git a/tests/pyi/fixtures/general/modern_pyi_example.pyi b/tests/pyi/fixtures/general/modern_pyi_example.pyi index 61cceecc4..15f1b229e 100644 --- a/tests/pyi/fixtures/general/modern_pyi_example.pyi +++ b/tests/pyi/fixtures/general/modern_pyi_example.pyi @@ -1,10 +1,10 @@ class particle: id: Int32 mass: Float64 - position: Float64[Shape('3'), ORDER_F] + position: Float64[3] class vector3: - values: Float64[Shape('3'), ORDER_F] + values: Float64[3] @private class hidden_state: @@ -14,40 +14,41 @@ counter: Int32 hidden_scale: private[Float64] -@native_call([Return(0), Arg(0), Arg(1), Arg(2), Arg(3), Arg(4)]) def init_particle( - pid: Int32, - mass: Float64, - x: Float64, - y: Float64, - z: Float64 -) -> particle: ... + p: Annotated[Ptr(particle), Intent('out')], + pid: Ptr(Const(Int32)), + mass: Ptr(Const(Float64)), + x: Ptr(Const(Float64)), + y: Ptr(Const(Float64)), + z: Ptr(Const(Float64)) +) -> None: ... def kinetic_energy( - p: particle, - vx: Float64, - vy: Float64, - vz: Float64 + p: Ptr(Const(particle)), + vx: Ptr(Const(Float64)), + vy: Ptr(Const(Float64)), + vz: Ptr(Const(Float64)) ) -> Float64: ... def scale_vector( - v: Float64[Shape(':'), ORDER_F], - alpha: Float64 -) -> Returns["v", Float64[Shape(':'), ORDER_F]]: ... + v: Float64[::Strided], + alpha: Ptr(Const(Float64)) +) -> None: ... def dot3( - a: Float64[Shape('3'), ORDER_F], - b: Float64[Shape('3'), ORDER_F] + a: Const(Float64[3]), + b: Const(Float64[3]) ) -> Float64: ... -@native_call([Return(0)]) -def fill_identity3() -> Float64[Shape('3', '3'), ORDER_F]: ... +def fill_identity3( + a: Annotated[Float64[3, 3], ORDER_F, Intent('out')] +) -> None: ... def normalize_particle( - p: particle -) -> Returns["p", particle]: ... + p: Ptr(particle) +) -> None: ... @private def hidden_proc( - x: Int32 + x: Ptr(Const(Int32)) ) -> None: ... diff --git a/tests/pyi/fixtures/general/module_vars_use.pyi b/tests/pyi/fixtures/general/module_vars_use.pyi index f734a6ef0..913182f20 100644 --- a/tests/pyi/fixtures/general/module_vars_use.pyi +++ b/tests/pyi/fixtures/general/module_vars_use.pyi @@ -2,4 +2,4 @@ from iso_c_binding import c_int, c_double nmax: Final[Int32] -origin: Float64[Shape('3'), ORDER_F] +origin: Float64[3] diff --git a/tests/pyi/fixtures/general/procedures_and_functions.pyi b/tests/pyi/fixtures/general/procedures_and_functions.pyi index cadc8448b..0649f11ba 100644 --- a/tests/pyi/fixtures/general/procedures_and_functions.pyi +++ b/tests/pyi/fixtures/general/procedures_and_functions.pyi @@ -1,8 +1,8 @@ def norm2( - x: Float64[Shape(':'), ORDER_F] + x: Const(Float64[::Strided]) ) -> Float64: ... def scale( - a: Float64, - x: Float64[Shape(':'), ORDER_F] -) -> Returns["x", Float64[Shape(':'), ORDER_F]]: ... + a: Ptr(Const(Float64)), + x: Float64[::Strided] +) -> None: ... diff --git a/tests/pyi/fixtures/general/scope_name_reuse_combinations.pyi b/tests/pyi/fixtures/general/scope_name_reuse_combinations.pyi index e9eb07ce4..37c4da2a3 100644 --- a/tests/pyi/fixtures/general/scope_name_reuse_combinations.pyi +++ b/tests/pyi/fixtures/general/scope_name_reuse_combinations.pyi @@ -12,33 +12,33 @@ same_name_c: Complex128 same_name_s: String def do_work_i( - same_name: Int32 -) -> Returns["same_name", Int32]: ... + same_name: Ptr(Int32) +) -> None: ... def do_work_r( - same_name: Float64 + same_name: Ptr(Const(Float64)) ) -> None: ... def do_work_l( - same_name: Bool + same_name: Ptr(Const(Bool)) ) -> None: ... def host_one( - same_name: Int32 -) -> Returns["same_name", Int32]: ... + same_name: Ptr(Int32) +) -> None: ... def host_two( - same_name: Float64 -) -> Returns["same_name", Float64]: ... + same_name: Ptr(Float64) +) -> None: ... def convert_to_complex( - same_name: Int32 + same_name: Ptr(Const(Int32)) ) -> Complex128: ... def convert_to_char( - same_name: Float64 + same_name: Ptr(Const(Float64)) ) -> String: ... def convert_to_logical( - same_name: String + same_name: Ptr(Const(String)) ) -> Bool: ... diff --git a/tests/pyi/test_pyi_to_ir.py b/tests/pyi/test_pyi_to_ir.py index 6e4be7d43..6e087b412 100644 --- a/tests/pyi/test_pyi_to_ir.py +++ b/tests/pyi/test_pyi_to_ir.py @@ -206,7 +206,7 @@ def test_parse_pyi_text_accepts_qualified_ast_wrapper_names(): """ import typing -alias: typing.Annotated[Float64[typing.Shape("1:n")], typing.Name("native_alias")] +alias: typing.Annotated[Float64[1:n], typing.Name("native_alias")] def f() -> typing.Tuple[Float64, typing.Returns["y", Float64]]: ... """, @@ -224,7 +224,7 @@ def f() -> typing.Tuple[Float64, typing.Returns["y", Float64]]: ... def test_parse_pyi_text_accepts_ast_only_projection_value_refs(): module = parse_pyi_text( """ -@native_call([Return(0), Len(Return(0)), Shape(Work("tmp"), 0)]) +@native_call([Return(0), Len(Return(0)), Work("tmp").shape[0]]) def f() -> Float64: ... """, module_name="edited", @@ -255,8 +255,8 @@ def test_function_equality_treats_argument_names_as_placeholders(): """ def resize( n: Int32, - x: Float64[Shape('1:n'), ORDER_F] -) -> Returns["x", Float64[Shape('1:n'), ORDER_F]]: ... + x: Float64[1:n] +) -> None: ... """, module_name="edited", ) @@ -264,8 +264,8 @@ def resize( """ def resize( extent: Int32, - values: Float64[Shape('1:extent'), ORDER_F] -) -> Returns["values", Float64[Shape('1:extent'), ORDER_F]]: ... + values: Float64[1:extent] +) -> None: ... """, module_name="edited", ) @@ -274,7 +274,7 @@ def resize( assert left.functions[0].arguments[0] != right.functions[0].arguments[0] -def test_plain_return_type_compares_equal_to_unnamed_output_argument(): +def test_plain_return_type_represents_direct_return_not_output_argument(): from_pyi = parse_pyi_text( """ def add( @@ -284,26 +284,9 @@ def add( """, module_name="edited", ) - from_ir = SemanticModule( - name="edited", - functions=[ - SemanticFunction( - name="add", - native_name="add", - arguments=[ - SemanticArgument("a", SemanticType("Float64", dtype="Float64")), - SemanticArgument("b", SemanticType("Float64", dtype="Float64")), - SemanticArgument( - "c", - SemanticType("Float64", dtype="Float64"), - intent="out", - ), - ], - ) - ], - ) - - assert from_pyi == from_ir + func = from_pyi.functions[0] + assert func.return_type.name == "Float64" + assert [arg.name for arg in func.arguments] == ["a", "b"] def test_native_call_preserves_unnamed_output_argument_position(): @@ -344,7 +327,7 @@ def add( ], ) - assert from_pyi == from_ir + assert from_pyi != from_ir assert from_pyi.functions[0].arguments[2].intent == "out" assert from_pyi.functions[0].projection[2].native_position == 2 @@ -356,12 +339,12 @@ def test_native_call_accepts_hidden_native_values(): Arg(0), Const(1), Len(Arg(0)), - Shape(Arg(0), 0), + Arg(0).shape[0], IsPresent(Arg(1)), Work("tmp"), ]) def wrapper( - x: Float64[Shape("n"), ORDER_F], + x: Float64[n], b: Vector | None = None ) -> None: ... """, @@ -420,7 +403,7 @@ def test_emit_native_call_hidden_native_values(): pyi = emit_module(module) - assert "@native_call([Arg(0), Const(1), Len(Arg(0)), Shape(Arg(0), 0), IsPresent(Arg(1)), Work('tmp')])" in pyi + assert "@native_call([Arg(0), Const(1), Len(Arg(0)), Arg(0).shape[0], IsPresent(Arg(1)), Work('tmp')])" in pyi def test_plain_return_without_native_call_does_not_preserve_native_output_position(): @@ -463,7 +446,7 @@ def add( assert from_pyi != with_native_call -def test_plain_tuple_return_types_compare_equal_to_unnamed_output_arguments(): +def test_plain_tuple_return_types_parse_component_returns(): from_pyi = parse_pyi_text( """ def split( @@ -472,30 +455,10 @@ def split( """, module_name="edited", ) - from_ir = SemanticModule( - name="edited", - functions=[ - SemanticFunction( - name="split", - native_name="split", - arguments=[ - SemanticArgument("x", SemanticType("Float64", dtype="Float64")), - SemanticArgument( - "lo", - SemanticType("Float64", dtype="Float64"), - intent="out", - ), - SemanticArgument( - "hi", - SemanticType("Int32", dtype="Int32"), - intent="out", - ), - ], - ) - ], - ) - - assert from_pyi == from_ir + func = from_pyi.functions[0] + assert func.return_type.name == "Float64" + assert [arg.name for arg in func.arguments] == ["x", "__return_1"] + assert func.arguments[1].intent == "out" def test_method_equality_treats_argument_names_as_placeholders(): @@ -505,7 +468,7 @@ class vector: def scale( self, n: Int32, - x: Float64[Shape('1:n'), ORDER_F] + x: Float64[1:n] ) -> None: ... """, module_name="edited", @@ -516,7 +479,7 @@ class vector: def scale( self, extent: Int32, - values: Float64[Shape('1:extent'), ORDER_F] + values: Float64[1:extent] ) -> None: ... """, module_name="edited", @@ -566,10 +529,6 @@ class vector: ("@native_call([Return()])\ndef f(x: Int32) -> None: ...\n", "Return expects one positional index"), ("@native_call([Const()])\ndef f(x: Int32) -> None: ...\n", "Const expects one value"), ("@native_call([Len()])\ndef f(x: Int32) -> None: ...\n", "Len expects one value reference"), - ( - "@native_call([Shape(Arg(0))])\ndef f(x: Int32) -> None: ...\n", - "Shape expects a value reference and dimension", - ), ("@native_call([IsPresent()])\ndef f(x: Int32) -> None: ...\n", "IsPresent expects one value reference"), ("@native_call([Work()])\ndef f(x: Int32) -> None: ...\n", "Work expects one workspace name"), ("@native_call([Len(1)])\ndef f(x: Int32) -> None: ...\n", "Expected Arg"), @@ -623,33 +582,32 @@ def test_fortran_to_pyi_and_back_preserves_mixed_input_output_projection(): pyi = "\n\n".join(emit_module(module) for module in modules) reparsed = parse_pyi_text(pyi, module_name="solver_mod") - assert "@native_call([Arg(0), Return(0), Arg(1)])" in pyi + assert "@native_call" not in pyi func = reparsed.functions[0] assert func.name == "solve" - assert [m.native_position for m in func.projection] == [0, 1, 2] - assert func.projection[0].python_position == 0 - assert func.projection[1].result_position == 0 - assert func.projection[2].python_position == 1 + assert [arg.name for arg in func.arguments] == ["a", "x", "b"] + assert func.arguments[1].intent == "out" def test_parse_pyi_text_accepts_c_and_fortran_order_constraints(): module = parse_pyi_text( """ def consume( - a: Float64[Shape(':', ':'), ORDER_C], - b: Float64[Shape(':', ':'), ORDER_F] + a: Float64[:, :], + b: Annotated[Float64[:, :], ORDER_F] ) -> None: ... """, module_name="edited", ) - constraint_names = [ - constraint.name + arrays = [ + arg.semantic_type.storage.array for arg in module.functions[0].arguments - for constraint in arg.semantic_type.constraints ] - assert "ORDER_C" in constraint_names - assert "ORDER_F" in constraint_names + assert arrays[0].order == "ORDER_C" + assert arrays[1].order == "ORDER_F" + assert arrays[0].category is None + assert arrays[1].source_shape == [] def test_generated_pyi_compares_equal_to_original_ir_for_all_fortran_fixtures(tmp_path: Path): diff --git a/tests/semantics/fixtures/general/basic_subroutine.json b/tests/semantics/fixtures/general/basic_subroutine.json index fae66c1a6..6151d692b 100644 --- a/tests/semantics/fixtures/general/basic_subroutine.json +++ b/tests/semantics/fixtures/general/basic_subroutine.json @@ -21,13 +21,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "n", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "n", + "native_scope": "add1", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x", @@ -38,31 +88,101 @@ "shape": [ "n" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "n" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "n" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "n" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "n" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "n" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": "add1", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "n" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "n" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -83,20 +203,38 @@ "native_name": "x", "native_position": 1, "python_position": 1, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "add1", + "native_scope": "m1", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "classes": [], "variables": [], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "m1", + "native_scope": "m1", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/compile_time_all_exprs.json b/tests/semantics/fixtures/general/compile_time_all_exprs.json index 1a2e130e1..f3bf01cd2 100644 --- a/tests/semantics/fixtures/general/compile_time_all_exprs.json +++ b/tests/semantics/fixtures/general/compile_time_all_exprs.json @@ -14,33 +14,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:p_add" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:p_add" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "p_add" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "p_add" + ], + "lower_bounds": [], + "upper_bounds": [ + "p_add" + ], + "source_shape": [ + "1:p_add" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x1", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_add" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_add" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x1", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_add" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_add" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x2", @@ -49,33 +121,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:p_sub" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:p_sub" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "p_sub" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "p_sub" + ], + "lower_bounds": [], + "upper_bounds": [ + "p_sub" + ], + "source_shape": [ + "1:p_sub" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x2", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_sub" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_sub" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x2", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_sub" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_sub" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x3", @@ -84,33 +228,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:p_mul" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:p_mul" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "p_mul" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "p_mul" + ], + "lower_bounds": [], + "upper_bounds": [ + "p_mul" + ], + "source_shape": [ + "1:p_mul" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x3", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_mul" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_mul" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x3", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_mul" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_mul" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x4", @@ -119,33 +335,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:p_div" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:p_div" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "p_div" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "p_div" + ], + "lower_bounds": [], + "upper_bounds": [ + "p_div" + ], + "source_shape": [ + "1:p_div" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x4", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_div" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_div" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x4", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_div" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_div" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x5", @@ -154,33 +442,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:p_pow" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:p_pow" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "p_pow" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "p_pow" + ], + "lower_bounds": [], + "upper_bounds": [ + "p_pow" + ], + "source_shape": [ + "1:p_pow" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x5", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_pow" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_pow" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x5", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:p_pow" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "p_pow" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x6", @@ -189,33 +549,107 @@ "rank": 1, "dtype": "Int32", "shape": [ - "0:p_mix" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "0:p_mix" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "p_mix - 0 + 1" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "p_mix - 0 + 1" + ], + "lower_bounds": [ + "0" + ], + "upper_bounds": [ + "p_mix" + ], + "source_shape": [ + "0:p_mix" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x6", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "0:p_mix" + ], + "lower_bounds": [ + "0" + ], + "upper_bounds": [ + "p_mix" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x6", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "0:p_mix" + ], + "lower_bounds": [ + "0" + ], + "upper_bounds": [ + "p_mix" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x7", @@ -224,33 +658,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:-(-a + b)" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:-(-a + b)" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "-(-a + b)" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "-(-a + b)" + ], + "lower_bounds": [], + "upper_bounds": [ + "-(-a + b)" + ], + "source_shape": [ + "1:-(-a + b)" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x7", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:-(-a + b)" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "-(-a + b)" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x7", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:-(-a + b)" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "-(-a + b)" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x8", @@ -259,33 +765,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:(a+b)*(c+1)-1" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:(a+b)*(c+1)-1" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "(a + b) * (c + 1) - 1" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "(a + b) * (c + 1) - 1" + ], + "lower_bounds": [], + "upper_bounds": [ + "(a+b)*(c+1)-1" + ], + "source_shape": [ + "1:(a+b)*(c+1)-1" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x8", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:(a+b)*(c+1)-1" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "(a+b)*(c+1)-1" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x8", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:(a+b)*(c+1)-1" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "(a+b)*(c+1)-1" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x9", @@ -294,33 +872,105 @@ "rank": 1, "dtype": "Int32", "shape": [ - "1:(a-b)*(a-c)" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:(a-b)*(a-c)" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "(a - b) * (a - c)" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "(a - b) * (a - c)" + ], + "lower_bounds": [], + "upper_bounds": [ + "(a-b)*(a-c)" + ], + "source_shape": [ + "1:(a-b)*(a-c)" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x9", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:(a-b)*(a-c)" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "(a-b)*(a-c)" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x9", + "native_scope": "all_exprs", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:(a-b)*(a-c)" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "(a-b)*(a-c)" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -331,7 +981,7 @@ "native_name": "x1", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -341,7 +991,7 @@ "native_name": "x2", "native_position": 1, "python_position": 1, - "result_position": 1, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -351,7 +1001,7 @@ "native_name": "x3", "native_position": 2, "python_position": 2, - "result_position": 2, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -361,7 +1011,7 @@ "native_name": "x4", "native_position": 3, "python_position": 3, - "result_position": 3, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -371,7 +1021,7 @@ "native_name": "x5", "native_position": 4, "python_position": 4, - "result_position": 4, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -381,7 +1031,7 @@ "native_name": "x6", "native_position": 5, "python_position": 5, - "result_position": 5, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -391,7 +1041,7 @@ "native_name": "x7", "native_position": 6, "python_position": 6, - "result_position": 6, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -401,7 +1051,7 @@ "native_name": "x8", "native_position": 7, "python_position": 7, - "result_position": 7, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -411,14 +1061,23 @@ "native_name": "x9", "native_position": 8, "python_position": 8, - "result_position": 8, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "all_exprs", + "native_scope": "expr_mod", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "classes": [], @@ -442,13 +1101,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "b", @@ -469,13 +1171,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "b", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "b", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "c", @@ -496,13 +1241,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "c", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "c", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "p_add", @@ -523,13 +1311,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "p_add", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p_add", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "p_sub", @@ -550,13 +1381,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "p_sub", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p_sub", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "p_mul", @@ -577,13 +1451,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "p_mul", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p_mul", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "p_div", @@ -604,13 +1521,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "p_div", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p_div", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "p_pow", @@ -631,13 +1591,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "p_pow", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p_pow", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "p_mix", @@ -658,17 +1661,69 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "p_mix", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p_mix", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } } ], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "expr_mod", + "native_scope": "expr_mod", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/compile_time_shape_exprs.json b/tests/semantics/fixtures/general/compile_time_shape_exprs.json index 680af3b91..cb5e6efde 100644 --- a/tests/semantics/fixtures/general/compile_time_shape_exprs.json +++ b/tests/semantics/fixtures/general/compile_time_shape_exprs.json @@ -14,33 +14,107 @@ "rank": 1, "dtype": "Int32", "shape": [ - "0:n1-1" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "0:n1-1" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "n1 - 1 - 0 + 1" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "n1 - 1 - 0 + 1" + ], + "lower_bounds": [ + "0" + ], + "upper_bounds": [ + "n1-1" + ], + "source_shape": [ + "0:n1-1" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "0:n1-1" + ], + "lower_bounds": [ + "0" + ], + "upper_bounds": [ + "n1-1" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": "use_expr", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "0:n1-1" + ], + "lower_bounds": [ + "0" + ], + "upper_bounds": [ + "n1-1" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "y", @@ -49,33 +123,105 @@ "rank": 1, "dtype": "Float64", "shape": [ - "1:n0*2" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "1:n0*2" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "n0 * 2" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "n0 * 2" + ], + "lower_bounds": [], + "upper_bounds": [ + "n0*2" + ], + "source_shape": [ + "1:n0*2" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "y", + "native_scope": null, + "source_kind": "variable", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:n0*2" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "n0*2" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "y", + "native_scope": "use_expr", + "source_kind": "argument", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "1:n0*2" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "n0*2" + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -86,7 +232,7 @@ "native_name": "x", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -96,14 +242,23 @@ "native_name": "y", "native_position": 1, "python_position": 1, - "result_position": 1, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "use_expr", + "native_scope": "dims_mod", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "classes": [], @@ -127,13 +282,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "n0", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "n0", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "n1", @@ -154,17 +352,69 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "n1", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "n1", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } } ], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "dims_mod", + "native_scope": "dims_mod", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/derived_type.json b/tests/semantics/fixtures/general/derived_type.json index 3aea76a88..d95e3f0c4 100644 --- a/tests/semantics/fixtures/general/derived_type.json +++ b/tests/semantics/fixtures/general/derived_type.json @@ -21,13 +21,63 @@ "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": false, + "mutable": true, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": null, + "source_kind": "variable", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": "touch", + "source_kind": "argument", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -38,14 +88,23 @@ "native_name": "p", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "touch", + "native_scope": "particle_mod", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "classes": [ @@ -67,13 +126,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "id", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "id", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x", @@ -84,43 +184,131 @@ "shape": [ "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "methods": [], "base_classes": [], "contracts": [], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "particle", + "native_scope": "particle_mod", + "source_kind": "derived_type", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "variables": [], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "particle_mod", + "native_scope": "particle_mod", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/derived_types_and_methods.json b/tests/semantics/fixtures/general/derived_types_and_methods.json index ecac766b2..0af28da19 100644 --- a/tests/semantics/fixtures/general/derived_types_and_methods.json +++ b/tests/semantics/fixtures/general/derived_types_and_methods.json @@ -22,13 +22,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "id", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "id", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "xyz", @@ -39,38 +80,117 @@ "shape": [ "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "xyz", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "xyz", + "native_scope": null, + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "methods": [], "base_classes": [], "contracts": [], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "node", + "native_scope": "mesh_mod", + "source_kind": "derived_type", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "mesh", @@ -90,13 +210,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "nnodes", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "nnodes", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "nodes", @@ -107,47 +268,131 @@ "shape": [ ":" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - ":" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - }, - { - "name": "Allocatable", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + ":" + ], + "category": "deferred_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": true, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "nodes", + "native_scope": null, + "source_kind": "variable", + "source_type": "derived(kind=node)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": true, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "nodes", + "native_scope": null, + "source_kind": "argument", + "source_type": "derived(kind=node)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": true, + "pointer": false, + "contiguous": false + } + } } ], "methods": [], "base_classes": [], "contracts": [], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "mesh", + "native_scope": "mesh_mod", + "source_kind": "derived_type", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "variables": [], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "mesh_mod", + "native_scope": "mesh_mod", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/modern_pyi_example.json b/tests/semantics/fixtures/general/modern_pyi_example.json index 8e08e4faa..31ce8f22b 100644 --- a/tests/semantics/fixtures/general/modern_pyi_example.json +++ b/tests/semantics/fixtures/general/modern_pyi_example.json @@ -8,33 +8,83 @@ "native_name": "init_particle", "arguments": [ { - "name": "pid", + "name": "p", "semantic_type": { - "name": "Int32", + "name": "particle", "rank": 0, - "dtype": "Int32", + "dtype": "particle", "shape": [], "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", - "mutable": false, + "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": false, + "mutable": true, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": null, + "source_kind": "variable", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "out", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, - "intent": "in", + "intent": "out", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": "init_particle", + "source_kind": "argument", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "out", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { - "name": "mass", + "name": "pid", "semantic_type": { - "name": "Float64", + "name": "Int32", "rank": 0, - "dtype": "Float64", + "dtype": "Int32", "shape": [], "constraints": [], "coercions": [], @@ -43,16 +93,66 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "pid", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "pid", + "native_scope": "init_particle", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { - "name": "x", + "name": "mass", "semantic_type": { "name": "Float64", "rank": 0, @@ -65,16 +165,66 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "mass", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "mass", + "native_scope": "init_particle", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { - "name": "y", + "name": "x", "semantic_type": { "name": "Float64", "rank": 0, @@ -87,16 +237,66 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": "init_particle", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { - "name": "z", + "name": "y", "semantic_type": { "name": "Float64", "rank": 0, @@ -109,46 +309,146 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "y", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "y", + "native_scope": "init_particle", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { - "name": "p", + "name": "z", "semantic_type": { - "name": "particle", + "name": "Float64", "rank": 0, - "dtype": "particle", + "dtype": "Float64", "shape": [], "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", - "mutable": true, + "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "z", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, - "intent": "out", + "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "z", + "native_scope": "init_particle", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, "contracts": [], "projection": [ { - "python_name": null, + "python_name": "p", "native_name": "p", "native_position": 0, - "python_position": null, - "result_position": 0, + "python_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "out" @@ -157,7 +457,7 @@ "python_name": "pid", "native_name": "pid", "native_position": 1, - "python_position": 0, + "python_position": 1, "result_position": null, "value_kind": "", "value": null, @@ -167,7 +467,7 @@ "python_name": "mass", "native_name": "mass", "native_position": 2, - "python_position": 1, + "python_position": 2, "result_position": null, "value_kind": "", "value": null, @@ -177,7 +477,7 @@ "python_name": "x", "native_name": "x", "native_position": 3, - "python_position": 2, + "python_position": 3, "result_position": null, "value_kind": "", "value": null, @@ -187,7 +487,7 @@ "python_name": "y", "native_name": "y", "native_position": 4, - "python_position": 3, + "python_position": 4, "result_position": null, "value_kind": "", "value": null, @@ -197,7 +497,7 @@ "python_name": "z", "native_name": "z", "native_position": 5, - "python_position": 4, + "python_position": 5, "result_position": null, "value_kind": "", "value": null, @@ -205,7 +505,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "init_particle", + "native_scope": "modern_math_physics", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "kinetic_energy", @@ -225,13 +534,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": null, + "source_kind": "variable", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": "kinetic_energy", + "source_kind": "argument", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "vx", @@ -247,13 +606,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "vx", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "vx", + "native_scope": "kinetic_energy", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "vy", @@ -269,13 +678,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "vy", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "vy", + "native_scope": "kinetic_energy", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "vz", @@ -291,13 +750,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "vz", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "vz", + "native_scope": "kinetic_energy", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": { @@ -312,7 +821,28 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "e", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "contracts": [], "projection": [ @@ -358,7 +888,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "kinetic_energy", + "native_scope": "modern_math_physics", + "source_kind": "function", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "scale_vector", @@ -371,33 +910,103 @@ "rank": 1, "dtype": "Float64", "shape": [ - ":" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - ":" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "::Strided" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "::Strided" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + ":" + ], + "category": "assumed_shape", + "order": null, + "axes": [ + "strided" + ], + "contiguous": false, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "v", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "v", + "native_scope": "scale_vector", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "alpha", @@ -413,13 +1022,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "alpha", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "alpha", + "native_scope": "scale_vector", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -430,7 +1089,7 @@ "native_name": "v", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" @@ -447,7 +1106,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "scale_vector", + "native_scope": "modern_math_physics", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "dot3", @@ -462,31 +1130,101 @@ "shape": [ "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": true, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": "dot3", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "b", @@ -497,31 +1235,101 @@ "shape": [ "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": true, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "b", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "b", + "native_scope": "dot3", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": { @@ -536,7 +1344,28 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "s", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "contracts": [], "projection": [ @@ -562,7 +1391,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "dot3", + "native_scope": "modern_math_physics", + "source_kind": "function", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "fill_identity3", @@ -578,50 +1416,137 @@ "3", "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3", - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 2, + "shape": [ + "3", + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3", + "3" + ], + "category": "explicit_shape", + "order": "ORDER_F", + "axes": [ + "dense", + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 2, + "shape": [ + "3", + "3" + ], + "lower_bounds": [ + "1", + "1" + ], + "upper_bounds": [ + "3", + "3" + ], + "intent": "out", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "out", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": "fill_identity3", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 2, + "shape": [ + "3", + "3" + ], + "lower_bounds": [ + "1", + "1" + ], + "upper_bounds": [ + "3", + "3" + ], + "intent": "out", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, "contracts": [], "projection": [ { - "python_name": null, + "python_name": "a", "native_name": "a", "native_position": 0, - "python_position": null, - "result_position": 0, + "python_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "out" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "fill_identity3", + "native_scope": "modern_math_physics", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "normalize_particle", @@ -641,13 +1566,63 @@ "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": false, + "mutable": true, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": null, + "source_kind": "variable", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "p", + "native_scope": "normalize_particle", + "source_kind": "argument", + "source_type": "derived(kind=particle)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -658,14 +1633,23 @@ "native_name": "p", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "normalize_particle", + "native_scope": "modern_math_physics", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "hidden_proc", @@ -685,13 +1669,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": "hidden_proc", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -709,7 +1743,16 @@ } ], "metadata": {}, - "visibility": "private" + "visibility": "private", + "origin": { + "source_language": "fortran", + "native_name": "hidden_proc", + "native_scope": "modern_math_physics", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "classes": [ @@ -731,13 +1774,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "id", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "id", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "mass", @@ -753,13 +1837,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "mass", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "mass", + "native_scope": null, + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "position", @@ -770,38 +1895,117 @@ "shape": [ "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "position", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "position", + "native_scope": null, + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "methods": [], "base_classes": [], "contracts": [], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "particle", + "native_scope": "modern_math_physics", + "source_kind": "derived_type", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "vector3", @@ -816,38 +2020,117 @@ "shape": [ "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "values", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "values", + "native_scope": null, + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "methods": [], "base_classes": [], "contracts": [], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "vector3", + "native_scope": "modern_math_physics", + "source_kind": "derived_type", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "hidden_state", @@ -867,20 +2150,70 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "code", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "code", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "methods": [], "base_classes": [], "contracts": [], "metadata": {}, - "visibility": "private" + "visibility": "private", + "origin": { + "source_language": "fortran", + "native_name": "hidden_state", + "native_scope": "modern_math_physics", + "source_kind": "derived_type", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "variables": [ @@ -898,13 +2231,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "counter", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "counter", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "hidden_scale", @@ -920,17 +2294,67 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "hidden_scale", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "private", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "hidden_scale", + "native_scope": null, + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "modern_math_physics", + "native_scope": "modern_math_physics", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/module_vars_use.json b/tests/semantics/fixtures/general/module_vars_use.json index 618eea0f9..5788f9ba5 100644 --- a/tests/semantics/fixtures/general/module_vars_use.json +++ b/tests/semantics/fixtures/general/module_vars_use.json @@ -24,13 +24,56 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "nmax", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer(kind=c_int)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "nmax", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer(kind=c_int)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false, + "constant": true + } + } }, { "name": "origin", @@ -41,31 +84,101 @@ "shape": [ "3" ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - "3" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } - ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + "3" + ], + "category": "explicit_shape", + "order": null, + "axes": [ + "dense" + ], + "contiguous": true, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "origin", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=c_double)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "origin", + "native_scope": null, + "source_kind": "argument", + "source_type": "real(kind=c_double)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + "3" + ], + "lower_bounds": [ + "1" + ], + "upper_bounds": [ + "3" + ], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "imports": [ @@ -83,7 +196,16 @@ ] } ], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "constants_mod", + "native_scope": "constants_mod", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/procedures_and_functions.json b/tests/semantics/fixtures/general/procedures_and_functions.json index 809afbaae..bfa93e31e 100644 --- a/tests/semantics/fixtures/general/procedures_and_functions.json +++ b/tests/semantics/fixtures/general/procedures_and_functions.json @@ -14,33 +14,103 @@ "rank": 1, "dtype": "Float64", "shape": [ - ":" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - ":" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "::Strided" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": true, + "mutable": false, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "::Strided" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + ":" + ], + "category": "assumed_shape", + "order": null, + "axes": [ + "strided" + ], + "contiguous": false, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": "norm2", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": { @@ -55,7 +125,28 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "res", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "contracts": [], "projection": [ @@ -71,7 +162,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "norm2", + "native_scope": "math_mod", + "source_kind": "function", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "scale", @@ -91,13 +191,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "a", + "native_scope": "scale", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "x", @@ -106,33 +256,103 @@ "rank": 1, "dtype": "Float64", "shape": [ - ":" - ], - "constraints": [ - { - "name": "Shape", - "arguments": [ - ":" - ] - }, - { - "name": "ORDER_F", - "arguments": [] - } + "::Strided" ], + "constraints": [], "coercions": [], "ownership": { "ownership": "borrowed", "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "array", + "read_only": false, + "mutable": true, + "pointer_depth": 0, + "ownership": "borrowed", + "array": { + "rank": 1, + "shape": [ + "::Strided" + ], + "lower_bounds": [], + "upper_bounds": [], + "source_shape": [ + ":" + ], + "category": "assumed_shape", + "order": null, + "axes": [ + "strided" + ], + "contiguous": false, + "allocatable": false, + "pointer": false, + "metadata": {} + }, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": null, + "source_kind": "variable", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "x", + "native_scope": "scale", + "source_kind": "argument", + "source_type": "real(kind=8)", + "source_location": {}, + "metadata": { + "rank": 1, + "shape": [ + ":" + ], + "lower_bounds": [ + null + ], + "upper_bounds": [ + null + ], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -153,20 +373,38 @@ "native_name": "x", "native_position": 1, "python_position": 1, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "scale", + "native_scope": "math_mod", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "classes": [], "variables": [], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "math_mod", + "native_scope": "math_mod", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/general/scope_name_reuse_combinations.json b/tests/semantics/fixtures/general/scope_name_reuse_combinations.json index d47888c3d..17bc937b9 100644 --- a/tests/semantics/fixtures/general/scope_name_reuse_combinations.json +++ b/tests/semantics/fixtures/general/scope_name_reuse_combinations.json @@ -21,13 +21,63 @@ "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": false, + "mutable": true, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "do_work_i", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -38,14 +88,23 @@ "native_name": "same_name", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "do_work_i", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "do_work_r", @@ -65,13 +124,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "do_work_r", + "source_kind": "argument", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -89,7 +198,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "do_work_r", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "do_work_l", @@ -109,13 +227,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "logical", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "do_work_l", + "source_kind": "argument", + "source_type": "logical", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -133,7 +301,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "do_work_l", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "host_one", @@ -153,13 +330,63 @@ "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": false, + "mutable": true, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "host_one", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -170,14 +397,23 @@ "native_name": "same_name", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "host_one", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "host_two", @@ -197,13 +433,63 @@ "mutable": true, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": false, + "mutable": true, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "inout", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "host_two", + "source_kind": "argument", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "inout", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": null, @@ -214,14 +500,23 @@ "native_name": "same_name", "native_position": 0, "python_position": 0, - "result_position": 0, + "result_position": null, "value_kind": "", "value": null, "intent": "inout" } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "host_two", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "subroutine", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "convert_to_complex", @@ -241,13 +536,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "convert_to_complex", + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": { @@ -262,7 +607,28 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "shared", + "native_scope": null, + "source_kind": "variable", + "source_type": "complex", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "contracts": [], "projection": [ @@ -278,7 +644,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "convert_to_complex", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "function", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "convert_to_char", @@ -298,13 +673,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "convert_to_char", + "source_kind": "argument", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": { @@ -319,7 +744,28 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "shared", + "native_scope": null, + "source_kind": "variable", + "source_type": "character(kind=len=16)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "contracts": [], "projection": [ @@ -335,7 +781,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "convert_to_char", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "function", + "source_type": null, + "source_location": {}, + "metadata": {} + } }, { "name": "convert_to_logical", @@ -355,13 +810,63 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": { + "kind": "reference", + "read_only": true, + "mutable": false, + "pointer_depth": 1, + "ownership": "borrowed", + "array": null, + "calling_convention": null, + "metadata": {} + }, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": null, + "source_kind": "variable", + "source_type": "character(kind=len=*)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "convert_to_logical", + "source_kind": "argument", + "source_type": "character(kind=len=*)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "in", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "return_type": { @@ -376,7 +881,28 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "shared", + "native_scope": null, + "source_kind": "variable", + "source_type": "logical", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "contracts": [], "projection": [ @@ -392,7 +918,16 @@ } ], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "convert_to_logical", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "function", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "classes": [ @@ -414,20 +949,70 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "payload", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "payload", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "methods": [], "base_classes": [], "contracts": [], "metadata": {}, - "visibility": "public" + "visibility": "public", + "origin": { + "source_language": "fortran", + "native_name": "same_name", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "derived_type", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ], "variables": [ @@ -445,13 +1030,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "same_name_i", + "native_scope": null, + "source_kind": "variable", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name_i", + "native_scope": null, + "source_kind": "argument", + "source_type": "integer", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "same_name_r", @@ -467,13 +1093,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "same_name_r", + "native_scope": null, + "source_kind": "variable", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name_r", + "native_scope": null, + "source_kind": "argument", + "source_type": "real", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "same_name_l", @@ -489,13 +1156,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "same_name_l", + "native_scope": null, + "source_kind": "variable", + "source_type": "logical", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name_l", + "native_scope": null, + "source_kind": "argument", + "source_type": "logical", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "same_name_c", @@ -511,13 +1219,54 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "same_name_c", + "native_scope": null, + "source_kind": "variable", + "source_type": "complex", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name_c", + "native_scope": null, + "source_kind": "argument", + "source_type": "complex", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, { "name": "same_name_s", @@ -533,17 +1282,67 @@ "mutable": false, "aliasing": true }, - "metadata": {} + "metadata": {}, + "storage": null, + "origin": { + "source_language": "fortran", + "native_name": "same_name_s", + "native_scope": null, + "source_kind": "variable", + "source_type": "character(kind=len=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } }, "intent": "in", "optional": false, "visibility": "public", "default_value": null, - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "same_name_s", + "native_scope": null, + "source_kind": "argument", + "source_type": "character(kind=len=8)", + "source_location": {}, + "metadata": { + "rank": 0, + "shape": [], + "lower_bounds": [], + "upper_bounds": [], + "intent": "unknown", + "optional": false, + "value": false, + "allocatable": false, + "pointer": false, + "contiguous": false + } + } } ], "imports": [], - "metadata": {} + "metadata": {}, + "origin": { + "source_language": "fortran", + "native_name": "scope_name_reuse_combinations", + "native_scope": "scope_name_reuse_combinations", + "source_kind": "module", + "source_type": null, + "source_location": {}, + "metadata": {} + } } ] } diff --git a/tests/semantics/fixtures/wrap_readiness_messages.json b/tests/semantics/fixtures/wrap_readiness_messages.json index 0b0c67b39..f26be8984 100644 --- a/tests/semantics/fixtures/wrap_readiness_messages.json +++ b/tests/semantics/fixtures/wrap_readiness_messages.json @@ -1875,7 +1875,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 8 }, { "code": "unresolved_semantic_types", @@ -1961,14 +1961,22 @@ "blockers": [] }, "general/modern_pyi_example.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 6, "n_classes": 2, "n_variables": 1, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 2 + } + ] }, "general/module_vars_use.f90": { "wrappable": true, @@ -1981,14 +1989,22 @@ "blockers": [] }, "general/procedures_and_functions.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 4 + } + ] }, "general/scope_name_reuse_combinations.f90": { "wrappable": true, @@ -27116,7 +27132,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 16 + "n_items": 84 } ] }, @@ -27272,7 +27288,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 4 } ] }, @@ -27300,7 +27316,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 12 + "n_items": 24 } ] }, @@ -27318,7 +27334,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 68 } ] }, @@ -27333,14 +27349,22 @@ "blockers": [] }, "scifortran/SF_INTEGRATE.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 2 + } + ] }, "scifortran/SF_INTERPOLATE.f90": { "wrappable": true, @@ -27483,14 +27507,22 @@ ] }, "scifortran/SF_SPARSE_ARRAY_COO.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 8, "n_classes": 2, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/SF_SPARSE_ARRAY_CSC.f90": { "wrappable": true, @@ -27526,7 +27558,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 6 } ] }, @@ -27590,7 +27622,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 6 + "n_items": 22 } ] }, @@ -27618,7 +27650,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 8 } ] }, @@ -27642,7 +27674,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 8 } ] }, @@ -27666,7 +27698,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 8 } ] }, @@ -27678,13 +27710,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 8 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 6 } ] }, @@ -27696,13 +27734,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 1 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 4 } ] }, @@ -27720,7 +27764,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 12 } ] }, @@ -28244,7 +28288,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 24 } ] }, @@ -28268,7 +28312,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 32 + "n_items": 56 } ] }, @@ -28292,7 +28336,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 32 + "n_items": 56 } ] }, @@ -28314,13 +28358,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 1 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 6 } ] }, @@ -28400,7 +28450,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 4 } ] }, @@ -28430,19 +28480,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", - "Some shape expressions refer to symbols not supplied by the semantic interface." + "Some shape expressions refer to symbols not supplied by the semantic interface.", + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." ], "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + }, { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 3 - }, - { - "code": "unresolved_shape_symbols", - "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 } ] }, @@ -28454,19 +28504,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", - "Some shape expressions refer to symbols not supplied by the semantic interface." + "Some shape expressions refer to symbols not supplied by the semantic interface.", + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." ], "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + }, { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 3 - }, - { - "code": "unresolved_shape_symbols", - "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 } ] }, @@ -28478,9 +28528,15 @@ "n_classes": 0, "n_variables": 0, "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface.", "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." ], "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 4 + }, { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", @@ -28514,25 +28570,39 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 6 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 } ] }, "scifortran/functions_bethe.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 5, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 2 + } + ] }, "scifortran/functions_wofz.f90": { "wrappable": true, @@ -28772,13 +28842,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 8 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 } ] }, @@ -28808,25 +28884,39 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 1 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 2 } ] }, "scifortran/integrate_quad_sample.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 1, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 4 + } + ] }, "scifortran/integrate_sample_1d.f90": { "wrappable": false, @@ -28842,19 +28932,27 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 32 } ] }, "scifortran/integrate_sample_2d.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 4, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 16 + } + ] }, "scifortran/interpolate_cubspl_routines.f90": { "wrappable": true, @@ -28886,7 +28984,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 12 } ] }, @@ -28910,19 +29008,27 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 12 } ] }, "scifortran/interpolate_nr.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 3, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 14 + } + ] }, "scifortran/interpolate_pack.f90": { "wrappable": true, @@ -28966,7 +29072,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 36 } ] }, @@ -28984,7 +29090,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 116 + "n_items": 176 } ] }, @@ -29012,7 +29118,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 80 + "n_items": 92 } ] }, @@ -29030,19 +29136,27 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 18 + "n_items": 54 } ] }, "scifortran/ioplot_save_array.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 16, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 112 + } + ] }, "scifortran/ioplot_splot.f90": { "wrappable": false, @@ -29058,7 +29172,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 28 + "n_items": 140 } ] }, @@ -29076,7 +29190,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 36 } ] }, @@ -29094,7 +29208,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 116 + "n_items": 176 } ] }, @@ -29122,7 +29236,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 80 + "n_items": 92 } ] }, @@ -29140,19 +29254,27 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 12 + "n_items": 48 } ] }, "scifortran/ioread_read_array.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 16, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 112 + } + ] }, "scifortran/ioread_sread.f90": { "wrappable": false, @@ -29168,7 +29290,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 28 + "n_items": 140 } ] }, @@ -29180,13 +29302,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some semantic type references are not declared by the .pyi interface or its imports." + "Some semantic type references are not declared by the .pyi interface or its imports.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "unresolved_semantic_types", "message": "Some semantic type references are not declared by the .pyi interface or its imports.", "n_items": 20 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 4 } ] }, @@ -29210,7 +29338,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, @@ -29234,7 +29362,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, @@ -29258,7 +29386,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, @@ -29270,13 +29398,19 @@ "n_classes": 0, "n_variables": 0, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 6 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 } ] }, @@ -29294,19 +29428,27 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 32 } ] }, "scifortran/linalg_blacs_aux.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 4, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 32 + } + ] }, "scifortran/linalg_blas.f90": { "wrappable": false, @@ -29322,7 +29464,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 8 + "n_items": 48 } ] }, @@ -29340,29 +29482,45 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 16 + "n_items": 20 } ] }, "scifortran/linalg_check_tridiag.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 4, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/linalg_eig.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 20 + } + ] }, "scifortran/linalg_eigh.f90": { "wrappable": false, @@ -29378,7 +29536,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 10 + "n_items": 52 } ] }, @@ -29396,7 +29554,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 18 + "n_items": 26 } ] }, @@ -29414,7 +29572,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, @@ -29432,7 +29590,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, @@ -29450,7 +29608,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 28 + "n_items": 76 } ] }, @@ -29468,79 +29626,135 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 12 + "n_items": 20 } ] }, "scifortran/linalg_inv.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/linalg_inv_gj.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 8, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 24 + } + ] }, "scifortran/linalg_inv_her.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 1, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 4 + } + ] }, "scifortran/linalg_inv_sym.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/linalg_inv_triang.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/linalg_inv_tridiag.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 8, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/linalg_lstsq.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 12 + } + ] }, "scifortran/linalg_p_blas.f90": { "wrappable": false, @@ -29556,7 +29770,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 12 + "n_items": 48 } ] }, @@ -29574,49 +29788,81 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, "scifortran/linalg_p_inv.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/linalg_solve.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 4, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 28 + } + ] }, "scifortran/linalg_svd.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 28 + } + ] }, "scifortran/linalg_svdvals.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 2, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 + } + ] }, "scifortran/linear_mix.f90": { "wrappable": false, @@ -29632,7 +29878,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 112 + "n_items": 224 } ] }, @@ -29795,14 +30041,22 @@ "blockers": [] }, "scifortran/mpi_bcast.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 32, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 224 + } + ] }, "scifortran/mpi_lanczos_c.f90": { "wrappable": false, @@ -29824,7 +30078,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, @@ -29848,7 +30102,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 4 + "n_items": 12 } ] }, @@ -30022,7 +30276,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 10 + "n_items": 82 } ] }, @@ -30034,13 +30288,19 @@ "n_classes": 0, "n_variables": 5, "messages": [ - "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file." + "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", + "Some shape expressions refer to symbols not supplied by the semantic interface." ], "blockers": [ { "code": "callback_signature_incomplete", "message": "Some callback or procedure arguments need complete Callable[[...], ...] metadata in the .pyi file.", "n_items": 6 + }, + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 8 } ] }, @@ -30064,7 +30324,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 8 } ] }, @@ -30088,7 +30348,7 @@ { "code": "unresolved_shape_symbols", "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", - "n_items": 2 + "n_items": 8 } ] }, @@ -30393,14 +30653,22 @@ "blockers": [] }, "scifortran/random_mt.f90": { - "wrappable": true, + "wrappable": false, "status": "ok", "n_modules": 1, "n_functions": 35, "n_classes": 0, "n_variables": 0, - "messages": [], - "blockers": [] + "messages": [ + "Some shape expressions refer to symbols not supplied by the semantic interface." + ], + "blockers": [ + { + "code": "unresolved_shape_symbols", + "message": "Some shape expressions refer to symbols not supplied by the semantic interface.", + "n_items": 112 + } + ] }, "scifortran/random_routines.f90": { "wrappable": false, diff --git a/tests/semantics/test_fortran2ir.py b/tests/semantics/test_fortran2ir.py index a2c9a854f..d80d3ff29 100644 --- a/tests/semantics/test_fortran2ir.py +++ b/tests/semantics/test_fortran2ir.py @@ -67,6 +67,12 @@ def has_constraint(obj, name: str) -> bool: return any(c.name == name for c in obj.constraints) +def array_contract(semantic_type: SemanticType): + assert semantic_type.storage is not None + assert semantic_type.storage.array is not None + return semantic_type.storage.array + + def test_converter_visitor_and_compatibility_methods_cover_public_paths(): converter = FortranToIRConverter() scale = FortranVariable(name="scale", base_type="real", kind="8", is_parameter=True) @@ -104,8 +110,8 @@ def test_converter_visitor_and_compatibility_methods_cover_public_paths(): semantic_arg = converter.visit(arg) assert semantic_arg.intent == "inout" - assert has_constraint(semantic_arg.semantic_type, "Allocatable") - assert has_constraint(semantic_arg.semantic_type, "Pointer") + assert semantic_arg.semantic_type.storage.kind == "reference" + assert semantic_arg.semantic_type.storage.mutable is True semantic_var = converter.variable_to_semantic_type(scale) assert semantic_var.name == "Float64" @@ -303,7 +309,14 @@ def test_resolve_semantic_compile_time_values_rewrites_shapes_and_constraints(): dtype="Float64", rank=1, shape=["1:n"], - constraints=[SemanticConstraint("Shape", ["1:n"])], + storage=semantic_models.SemanticStorageContract( + kind="array", + array=semantic_models.SemanticArrayContract( + rank=1, + shape=["1:n"], + source_shape=["1:n"], + ), + ), ), ) ], @@ -313,7 +326,7 @@ def test_resolve_semantic_compile_time_values_rewrites_shapes_and_constraints(): assert module.variables[0].semantic_type.shape == ["1:n"] assert resolved.variables[0].semantic_type.shape == ["1:8"] - assert resolved.variables[0].semantic_type.constraints[0].arguments == ["1:8"] + assert resolved.variables[0].semantic_type.storage.array.shape == ["1:8"] def test_resolve_semantic_compile_time_values_handles_nested_modules(): @@ -327,7 +340,15 @@ def test_resolve_semantic_compile_time_values_handles_nested_modules(): dtype="Float64", rank=1, shape=["n"], - constraints=[SemanticConstraint("Shape", [{"extent": "n"}])], + storage=semantic_models.SemanticStorageContract( + kind="array", + array=semantic_models.SemanticArrayContract( + rank=1, + shape=["n"], + source_shape=["1:n"], + upper_bounds=["n"], + ), + ), metadata={"bounds": ("n", ["m"])}, ), default_value="n", @@ -382,7 +403,8 @@ def test_resolve_semantic_compile_time_values_handles_nested_modules(): assert module.variables[0].semantic_type.shape == ["n"] resolved_module = resolved[0] assert resolved_module.variables[0].semantic_type.shape == ["4"] - assert resolved_module.variables[0].semantic_type.constraints[0].arguments == [{"extent": "4"}] + assert resolved_module.variables[0].semantic_type.storage.array.shape == ["4"] + assert resolved_module.variables[0].semantic_type.storage.array.source_shape == ["1:4"] assert resolved_module.variables[0].semantic_type.metadata == {"bounds": ("4", ["2"])} assert resolved_module.functions[0].projection[0].value == {"shape": ["4", ("2",)]} assert resolved_module.functions[1].return_type.metadata == {"extent": "4"} @@ -534,17 +556,11 @@ def test_array_constraints(): assert x.semantic_type.rank == 1 - assert has_constraint( - x.semantic_type, - "Shape", - ) - - assert has_constraint( - x.semantic_type, - "ORDER_F", - ) - - assert x.semantic_type.shape == [":"] + contract = array_contract(x.semantic_type) + assert contract.category == "assumed_shape" + assert contract.shape == ["::Strided"] + assert contract.source_shape == [":"] + assert contract.order is None # ============================================================ @@ -579,17 +595,87 @@ def test_matrix_semantics(): assert A.semantic_type.rank == 2 - assert A.semantic_type.shape == [":", ":"] + contract = array_contract(A.semantic_type) + assert A.semantic_type.shape == ["::Strided", "::Strided"] + assert contract.source_shape == [":", ":"] + assert contract.category == "assumed_shape" + assert contract.order == "ORDER_F" - assert has_constraint( - A.semantic_type, - "Shape", - ) - assert has_constraint( - A.semantic_type, - "ORDER_F", - ) +def test_fortran_native_storage_contracts_cover_array_categories_and_scalars(): + source = """ +module contract_mod +contains +subroutine contracts(n, m, explicit, legacy, assumed, contig, alloc, ptr, scalar_value, scalar_ref, scalar_out) + integer, intent(in) :: n + integer, intent(in) :: m + real(8), intent(in) :: explicit(n, m) + real(8), intent(inout) :: legacy(n, *) + real(8), intent(in) :: assumed(:, :) + real(8), contiguous, intent(inout) :: contig(:, :) + real(8), allocatable, intent(out) :: alloc(:) + real(8), pointer, intent(inout) :: ptr(:) + real(8), value, intent(in) :: scalar_value + real(8), intent(in) :: scalar_ref + real(8), intent(out) :: scalar_out +end subroutine contracts +end module contract_mod +""" + module = fortran_module_to_semantic_module(parse_fortran_source(source)) + func = get_function(module, "contracts") + args = {arg.name: arg for arg in func.arguments} + + explicit = array_contract(args["explicit"].semantic_type) + assert explicit.category == "explicit_shape" + assert explicit.shape == ["n", "m"] + assert explicit.order == "ORDER_F" + assert args["explicit"].semantic_type.storage.read_only is True + + legacy = array_contract(args["legacy"].semantic_type) + assert legacy.category == "assumed_size" + assert legacy.shape == ["n", ":"] + assert legacy.source_shape == ["n", "*"] + assert legacy.order == "ORDER_F" + + assumed = array_contract(args["assumed"].semantic_type) + assert assumed.category == "assumed_shape" + assert assumed.shape == ["::Strided", "::Strided"] + assert assumed.order == "ORDER_F" + + contig = array_contract(args["contig"].semantic_type) + assert contig.category == "assumed_shape" + assert contig.shape == [":", ":"] + assert contig.order == "ORDER_F" + assert contig.contiguous is True + + assert array_contract(args["alloc"].semantic_type).allocatable is True + assert array_contract(args["ptr"].semantic_type).pointer is True + assert args["scalar_value"].semantic_type.storage is None + assert args["scalar_ref"].semantic_type.storage.read_only is True + assert args["scalar_out"].semantic_type.storage.mutable is True + + +def test_explicit_bound_ranges_remain_shaped_storage_contracts(): + source = """ +module bound_mod +contains +subroutine bounded(n, default_bound, zero_bound) + integer, intent(in) :: n + real(8), intent(inout) :: default_bound(1:n) + real(8), intent(inout) :: zero_bound(0:n-1) +end subroutine bounded +end module bound_mod +""" + module = fortran_module_to_semantic_module(parse_fortran_source(source)) + args = {arg.name: arg for arg in get_function(module, "bounded").arguments} + + default_bound = array_contract(args["default_bound"].semantic_type) + assert default_bound.category == "explicit_shape" + assert default_bound.shape == ["n"] + + zero_bound = array_contract(args["zero_bound"].semantic_type) + assert zero_bound.category == "explicit_shape" + assert zero_bound.shape == ["n - 1 - 0 + 1"] # ============================================================ @@ -652,10 +738,7 @@ def test_allocatable_pointer(): x = func.arguments[0] - assert has_constraint( - x.semantic_type, - "Allocatable", - ) + assert array_contract(x.semantic_type).allocatable is True # ============================================================ @@ -902,10 +985,7 @@ def test_complex_module(): assert K.semantic_type.rank == 2 - assert has_constraint( - K.semantic_type, - "ORDER_F", - ) + assert array_contract(K.semantic_type).order == "ORDER_F" connectivity = next(arg for arg in assemble.arguments if arg.name == "connectivity") @@ -971,7 +1051,7 @@ def test_fortran_to_ir_preserves_module_semantics_from_inline_source(): assert semantic_var.semantic_type.name == "Int32" assert semantic_arg.intent == "inout" - assert semantic_arg.semantic_type.constraints[-1].name == "Allocatable" + assert array_contract(semantic_arg.semantic_type).allocatable is True assert semantic_proc.projection[0].python_position == 0 assert semantic_dtype.base_classes == ["base"] assert semantic_module.imports == ["iso_c_binding"] @@ -996,7 +1076,8 @@ def test_fortran_file_to_semantic_modules_keeps_standalone_procedures_from_inlin func = get_function(modules[0], "scale") assert [arg.name for arg in func.arguments] == ["n", "x"] assert func.projection[0].python_position == 0 - assert func.projection[1].result_position == 0 + assert func.projection[1].python_position == 1 + assert func.projection[1].result_position is None def test_semantic_function_projection_equality_and_placeholders(): diff --git a/tests/semantics/test_pyi_printer.py b/tests/semantics/test_pyi_printer.py index e4093eb17..1eae6ca50 100644 --- a/tests/semantics/test_pyi_printer.py +++ b/tests/semantics/test_pyi_printer.py @@ -13,12 +13,14 @@ from semantics.models import ( ProjectionMapping, SemanticArgument, + SemanticArrayContract, SemanticClass, SemanticConstraint, SemanticImport, SemanticMethod, SemanticModule, SemanticFunction, + SemanticStorageContract, SemanticType, ) @@ -70,12 +72,12 @@ def test_emit_basic_scalar_function(): assert "def add(" in code - assert "a: Float64" in code - assert "b: Float64" in code - assert "-> Float64" in code + assert "a: Ptr(Const(Float64))" in code + assert "b: Ptr(Const(Float64))" in code + assert "c: Annotated[Ptr(Float64), Intent('out')]" in code assert 'Returns["c", Float64]' not in code - assert "-> None" not in code + assert "-> None" in code def test_emit_rejects_unknown_semantic_type(): @@ -137,9 +139,10 @@ def test_emit_array_constraints(): assert "Float64[" in code - assert "Shape" in code - - assert "ORDER_F" in code + assert "Shape" not in code + assert "Float64[::Strided]" in code + assert "ArrayCategory" not in code + assert "SourceDims" not in code # ============================================================ @@ -166,14 +169,31 @@ def test_emit_matrix_shapes(): code = generate_pyi(source) - assert "A: Float64[" in code + assert "A: Annotated[Const(Float64[::Strided, ::Strided]), ORDER_F" in code + assert "Shape" not in code + assert "x: Const(Float64[::Strided])" in code + assert "y: Annotated[Float64[::Strided], Intent('out')]" in code + assert "-> None" in code + assert 'Returns["y", Float64[' not in code - assert "Shape(':', ':')" in code - assert "x: Float64[" in code +def test_emit_explicit_bound_ranges_as_extents_without_source_dimension_metadata(): + source = """ +module bound_mod +contains +subroutine bounded(n, default_bound, zero_bound) + integer, intent(in) :: n + real(8), intent(inout) :: default_bound(1:n) + real(8), intent(inout) :: zero_bound(0:n-1) +end subroutine bounded +end module bound_mod +""" + code = generate_pyi(source) - assert "-> Float64[" in code - assert 'Returns["y", Float64[' not in code + assert "default_bound: Float64[n]" in code + assert "zero_bound: Float64[n - 1 - 0 + 1]" in code + assert "ArrayCategory" not in code + assert "SourceDims" not in code # ============================================================ @@ -327,7 +347,7 @@ def test_emit_explicit_shape(): code = generate_pyi(source) - assert "Shape('10', '20')" in code + assert "A: Annotated[Const(Float64[10, 20]), ORDER_F]" in code # ============================================================ @@ -485,18 +505,19 @@ def test_emit_complex_fem_module(): # Matrix annotations # -------------------------------------------------------- - assert "-> Float64[" in code + assert "K: Annotated[Float64[::Strided, ::Strided], ORDER_F" in code assert 'Returns["K", Float64[' not in code - assert "coords: Float64[" in code + assert "coords: Annotated[Const(Float64[::Strided, ::Strided]), ORDER_F" in code - assert "connectivity: Int32[" in code + assert "connectivity: Annotated[Const(Int32[::Strided, ::Strided]), ORDER_F" in code # -------------------------------------------------------- # Return type # -------------------------------------------------------- - assert "-> Float64" in code + assert "def compute_norm(" in code + assert ") -> Float64: ..." in code # ============================================================ @@ -524,8 +545,8 @@ def test_emit_exact_output(): expected = normalize( ''' def scale( - x: Float64[Shape(':'), ORDER_F] -) -> Returns["x", Float64[Shape(':'), ORDER_F]]: ... + x: Float64[::Strided] +) -> None: ... ''' ) @@ -554,7 +575,8 @@ def test_output_argument_uses_plain_return_annotation(): code = PyiPrinter().emit_module(smod) - assert "-> Float64" in code + assert "-> None" in code + assert "c: Annotated[Ptr(Float64), Intent('out')]" in code assert 'Returns["c", Float64]' not in code @@ -624,13 +646,22 @@ def test_printer_class_entrypoint(): code = PyiPrinter().emit_module(smod) assert "def touch(" in code - assert "x: Int32" in code + assert "x: Ptr(Int32)" in code def test_printer_emit_visitor_dispatches_semantic_models(): printer = PyiPrinter() - constraint = SemanticConstraint("Shape", [":"]) - semantic_type = SemanticType("Float64", dtype="Float64", constraints=[constraint]) + constraint = SemanticConstraint("Constant") + semantic_type = SemanticType( + "Float64", + dtype="Float64", + rank=1, + shape=[":"], + storage=SemanticStorageContract( + kind="array", + array=SemanticArrayContract(rank=1, shape=[":"], source_shape=[":"]), + ), + ) argument = SemanticArgument("class", semantic_type, optional=True) method = SemanticMethod(name="reset") cls = SemanticClass( @@ -642,12 +673,12 @@ def test_printer_emit_visitor_dispatches_semantic_models(): func = SemanticFunction(name="wrap", arguments=[argument]) module = SemanticModule(name="visitor_mod", classes=[cls], functions=[func]) - assert printer.emit(constraint) == "Shape(':')" - assert printer.emit(semantic_type) == "Float64[Shape(':')]" - assert printer.emit(argument) == 'class_: Annotated[Float64[Shape(\':\')], Name("class")] = ...' + assert printer.emit(constraint) == "Constant" + assert printer.emit(semantic_type) == "Float64[:]" + assert printer.emit(argument) == 'class_: Annotated[Float64[:], Name("class")] = ...' assert "def reset(self) -> None: ..." in printer.emit(method) assert "@private\nclass thing:" in printer.emit(cls) - assert "var['bad-name']: Float64[Shape(':')]" in printer.emit(cls) + assert "var['bad-name']: Float64[:]" in printer.emit(cls) assert "def wrap(" in printer.emit(func) assert "class thing:" in printer.emit(module) @@ -694,8 +725,8 @@ def test_emit_type_bound_procedure_as_python_method_without_duplicate_self(): code = generate_pyi(source) assert "class vector:" in code - assert "values: Float64[Shape(':'), ORDER_F, Allocatable]" in code - assert " def scale(\n self,\n alpha: Float64\n ) -> Returns[\"self\", vector]: ..." in code + assert "values: Annotated[Float64[:], Allocatable]" in code + assert " def scale(\n self,\n alpha: Ptr(Const(Float64))\n ) -> None: ..." in code assert " self: vector" not in code @@ -758,7 +789,7 @@ def test_emit_module_with_projection_helpers_and_private_function(): code = emit_module(module) - assert "@native_call([Arg(0), Const(1), Len(Arg(0)), Shape(Arg(0), 0), IsPresent(Arg(1)), Work('tmp')])" in code + assert "@native_call([Arg(0), Const(1), Len(Arg(0)), Arg(0).shape[0], IsPresent(Arg(1)), Work('tmp')])" in code def test_emit_native_call_supports_return_and_work_value_references(): @@ -787,7 +818,7 @@ def test_emit_native_call_supports_return_and_work_value_references(): code = emit_module(module) - assert "@native_call([Len(Return(0)), Shape(Work('tmp'), 1)])" in code + assert "@native_call([Len(Return(0)), Work('tmp').shape[1]])" in code assert "def wrapper() -> Float64: ..." in code diff --git a/tests/semantics/test_semantic_wrap_readiness.py b/tests/semantics/test_semantic_wrap_readiness.py index 1df0d754f..57fd56437 100644 --- a/tests/semantics/test_semantic_wrap_readiness.py +++ b/tests/semantics/test_semantic_wrap_readiness.py @@ -46,13 +46,13 @@ def test_completed_pyi_interface_is_semantically_ready(): class sim_state: n: Int32 - values: Float64[Shape('n'), ORDER_F] + values: Float64[n] def step( state: sim_state, t: Float64, objective: Callable[[sim_state, Float64], Float64], - scratch: Float64[Shape('nmax'), ORDER_F] + scratch: Float64[nmax] ) -> tuple[Returns["state", sim_state], Returns["score", Float64]]: ... """ ) @@ -87,7 +87,7 @@ def step(state: sim_state) -> Returns["state", sim_state]: ... def test_shape_argument_makes_shape_symbol_ready(): report = _readiness_from_pyi( """ -def fill(n: Int32, x: Float64[Shape('n'), ORDER_F]) -> Returns["x", Float64[Shape('n'), ORDER_F]]: ... +def fill(n: Int32, x: Float64[n]) -> None: ... """ ) @@ -99,7 +99,7 @@ def test_final_constant_needs_literal_value_for_shape_readiness(): """ n: Final[Int32] -def fill(x: Float64[Shape('n'), ORDER_F]) -> Returns["x", Float64[Shape('n'), ORDER_F]]: ... +def fill(x: Float64[n]) -> None: ... """ ) @@ -112,7 +112,7 @@ def test_final_constant_literal_value_makes_shape_ready(): """ n: Final[Int32] = 16 -def fill(x: Float64[Shape('n'), ORDER_F]) -> Returns["x", Float64[Shape('n'), ORDER_F]]: ... +def fill(x: Float64[n]) -> None: ... """ ) @@ -167,7 +167,7 @@ def test_cli_wrap_readiness_loads_completed_pyi(tmp_path: Path): """ n: Final[Int32] = 8 -def fill(x: Float64[Shape('n'), ORDER_F]) -> Returns["x", Float64[Shape('n'), ORDER_F]]: ... +def fill(x: Float64[n]) -> None: ... """, encoding="utf-8", )