From 5893e099fee735b8602cf8429d2a65164955407a Mon Sep 17 00:00:00 2001
From: Nikola Matic <nikola.matic@ethereum.org>
Date: Fri, 26 May 2023 11:08:34 +0200
Subject: [PATCH] Allow qualified access to events from other contracts

---
 Changelog.md                                  |  2 +-
 libsolidity/ast/AST.h                         |  2 +-
 .../semanticTests/events/event_selector.sol   | 29 +++++++++++++++----
 ...event_selector_access_foreign_contract.sol |  1 -
 .../event_selector_access_interface.sol       |  1 -
 .../events/event_selector_syntax.sol          | 15 ++++++++++
 6 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/Changelog.md b/Changelog.md
index 159ec5187a9a..79c8a634f9d0 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,7 +1,7 @@
 ### 0.8.21 (unreleased)
 
 Language Features:
-
+ * Allow qualified access to events from other contracts.
 
 Compiler Features:
  * EWasm: Remove EWasm backend.
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 494cbeac2123..9d754202da59 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -1261,7 +1261,7 @@ class EventDefinition: public CallableDeclaration, public StructurallyDocumented
 	FunctionTypePointer functionType(bool /*_internal*/) const override;
 
 	bool isVisibleInDerivedContracts() const override { return true; }
-	bool isVisibleViaContractTypeAccess() const override { return false; /* TODO */ }
+	bool isVisibleViaContractTypeAccess() const override { return true; }
 
 	EventDefinitionAnnotation& annotation() const override;
 
diff --git a/test/libsolidity/semanticTests/events/event_selector.sol b/test/libsolidity/semanticTests/events/event_selector.sol
index 116e2329e649..b42ba490838b 100644
--- a/test/libsolidity/semanticTests/events/event_selector.sol
+++ b/test/libsolidity/semanticTests/events/event_selector.sol
@@ -1,32 +1,49 @@
 library L {
     event E();
 }
+
 library S {
     event E(uint);
 }
+
 library T {
     event E();
 }
 
+interface I {
+    event E();
+}
+
+contract B {
+    event E();
+}
+
 contract D {
     event F();
 }
 
 contract C is D {
-    function test1() external pure returns (bytes32, bytes32) {
+    function test1() external pure returns (bytes32, bytes32, bytes32, bytes32) {
         assert(L.E.selector == T.E.selector);
+        assert(I.E.selector == L.E.selector);
+        assert(T.E.selector == I.E.selector);
+        assert(B.E.selector == T.E.selector);
 
         assert(L.E.selector != S.E.selector);
         assert(T.E.selector != S.E.selector);
+        assert(I.E.selector != S.E.selector);
+        assert(B.E.selector != S.E.selector);
 
-        return (L.E.selector, S.E.selector);
+        return (L.E.selector, S.E.selector, I.E.selector, B.E.selector);
     }
 
     bytes32 s1 = L.E.selector;
     bytes32 s2 = S.E.selector;
     bytes32 s3 = T.E.selector;
-    function test2() external returns (bytes32, bytes32, bytes32) {
-        return (s1, s2, s3);
+    bytes32 s4 = I.E.selector;
+    bytes32 s5 = B.E.selector;
+    function test2() external returns (bytes32, bytes32, bytes32, bytes32, bytes32) {
+        return (s1, s2, s3, s4, s5);
     }
 
     function test3() external returns (bytes32) {
@@ -36,6 +53,6 @@ contract C is D {
 // ====
 // compileViaYul: also
 // ----
-// test1() -> 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x2ff0672f372fbe844b353429d4510ea5e43683af134c54f75f789ff57bc0c0
-// test2() -> 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x2ff0672f372fbe844b353429d4510ea5e43683af134c54f75f789ff57bc0c0, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028
+// test1() -> 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x2ff0672f372fbe844b353429d4510ea5e43683af134c54f75f789ff57bc0c0, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028
+// test2() -> 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x2ff0672f372fbe844b353429d4510ea5e43683af134c54f75f789ff57bc0c0, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028
 // test3() -> 0x28811f5935c16a099486acb976b3a6b4942950a1425a74e9eb3e9b7f7135e12a
diff --git a/test/libsolidity/syntaxTests/events/event_selector_access_foreign_contract.sol b/test/libsolidity/syntaxTests/events/event_selector_access_foreign_contract.sol
index b878543fc07f..ccc2b199cff9 100644
--- a/test/libsolidity/syntaxTests/events/event_selector_access_foreign_contract.sol
+++ b/test/libsolidity/syntaxTests/events/event_selector_access_foreign_contract.sol
@@ -8,4 +8,3 @@ contract C {
     }
 }
 // ----
-// TypeError 9582: (110-113): Member "E" not found or not visible after argument-dependent lookup in type(contract D).
diff --git a/test/libsolidity/syntaxTests/events/event_selector_access_interface.sol b/test/libsolidity/syntaxTests/events/event_selector_access_interface.sol
index 2877fee5659b..2b4cd4e92992 100644
--- a/test/libsolidity/syntaxTests/events/event_selector_access_interface.sol
+++ b/test/libsolidity/syntaxTests/events/event_selector_access_interface.sol
@@ -8,4 +8,3 @@ contract C {
     }
 }
 // ----
-// TypeError 9582: (111-114): Member "E" not found or not visible after argument-dependent lookup in type(contract I).
diff --git a/test/libsolidity/syntaxTests/events/event_selector_syntax.sol b/test/libsolidity/syntaxTests/events/event_selector_syntax.sol
index ecbfe9bc51c5..fec21b55f53b 100644
--- a/test/libsolidity/syntaxTests/events/event_selector_syntax.sol
+++ b/test/libsolidity/syntaxTests/events/event_selector_syntax.sol
@@ -2,19 +2,34 @@ library L {
     event E(bytes32, bool, bytes indexed);
 }
 
+interface I {
+    event E(bytes32, bool, bytes indexed);
+}
+
+contract A {
+    event E(bytes32, bool, bytes indexed);
+}
+
 contract B {
     event E(bytes32, bool, bytes indexed);
 }
 
 contract C is B {
     bytes32 public librarySelector = L.E.selector;
+    bytes32 public interfaceSelector = I.E.selector;
+    bytes32 public foreignContractSelector = A.E.selector;
     bytes32 inheritedSelector = E.selector;
 
     function f() public {
         assert(librarySelector == L.E.selector);
+        assert(interfaceSelector == I.E.selector);
+        assert(foreignContractSelector == A.E.selector);
         assert(E.selector == B.E.selector);
 
         emit E(E.selector, true, "123");
+        emit I.E((B.E.selector), true, "123");
+        emit A.E((B.E.selector), true, "123");
         emit L.E((B.E.selector), true, "123");
     }
 }
+// ----