Skip to content

feat(slang): recursive structs - #699

Open
hedgar2017 wants to merge 1 commit into
mainfrom
az-slang-recursive-types
Open

hedgar2017 wants to merge 1 commit into
mainfrom
az-slang-recursive-types

Conversation

@hedgar2017

@hedgar2017 hedgar2017 commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Supports recursive structs: those on a cycle through a dynamic array, a mapping, a nested struct or a function type.

@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

Coverage Summary

Crate Line Coverage Function Coverage
solx 🟢 83.6% 🔴 20.0%
solx-benchmark-converter 🔴 0.0% 🔴 0.0%
solx-codegen-evm 🟡 55.3% 🔴 49.2%
solx-compiler-downloader 🔴 0.0% 🔴 0.0%
solx-core 🔴 47.1% 🟡 54.2%
solx-dev 🔴 3.2% 🔴 4.2%
solx-mlir 🔴 50.0% 🔴 45.2%
solx-slang 🔴 22.6% 🔴 30.5%
solx-solc-test-adapter 🔴 1.7% 🔴 2.1%
solx-standard-json 🔴 41.0% 🔴 45.8%
solx-tester 🔴 36.7% 🔴 34.6%
solx-utils 🔴 32.7% 🔴 37.5%
Total 🔴 12.9% 🔴 15.9%

Codecov Report | HTML Report | Workflow Run

@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 793d8f8 to 06722d7 Compare September 8, 2026 08:28
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 06722d7 to ffc030e Compare September 8, 2026 17:15
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from ffc030e to c461566 Compare September 8, 2026 22:16
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch 2 times, most recently from 5cbdd13 to 75cffc7 Compare September 9, 2026 08:17
@hedgar2017
hedgar2017 force-pushed the az-slang-modifiers branch 2 times, most recently from 7697cac to 9f48b04 Compare September 9, 2026 16:04
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 75cffc7 to 36d0404 Compare September 9, 2026 16:04
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch 2 times, most recently from f70d347 to 747aa5e Compare September 16, 2026 20:50
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 747aa5e to 0998552 Compare September 18, 2026 15:28
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 0998552 to d08e50d Compare September 19, 2026 15:24
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from d08e50d to 2f7993d Compare September 19, 2026 21:29
@hedgar2017
hedgar2017 force-pushed the az-slang-modifiers branch 7 times, most recently from f0e294a to 55a3c9a Compare September 24, 2026 15:31
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 2f7993d to 67561e6 Compare September 24, 2026 15:51
Base automatically changed from az-slang-modifiers to main September 28, 2026 14:42
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 54ba97c to ca59040 Compare September 29, 2026 19:14
@hedgar2017 hedgar2017 changed the title feat(slang): recursive types feat(slang): recursive structs Sep 30, 2026
@hedgar2017
hedgar2017 requested a balanced review from Copilot September 30, 2026 17:47
@hedgar2017
hedgar2017 removed the request for review from Copilot September 30, 2026 17:47
@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch 3 times, most recently from e32600b to 08301b8 Compare September 30, 2026 20:18
@hedgar2017
hedgar2017 requested review from a team and a balanced review from Copilot September 30, 2026 20:24
@hedgar2017 hedgar2017 self-assigned this Sep 30, 2026
@hedgar2017
hedgar2017 marked this pull request as ready for review September 30, 2026 20:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Recursive compiler type construction and new unsafe Rust/C++ FFI boundaries warrant final human review.

Review effort: Balanced
Findings: None

What changed in this PR

Adds recursive struct lowering across Slang and MLIR, including cycles through arrays, mappings, nested structs, and function types.

Changes:

  • Introduces identified MLIR struct types with deferred bodies.
  • Tracks recursive type resolution state and data locations.
  • Adds extensive MLIR and runtime regression coverage.
File Description
Cargo.toml Updates the Slang revision.
Cargo.lock Locks updated Slang packages.
solx-utils/​src/​data_location.rs Makes data locations hashable.
solx-slang/​src/​type.rs Resolves recursive structs through identified types.
solx-slang/​src/​scope/​source_unit.rs Tracks recursive resolution state.
solx-slang/​src/​scope/​function.rs Permits mutable type resolution.
solx-slang/​src/​contract/​getter/​mod.rs Passes mutable source-unit scope.
solx-slang/​src/​contract/​function/​expression/​call/​external_callee.rs Supports mutable signature resolution.
solx-mlir/​src/​ir/​type/​mod.rs Exposes identified struct operations.
solx-mlir/​src/​ffi.rs Declares recursive struct FFI functions.
solx-mlir/​dialect_stubs.cpp Implements identified struct FFI wrappers.
solx-mlir/​tests/​lit/​recursive_struct.sol Covers recursive MLIR type shapes and operations.
tests/​solidity/​simple/​recursion/​struct_function_type_cycle.sol Tests function-type recursion behavior.
tests/​solidity/​simple/​recursion/​struct_doubling_chain.sol Tests bounded resolution of branching cycles.
tests/​solidity/​simple/​recursion/​struct_by_value_member_offset.sol Tests recursive storage offsets.
tests/​solidity/​complex/​recursive_struct_per_file/​test.json Configures cross-file runtime assertions.
tests/​solidity/​complex/​recursive_struct_per_file/​first.sol Exercises local and imported recursive structs.
tests/​solidity/​complex/​recursive_struct_per_file/​second.sol Defines the imported recursive struct.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@hedgar2017
hedgar2017 force-pushed the az-slang-recursive-types branch from 08301b8 to 51801e5 Compare September 30, 2026 20:38

@PavelKopyl PavelKopyl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, thanks!

Comment on lines +29 to +31
/// Whether a struct at the current position may stay opaque: behind an array, a mapping or a
/// function reference.
pub breaks_cycle: bool,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd recommend to use a enum instead of plain bool for to improve readability, as this field plays critical role for proper storage layout of recursive structures. For instance, something like:

/// How the position being resolved holds a struct named at it, deciding whether an
/// in-progress recursive struct may stay opaque there. The distinction guards storage
/// layout, not termination: setting a body computes and caches the holder's layout from
/// its members' sizes at that moment.
pub enum Position {
    /// The member is embedded field-by-field, so its size enters the holder's layout: an
    /// in-progress struct met here has its body completed before the holder's is set, and
    /// the suspended frame's later identical `setBody` is a no-op.
    ByValue,
    /// A dynamic array, a mapping or a function reference occupies a fixed footprint
    /// independent of what it refers to, so an in-progress struct stays an opaque
    /// reference: the one place the recursive knot ties.
    Breaking,
}

Mis-handling of break_cycles (in case of a refactoring) can easily lead to text MLIR that look correct, but compiler to a wrong bytecode. That's because we do not print in MLIR dialect a structure layout.
To handle that, I'll force checking for ill formed structures on MLIR level by:

LogicalResult StructType::setBody(ArrayRef<Type> memberTypes) {
  assert(isIdentified() && "cannot set the body of a literal struct");
  for (Type memTy : memberTypes)
    if (StructType opaque = findIllFoundedOpaqueRef(memTy))
      llvm::report_fatal_error("struct body set while by-value member '" +
                               opaque.getName() + "' is still opaque");
  return Base::mutate(memberTypes);
}

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants