fix: resolve solidity pragma versions across imports#163
Conversation
670f559 to
2d28ca1
Compare
2d28ca1 to
86c6dfe
Compare
|
Follow-up on whether we can keep using I checked this against Solidity's The key Solidity rule is that after comparing only the version levels present in the pragma expression, if the numeric comparison ties and the candidate version has prerelease metadata, Solidity treats the candidate as lower than the compared release. That means Solidity accepts cases such as:
I also checked whether So the current approach is intentional: still use |
|
Additional context on
Some published solc semver strings either get normalized into a different PEP 440 spelling or cannot be represented by So I also prototyped a variant that removes the direct Prototype validation: I also smoke-tested the prototype against the published My read from the prototype: this functionality does not cleanly belong in
If dependency avoidance is important, option 2 looks feasible and fairly small. The important part either way is not to model all solc versions as |
Motivation
Solidity validates version pragmas across every source compiled in a single solc invocation, including imported files. Ape installs or selects the compiler before invoking solc, so choosing from only the requested root source can pick a compiler version that an imported source rejects.
Ape also needs to understand Solidity pragma expressions before it can safely preselect a compiler. The previous parser handled simple constraints, but did not cover the full Solidity semver matcher behavior used by solc, including hyphen ranges, wildcards, tilde/caret ranges, quoted ranges, OR alternatives, adjacent constraints, and Solidity's prerelease comparison rules.
Summary
SolidityVersionSpecifier, which mirrors Solidity's semver matcher instead of delegating range matching to Python PEP 440 specifiers or npm range semantics.packaging.version.Versionas Ape's compiler-version type for stable py-solc-x compiler versions, while preserving exact Solidity semver parsing for pragma candidates with a tiny localSoliditySemVervalue.<,<=, wildcard, hyphen, and partial-version constraints differently from npm range semantics.semantic-versionas a direct dependency; Solidity semver parsing and matching are local to this plugin.>=3.10,<4support range, including Python 3.14.Why Not
packagingOrNpmSpecSolidity pragmas are semver match expressions, not PEP 440 specifiers.
packaging.version.Versionis still appropriate for Ape's stable compiler-version flow, but it cannot faithfully represent every solc semver string. Some published solc versions are normalized into different PEP 440 spellings, and nightly-style prereleases can be invalid PEP 440 entirely.Solidity pragmas also look npm-like, but solc's matcher is not equivalent to
semantic_version.NpmSpec. In Solidity'sSemVerHandler, candidate prerelease versions compare as lower than the release when the compared numeric levels tie. That accepts cases such as:NpmSpecrejects some of these, and forcing always-on prerelease matching creates false positives for Solidity caret ranges, such as accepting prereleases that solc rejects. This PR therefore owns both the small Solidity semver value parser and the Solidity-specific range matcher locally.References
parsePragmaVersion()checks the current compiler version andparsePragmaDirective()feeds Solidity pragma tokens into that check.Validation
uv run black --check ape_solidity/_utils.pyuv run isort --check-only ape_solidity/_utils.pyuv run flake8 ape_solidity/_utils.pyuv run mypy .uv run pytest tests/test_compiler.py -k 'pragma_spec or get_version_map'(164 passedon Python 3.12.12)longVersionstrings, generated 1,237 pragma expressions, and ran 2,495,029 matcher comparisons without parser errors.Note: a full local
tests/test_compiler.pyrun was previously blocked by the existing local dependency fixture/remapping setup for Safe contracts, but the live PR checks have been passing.