diff --git a/Changelog.md b/Changelog.md index cdabe189b..cc039ceb6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -57,6 +57,7 @@ Bugfixes: * Yul Optimizer: Ensure that the assignment of memory slots for variables moved to memory does not depend on AST IDs that may depend on whether additional files are included during compilation. * Yul Optimizer: Fix ``FullInliner`` step not ignoring code that is not in expression-split form. * Yul Optimizer: Fix optimized IR being unnecessarily passed through the Yul optimizer again before bytecode generation. + * TypeChecker: Fix non-constant event and error selectors. AST Changes: diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 5c28d3cd2..8c30ac782 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3357,6 +3357,29 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) annotation.isPure = isPure; } + if ( + auto const* functionType = dynamic_cast(exprType); + !annotation.isPure.set() && + functionType && + functionType->kind() == FunctionType::Kind::Event && + functionType->hasDeclaration() && + memberName == "selector" + ) + if ( + auto const* eventDefinition = dynamic_cast(&functionType->declaration()); + eventDefinition && + !eventDefinition->isAnonymous() + ) + annotation.isPure = true; + if ( + auto const* functionType = dynamic_cast(exprType); + !annotation.isPure.set() && + functionType && + functionType->kind() == FunctionType::Kind::Error && + functionType->hasDeclaration() && + memberName == "selector" + ) + annotation.isPure = true; if ( auto const* varDecl = dynamic_cast(annotation.referencedDeclaration); !annotation.isPure.set() && diff --git a/test/libsolidity/syntaxTests/constants/constant_from_error_selector.sol b/test/libsolidity/syntaxTests/constants/constant_from_error_selector.sol new file mode 100644 index 000000000..b120e3045 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constant_from_error_selector.sol @@ -0,0 +1,10 @@ +interface I { + error Er1(); +} +contract C { + function f() external {} + error Er2(); + bytes4 constant errorSelector1 = I.Er1.selector; + bytes4 constant errorSelector2 = Er2.selector; +} +// ---- diff --git a/test/libsolidity/syntaxTests/constants/constant_from_event_selector.sol b/test/libsolidity/syntaxTests/constants/constant_from_event_selector.sol new file mode 100644 index 000000000..4a3898989 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constant_from_event_selector.sol @@ -0,0 +1,10 @@ +interface I { + event Ev1(); +} +contract C { + function f() external {} + event Ev2(); + bytes32 constant eventSelector1 = I.Ev1.selector; + bytes32 constant eventSelector2 = Ev2.selector; +} +// ---- diff --git a/test/libsolidity/syntaxTests/constants/constant_from_function_selector.sol b/test/libsolidity/syntaxTests/constants/constant_from_function_selector.sol new file mode 100644 index 000000000..8acc25388 --- /dev/null +++ b/test/libsolidity/syntaxTests/constants/constant_from_function_selector.sol @@ -0,0 +1,9 @@ +interface I { + function f() external; +} +contract C { + function f() external {} + bytes4 constant functionSelector1 = I.f.selector; + bytes4 constant functionSelector2 = this.f.selector; +} +// ----