From 73b9da30c14eb2967034962de62c32d429199f2c Mon Sep 17 00:00:00 2001 From: Matheus Aguiar Date: Sun, 18 May 2025 13:00:17 -0300 Subject: [PATCH 1/2] Add and update tests --- .../array/length/constant_member_access.sol | 10 ++++++++++ .../constantEvaluator/member_access.sol | 9 +++++++++ .../member_access_library_constant.sol | 7 +++++++ .../member_access_module_constant.sol | 8 ++++++++ .../member_access_module_contract_constant.sol | 10 ++++++++++ .../member_access_non_constant.sol | 8 ++++++++ ...constant_variables_as_static_array_length.sol | 11 ++++------- ...constant_with_dependencies_as_array_sizes.sol | 16 ++++++++-------- 8 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 test/libsolidity/syntaxTests/array/length/constant_member_access.sol create mode 100644 test/libsolidity/syntaxTests/constantEvaluator/member_access.sol create mode 100644 test/libsolidity/syntaxTests/constantEvaluator/member_access_library_constant.sol create mode 100644 test/libsolidity/syntaxTests/constantEvaluator/member_access_module_constant.sol create mode 100644 test/libsolidity/syntaxTests/constantEvaluator/member_access_module_contract_constant.sol create mode 100644 test/libsolidity/syntaxTests/constantEvaluator/member_access_non_constant.sol diff --git a/test/libsolidity/syntaxTests/array/length/constant_member_access.sol b/test/libsolidity/syntaxTests/array/length/constant_member_access.sol new file mode 100644 index 000000000000..d6343b8c07b1 --- /dev/null +++ b/test/libsolidity/syntaxTests/array/length/constant_member_access.sol @@ -0,0 +1,10 @@ +contract A { + uint constant INHERITED = 42; +} + +contract C is A { + uint constant CONST = 64; + uint[A.INHERITED] x; + uint[C.CONST] y; +} +// ---- diff --git a/test/libsolidity/syntaxTests/constantEvaluator/member_access.sol b/test/libsolidity/syntaxTests/constantEvaluator/member_access.sol new file mode 100644 index 000000000000..8f64e0d4e53d --- /dev/null +++ b/test/libsolidity/syntaxTests/constantEvaluator/member_access.sol @@ -0,0 +1,9 @@ +contract A { + uint constant INHERITED = 1; +} +contract C is A { + uint constant CONST = 2 + A.INHERITED; + uint[C.CONST] array; + uint[1 + A.INHERITED + 2] array2; +} +// ---- diff --git a/test/libsolidity/syntaxTests/constantEvaluator/member_access_library_constant.sol b/test/libsolidity/syntaxTests/constantEvaluator/member_access_library_constant.sol new file mode 100644 index 000000000000..bd7a6bdc1a16 --- /dev/null +++ b/test/libsolidity/syntaxTests/constantEvaluator/member_access_library_constant.sol @@ -0,0 +1,7 @@ +library L { + uint public constant CONST = 32; +} +contract C { + uint[L.CONST] a; +} +// ---- diff --git a/test/libsolidity/syntaxTests/constantEvaluator/member_access_module_constant.sol b/test/libsolidity/syntaxTests/constantEvaluator/member_access_module_constant.sol new file mode 100644 index 000000000000..67a908e3be07 --- /dev/null +++ b/test/libsolidity/syntaxTests/constantEvaluator/member_access_module_constant.sol @@ -0,0 +1,8 @@ +==== Source: A.sol ==== +uint constant CONST = 2; +==== Source: B.sol ==== +import "A.sol" as M; +contract C { + uint[M.CONST] array1; +} +// ---- diff --git a/test/libsolidity/syntaxTests/constantEvaluator/member_access_module_contract_constant.sol b/test/libsolidity/syntaxTests/constantEvaluator/member_access_module_contract_constant.sol new file mode 100644 index 000000000000..f79eac5207dc --- /dev/null +++ b/test/libsolidity/syntaxTests/constantEvaluator/member_access_module_contract_constant.sol @@ -0,0 +1,10 @@ +==== Source: A.sol ==== +contract A { + uint constant CONST = 2; +} +==== Source: B.sol ==== +import "A.sol" as M; +contract C is M.A { + uint[M.A.CONST] array; +} +// ---- diff --git a/test/libsolidity/syntaxTests/constantEvaluator/member_access_non_constant.sol b/test/libsolidity/syntaxTests/constantEvaluator/member_access_non_constant.sol new file mode 100644 index 000000000000..5645ae1e6f86 --- /dev/null +++ b/test/libsolidity/syntaxTests/constantEvaluator/member_access_non_constant.sol @@ -0,0 +1,8 @@ +contract A { + uint notConst = 1; +} +contract C is A { + uint[A.notConst] array; +} +// ---- +// TypeError 5462: (65-75): Invalid array length, expected integer literal or constant expression. diff --git a/test/libsolidity/syntaxTests/constants/constant_variables_as_static_array_length.sol b/test/libsolidity/syntaxTests/constants/constant_variables_as_static_array_length.sol index 19e8bfee2108..5eb9ac7ce402 100644 --- a/test/libsolidity/syntaxTests/constants/constant_variables_as_static_array_length.sol +++ b/test/libsolidity/syntaxTests/constants/constant_variables_as_static_array_length.sol @@ -7,15 +7,15 @@ library L1 { contract C1 { uint256 internal constant CONST1 = L1.INT; - uint256[L1.INT] internal arr1; // error, backward reference + uint256[L1.INT] internal arr1; uint256[L2.INT] internal arr2; // error, forward reference } contract C2 is C1 { uint256 internal constant CONST2 = CONST1; - uint256[CONST1] internal arr3; // error, inherited constants - uint256[CONST2] internal arr4; // error, same contract constant + uint256[CONST1] internal arr3; + uint256[CONST2] internal arr4; } library L2 { @@ -23,7 +23,4 @@ library L2 { } // ---- -// TypeError 5462: (158-164): Invalid array length, expected integer literal or constant expression. -// TypeError 5462: (222-228): Invalid array length, expected integer literal or constant expression. -// TypeError 5462: (356-362): Invalid array length, expected integer literal or constant expression. -// TypeError 5462: (421-427): Invalid array length, expected integer literal or constant expression. +// TypeError 5462: (193-199): Invalid array length, expected integer literal or constant expression. diff --git a/test/libsolidity/syntaxTests/constants/constant_with_dependencies_as_array_sizes.sol b/test/libsolidity/syntaxTests/constants/constant_with_dependencies_as_array_sizes.sol index a2a1ce20ee15..bbd0876724fe 100644 --- a/test/libsolidity/syntaxTests/constants/constant_with_dependencies_as_array_sizes.sol +++ b/test/libsolidity/syntaxTests/constants/constant_with_dependencies_as_array_sizes.sol @@ -5,12 +5,14 @@ library L1 { } contract C1 { - uint256 internal constant CONST = 20 + L2.INT; // forward reference + uint256 internal constant CONST = 10 + L1.INT; // backward reference + uint256 internal constant CONST2 = 20 + L2.INT; // forward reference uint256 internal constant LIMIT = MAX * L1.INT; // same file & external library constant uint256 internal constant NESTED = LIMIT + CONST; // nested & same contract constant - uint256[L1.INT] internal arr1; // error, backward reference + uint256[L1.INT] internal arr1; // ok, backward reference uint256[L2.INT] internal arr2; // error, forward reference + uint256[CONST2] internal arr3; // error, computed with forward reference } contract C2 is C1 { @@ -20,8 +22,8 @@ contract C2 is C1 { contract C3 is C2 { uint256 internal constant NESTED_INHERITED = INHERITED + NESTED + CONST * LIMIT; // nest-inherited constants - uint256[CONST] internal arr3; // error, nest-inherited constants - uint256[NESTED_INHERITED] internal arr4; // error, same contract constant + uint256[CONST] internal arr4; // nest-inherited constants + uint256[NESTED_INHERITED] internal arr5; // same contract constant } library L2 { @@ -29,7 +31,5 @@ library L2 { } // ---- -// TypeError 5462: (366-372): Invalid array length, expected integer literal or constant expression. -// TypeError 5462: (430-436): Invalid array length, expected integer literal or constant expression. -// TypeError 5462: (742-747): Invalid array length, expected integer literal or constant expression. -// TypeError 5462: (822-838): Invalid array length, expected integer literal or constant expression. +// TypeError 5462: (501-507): Invalid array length, expected integer literal or constant expression. +// TypeError 5462: (564-570): Invalid array length, expected integer literal or constant expression. From 394888c7ccfcbb8ad6962ce4bc69ad185a4624ee Mon Sep 17 00:00:00 2001 From: Matheus Aguiar Date: Sat, 17 May 2025 15:52:33 -0300 Subject: [PATCH 2/2] Support member access --- Changelog.md | 1 + libsolidity/analysis/ConstantEvaluator.cpp | 12 ++++++++ libsolidity/analysis/ConstantEvaluator.h | 1 + libsolidity/analysis/ReferencesResolver.cpp | 34 +++++++++++++++++++++ libsolidity/analysis/ReferencesResolver.h | 1 + 5 files changed, 49 insertions(+) diff --git a/Changelog.md b/Changelog.md index df45a558f41a..5cd04f65e90a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ Language Features: Compiler Features: +* Constant Evaluator: Support for constants referenced by member access expressions. * ethdebug: Experimental support for instructions and source locations under EOF. Bugfixes: diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index 691d273d5855..b8c16738525c 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -407,3 +407,15 @@ void ConstantEvaluator::endVisit(TupleExpression const& _tuple) if (!_tuple.isInlineArray() && _tuple.components().size() == 1) m_values[&_tuple] = evaluate(*_tuple.components().front()); } + +void ConstantEvaluator::endVisit(MemberAccess const& _memberAccess) +{ + auto const* referencedDeclaration = _memberAccess.annotation().referencedDeclaration; + if (!referencedDeclaration) + return; + if ( + auto const* variable = dynamic_cast(referencedDeclaration); + variable && variable->isConstant() + ) + m_values[&_memberAccess] = evaluate(*variable); +} diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h index 297d5f6e80c9..78a9a30f9fa2 100644 --- a/libsolidity/analysis/ConstantEvaluator.h +++ b/libsolidity/analysis/ConstantEvaluator.h @@ -79,6 +79,7 @@ class ConstantEvaluator: private ASTConstVisitor void endVisit(Literal const& _literal) override; void endVisit(Identifier const& _identifier) override; void endVisit(TupleExpression const& _tuple) override; + void endVisit(MemberAccess const& _memberAcess) override; langutil::ErrorReporter& m_errorReporter; /// Current recursion depth. diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index cfbdec91ab52..0fac3734a553 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -39,6 +39,8 @@ #include #include +#include + using namespace solidity; using namespace solidity::langutil; using namespace solidity::frontend; @@ -504,3 +506,35 @@ void ReferencesResolver::validateYulIdentifierName(yul::YulName _name, SourceLoc "The identifier name \"" + _name.str() + "\" is reserved." ); } + +void ReferencesResolver::endVisit(MemberAccess const& _memberAccess) +{ + // This is only for specific cases to support ConstantEvaluator. + std::vector candidates; + if (auto const* identifier = dynamic_cast(&_memberAccess.expression())) + { + if (auto const* contract = dynamic_cast(identifier->annotation().referencedDeclaration)) + candidates += contract->stateVariables(); + else if (auto const* importedModule = dynamic_cast(identifier->annotation().referencedDeclaration)) + { + SourceUnit const* sourceUnit = importedModule->annotation().sourceUnit; + solAssert(sourceUnit); + candidates += ASTNode::filteredNodes(sourceUnit->nodes()); + candidates += ASTNode::filteredNodes(sourceUnit->nodes()); + } + } + else if (auto const* nestedMemberAccess = dynamic_cast(&_memberAccess.expression())) + { + auto const* contract = dynamic_cast(nestedMemberAccess->annotation().referencedDeclaration); + if (!contract) + return; + candidates += contract->stateVariables(); + } + + auto declaration = ranges::find_if( + candidates, + [&](Declaration const* _declaration) { return _declaration->name() == _memberAccess.memberName(); } + ); + if (declaration != ranges::end(candidates)) + _memberAccess.annotation().referencedDeclaration = *declaration; +} diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index 0b7f9d37329f..e4bc474ccc95 100644 --- a/libsolidity/analysis/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -86,6 +86,7 @@ class ReferencesResolver: private ASTConstVisitor, private yul::ASTWalker bool visit(Return const& _return) override; bool visit(UsingForDirective const& _usingFor) override; bool visit(BinaryOperation const& _binaryOperation) override; + void endVisit(MemberAccess const& _memberAccess) override; void operator()(yul::FunctionDefinition const& _function) override; void operator()(yul::Identifier const& _identifier) override;