mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #8987 from ethereum/sol-yul-bound-functions
[Sol->Yul] Bound functions
This commit is contained in:
		
						commit
						6d64095ccf
					
				| @ -627,14 +627,20 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) | |||||||
| 
 | 
 | ||||||
| 	auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()); | 	auto memberAccess = dynamic_cast<MemberAccess const*>(&_functionCall.expression()); | ||||||
| 	if (memberAccess) | 	if (memberAccess) | ||||||
|  | 	{ | ||||||
| 		if (auto expressionType = dynamic_cast<TypeType const*>(memberAccess->expression().annotation().type)) | 		if (auto expressionType = dynamic_cast<TypeType const*>(memberAccess->expression().annotation().type)) | ||||||
|  | 		{ | ||||||
|  | 			solAssert(!functionType->bound(), ""); | ||||||
| 			if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType())) | 			if (auto contractType = dynamic_cast<ContractType const*>(expressionType->actualType())) | ||||||
| 				solUnimplementedAssert( | 				solUnimplementedAssert( | ||||||
| 					!contractType->contractDefinition().isLibrary() || functionType->kind() == FunctionType::Kind::Internal, | 					!contractType->contractDefinition().isLibrary() || functionType->kind() == FunctionType::Kind::Internal, | ||||||
| 					"Only internal function calls implemented for libraries" | 					"Only internal function calls implemented for libraries" | ||||||
| 				); | 				); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 		solAssert(!functionType->bound(), ""); | ||||||
| 
 | 
 | ||||||
| 	solUnimplementedAssert(!functionType->bound(), ""); |  | ||||||
| 	switch (functionType->kind()) | 	switch (functionType->kind()) | ||||||
| 	{ | 	{ | ||||||
| 	case FunctionType::Kind::Declaration: | 	case FunctionType::Kind::Declaration: | ||||||
| @ -658,14 +664,18 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) | |||||||
| 		else | 		else | ||||||
| 			solAssert(!functionType->hasDeclaration(), ""); | 			solAssert(!functionType->hasDeclaration(), ""); | ||||||
| 
 | 
 | ||||||
| 		if (memberAccess) |  | ||||||
| 			solUnimplementedAssert(!functionType->bound(), ""); |  | ||||||
| 		else |  | ||||||
| 			solAssert(!functionType->bound(), ""); |  | ||||||
| 
 |  | ||||||
| 		solAssert(!functionType->takesArbitraryParameters(), ""); | 		solAssert(!functionType->takesArbitraryParameters(), ""); | ||||||
| 
 | 
 | ||||||
| 		vector<string> args; | 		vector<string> args; | ||||||
|  | 		if (functionType->bound()) | ||||||
|  | 		{ | ||||||
|  | 			solAssert(memberAccess && functionDef, ""); | ||||||
|  | 			solAssert(functionDef->parameters().size() == arguments.size() + 1, ""); | ||||||
|  | 			args += convert(memberAccess->expression(), *functionDef->parameters()[0]->type()).stackSlots(); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 			solAssert(!functionDef || functionDef->parameters().size() == arguments.size(), ""); | ||||||
|  | 
 | ||||||
| 		for (size_t i = 0; i < arguments.size(); ++i) | 		for (size_t i = 0; i < arguments.size(); ++i) | ||||||
| 			args += convert(*arguments[i], *parameterTypes[i]).stackSlots(); | 			args += convert(*arguments[i], *parameterTypes[i]).stackSlots(); | ||||||
| 
 | 
 | ||||||
| @ -1221,13 +1231,27 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options) | |||||||
| void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) | void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) | ||||||
| { | { | ||||||
| 	ASTString const& member = _memberAccess.memberName(); | 	ASTString const& member = _memberAccess.memberName(); | ||||||
| 	if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type)) | 	auto memberFunctionType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type); | ||||||
| 		if (funType->bound()) | 	Type::Category objectCategory = _memberAccess.expression().annotation().type->category(); | ||||||
|  | 
 | ||||||
