feat(slang): emit every contract in a source unit#460
Open
hedgar2017 wants to merge 1 commit into
Open
Conversation
5a6eff0 to
7fe873f
Compare
The Slang frontend was processing only the first contract per source unit, silently dropping the rest of the file. Tests targeting a non-first contract failed with `selector not found` because the contract was never registered, and any future cross-contract lowering would have nothing to point at on the right-hand side of `new B()` or `B(addr).method()`. `AstEmitter::emit` now takes a single `ContractDefinition` and is invoked once per concrete contract, with a fresh `solx_mlir::Context` per contract. Each contract gets its own deploy + runtime MLIR module pair through the existing `finalize_module` path and lands in `output.contracts[file_id][contract_name]` independently. Abstract contracts are skipped — their unimplemented members would crash the emitter, and derived concrete contracts continue to emit on their own.
7fe873f to
f579275
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes a Slang-frontend correctness gap where only the first contract in each Solidity source unit was lowered, by iterating over all concrete contracts and emitting each into output.contracts[file_id][contract_name] independently (with a fresh solx_mlir::Context per contract).
Changes:
- Iterate through
source_unit.contracts()and emit each non-abstract contract instead of only the first one. - Refactor
AstEmitter::emitto operate on a singleContractDefinition(instead of aSourceUnit) and return(contract_name, method_identifiers)directly. - Create/insert per-contract standard-json
Contractoutputs (MLIR stages + method identifiers) under the correct file/contract keys.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
solx-slang/src/slang/mod.rs |
Emit and register outputs for each concrete contract in a source unit rather than only the first. |
solx-slang/src/ast/mod.rs |
Change the emitter API to lower exactly one contract definition at a time. |
Comment on lines
+180
to
+206
| let runtime_code_identifier = format!( | ||
| "{contract_name}{}", | ||
| solx_codegen_evm::DEPLOYED_OBJECT_SUFFIX | ||
| ); | ||
| let capture_sol_dialect = input_json.settings.output_selection.check_selection( | ||
| file_identifier, | ||
| Some(contract_name.as_str()), | ||
| solx_standard_json::InputSelector::MLIR, | ||
| ); | ||
| let mlir_stages = | ||
| context.finalize_module(&runtime_code_identifier, capture_sol_dialect)?; | ||
|
|
||
| output | ||
| .contracts | ||
| .entry(file_identifier.to_string()) | ||
| .or_default() | ||
| .insert( | ||
| contract_name, | ||
| solx_standard_json::output::contract::Contract { | ||
| mlir: Some(mlir_stages), | ||
| evm: Some(solx_standard_json::output::contract::evm::EVM { | ||
| method_identifiers: Some(method_identifiers), | ||
| ..Default::default() | ||
| }), | ||
| ..Default::default() | ||
| }, | ||
| ); |
abinavpp
reviewed
Jun 1, 2026
abinavpp
left a comment
Contributor
There was a problem hiding this comment.
can we add a lit test with 2 contracts?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Slang frontend was processing only the first contract per source unit, silently dropping the rest of the file. Tests targeting a non-first contract failed with
selector not foundbecause the contract was never registered, and any future cross-contract lowering would have nothing to point at on the right-hand side ofnew B()orB(addr).method().AstEmitter::emitnow takes a singleContractDefinitionand is invoked once per concrete contract in the source unit, with a freshsolx_mlir::Contextper contract. Each contract gets its own deploy + runtime MLIR module pair through the existingfinalize_modulepath and lands inoutput.contracts[file_id][contract_name]independently. Abstract contracts are skipped — their unimplemented members would crash the emitter, and derived concrete contracts continue to emit on their own.Test delta on
tests/solidity/simple -O M3B3is zero (1903 passed, 4 failed, 305 invalid both with and without this change). Every multi-contract test in that suite also depends on contract creation, external calls, or inheritance — none of which are wired in the Slang pipeline yet. This change is a prerequisite for those: without it, the second contract's MLIR is never produced, so even after loweringnew B()andb.method()the call sites would have nothing to bind to.solx-soliditysemantic tests are unaffected — they exercise the solc-based frontend, not Slang.Direct verification with a synthetic two-contract source confirms both contracts now appear in
output.contracts[file_id]where previously only the first did.