Latest release of Solidity compiler Improvements and highlights of new features

New and Improved Solidity Compiler Highlights of Latest Updates and Features

Compiled: Denglian Translation Plan; Source: soliditylang.org

The latest version v0.8.22 of the Solidity compiler has been released. The compiler version 0.8.22 includes a series of language and compiler improvements, such as file-level event definitions, unchecked loop increment optimization, support for importing EVM assembly JSON, and so on.

Important Note

This release deprecates support for EVM versions lower than Constantinople. These older versions have become increasingly difficult to maintain. They are already outdated on the Ethereum mainnet and test networks, and we suspect they are no longer relevant for other networks as well. Complex code paths and solutions slow down the development and testing of features for newer versions, so we hope to stop supporting them in future compiler versions.

New Feature Highlights

Unchecked Loop Increment

Using unchecked arithmetic operations when incrementing loop counters is a common practice for gas optimization. Let’s illustrate this with an example of a loop and a counter variable i:

for (uint i = 0; i < array.length; ++i) { acc += array[i]; // i is not modified by the loop body}

In many cases (detailed conditions below), the comparison operation ensures that i will never reach the maximum value of its type. Therefore, it is safe to assume that the loop will stop before reaching the maximum value. In this case, performing a safe check on the counter would be redundant and a waste of gas. This encourages users to use the lengthy unchecked pattern, wrapping the counter increment in an unchecked arithmetic block inside the loop body:

for (uint i = 0; i < array.length;) { acc += array[i]; unchecked { i++; } // i gets incremented without overflow checks -- less gas used}

Solidity 0.8.22 introduces an overflow check optimization that automatically generates the unchecked arithmetic increment for loop counters. This new optimization eliminates the need for using the lengthy unchecked increment pattern in the loop body like the previous example.

In contrast, the new optimization allows users to return to the original, more readable code without sacrificing gas efficiency.

The new optimization avoids overflow checks under the following precise conditions:

  • The loop condition is a comparison of the form i < ..., where i is a local variable (now referred to as “loop counter”).

  • This comparison must be performed on the same type as the loop counter, i.e., the type on the right must be implicitly convertible to the type of the loop counter, so that the loop counter is not implicitly extended before the comparison.

  • The loop counter must be a local variable of a built-in integer type.

  • The loop expression must be the prefix or postfix increment of the loop counter, i.e., either i++ or ++i.

  • The loop counter must not be modified in the loop condition or loop body.

To clarify the second condition, consider the following code snippet:

for (uint8 i = 0; i < uint16(1000); ++i) {    // loop body}

In this case, i is converted to uint16 before the comparison, and the condition will never be false, so the increment overflow check cannot be removed.

Also note that < is the only comparison operator that triggers this optimization. Operators <= and others are deliberately excluded. Additionally, the operator must be built-in – user-defined < does not qualify.

This optimization is direct and always beneficial, so it is enabled even if the rest of the optimizer is disabled using the settings.optimizer.enabled general setting. It can be explicitly disabled by setting settings.optimizer.details.simpleCounterForLoopUncheckedIncrement to false in the standard JSON input. It cannot be disabled via the command-line interface.

Adjust Yul optimizer to regenerate zero literals

This new version builds on the support of the PUSH0 opcode introduced in version 0.8.20, by extending the Rematerialiser[8] optimization step to always regenerate zero literals instead of storing them as variable references, enabling the use of PUSH0 instead of DUP to reduce gas costs. To ensure effective execution of this operation, the Rematerialiser and UnusedPruner[9] steps have been added to the default optimization sequence of the Yul optimizer.

Add support for importing EVM assembly JSON (experimental)

This new version adds experimental support for importing EVM assembly, providing possibilities for external tools to perform super-optimizations before bytecode generation. The primary purpose of this feature is to define a serialization format for low-level EVM assembly, allowing the generated assembly by the compiler to be exported, modified, and reimported, thus restoring normal compilation processes.

Important note: This is an experimental feature and is currently not suitable for production environments. We are providing this feature in this version for you to try out and provide feedback.

Allow event definitions at the file level

Solidity 0.8.22 allows you to define events at the file level. Now, event definitions can be placed outside the scope of a contract. This provides another option for code organization without the need to artificially wrap events in libraries.

In addition, this version also fixes an issue that caused NatSpec generation to fail when emitting events defined in external contracts or interfaces. In the previous version (0.8.21), the Solidity compiler added support for limited access to events defined in contracts and interfaces that are not inherited by the current contract, but this bug prevented the full use of that feature.

With this bug fix and the ability to define events at the file level, the latest version of Solidity allows users to compile the following example without any errors:

interface I {    event ForeignEvent();}contract C {    event ForeignEvent();}event E();contract D {    function f() public {        // Emitting a foreign event would trigger an internal error on 0.8.21        emit I.ForeignEvent();        emit C.ForeignEvent();        // Emitting a file-level event. New feature.        emit E();    }}

Complete Change Log

Language Features

  • Allow events to be defined at the file level.

Compiler Features

  • Code generator: Remove redundant overflow checks for certain for loops when the counter variable will not overflow.

  • Command-line interface: Add --no-import-callback option to prevent the compiler from loading source files that are not explicitly given in the CLI or standard JSON input.

  • Command-line interface: Add experimental --import-asm-json option to import EVM assembly in the format used with --asm-json.

  • Command-line interface: Use appropriate severity and coloring for error messages generated outside of the compilation pipeline.

  • EVM: Deprecate support for “homestead”, “tangerineWhistle”, “spuriousDragon”, and “byzantium” versions of the EVM.

  • Parser (LianGuairser): Remove experimental error recovery mode (--error-recovery / settings.parserErrorRecovery).

  • SMTChecker: Support user-defined operators.

  • Yul optimizer: Prioritize using zero literals instead of storing zero values in variables if support for PUSH0 exists.

  • Yul optimizer: Run Rematerializer and UnusedPruner steps at the end of the default cleanup sequence.

Bug Fixes

  • Code generator: Fix an issue where the result of code generation via the via-IR code generator would depend on files discovered in the import callback. In some cases, different AST ID assignments would change the order of functions in the internal schedule, resulting in bytecodes that were seemingly different but semantically equivalent.

  • NatSpec: Fix an internal error when requesting docstrings or devdoc for a contract that emits events defined in external contracts or interfaces.

  • SMTChecker: Fix encoding error causing loops to be unrolled after completion.

  • SMTChecker: Fix inconsistency in constant condition check when while or for loops are unrolled before the condition check.

  • Yul optimizer: Fix an issue where decisions on variable replacement were influenced by Yul variable names generated by the compiler during CSE, resulting in bytecodes that were different but equivalent in some cases.

We will continue to update Blocking; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Market

MetaMask Introduces Revolutionary Transaction Routing Feature for Smart Swaps

SMG, backed by ConsenSys, has developed cutting-edge routing technology that allows for intelligent swapping on the p...

Market

TrueUSD Stablecoin: A Rollercoaster Ride to Depegging and Recovery 💰💥

TrueUSD (TUSD), a stablecoin with reputed ties to Justin Sun, has seen a decrease in value since January 15.

Market

Zeitgeist Introduces DLMSR-Based AMM: Revolutionizing Predictions Markets on Blockchain 🚀

Zeitgeist's innovative Dynamic Logarithmic Market Scoring Rule (DLMSR) technology is revolutionizing decentralized pr...

Blockchain

Uniswap: Now on Android, Swapping Like a Master

Uniswap caters to the growing demand from Android users by launching a customized crypto wallet for their devices.

Market

Apple Blocks Cryptocurrency Exchange Apps in India: What You Need to Know 🍎🔒💱

Apple has taken a bold step in India by implementing restrictions on several popular cryptocurrency exchange apps in ...

Market

Blyth Fund’s Bold Move: Embracing Bitcoin and Challenging Convention

In early February, Kole Lee, the esteemed leader of Stanford's Blockchain Club, presented the highly promising opport...