-
Notifications
You must be signed in to change notification settings - Fork 6.3k
Support constants in custom storage layout expression #15944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |||||||
| #include <libsolidity/analysis/PostTypeContractLevelChecker.h> | ||||||||
|
|
||||||||
| #include <fmt/format.h> | ||||||||
| #include <libsolidity/analysis/ConstantEvaluator.h> | ||||||||
| #include <libsolidity/ast/AST.h> | ||||||||
| #include <libsolidity/ast/ASTUtils.h> | ||||||||
| #include <libsolidity/ast/TypeProvider.h> | ||||||||
|
|
@@ -101,29 +102,71 @@ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinitio | |||||||
| } | ||||||||
|
|
||||||||
| auto const* baseSlotExpressionType = type(baseSlotExpression); | ||||||||
| auto const* integerType = dynamic_cast<IntegerType const*>(baseSlotExpressionType); | ||||||||
| auto const* rationalType = dynamic_cast<RationalNumberType const*>(baseSlotExpressionType); | ||||||||
| if (!rationalType) | ||||||||
| if ( | ||||||||
| !integerType && | ||||||||
| !rationalType | ||||||||
| ) | ||||||||
| { | ||||||||
| std::string errorMsg = "The base slot of the storage layout must evaluate to an integer"; | ||||||||
| if (dynamic_cast<AddressType const*>(baseSlotExpressionType)) | ||||||||
| errorMsg += " (the type is 'address' instead)"; | ||||||||
| else if (auto const* fixedBytesType = dynamic_cast<FixedBytesType const*>(baseSlotExpressionType)) | ||||||||
| errorMsg += fmt::format( | ||||||||
| " (the type is 'bytes{}' instead)", | ||||||||
| fixedBytesType->numBytes() | ||||||||
| ) | ||||||||
| ; | ||||||||
|
Comment on lines
+119
to
+120
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Same below. |
||||||||
| else if (auto const* userDefinedType = dynamic_cast<UserDefinedValueType const*>(baseSlotExpressionType)) | ||||||||
| errorMsg += fmt::format( | ||||||||
| " (the type is '{}' instead)", | ||||||||
| userDefinedType->canonicalName() | ||||||||
| ) | ||||||||
| ; | ||||||||
| errorMsg += "."; | ||||||||
|
|
||||||||
| m_errorReporter.typeError( | ||||||||
| 6396_error, | ||||||||
| 1763_error, | ||||||||
| baseSlotExpression.location(), | ||||||||
| "The base slot of the storage layout must evaluate to a rational number." | ||||||||
| errorMsg | ||||||||
| ); | ||||||||
| return; | ||||||||
| } | ||||||||
|
|
||||||||
| if (rationalType->isFractional()) | ||||||||
| rational baseSlotRationalValue; | ||||||||
| if (integerType) | ||||||||
| { | ||||||||
| m_errorReporter.typeError( | ||||||||
| 1763_error, | ||||||||
| baseSlotExpression.location(), | ||||||||
| "The base slot of the storage layout must evaluate to an integer." | ||||||||
| ); | ||||||||
| return; | ||||||||
| std::optional<ConstantEvaluator::TypedRational> typedRational = ConstantEvaluator::evaluate(m_errorReporter, baseSlotExpression); | ||||||||
| if (!typedRational) | ||||||||
| { | ||||||||
| m_errorReporter.typeError( | ||||||||
| 1505_error, | ||||||||
| baseSlotExpression.location(), | ||||||||
| "The base slot expression contains elements that are not yet supported " | ||||||||
| "by the internal constant evaluator and therefore cannot be evaluated at compilation time." | ||||||||
| ); | ||||||||
| return; | ||||||||
| } | ||||||||
| baseSlotRationalValue = typedRational->value; | ||||||||
| } | ||||||||
| else | ||||||||
| { | ||||||||
| solAssert(rationalType); | ||||||||
| if (rationalType->isFractional()) | ||||||||
matheusaaguiar marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| { | ||||||||
| m_errorReporter.typeError( | ||||||||
| ErrorId{1763}, | ||||||||
| baseSlotExpression.location(), | ||||||||
| "The base slot of the storage layout must evaluate to an integer." | ||||||||
| ); | ||||||||
| return; | ||||||||
| } | ||||||||
| baseSlotRationalValue = rationalType->value(); | ||||||||
| } | ||||||||
| solAssert(rationalType->value().denominator() == 1); | ||||||||
|
|
||||||||
| bigint baseSlot = rationalType->value().numerator(); | ||||||||
| solAssert(baseSlotRationalValue.denominator() == 1); | ||||||||
| bigint baseSlot = baseSlotRationalValue.numerator(); | ||||||||
| if (!(0 <= baseSlot && baseSlot <= std::numeric_limits<u256>::max())) | ||||||||
| { | ||||||||
| m_errorReporter.typeError( | ||||||||
|
|
@@ -137,7 +180,18 @@ void PostTypeContractLevelChecker::checkStorageLayoutSpecifier(ContractDefinitio | |||||||
| return; | ||||||||
| } | ||||||||
|
|
||||||||
| solAssert(baseSlotExpressionType->isImplicitlyConvertibleTo(*TypeProvider::uint256())); | ||||||||
| if (!baseSlotExpressionType->isImplicitlyConvertibleTo(*TypeProvider::uint256())) | ||||||||
| { | ||||||||
| m_errorReporter.typeError( | ||||||||
| 1481_error, | ||||||||
| baseSlotExpression.location(), | ||||||||
| fmt::format( | ||||||||
| "Base slot expression of type '{}' is not convertible to uint256.", | ||||||||
| baseSlotExpressionType->humanReadableName() | ||||||||
| ) | ||||||||
| ); | ||||||||
| return; | ||||||||
| } | ||||||||
| storageLayoutSpecifier->annotation().baseSlot = u256(baseSlot); | ||||||||
|
|
||||||||
| bigint size = contractStorageSizeUpperBound(_contract, VariableDeclaration::Location::Unspecified); | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at abi.decode(abi.encode(42), (uint)) {} | ||
| // ---- | ||
| // TypeError 6396: (21-55): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (21-55): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at address(0x1234) {} | ||
| // ---- | ||
| // TypeError 6396: (21-36): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-36): The base slot of the storage layout must evaluate to an integer (the type is 'address' instead). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| address constant x = 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF; | ||
| contract C layout at x {} | ||
| // ---- | ||
| // TypeError 1763: (86-87): The base slot of the storage layout must evaluate to an integer (the type is 'address' instead). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at [1, 2, 3] {} | ||
| // ---- | ||
| // TypeError 6396: (21-30): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-30): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at ~uint(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {} | ||
| // ---- | ||
| // TypeError 6396: (21-94): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (21-94): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| bool constant x = false; | ||
| contract C layout at x {} | ||
| // ---- | ||
| // TypeError 1763: (46-47): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at true {} | ||
| // ---- | ||
| // TypeError 6396: (21-25): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-25): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| bytes32 constant CONST1 = "12345"; | ||
| contract A layout at CONST1 {} | ||
| contract C layout at CONST1[1] {} | ||
| // ---- | ||
| // TypeError 1763: (56-62): The base slot of the storage layout must evaluate to an integer (the type is 'bytes32' instead). | ||
| // TypeError 1763: (87-96): The base slot of the storage layout must evaluate to an integer (the type is 'bytes1' instead). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| uint constant N = 100; | ||
| contract C layout at N / ~N {} | ||
| // ---- | ||
| // TypeError 6396: (44-50): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 3667: (48-50): Arithmetic error when computing constant value. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| uint constant N = 100; | ||
| contract C layout at N / 0 {} | ||
| // ---- | ||
| // TypeError 6396: (44-49): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (44-49): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find this message a bit too vague and a bit too verbose. I'm pretty sure we'll never support division by 0 in the constant evaluator (or otherwise), but then, Eh, you know what, the message is good as as, ignore my rambling.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. This should just say that you can't divide by zero at compilation time. We should adjust For the purpose of this PR it's good enough though. We should merge it and fix that separately. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| ==== Source: A ==== | ||
| uint constant x = 77; | ||
|
|
||
| ==== Source: B ==== | ||
| import "A" as M; | ||
| contract C layout at M.x{ } | ||
| // ---- | ||
| // TypeError 1505: (B:38-41): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| uint constant x = addmod(10, 2, 8); | ||
| uint constant y = mulmod(10, 2, 8); | ||
| contract C layout at x {} | ||
| contract D layout at y {} | ||
| // ---- | ||
| // TypeError 1505: (93-94): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. | ||
| // TypeError 1505: (119-120): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| uint constant x = uint(42); | ||
| contract C layout at x {} | ||
| // ---- | ||
| // TypeError 1505: (49-50): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| uint constant x = 42; | ||
| uint constant y = x * 2; | ||
| contract C layout at y {} | ||
| // ---- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| uint constant x = ((2**5 + 2**5) * (2 ** 10 + 1 << 1)) % 2**256 - 1; | ||
| contract C layout at x {} | ||
| // ---- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| uint constant CONST1 = 1.23e100 / 2e50; | ||
| contract C layout at CONST1 {} | ||
| uint constant CONST2 = 2**256 * (500e-3); | ||
| contract D layout at CONST2 {} | ||
| uint constant CONST3 = (2**255 * 2) - (2**256 + 1) + 1; | ||
| contract E layout at CONST3 {} | ||
| // ---- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF {} | ||
| // ---- | ||
| // TypeError 6396: (21-63): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-63): The base slot of the storage layout must evaluate to an integer (the type is 'address' instead). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at hex"616263" {} | ||
| // ---- | ||
| // TypeError 6396: (21-32): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-32): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract at layout at uint40(bytes5(hex"0011223344")) { } | ||
| // ---- | ||
| // TypeError 6396: (22-53): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (22-53): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| function f() returns (uint) { | ||
| return 2; | ||
| } | ||
|
|
||
| contract A { | ||
| address immutable a = 0x0000000000000000000000000000000000000001; | ||
| uint immutable x = 1; // considered pure by the compiler (initialized with a literal) | ||
| uint immutable y = f(); // considered not pure by the compiler (initialized with a function) | ||
| } | ||
|
|
||
| contract B is A layout at A.a { } | ||
| contract C is A layout at A.x { } | ||
| contract D is A layout at A.y { } | ||
| // ---- | ||
| // TypeError 1139: (346-349): The base slot of the storage layout must be a compile-time constant expression. | ||
| // TypeError 1139: (380-383): The base slot of the storage layout must be a compile-time constant expression. | ||
| // TypeError 1139: (414-417): The base slot of the storage layout must be a compile-time constant expression. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| int constant x = -42; | ||
| int constant y = 64; | ||
| contract C layout at x {} | ||
| contract D layout at y {} | ||
| // ---- | ||
| // TypeError 6753: (64-65): The base slot of the storage layout evaluates to -42, which is outside the range of type uint256. | ||
| // TypeError 1481: (90-91): Base slot expression of type 'int256' is not convertible to uint256. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| bytes32 constant b = "bytes"; | ||
| contract A layout at b[1] {} | ||
| // ---- | ||
| // TypeError 6396: (51-55): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (51-55): The base slot of the storage layout must evaluate to an integer (the type is 'bytes1' instead). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| uint constant X = 42; | ||
| contract C layout at 0xffff * (50 - X) { } | ||
| // ---- | ||
| // TypeError 6396: (43-60): The base slot of the storage layout must evaluate to a rational number. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| contract A {} | ||
| contract C layout at A(address(0x1234)) {} | ||
| // ---- | ||
| // TypeError 6396: (35-53): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (35-53): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract A layout at uint {} | ||
| // ---- | ||
| // TypeError 6396: (21-25): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-25): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract at layout at uint(42) { } | ||
| // ---- | ||
| // TypeError 6396: (22-30): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (22-30): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| contract A layout at addmod(1, 2, 3) {} | ||
| contract B layout at mulmod(3, 2, 1) {} | ||
| // ---- | ||
| // TypeError 6396: (21-36): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 6396: (61-76): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (21-36): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. | ||
| // TypeError 1505: (61-76): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| contract A layout at 42.0 {} | ||
| contract B layout at 2.5e10 {} | ||
| contract C layout at 12/3 {} | ||
| // ---- |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at "MyLayoutBase" {} | ||
| // ---- | ||
| // TypeError 6396: (21-35): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-35): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| contract A layout at true ? 42 : 94 {} | ||
| contract B layout at 255 + (true ? 1 : 0) {} | ||
| // ---- | ||
| // TypeError 6396: (21-35): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 6396: (60-80): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (21-35): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. | ||
| // TypeError 1505: (60-80): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract C layout at (1, 2, 3) {} | ||
| // ---- | ||
| // TypeError 6396: (21-30): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (21-30): The base slot of the storage layout must evaluate to an integer. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| contract at layout at type(uint).max { } | ||
| // ---- | ||
| // TypeError 6396: (22-36): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (22-36): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| type MyUint is uint128; | ||
| contract C layout at MyUint.wrap(42) {} | ||
| // ---- | ||
| // TypeError 6396: (45-60): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1763: (45-60): The base slot of the storage layout must evaluate to an integer (the type is 'MyUint' instead). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| contract A layout at [1, 2, 3][0] {} | ||
| contract B layout at 255 + [1, 2, 3][0] {} | ||
| // ---- | ||
| // TypeError 6396: (21-33): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 6396: (58-76): The base slot of the storage layout must evaluate to a rational number. | ||
| // TypeError 1505: (21-33): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. | ||
| // TypeError 1505: (58-76): The base slot expression contains elements that are not yet supported by the internal constant evaluator and therefore cannot be evaluated at compilation time. |
Uh oh!
There was an error while loading. Please reload this page.