mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10230 from ethereum/sol-yul-external-library-calls
[Sol->Yul] External library calls
This commit is contained in:
commit
804efba068
@ -3059,6 +3059,19 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
solUnimplementedAssert(false, "Tuple conversion not implemented.");
|
solUnimplementedAssert(false, "Tuple conversion not implemented.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Type::Category::TypeType:
|
||||||
|
{
|
||||||
|
TypeType const& typeType = dynamic_cast<decltype(typeType)>(_from);
|
||||||
|
if (
|
||||||
|
auto const* contractType = dynamic_cast<ContractType const*>(typeType.actualType());
|
||||||
|
contractType->contractDefinition().isLibrary() &&
|
||||||
|
_to == *TypeProvider::address()
|
||||||
|
)
|
||||||
|
body = "converted := value";
|
||||||
|
else
|
||||||
|
solAssert(false, "Invalid conversion from " + _from.canonicalName() + " to " + _to.canonicalName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
solAssert(false, "Invalid conversion from " + _from.canonicalName() + " to " + _to.canonicalName());
|
solAssert(false, "Invalid conversion from " + _from.canonicalName() + " to " + _to.canonicalName());
|
||||||
}
|
}
|
||||||
|
@ -838,10 +838,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
solAssert(!functionType->bound(), "");
|
solAssert(!functionType->bound(), "");
|
||||||
if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType()))
|
if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType()))
|
||||||
solUnimplementedAssert(
|
if (contractType->contractDefinition().isLibrary())
|
||||||
!contractType->contractDefinition().isLibrary() || functionType->kind() == FunctionType::Kind::Internal,
|
solAssert(functionType->kind() == FunctionType::Kind::Internal || functionType->kind() == FunctionType::Kind::DelegateCall, "");
|
||||||
"Only internal function calls implemented for libraries"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2146,9 +2144,10 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
|
|||||||
}
|
}
|
||||||
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
handleVariableReference(*varDecl, _identifier);
|
handleVariableReference(*varDecl, _identifier);
|
||||||
else if (dynamic_cast<ContractDefinition const*>(declaration))
|
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
// no-op
|
if (contract->isLibrary())
|
||||||
|
define(IRVariable(_identifier).part("address")) << linkerSymbol(*contract) << "\n";
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<EventDefinition const*>(declaration))
|
else if (dynamic_cast<EventDefinition const*>(declaration))
|
||||||
{
|
{
|
||||||
@ -2967,3 +2966,9 @@ void IRGeneratorForStatements::setLocation(ASTNode const& _node)
|
|||||||
{
|
{
|
||||||
m_currentLocation = _node.location();
|
m_currentLocation = _node.location();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const
|
||||||
|
{
|
||||||
|
solAssert(_library.isLibrary(), "");
|
||||||
|
return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")";
|
||||||
|
}
|
||||||
|
@ -184,6 +184,8 @@ private:
|
|||||||
|
|
||||||
void setLocation(ASTNode const& _node);
|
void setLocation(ASTNode const& _node);
|
||||||
|
|
||||||
|
std::string linkerSymbol(ContractDefinition const& _library) const;
|
||||||
|
|
||||||
std::ostringstream m_code;
|
std::ostringstream m_code;
|
||||||
IRGenerationContext& m_context;
|
IRGenerationContext& m_context;
|
||||||
YulUtilFunctions& m_utils;
|
YulUtilFunctions& m_utils;
|
||||||
|
@ -16,6 +16,8 @@ contract C {
|
|||||||
return fu();
|
return fu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// library: L
|
// library: L
|
||||||
// f() -> 7, 8
|
// f() -> 7, 8
|
@ -0,0 +1,26 @@
|
|||||||
|
library L {
|
||||||
|
function run(
|
||||||
|
function(uint256) external returns (uint256) _operation,
|
||||||
|
uint256 _a
|
||||||
|
)
|
||||||
|
external
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
return _operation(_a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function double(uint256 _a) external returns (uint256) {
|
||||||
|
return _a * _a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function g(uint256 _value) external returns (uint256) {
|
||||||
|
return L.run(this.double, _value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// g(uint256): 4 -> 16
|
@ -0,0 +1,19 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256[2] storage _a) external returns (uint256) {
|
||||||
|
return _a[0] * _a[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
uint256[2] x;
|
||||||
|
|
||||||
|
function g(uint256 _value) external returns (uint256) {
|
||||||
|
x[0] = x[1] = _value;
|
||||||
|
return L.f(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// g(uint256): 4 -> 16
|
@ -0,0 +1,17 @@
|
|||||||
|
library L {
|
||||||
|
function f(mapping(uint256 => uint256) storage _a) external returns (uint256) {
|
||||||
|
return _a[0] * _a[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
mapping(uint256 => uint256) x;
|
||||||
|
|
||||||
|
function g(uint256 _value) external returns (uint256) {
|
||||||
|
x[0] = x[1] = _value;
|
||||||
|
return L.f(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// library: L
|
||||||
|
// g(uint256): 4 -> 16
|
@ -12,6 +12,8 @@ contract C {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// library: L
|
// library: L
|
||||||
// g(uint256,uint256): 1, 1 -> true
|
// g(uint256,uint256): 1, 1 -> true
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
==== Source: a.sol ====
|
||||||
|
|
||||||
|
import "a.sol" as M;
|
||||||
|
|
||||||
|
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(M.L) == address(0);
|
||||||
|
}
|
||||||
|
function g(uint256 v) public view returns (uint256) {
|
||||||
|
return M.L.f(v);
|
||||||
|
}
|
||||||
|
function h(uint256 v) public returns (uint256) {
|
||||||
|
(bool success, bytes memory result) = address(M.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(M.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(M.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(M.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
|
@ -6,6 +6,8 @@ contract C {
|
|||||||
return L.f(v);
|
return L.f(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// library: L
|
// library: L
|
||||||
// g(uint256): 1 -> 1
|
// g(uint256): 1 -> 1
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
library L {
|
||||||
|
function f(uint256 _a) external returns (uint256) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function run(function(uint256) external returns (uint256) _operation) internal returns (uint256) {}
|
||||||
|
function test() public {
|
||||||
|
run(L.f);
|
||||||
|
function(uint256) external returns (uint256) _operation = L.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9553: (230-233): Invalid type for argument in function call. Invalid implicit conversion from function (uint256) returns (uint256) to function (uint256) external returns (uint256) requested.
|
||||||
|
// TypeError 9574: (244-305): Type function (uint256) returns (uint256) is not implicitly convertible to expected type function (uint256) external returns (uint256).
|
@ -0,0 +1,21 @@
|
|||||||
|
interface I {}
|
||||||
|
|
||||||
|
library L {}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
address(C);
|
||||||
|
address(I);
|
||||||
|
address(L); // This one is allowed
|
||||||
|
|
||||||
|
address(type(C));
|
||||||
|
address(type(I));
|
||||||
|
address(type(L));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9640: (82-92): Explicit type conversion not allowed from "type(contract C)" to "address".
|
||||||
|
// TypeError 9640: (102-112): Explicit type conversion not allowed from "type(contract I)" to "address".
|
||||||
|
// TypeError 9640: (166-182): Explicit type conversion not allowed from "type(contract C)" to "address".
|
||||||
|
// TypeError 9640: (192-208): Explicit type conversion not allowed from "type(contract I)" to "address".
|
||||||
|
// TypeError 9640: (218-234): Explicit type conversion not allowed from "type(library L)" to "address".
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
address(super);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9640: (52-66): Explicit type conversion not allowed from "contract super C" to "address".
|
@ -0,0 +1,46 @@
|
|||||||
|
struct S {
|
||||||
|
uint x;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum E {A, B, C}
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
address(uint);
|
||||||
|
address(bytes16);
|
||||||
|
address(bool);
|
||||||
|
address(address);
|
||||||
|
address(fixed);
|
||||||
|
|
||||||
|
address(S);
|
||||||
|
address(E);
|
||||||
|
|
||||||
|
address(uint[]);
|
||||||
|
address(uint[][]);
|
||||||
|
address(uint[5]);
|
||||||
|
address(string);
|
||||||
|
address(bytes);
|
||||||
|
address(S[]);
|
||||||
|
address(E[]);
|
||||||
|
address((uint, uint));
|
||||||
|
|
||||||
|
address(type(uint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 9640: (96-109): Explicit type conversion not allowed from "type(uint256)" to "address".
|
||||||
|
// TypeError 9640: (119-135): Explicit type conversion not allowed from "type(bytes16)" to "address".
|
||||||
|
// TypeError 9640: (145-158): Explicit type conversion not allowed from "type(bool)" to "address".
|
||||||
|
// TypeError 9640: (168-184): Explicit type conversion not allowed from "type(address)" to "address".
|
||||||
|
// TypeError 9640: (194-208): Explicit type conversion not allowed from "type(fixed128x18)" to "address".
|
||||||
|
// TypeError 9640: (219-229): Explicit type conversion not allowed from "type(struct S storage pointer)" to "address".
|
||||||
|
// TypeError 9640: (239-249): Explicit type conversion not allowed from "type(enum E)" to "address".
|
||||||
|
// TypeError 9640: (260-275): Explicit type conversion not allowed from "type(uint256[] memory)" to "address".
|
||||||
|
// TypeError 9640: (285-302): Explicit type conversion not allowed from "type(uint256[] memory[] memory)" to "address".
|
||||||
|
// TypeError 9640: (312-328): Explicit type conversion not allowed from "type(uint256[5] memory)" to "address".
|
||||||
|
// TypeError 9640: (338-353): Explicit type conversion not allowed from "type(string storage pointer)" to "address".
|
||||||
|
// TypeError 9640: (363-377): Explicit type conversion not allowed from "type(bytes storage pointer)" to "address".
|
||||||
|
// TypeError 9640: (387-399): Explicit type conversion not allowed from "type(struct S memory[] memory)" to "address".
|
||||||
|
// TypeError 9640: (409-421): Explicit type conversion not allowed from "type(enum E[] memory)" to "address".
|
||||||
|
// TypeError 9640: (431-452): Explicit type conversion not allowed from "tuple(type(uint256),type(uint256))" to "address".
|
||||||
|
// TypeError 9640: (463-482): Explicit type conversion not allowed from "type(uint256)" to "address".
|
Loading…
Reference in New Issue
Block a user