From 3b2c6de61ca4ba940e82f546e9db2e4d029bf8a1 Mon Sep 17 00:00:00 2001 From: Ryan Date: Mon, 11 Apr 2022 21:45:20 -0500 Subject: [PATCH] Propagate purity information for member access to foreign pure variables --- Changelog.md | 2 +- libsolidity/analysis/TypeChecker.cpp | 7 ++++ ...stant_variables_as_static_array_length.sol | 29 +++++++++++++++ ...stant_with_dependencies_as_array_sizes.sol | 35 +++++++++++++++++++ ...onstant_with_dependencies_on_constants.sol | 25 +++++++++++++ ...h_dependencies_on_file_level_constants.sol | 11 ++++++ ...encies_on_library_constants_multi_file.sol | 17 +++++++++ ..._dependency_file_and_library_constants.sol | 15 ++++++++ .../cyclic_dependency_file_constants.sol | 13 +++++++ .../cyclic_dependency_library_constants.sol | 11 ++++++ 10 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/syntaxTests/constants/constant_variables_as_static_array_length.sol create mode 100644 test/libsolidity/syntaxTests/constants/constant_with_dependencies_as_array_sizes.sol create mode 100644 test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_constants.sol create mode 100644 test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_file_level_constants.sol create mode 100644 test/libsolidity/syntaxTests/constants/constants_with_dependencies_on_library_constants_multi_file.sol create mode 100644 test/libsolidity/syntaxTests/constants/cyclic_dependency_file_and_library_constants.sol create mode 100644 test/libsolidity/syntaxTests/constants/cyclic_dependency_file_constants.sol create mode 100644 test/libsolidity/syntaxTests/constants/cyclic_dependency_library_constants.sol diff --git a/Changelog.md b/Changelog.md index 660f13c9c..bfe994da6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,7 +4,7 @@ Language Features: Compiler Features: - + * TypeChecker: Support using library constants in initializers of other constants. Bugfixes: diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 2467125d7..ae27741a8 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3214,6 +3214,13 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) annotation.isPure = isPure; } + if ( + auto const* varDecl = dynamic_cast(annotation.referencedDeclaration); + !annotation.isPure.set() && + varDecl && + varDecl->isConstant() + ) + annotation.isPure = true; if (auto magicType = dynamic_cast(exprType)) { 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 new file mode 100644 index 000000000..19e8bfee2 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constant_variables_as_static_array_length.sol @@ -0,0 +1,29 @@ +uint256 constant MAX = 1; + +library L1 { + uint256 internal constant INT = 100; +} + +contract C1 { + uint256 internal constant CONST1 = L1.INT; + + uint256[L1.INT] internal arr1; // error, backward reference + 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 +} + +library L2 { + uint256 internal constant INT = 100; +} + +// ---- +// 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. 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 new file mode 100644 index 000000000..a2a1ce20e --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constant_with_dependencies_as_array_sizes.sol @@ -0,0 +1,35 @@ +uint256 constant MAX = 1; + +library L1 { + uint256 internal constant INT = 100; +} + +contract C1 { + uint256 internal constant CONST = 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[L2.INT] internal arr2; // error, forward reference +} + +contract C2 is C1 { + uint256 internal constant INHERITED = NESTED + CONST * LIMIT; // inherited constants +} + +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 +} + +library L2 { + uint256 internal constant INT = 100; +} + +// ---- +// 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. diff --git a/test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_constants.sol b/test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_constants.sol new file mode 100644 index 000000000..964ffb5f2 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_constants.sol @@ -0,0 +1,25 @@ +uint256 constant MAX = 1; + +library L1 { + uint256 internal constant INT = 100; +} + +contract C1 { + uint256 internal constant CONST = 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 +} + +contract C2 is C1 { + uint256 internal constant INHERITED = NESTED + CONST * LIMIT; // inherited constants +} + +contract C3 is C2 { + uint256 internal constant NESTED_INHERITED = INHERITED + NESTED + CONST * LIMIT; // nest-inherited constants +} + +library L2 { + uint256 internal constant INT = 100; +} + +// ---- diff --git a/test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_file_level_constants.sol b/test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_file_level_constants.sol new file mode 100644 index 000000000..9bb1723e7 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constant_with_dependencies_on_file_level_constants.sol @@ -0,0 +1,11 @@ +==== Source: A.sol ==== +import "B.sol" as B; + +uint constant X = 1; +uint constant Y = B.Y; + +==== Source: B.sol ==== +import "A.sol" as A; + +uint constant X = A.X; +uint constant Y = 2; diff --git a/test/libsolidity/syntaxTests/constants/constants_with_dependencies_on_library_constants_multi_file.sol b/test/libsolidity/syntaxTests/constants/constants_with_dependencies_on_library_constants_multi_file.sol new file mode 100644 index 000000000..4518a510a --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constants_with_dependencies_on_library_constants_multi_file.sol @@ -0,0 +1,17 @@ +==== Source: A.sol ==== +import "B.sol"; + +library L { + uint constant X = 1; + uint constant Y = K.Y; +} + +==== Source: B.sol ==== +import "A.sol"; + +library K { + uint constant X = L.X; + uint constant Y = 2; +} + +// ==== diff --git a/test/libsolidity/syntaxTests/constants/cyclic_dependency_file_and_library_constants.sol b/test/libsolidity/syntaxTests/constants/cyclic_dependency_file_and_library_constants.sol new file mode 100644 index 000000000..92f5dfce6 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/cyclic_dependency_file_and_library_constants.sol @@ -0,0 +1,15 @@ +==== Source: A.sol ==== +import "B.sol"; + +uint256 constant A = B.VAL + 1; + +==== Source: B.sol ==== +import "A.sol"; + +library B { + uint256 constant VAL = A + 1; +} + +// ---- +// TypeError 6161: (B.sol:33-61): The value of the constant VAL has a cyclic dependency via A. +// TypeError 6161: (A.sol:17-47): The value of the constant A has a cyclic dependency via VAL. diff --git a/test/libsolidity/syntaxTests/constants/cyclic_dependency_file_constants.sol b/test/libsolidity/syntaxTests/constants/cyclic_dependency_file_constants.sol new file mode 100644 index 000000000..d874abba7 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/cyclic_dependency_file_constants.sol @@ -0,0 +1,13 @@ +==== Source: A.sol ==== +import "B.sol"; + +uint256 constant A = B + 1; + +==== Source: B.sol ==== +import "A.sol"; + +uint256 constant B = A + 1; + +// ---- +// TypeError 6161: (B.sol:17-43): The value of the constant B has a cyclic dependency via A. +// TypeError 6161: (A.sol:17-43): The value of the constant A has a cyclic dependency via B. diff --git a/test/libsolidity/syntaxTests/constants/cyclic_dependency_library_constants.sol b/test/libsolidity/syntaxTests/constants/cyclic_dependency_library_constants.sol new file mode 100644 index 000000000..d72ea0a66 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/cyclic_dependency_library_constants.sol @@ -0,0 +1,11 @@ +library A { + uint256 constant VAL = B.VAL + 1; +} + +library B { + uint256 constant VAL = A.VAL + 1; +} + +// ---- +// TypeError 6161: (16-48): The value of the constant VAL has a cyclic dependency via VAL. +// TypeError 6161: (69-101): The value of the constant VAL has a cyclic dependency via VAL.