Merge pull request #8091 from random-internet-cat/interface-inheritance

Interface inheritance
This commit is contained in:
chriseth 2020-01-22 20:10:06 +01:00 committed by GitHub
commit 641bb815e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 227 additions and 6 deletions

View File

@ -3,6 +3,7 @@
Language Features: Language Features:
* Allow accessing external functions via contract and interface names to obtain their selector. * Allow accessing external functions via contract and interface names to obtain their selector.
* Inline Assembly: Support literals ``true`` and ``false``. * Inline Assembly: Support literals ``true`` and ``false``.
* Allow interfaces to inherit from other interfaces
Compiler Features: Compiler Features:

View File

@ -8,7 +8,7 @@ Interfaces
Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions: 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. - All declared functions must be external.
- They cannot declare a constructor. - They cannot declare a constructor.
- They cannot declare state variables. - 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 can be overridden again - this is only possible if the overriding
function is marked ``virtual``. 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 Types defined inside interfaces and other contract-like structures
can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``. can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``.
.. warning: .. warning:
Interfaces have supported ``enum`` types since :doc:`Solidity version 0.5.0 <050-breaking-changes>`, make 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. sure the pragma version specifies this version as a minimum.

View File

@ -237,8 +237,8 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name())); auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
solAssert(base, "Base contract not available."); solAssert(base, "Base contract not available.");
if (m_scope->isInterface()) if (m_scope->isInterface() && !base->isInterface())
m_errorReporter.typeError(_inheritance.location(), "Interfaces cannot inherit."); m_errorReporter.typeError(_inheritance.location(), "Interfaces can only inherit from other interfaces.");
if (base->isLibrary()) if (base->isLibrary())
m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from."); m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from.");

View File

@ -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

View File

@ -0,0 +1,5 @@
contract C {}
interface I is C {}
// ----
// TypeError: (29-30): Interfaces can only inherit from other interfaces.

View File

@ -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; }
}

View File

@ -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; }
}

View File

@ -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; }
}

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {}

View File

@ -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.

View File

@ -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".

View File

@ -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.

View File

@ -0,0 +1,5 @@
interface Super {
function test() external returns (uint256);
}
interface Sub is Super {}

View File

@ -2,5 +2,3 @@ interface A {
} }
interface I is A { interface I is A {
} }
// ----
// TypeError: (31-32): Interfaces cannot inherit.