argotorg / argotorg/solidity

Built-in value type conversions in comptime context

Open
#16,420 0 comments 0 reactions 1 assignee Claimed by @matheusaaguiar View on GitHub
medium effort medium impact should have
Dominant language
C++
Stars
25.7k
Forks
6.2k
Avg merge
1d 11h
Merged PRs (30d)
21

Description

## 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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.