Skip to content

fix(slang): type a pushed reference element as its own place - #637

Open
hedgar2017 wants to merge 2 commits into
main-slangfrom
fix-slang-push-reference-element
Open

fix(slang): type a pushed reference element as its own place#637
hedgar2017 wants to merge 2 commits into
main-slangfrom
fix-slang-push-reference-element

Conversation

@hedgar2017

@hedgar2017 hedgar2017 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Fixes the array push lowering fabricating !sol.ptr<element, Storage> slots for reference-typed elements, against the Sol_GepOp rule that a reference in storage is its own place.

  • s.push().a = 1 no longer crashes the Sol pass pipeline: the slot type comes from SourceUnitScope::pointer, the rule's owner, so a struct element's slot is the struct itself and the member gep lowers.
  • nested.push().push(2) no longer crashes: the inner push sees the array place instead of a pointer to it.
  • s.push(Y(1, 2)) was silently mis-lowered — a single-word store of the memory pointer into a two-slot struct; it now assigns through Place::assign and takes the sol.copy branch.
  • The place path (push() = v) reads the element back off the slot alone — the pointee where the slot points at one, the slot itself otherwise — inverting SourceUnitScope::pointer rather than consulting the binder a second time. Type::is_pointer is the sol::PointerType predicate this needs.

Three new dual-oracle cases join array_string_ops.sol (pushStructMember, pushStructValue, pushNested). Tester: 8792 → 8825 passing against the same base, zero regressed files. Pre-existing and untouched: push in value position (uint y = arr.push();, push_no_args_1d/2d).

@hedgar2017 hedgar2017 added the ci:slang Trigger slang unit tests on PR label Aug 7, 2026
@hedgar2017
hedgar2017 requested review from a team, abinavpp, Copilot and ggiraldez August 7, 2026 16:37
.expect("an array push in place position yields the new element's slot");
(Place::from(slot), slot.r#type().element_type(0))
let slang_type = node.get_type().expect("the binder types every expression");
let element_type = if slang_type.is_reference_type() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure about having 2 sources of truths here.
@abinavpp @ggiraldez do you think we should unify it somehow?

@hedgar2017 hedgar2017 Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@abinavpp I've tried to drop sol.byte in #638, but it looks like it's deeply woven into LLVM.
Please let me know if we can rework the dialect and drop it.

For the context, it looks like byte is an alias that is not valid in Solidity 0.8, and Slang doesn't emit it anywhere.

@abinavpp abinavpp Aug 10, 2026

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.

Re the two sources: agree - derive it from the push result's type alone (ptr -> pointee, else the type itself is the element); needs only an is_pointer FFI predicate.

Re sol.byte: keep it - it's !sol.string's element type and carries packed-byte place semantics bytes1 doesn't (mstore8 stores, masked loads, never-reverting cleanup); value-level casts between the two are no-ops.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@abinavpp thanks! Fixed and closed #638. Please check.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes Slang→Sol dialect lowering for array.push when the element type is reference-typed in Storage/CallData, aligning with the dialect rule that such references are their own place (not !sol.ptr<...>). This prevents crashes in the Sol pass pipeline and corrects previously incorrect stores for struct-valued pushes.

Changes:

  • Derive the pushed slot type via SourceUnitScope::pointer (through scope.pointer_type) so reference-typed elements in storage yield their own place type instead of a fabricated pointer.
  • Switch push(value) lowering from store(converted(..)) to Place::assign(..) so reference-typed assignments correctly lower to sol.copy when appropriate.
  • Add lit coverage for struct-member assignment, struct-value push (copy), and nested array pushes.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
solx-slang/src/contract/function/expression/call/mod.rs Fixes .push slot typing for reference elements and uses Place::assign to correctly handle copy-vs-store semantics (incl. bytes-like string literal folding).
solx-mlir/tests/lit/array_string_ops.sol Adds regression tests validating correct sol.push result types and expected sol.gep / sol.copy / nested push lowering.

@github-actions

github-actions Bot commented Aug 7, 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 🔴 25.5% 🔴 13.5%
solx-compiler-downloader 🔴 0.0% 🔴 0.0%
solx-core 🔴 38.6% 🔴 47.6%
solx-dev 🔴 2.4% 🔴 3.0%
solx-evm-assembly 🔴 0.0% 🔴 0.0%
solx-mlir 🟡 60.4% 🟡 57.9%
solx-slang 🔴 25.2% 🔴 32.0%
solx-solc-test-adapter 🔴 1.7% 🔴 2.1%
solx-standard-json 🔴 42.8% 🔴 47.7%
solx-tester 🔴 36.5% 🔴 34.3%
solx-utils 🔴 29.7% 🔴 33.3%
solx-yul 🔴 0.0% 🔴 0.0%
Total 🔴 10.9% 🔴 13.1%

Codecov Report | HTML Report | Workflow Run

The array push lowering built every new slot as `!sol.ptr<element, Storage>`,
violating the `Sol_GepOp` rule that a reference-typed element in storage is
its own place: a struct element's member write crashed the Sol pass pipeline,
a nested array's inner push crashed it too, and `push(value)` of a struct
wrote the memory pointer into the slot as one word. The slot type now comes
from `SourceUnitScope::pointer`, the rule's owner; `push(value)` assigns
through `Place::assign`, taking the copy branch for aggregates; and the place
path reads the element back off the slot, the pointee where the slot points
at one.
@hedgar2017
hedgar2017 force-pushed the fix-slang-push-reference-element branch from 642013e to 2dd78a7 Compare August 10, 2026 12:52

@abinavpp abinavpp 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, thank you!

@hedgar2017
hedgar2017 enabled auto-merge August 11, 2026 14:57
@hedgar2017
hedgar2017 disabled auto-merge August 11, 2026 14:58
@hedgar2017 hedgar2017 self-assigned this Aug 11, 2026
@hedgar2017
hedgar2017 enabled auto-merge August 11, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:slang Trigger slang unit tests on PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants