#16420·solidity

Built-in value type conversions in comptime context

Author: cameelCreated Jan 26, 2026Updated Sep 9, 2026
Labelsmedium effortmedium impactshould have

Abstract

Implement explicit type conversions between value types in comptime context. This can be done in stages:

  • (1) Conversions to uint
  • (2) Conversion between any integer types
  • (3) All conversions between integers, fixed bytes and addresses

Note: support for user-defined value types (contracts, enums, UDVTs) is out of scope of this issue. It is also fine to leave out bool since there are no conversions allowed from booleans to other types and the ternary operator is not allowed in comptime context.

Motivation

Currently type conversions are only allowed in runtime context, even if the argument is a compile-time constant such as a literal. In comptime context (array sizing, layout base expression) they result in an error.

We already support finite-precision arithmetic in comptime context through constants (with overflow/underflow reported as compilation errors), so adding type conversions to the mix should be relatively straighforward, not requiring the full implementation of #3157.

The goal of the initial implementation is to support converting bytes32 values produced by keccak256() to uint, for which stage 1 is enough.

Specification

  • Stage 1: evaluate explicit uint() conversions in comptime context.
  • Stage 2: evaluate explicit int(), uint8()..uint248(), int8()..int248() conversions in comptime context.
  • Stage 3: evaluate explicit bytes1()..bytes32(), address(), payable() conversions in comptime context.

Conversions should produce limited-precision values, just like constants currently do. Overflows/underflows in calculation should result in a compile-time error. Note that this is not affected by unchecked blocks, as currently those never affect comptime context.

This change should not affect runtime context. Outside of base layout specifiers or array sizes, the explicit conversions should still be evaluated at runtime. In particular overflows/underflows should still be a runtime check.

Examples

Stage 1

  • Conversion from a literal to uint:
    solidity
    contract C layout at uint(123) + 456 {}
    contract C layout at uint(0x1111111111222222222233333333334444444444) {} // address literal
    contract C layout at uint(2**256) {} // Compilation error
    contract C layout at uint(-1) {}     // Compilation error
  • Conversion from a compile-time builtin returning bytes32:
    solidity
    contract C layout at uint(keccak256("abc")) + 10 {}
    • Note: this will only be possible in combination with #16421
  • Conversion from a constant initialized with a comptime expression:
    solidity
    bytes32 constant X = hex"12345678";
    bytes32 constant Y = ~X;
    ...
    contract C layout at uint(Y) {}
  • Conversion within constants:
    solidity
    uint constant X = uint(123);
    ...
    contract C layout at X {}
  • Overflow in arithmetic with unlimited-precision values:
    solidity
    contract C layout at 2**255 * 2 {}
    contract C layout at 2**255 * uint(2) {} // Compilation error
  • Chained conversions
    solidity
    contract C layout at uint(uint(1)) {}

Stage 2

  • Shorter integer types
    solidity
    contract C layout at uint8(1) + 2 {}
    contract C layout at uint8(256) {}   // Compilation error
    contract C layout at uint8(-1) {}    // Compilation error
  • Signed integer types
    solidity
    contract C layout at uint(int(-1)) {}
  • Chained conversions
    solidity
    contract C layout at uint(int(int8(-1))) {}

Stage 3

  • Conversions from/to non-integer value types
    solidity
    contract C layout at uint160(address(123)) {}
    contract C layout at uint160(payable(123)) {}
    contract C layout at uint32(bytes4("abcd")) {}
    contract C layout at uint(bytes32(bytes4(uint32(123)))) {}
  • Conversion from a compile-time builtin:
    solidity
    contract C layout at uint(bytes32(erc2701("abc"))) {}
    • Note: this depends on #15968.

Backwards Compatibility

Fully backwards-compatible.