Yul identifiers inconsistently treat builtins/keywords
For example, yul-variable-declaration specifies one or more yul-identifiers on the left hand side; yul-identifier is a separate rule from yul-evm-builtin, so I assume in practice this means that yul-identifier excludes all evm builtins. However, yul-path (part of yul-expression) specifies only yul-identifier as the first segment.
The following code is allowed:
contract C {
uint number;
function f() external {
assembly {
// whereas declaring 'number' inside is not
// let number := 0
sstore(number.slot, 1)
}
}
}
I believe the implementation is correct, but the grammar is missing this nuance.
Encountered in Optimism: https://github.com/ethereum-optimism/optimism/blob/5229fa195415136e5589787c5850101d06b15748/packages/contracts-bedrock/src/L2/L1Block.sol#L169-L170
I believe what's going on is that number and number.number are both identifiers, since . in the Yul parser is not treated specially. So the yul-path rules are not implemented in the parser. All of the following are allowed (--stop-after parsing):
contract C {
uint number;
function f() external {
assembly {
number.slot := 69
number.slot, number.slot := some_call()
number.number := 69
number.number, number.number := some_call()
sstore(number.slot, 1)
pop(number())
}
}
}