From 1cc8ce16562f94f156c0e97404c0d96ada1eb9f9 Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Thu, 2 Jan 2020 16:27:32 -0500 Subject: [PATCH 1/5] Don't prohibit interface inheritance --- libsolidity/analysis/TypeChecker.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 2c867b962..646edeb1a 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -237,9 +237,6 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) auto base = dynamic_cast(&dereference(_inheritance.name())); solAssert(base, "Base contract not available."); - if (m_scope->isInterface()) - m_errorReporter.typeError(_inheritance.location(), "Interfaces cannot inherit."); - if (base->isLibrary()) m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from."); From 573a054d5d304f9363f212199f658c34b1f0729c Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Thu, 2 Jan 2020 16:32:35 -0500 Subject: [PATCH 2/5] Prohibit interfaces inheriting from non-interfaces --- libsolidity/analysis/TypeChecker.cpp | 3 +++ .../syntaxTests/inheritance/interface/contract_base.sol | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/contract_base.sol diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 646edeb1a..153f4a774 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -237,6 +237,9 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) auto base = dynamic_cast(&dereference(_inheritance.name())); solAssert(base, "Base contract not available."); + if (m_scope->isInterface() && !base->isInterface()) + m_errorReporter.typeError(_inheritance.location(), "Interfaces can only inherit from other interfaces."); + if (base->isLibrary()) m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from."); diff --git a/test/libsolidity/syntaxTests/inheritance/interface/contract_base.sol b/test/libsolidity/syntaxTests/inheritance/interface/contract_base.sol new file mode 100644 index 000000000..1afb921c5 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/contract_base.sol @@ -0,0 +1,5 @@ +contract C {} +interface I is C {} + +// ---- +// TypeError: (29-30): Interfaces can only inherit from other interfaces. From 595f569e97e012ae00fc5259afb0bf4c1474f5e2 Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Thu, 2 Jan 2020 16:28:07 -0500 Subject: [PATCH 3/5] Update tests for interface inheritance --- .../interface_inheritance_conversions.sol | 39 +++++++++++++++++++ .../interface/diamond/diamond_no_relist.sol | 10 +++++ .../interface/diamond/diamond_with_relist.sol | 15 +++++++ .../interface/implementation/complete.sol | 17 ++++++++ .../interface/implementation/partial.sol | 19 +++++++++ .../linearization/invalid/lists_a.sol | 8 ++++ .../linearization/invalid/lists_b.sol | 8 ++++ .../linearization/invalid/lists_both.sol | 8 ++++ .../interface/linearization/valid.sol | 7 ++++ .../interface/multiple_parents.sol | 15 +++++++ .../interface/overrides_multiple.sol | 31 +++++++++++++++ .../interface/overrides_single.sol | 14 +++++++ .../inheritance/interface/single_parent.sol | 5 +++ .../418_interface_inheritance.sol | 2 - 14 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/interface_inheritance_conversions.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_no_relist.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_with_relist.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/implementation/complete.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/implementation/partial.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_a.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_b.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_both.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/linearization/valid.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/multiple_parents.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/interface/single_parent.sol diff --git a/test/libsolidity/semanticTests/interface_inheritance_conversions.sol b/test/libsolidity/semanticTests/interface_inheritance_conversions.sol new file mode 100644 index 000000000..4241afe81 --- /dev/null +++ b/test/libsolidity/semanticTests/interface_inheritance_conversions.sol @@ -0,0 +1,39 @@ +interface Parent { + function parentFun() external returns (uint256); +} + +interface SubA is Parent { + function subAFun() external returns (uint256); +} + +interface SubB is Parent { + function subBFun() external returns (uint256); +} + +contract Impl is SubA, SubB { + function parentFun() override external returns (uint256) { return 1; } + function subAFun() override external returns (uint256) { return 2; } + function subBFun() override external returns (uint256) { return 3; } +} + +contract C { + function convertParent() public returns (uint256) { + Parent p = new Impl(); + return p.parentFun(); + } + + function convertSubA() public returns (uint256, uint256) { + SubA sa = new Impl(); + return (sa.parentFun(), sa.subAFun()); + } + + function convertSubB() public returns (uint256, uint256) { + SubB sb = new Impl(); + return (sb.parentFun(), sb.subBFun()); + } +} + +// ---- +// convertParent() -> 1 +// convertSubA() -> 1, 2 +// convertSubB() -> 1, 3 diff --git a/test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_no_relist.sol b/test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_no_relist.sol new file mode 100644 index 000000000..5d525fde4 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_no_relist.sol @@ -0,0 +1,10 @@ +interface Parent { + function test() external returns (uint256); +} + +interface SubA is Parent {} +interface SubB is Parent {} + +contract C is SubA, SubB { + function test() external override returns (uint256) { return 42; } +} diff --git a/test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_with_relist.sol b/test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_with_relist.sol new file mode 100644 index 000000000..30ee63cc7 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/diamond/diamond_with_relist.sol @@ -0,0 +1,15 @@ +interface Parent { + function test() external returns (uint256); +} + +interface SubA is Parent { + function test() external override returns (uint256); +} + +interface SubB is Parent { + function test() external override returns (uint256); +} + +contract C is SubA, SubB { + function test() external override(SubA, SubB) returns (uint256) { return 42; } +} diff --git a/test/libsolidity/syntaxTests/inheritance/interface/implementation/complete.sol b/test/libsolidity/syntaxTests/inheritance/interface/implementation/complete.sol new file mode 100644 index 000000000..09334dafc --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/implementation/complete.sol @@ -0,0 +1,17 @@ +interface ParentA { + function testA() external returns (uint256); +} + +interface ParentB { + function testB() external returns (uint256); +} + +interface Sub is ParentA, ParentB { + function testSub() external returns (uint256); +} + +contract SubImpl is Sub { + function testA() external override returns (uint256) { return 12; } + function testB() external override(ParentB) returns (uint256) { return 42; } + function testSub() external override returns (uint256) { return 99; } +} diff --git a/test/libsolidity/syntaxTests/inheritance/interface/implementation/partial.sol b/test/libsolidity/syntaxTests/inheritance/interface/implementation/partial.sol new file mode 100644 index 000000000..378c3c41b --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/implementation/partial.sol @@ -0,0 +1,19 @@ +interface ParentA { + function testA() external returns (uint256); +} + +interface ParentB { + function testB() external returns (uint256); +} + +interface Sub is ParentA, ParentB { + function testSub() external returns (uint256); +} + +contract SubImpl is Sub { + function testA() external override returns (uint256) { return 12; } + function testSub() external override returns (uint256) { return 99; } +} + +// ---- +// TypeError: (234-407): Contract "SubImpl" should be marked as abstract. diff --git a/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_a.sol b/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_a.sol new file mode 100644 index 000000000..0528af074 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_a.sol @@ -0,0 +1,8 @@ +interface ParentA {} +interface ParentB {} +interface Sub is ParentA, ParentB {} + +contract ListsA is Sub, ParentA {} + +// ---- +// TypeError: (80-114): Linearization of inheritance graph impossible diff --git a/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_b.sol b/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_b.sol new file mode 100644 index 000000000..cea97889c --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_b.sol @@ -0,0 +1,8 @@ +interface ParentA {} +interface ParentB {} +interface Sub is ParentA, ParentB {} + +contract ListsB is Sub, ParentB {} + +// ---- +// TypeError: (80-114): Linearization of inheritance graph impossible diff --git a/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_both.sol b/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_both.sol new file mode 100644 index 000000000..8bf99bd91 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/linearization/invalid/lists_both.sol @@ -0,0 +1,8 @@ +interface ParentA {} +interface ParentB {} +interface Sub is ParentA, ParentB {} + +contract ListsBoth is Sub, ParentA, ParentB {} + +// ---- +// TypeError: (80-126): Linearization of inheritance graph impossible diff --git a/test/libsolidity/syntaxTests/inheritance/interface/linearization/valid.sol b/test/libsolidity/syntaxTests/inheritance/interface/linearization/valid.sol new file mode 100644 index 000000000..4f725e1b7 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/linearization/valid.sol @@ -0,0 +1,7 @@ +interface ParentA {} +interface ParentB {} +interface Sub is ParentA, ParentB {} + +contract ListsA is ParentA, Sub {} +contract ListsB is ParentB, Sub {} +contract ListsBoth is ParentA, ParentB, Sub {} diff --git a/test/libsolidity/syntaxTests/inheritance/interface/multiple_parents.sol b/test/libsolidity/syntaxTests/inheritance/interface/multiple_parents.sol new file mode 100644 index 000000000..f3dcf6f0e --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/multiple_parents.sol @@ -0,0 +1,15 @@ +interface SuperA { + function test() external returns (uint256); + function testA() external returns (int128); +} + +interface SuperB { + function test() external returns (uint256); + function testB() external returns (int256); +} + +interface Sub is SuperA, SuperB { +} + +// ---- +// TypeError: (236-271): Derived contract must override function "test". Two or more base classes define function with same name and parameter types. diff --git a/test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol b/test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol new file mode 100644 index 000000000..36d76f3a8 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol @@ -0,0 +1,31 @@ +interface SuperA { + function test1() external returns (uint256); + function test2() external returns (uint256); + function test3() external returns (uint256); + function test4() external returns (uint256); + function test5() external returns (uint256); +} + +interface SuperB { + function test1() external returns (uint256); + function test2() external returns (uint256); + function test3() external returns (uint256); + function test4() external returns (uint256); + function test5() external returns (uint256); +} + +interface Sub is SuperA, SuperB { + function test1() external returns (uint256); + function test2() external override returns (uint256); + function test3() external override(SuperA) returns (uint256); + function test4() external override(SuperB) returns (uint256); + function test5() external override(SuperA, SuperB) returns (uint256); +} + +// ---- +// TypeError: (572-616): Overriding function is missing "override" specifier. +// TypeError: (572-616): Overriding function is missing "override" specifier. +// TypeError: (572-616): Function needs to specify overridden contracts "SuperA" and "SuperB". +// TypeError: (647-655): Function needs to specify overridden contracts "SuperA" and "SuperB". +// TypeError: (705-721): Function needs to specify overridden contract "SuperB". +// TypeError: (771-787): Function needs to specify overridden contract "SuperA". diff --git a/test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol b/test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol new file mode 100644 index 000000000..1a68d980b --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol @@ -0,0 +1,14 @@ +interface Super { + function test1() external returns (uint256); + function test2() external returns (uint256); + function test3() external returns (uint256); +} + +interface Sub is Super { + function test1() external returns (uint256); + function test2() external override returns (uint256); + function test3() external override(Super) returns (uint256); +} + +// ---- +// TypeError: (197-241): Overriding function is missing "override" specifier. diff --git a/test/libsolidity/syntaxTests/inheritance/interface/single_parent.sol b/test/libsolidity/syntaxTests/inheritance/interface/single_parent.sol new file mode 100644 index 000000000..d6a7c747e --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/interface/single_parent.sol @@ -0,0 +1,5 @@ +interface Super { + function test() external returns (uint256); +} + +interface Sub is Super {} diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/418_interface_inheritance.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/418_interface_inheritance.sol index 92683cda3..53a45636e 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/418_interface_inheritance.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/418_interface_inheritance.sol @@ -2,5 +2,3 @@ interface A { } interface I is A { } -// ---- -// TypeError: (31-32): Interfaces cannot inherit. From f492a0a3ef46e5466c717e314be459ade5b03981 Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Tue, 21 Jan 2020 08:32:04 -0500 Subject: [PATCH 4/5] Update changelog for interface inheritance --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 0c700d1a6..44e515d16 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ Language Features: * Allow accessing external functions via contract and interface names to obtain their selector. * Inline Assembly: Support literals ``true`` and ``false``. + * Allow interfaces to inherit from other interfaces Compiler Features: From 86145adac8362f55e4cd1ccc903f02f909b67b06 Mon Sep 17 00:00:00 2001 From: Jason Cobb Date: Tue, 21 Jan 2020 08:42:58 -0500 Subject: [PATCH 5/5] Update documentation for interface inheritance --- docs/contracts/interfaces.rst | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index 69d4917cc..727809460 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -8,7 +8,7 @@ Interfaces Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions: -- They cannot inherit other contracts or interfaces. +- They cannot inherit from other contracts, but they can inherit from other interfaces. - All declared functions must be external. - They cannot declare a constructor. - They cannot declare state variables. @@ -37,10 +37,31 @@ they can be overridden. This does not automatically mean that an overriding func can be overridden again - this is only possible if the overriding function is marked ``virtual``. +Interfaces can inherit from other interfaces. This has the same rules as normal +inheritance. + +:: + + pragma solidity >0.6.1 <0.7.0; + + interface ParentA { + function test() external returns (uint256); + } + + interface ParentB { + function test() external returns (uint256); + } + + interface SubInterface is ParentA, ParentB { + // Must redefine test in order to assert that the parent + // meanings are compatible. + function test() external override(ParentA, ParentB) returns (uint256); + } + Types defined inside interfaces and other contract-like structures can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``. .. warning: Interfaces have supported ``enum`` types since :doc:`Solidity version 0.5.0 <050-breaking-changes>`, make - sure the pragma version specifies this version as a minimum. \ No newline at end of file + sure the pragma version specifies this version as a minimum.