Skip to content

Test coverage for constants and literal expressions with type smaller than uint256#16456

Open
matheusaaguiar wants to merge 1 commit intodevelopfrom
storageLayoutTests
Open

Test coverage for constants and literal expressions with type smaller than uint256#16456
matheusaaguiar wants to merge 1 commit intodevelopfrom
storageLayoutTests

Conversation

@matheusaaguiar
Copy link
Contributor

Suggested in #15968 (comment).

@github-actions
Copy link

This pull request is stale because it has been open for 14 days with no activity.
It will be closed in 7 days unless the stale label is removed.

@github-actions github-actions bot added the stale The issue/PR was marked as stale because it has been open for too long. label Feb 25, 2026
@cameel cameel removed the stale The issue/PR was marked as stale because it has been open for too long. label Feb 25, 2026
Comment on lines +4 to +5
uint[LEN + 256] array2;
uint[LEN * 2] array3; // Error, outside of constant and literal range
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I missing something or should both of these overflow? In either case the result is outside of uint8 range.

Copy link
Collaborator

@cameel cameel Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the literal gets converted to the smallest integer type that can hold it rather than the type of the limited-precision operand? I did not expect that.

Looks like we do have that (somewhat) documented under Rational and Integer Literals. I think we should at some point extend these docs to have more than just a single note for such conversions and explain the rules properly.

@@ -0,0 +1,5 @@
uint8 constant base = 2;
contract A layout at base + 256 {}
contract B layout at base + 255 {} // Error, outside of range of constant and literal
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bizarre. Also the fact that you cannot fix it with an explicit type conversion, but you can use a unintuitive workaround like base + 256 - 1 to force a bigger type and make it pass (I'd add that to the test BTW).

We really need #16420.

@@ -0,0 +1,13 @@
uint8 constant base = 255;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use capitals for constant names (e.g. BASE). This makes tests easier to read because you see at a glance what is what.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the layout_specification_ prefix in these tests? I see that in most cases existing tests for layout specifier do not have it. Also "specification" sounds weird in this context.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need coverage also for underflow in multiplication. Consider this:

uint8 constant UNSIGNED2 = 2;
int8 constant SIGNED2 = 2;

contract S layout at SIGNED2 * -1 * -1 {  // Error: Base slot expression of type 'int8' is not convertible to uint256.
    uint[SIGNED2 * -1 * -1] a;            // OK
    uint[2 * -1 * -1] b;                  // OK
}

contract U layout at UNSIGNED2 * -1 * -1 { // Built-in binary operator * cannot be applied to types uint8 and int_const -1.
    uint[UNSIGNED2 * -1 * -1] a;           // Error: Operator * not compatible with types uint8 and int_const -1
    uint[2 * -1 * -1] b;                   // OK
}

And this shows that we were indeed missing some coverage. We have a discrepancy between layouts and arrays here. Fortunately this is not a bug in how underflow is handled but rather the fact that we require the layout expression to be unsigned, even if the value is signed.

I think the two should work the same way. IMO it would be better for both to only accept unsigned, but changing that for arrays would be breaking. We have to change it the other way then - allow signed types in the specifier.

@@ -0,0 +1,4 @@
uint constant base = 2**256 - 1;
contract C layout at base + 1 {}
Copy link
Collaborator

@cameel cameel Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need coverage for intermediate overflows and underflows:

  • X + 1 - 1
  • Y - 4 + 4
  • X * 2 / 2
  • X**2 / 255
  • -~Y

where X = 255 and Y = 2 are both uint8 constants.

In unlimited precision all of these expressions would be valid.

Would not hurt to have these intermediate overflows covered for uint256 as well unless this is already tested somewhere.

@@ -0,0 +1,4 @@
uint constant base = 2**256 - 1;
contract C layout at base + 1 {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also have a test verifying that division on constants is performed in limited precision and therefore truncates:

  • ONE / 2 where ONE = 1 is an integer constant

This would be an error in unlimited precision.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should cover shifts as well.

  • SIXTEEN >> 5
  • SIXTEEN << 5

where SIXTEEN = 16 is a uint8 constant.

None of these should overflow, neither in limited nor unlimited precision.

I checked this and the second one actually seems to be a buggy, because it produces an error: Error: Arithmetic error when computing constant value. This is inconsistent with our runtime calculations - if you assign the same exact expression to a variable it will not revert at runtime.

@cameel cameel mentioned this pull request Mar 2, 2026
@github-actions github-actions bot added the stale The issue/PR was marked as stale because it has been open for too long. label Mar 13, 2026
@matheusaaguiar matheusaaguiar removed the stale The issue/PR was marked as stale because it has been open for too long. label Mar 13, 2026
@argotorg argotorg deleted a comment from github-actions bot Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants