mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7701 from ethereum/libraryAddresses
Allow obtaining the address of a library by conversion to ``address``.
This commit is contained in:
commit
6f500f0632
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
56
test/libsolidity/semanticTests/libraries/library_address.sol
Normal file
56
test/libsolidity/semanticTests/libraries/library_address.sol
Normal 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
|
@ -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
|
@ -0,0 +1,8 @@
|
|||||||
|
library L {
|
||||||
|
}
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns (address) {
|
||||||
|
return address(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
@ -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.
|
Loading…
Reference in New Issue
Block a user