Merge pull request #7701 from ethereum/libraryAddresses

Allow obtaining the address of a library by conversion to ``address``.
This commit is contained in:
chriseth 2019-11-13 12:00:57 +01:00 committed by GitHub
commit 6f500f0632
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 127 additions and 1 deletions

View File

@ -1,6 +1,7 @@
### 0.5.13 (unreleased) ### 0.5.13 (unreleased)
Language Features: Language Features:
* Allow to obtain the address of a linked library with ``address(LibraryName)``.
Compiler Features: Compiler Features:

View File

@ -178,6 +178,9 @@ custom types without the overhead of external function calls:
} }
} }
It is possible to obtain the address of a library by converting
the library type to the ``address`` type, i.e. using ``address(LibraryName)``.
As the compiler cannot know where the library will be As the compiler cannot know where the library will be
deployed at, these addresses have to be filled into the deployed at, these addresses have to be filled into the
final bytecode by a linker final bytecode by a linker

View File

@ -3373,6 +3373,15 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current
return members; return members;
} }
BoolResult TypeType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (auto const* address = dynamic_cast<AddressType const*>(&_convertTo))
if (address->stateMutability() == StateMutability::NonPayable)
if (auto const* contractType = dynamic_cast<ContractType const*>(m_actualType))
return contractType->contractDefinition().isLibrary();
return isImplicitlyConvertibleTo(_convertTo);
}
ModifierType::ModifierType(ModifierDefinition const& _modifier) ModifierType::ModifierType(ModifierDefinition const& _modifier)
{ {
TypePointers params; TypePointers params;

View File

@ -1287,6 +1287,7 @@ public:
std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; } std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
private: private:
TypePointer m_actualType; TypePointer m_actualType;
}; };

View File

@ -475,7 +475,22 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{ {
solAssert(_functionCall.arguments().size() == 1, ""); solAssert(_functionCall.arguments().size() == 1, "");
solAssert(_functionCall.names().empty(), ""); solAssert(_functionCall.names().empty(), "");
acceptAndConvert(*_functionCall.arguments().front(), *_functionCall.annotation().type); auto const& expression = *_functionCall.arguments().front();
auto const& targetType = *_functionCall.annotation().type;
if (auto const* typeType = dynamic_cast<TypeType const*>(expression.annotation().type))
if (auto const* addressType = dynamic_cast<AddressType const*>(&targetType))
{
auto const* contractType = dynamic_cast<ContractType const*>(typeType->actualType());
solAssert(
contractType &&
contractType->contractDefinition().isLibrary() &&
addressType->stateMutability() == StateMutability::NonPayable,
""
);
m_context.appendLibraryAddress(contractType->contractDefinition().fullyQualifiedName());
return false;
}
acceptAndConvert(expression, targetType);
return false; return false;
} }

View File

@ -0,0 +1,56 @@
library L {
function f(uint256 v) external pure returns (uint) {
return v * v;
}
function g(uint256 v) external returns (uint) {
return v * v;
}
}
contract C {
function addr() public view returns (bool) {
return address(L) == address(0);
}
function g(uint256 v) public view returns (uint256) {
return L.f(v);
}
function h(uint256 v) public returns (uint256) {
(bool success, bytes memory result) = address(L).delegatecall(abi.encodeWithSignature("f(uint256)", v));
assert(success);
return abi.decode(result, (uint256));
}
function i(uint256 v) public returns (uint256) {
(bool success, bytes memory result) = address(L).call(abi.encodeWithSignature("f(uint256)", v));
assert(success);
return abi.decode(result, (uint256));
}
function j(uint256 v) public returns (uint256) {
(bool success, bytes memory result) = address(L).delegatecall(abi.encodeWithSignature("g(uint256)", v));
assert(success);
return abi.decode(result, (uint256));
}
function k(uint256 v) public returns (uint256) {
(bool success, bytes memory result) = address(L).call(abi.encodeWithSignature("g(uint256)", v));
assert(success);
return abi.decode(result, (uint256));
}
}
// ====
// EVMVersion: >=byzantium
// ----
// library: L
// addr() -> false
// g(uint256): 1 -> 1
// g(uint256): 2 -> 4
// g(uint256): 4 -> 16
// h(uint256): 1 -> 1
// h(uint256): 2 -> 4
// h(uint256): 4 -> 16
// i(uint256): 1 -> 1
// i(uint256): 2 -> 4
// i(uint256): 4 -> 16
// j(uint256): 1 -> 1
// j(uint256): 2 -> 4
// j(uint256): 4 -> 16
// k(uint256): 1 -> FAILURE
// k(uint256): 2 -> FAILURE
// k(uint256): 4 -> FAILURE

View File

@ -0,0 +1,24 @@
library L {
function f(uint256 a, uint256 b) external {
assert(a * a == b);
}
}
contract C {
function addr() public view returns (bool) {
return address(L) == address(0);
}
function g(uint256 a, uint256 b) public returns (bool) {
(bool success,) = address(L).delegatecall(abi.encodeWithSignature("f(uint256,uint256)", a, b));
return success;
}
}
// ----
// library: L
// g(uint256,uint256): 1, 1 -> true
// g(uint256,uint256): 1, 2 -> false
// g(uint256,uint256): 2, 3 -> false
// g(uint256,uint256): 2, 4 -> true
// g(uint256,uint256): 2, 5 -> false
// g(uint256,uint256): 4, 15 -> false
// g(uint256,uint256): 4, 16 -> true
// g(uint256,uint256): 4, 17 -> false

View File

@ -0,0 +1,8 @@
library L {
}
contract C {
function f() public pure returns (address) {
return address(L);
}
}
// ----

View File

@ -0,0 +1,9 @@
library L {
}
contract C {
function f() public pure returns (address payable) {
return address(L);
}
}
// ----
// TypeError: (99-109): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.