|  | 	if (memberFunctionType && memberFunctionType->bound()) | ||||||
| 	{ | 	{ | ||||||
| 			solUnimplementedAssert(false, ""); | 		solAssert((set<Type::Category>{ | ||||||
|  | 			Type::Category::Contract, | ||||||
|  | 			Type::Category::Bool, | ||||||
|  | 			Type::Category::Integer, | ||||||
|  | 			Type::Category::Address, | ||||||
|  | 			Type::Category::Function, | ||||||
|  | 			Type::Category::Struct, | ||||||
|  | 			Type::Category::Enum, | ||||||
|  | 			Type::Category::Mapping, | ||||||
|  | 			Type::Category::Array, | ||||||
|  | 			Type::Category::FixedBytes, | ||||||
|  | 		}).count(objectCategory) > 0, ""); | ||||||
|  | 		return; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	switch (_memberAccess.expression().annotation().type->category()) | 	switch (objectCategory) | ||||||
| 	{ | 	{ | ||||||
| 	case Type::Category::Contract: | 	case Type::Category::Contract: | ||||||
| 	{ | 	{ | ||||||
| @ -1460,9 +1484,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) | |||||||
| 		{ | 		{ | ||||||
| 			if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration)) | 			if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration)) | ||||||
| 				handleVariableReference(*variable, _memberAccess); | 				handleVariableReference(*variable, _memberAccess); | ||||||
| 			else if (auto const* funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type)) | 			else if (memberFunctionType) | ||||||
| 			{ | 			{ | ||||||
| 				switch (funType->kind()) | 				switch (memberFunctionType->kind()) | ||||||
| 				{ | 				{ | ||||||
| 				case FunctionType::Kind::Declaration: | 				case FunctionType::Kind::Declaration: | ||||||
| 					break; | 					break; | ||||||
| @ -1481,7 +1505,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) | |||||||
| 					break; | 					break; | ||||||
| 				case FunctionType::Kind::DelegateCall: | 				case FunctionType::Kind::DelegateCall: | ||||||
| 					define(IRVariable(_memberAccess).part("address"), _memberAccess.expression()); | 					define(IRVariable(_memberAccess).part("address"), _memberAccess.expression()); | ||||||
| 					define(IRVariable(_memberAccess).part("functionIdentifier")) << formatNumber(funType->externalIdentifier()) << "\n"; | 					define(IRVariable(_memberAccess).part("functionIdentifier")) << formatNumber(memberFunctionType->externalIdentifier()) << "\n"; | ||||||
| 					break; | 					break; | ||||||
| 				case FunctionType::Kind::External: | 				case FunctionType::Kind::External: | ||||||
| 				case FunctionType::Kind::Creation: | 				case FunctionType::Kind::Creation: | ||||||
|  | |||||||
| @ -0,0 +1,18 @@ | |||||||
|  | library L { | ||||||
|  |     function equals(address a, address b) internal pure returns (bool) { | ||||||
|  |         return a == b; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for address; | ||||||
|  | 
 | ||||||
|  |     function foo(address a, address b) public returns (bool) { | ||||||
|  |         return a.equals(b); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // foo(address, address): 0x111122223333444455556666777788889999aAaa, 0x111122223333444455556666777788889999aAaa -> true | ||||||
|  | // foo(address, address): 0x111122223333444455556666777788889999aAaa, 0x0000000000000000000000000000000000000000 -> false | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | library L { | ||||||
|  |     function transfer(address a) internal {} | ||||||
|  |     function send(address a) internal {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for address; | ||||||
|  | 
 | ||||||
|  |     function useTransfer(address a) public { | ||||||
|  |         a.transfer(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function useSend(address a) public { | ||||||
|  |         a.send(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // useTransfer(address): 0x111122223333444455556666777788889999aAaa -> | ||||||
|  | // useSend(address): 0x111122223333444455556666777788889999aAaa -> | ||||||
| @ -0,0 +1,19 @@ | |||||||
|  | library L { | ||||||
|  |     function pop(uint[2] memory a) internal {} | ||||||
|  |     function push(uint[2] memory a) internal {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for uint[2]; | ||||||
|  | 
 | ||||||
|  |     function test() public { | ||||||
|  |         uint[2] memory input; | ||||||
|  | 
 | ||||||
|  |         input.push(); | ||||||
|  |         input.pop(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // test() -> | ||||||
| @ -0,0 +1,20 @@ | |||||||
|  | library L { | ||||||
|  |     function xor(bool a, bool b) internal pure returns (bool) { | ||||||
|  |         return a != b; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for bool; | ||||||
|  | 
 | ||||||
|  |     function foo(bool a, bool b) public returns (bool) { | ||||||
|  |         return a.xor(b); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // foo(bool, bool): true, true -> false | ||||||
|  | // foo(bool, bool): true, false -> true | ||||||
|  | // foo(bool, bool): false, true -> true | ||||||
|  | // foo(bool, bool): false, false -> false | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | contract E {} | ||||||
|  | 
 | ||||||
|  | library L { | ||||||
|  |     function foo(E e) internal pure returns (uint) { | ||||||
|  |         return 42; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for E; | ||||||
|  | 
 | ||||||
|  |     function test() public returns (uint) { | ||||||
|  |         E e = new E(); | ||||||
|  |         return e.foo(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // test() -> 42 | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | library L { | ||||||
|  |     function at(uint[] memory a, uint i) internal pure returns (uint) { | ||||||
|  |         return a[i]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for uint[]; | ||||||
|  | 
 | ||||||
|  |     function secondItem() public returns (uint) { | ||||||
|  |         uint[] memory input = new uint[](2); | ||||||
|  |         input[0] = 0x11; | ||||||
|  |         input[1] = 0x22; | ||||||
|  | 
 | ||||||
|  |         return input.at(1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // secondItem() -> 0x22 | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | library L { | ||||||
|  |     enum E { A, B } | ||||||
|  | 
 | ||||||
|  |     function equals(E a, E b) internal pure returns (bool) { | ||||||
|  |         return a == b; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for L.E; | ||||||
|  | 
 | ||||||
|  |     function equalsA(uint choice) public returns (bool) { | ||||||
|  |         L.E x = L.E.A; | ||||||
|  |         return x.equals(L.E(choice)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // equalsA(uint256): 0 -> true | ||||||
|  | // equalsA(uint256): 1 -> false | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | library L { | ||||||
|  |     // NOTE: External function takes up two stack slots | ||||||
|  |     function double(function(uint) external pure returns (uint) f, uint x) internal pure returns (uint) { | ||||||
|  |         return f(x) * 2; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for function(uint) external pure returns (uint); | ||||||
|  | 
 | ||||||
|  |     function identity(uint x) external pure returns (uint) { | ||||||
|  |         return x; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function test(uint value) public returns (uint) { | ||||||
|  |         return this.identity.double(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // test(uint256): 5 -> 10 | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | library L { | ||||||
|  |     function at(uint[2] memory a, uint i) internal pure returns (uint) { | ||||||
|  |         return a[i]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for uint[2]; | ||||||
|  | 
 | ||||||
|  |     function secondItem() public returns (uint) { | ||||||
|  |         uint[2] memory input; | ||||||
|  |         input[0] = 0x11; | ||||||
|  |         input[1] = 0x22; | ||||||
|  | 
 | ||||||
|  |         return input.at(1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // secondItem() -> 0x22 | ||||||
| @ -0,0 +1,17 @@ | |||||||
|  | library L { | ||||||
|  |     function add(bytes2 a, bytes2 b) internal pure returns (bytes2) { | ||||||
|  |         return bytes2(uint16(a) + uint16(b)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for bytes2; | ||||||
|  | 
 | ||||||
|  |     function sum(bytes2 a, bytes2 b) public returns (bytes2) { | ||||||
|  |         return a.add(b); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // sum(bytes2, bytes2): left(0x1100), left(0x0022) -> left(0x1122) | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | library L { | ||||||
|  |     function selector(function(uint) internal pure returns (uint) f, uint x) internal pure returns (uint) { | ||||||
|  |         return f(x) * 2; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for function(uint) internal pure returns (uint); | ||||||
|  | 
 | ||||||
|  |     function identity(uint x) internal pure returns (uint) { | ||||||
|  |         return x; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function test(uint value) public returns (uint) { | ||||||
|  |         return identity.selector(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // test(uint256): 5 -> 10 | ||||||
| @ -0,0 +1,17 @@ | |||||||
|  | library L { | ||||||
|  |     function add(uint256 a, uint256 b) internal pure returns (uint256) { | ||||||
|  |         return a + b; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for uint256; | ||||||
|  | 
 | ||||||
|  |     function foo(uint256 a, uint256 b) public returns (uint256) { | ||||||
|  |         return a.add(b); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // foo(uint256, uint256): 8, 42 -> 50 | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | interface I {} | ||||||
|  | contract E is I {} | ||||||
|  | 
 | ||||||
|  | library L { | ||||||
|  |     function foo(I i) internal pure returns (uint) { | ||||||
|  |         return 42; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for I; | ||||||
|  | 
 | ||||||
|  |     function test() public returns (uint) { | ||||||
|  |         E e = new E(); | ||||||
|  |         return I(e).foo(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // test() -> 42 | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | library L { | ||||||
|  |     function double(function(uint) internal pure returns (uint) f, uint x) internal pure returns (uint) { | ||||||
|  |         return f(x) * 2; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for function(uint) internal pure returns (uint); | ||||||
|  | 
 | ||||||
|  |     function identity(uint x) internal pure returns (uint) { | ||||||
|  |         return x; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function test(uint value) public returns (uint) { | ||||||
|  |         return identity.double(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // test(uint256): 5 -> 10 | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | library L { | ||||||
|  |     function at(mapping(uint => uint) storage a, uint i) internal view returns (uint) { | ||||||
|  |         return a[i]; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for mapping(uint => uint); | ||||||
|  | 
 | ||||||
|  |     mapping(uint => uint) map; | ||||||
|  | 
 | ||||||
|  |     function mapValue(uint a) public returns (uint) { | ||||||
|  |         map[42] = 0x24; | ||||||
|  |         map[66] = 0x66; | ||||||
|  | 
 | ||||||
|  |         return map.at(a); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // mapValue(uint256): 42 -> 0x24 | ||||||
| @ -0,0 +1,18 @@ | |||||||
|  | library L { | ||||||
|  |     function at(string memory a, uint i) internal pure returns (uint8) { | ||||||
|  |         return uint8(bytes(a)[i]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | contract C { | ||||||
|  |     using L for string; | ||||||
|  | 
 | ||||||
|  |     function secondChar() public returns (uint8) { | ||||||
|  |         string memory input = "abc"; | ||||||
|  |         return input.at(1); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // compileViaYul: also | ||||||
|  | // ---- | ||||||
|  | // secondChar() -> 98 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user