diff --git a/Changelog.md b/Changelog.md index c118e9f248a4..a283f3735d1b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Language Features: * Introduce a new overload ``require(bool, Error)`` that allows usage of ``require`` functions with custom errors. This feature is available in the ``via-ir`` pipeline only. + * General: New builtin function ``abi.encodeError(customError, (arg1, arg2, ...))`` that type-checks the arguments and returns the ABI-encoded error return data. Compiler Features: diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index bc678c647d54..1edb1120b2cc 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -11,8 +11,8 @@ Order of Precedence of Operators .. index:: abi;decode, abi;encode, abi;encodePacked, abi;encodeWithSelector, abi;encodeCall, abi;encodeWithSignature -ABI Encoding and Decoding Functions -=================================== +ABI Encoding and Decoding Functions and Errors +============================================== - ``abi.decode(bytes memory encodedData, (...)) returns (...)``: :ref:`ABI `-decodes the provided data. The types are given in parentheses as second argument. @@ -26,6 +26,8 @@ ABI Encoding and Decoding Functions tuple. Performs a full type-check, ensuring the types match the function signature. Result equals ``abi.encodeWithSelector(functionPointer.selector, (...))`` - ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)`` +- ``abi.encodeError(error errorPointer, (...)) returns (bytes memory)``: ABI-encodes the revert data for ``errorPointer`` with the arguments found in the + tuple. Performs a full type-check, ensuring the types match the error definition. Results equals ``abi.encodeWithSelector(errorPointer.selector, ...)`` .. index:: bytes;concat, string;concat @@ -167,4 +169,3 @@ Modifiers behavior to be changed in derived contracts. - ``override``: States that this function, modifier or public state variable changes the behavior of a function or modifier in a base contract. - diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index a743441d564d..d7760b35c1a5 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -135,15 +135,16 @@ Block and Transaction Properties .. index:: abi, encoding, packed -ABI Encoding and Decoding Functions ------------------------------------ +ABI Encoding and Decoding Functions and Errors +---------------------------------------------- - ``abi.decode(bytes memory encodedData, (...)) returns (...)``: ABI-decodes the given data, while the types are given in parentheses as second argument. Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))`` - ``abi.encode(...) returns (bytes memory)``: ABI-encodes the given arguments - ``abi.encodePacked(...) returns (bytes memory)``: Performs :ref:`packed encoding ` of the given arguments. Note that packed encoding can be ambiguous! - ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: ABI-encodes the given arguments starting from the second and prepends the given four-byte selector - ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)`` -- ``abi.encodeCall(function functionPointer, (...)) returns (bytes memory)``: ABI-encodes a call to ``functionPointer`` with the arguments found in the tuple. Performs a full type-check, ensuring the types match the function signature. Result equals ``abi.encodeWithSelector(functionPointer.selector, (...))`` +- ``abi.encodeCall(function functionPointer, (...)) returns (bytes memory)``: ABI-encodes a call to ``functionPointer`` with the arguments found in the tuple. Performs a full type-check, ensuring the types match the function signature. Result equals ``abi.encodeWithSelector(functionPointer.selector, ...)`` +- ``abi.encodeError(function errorPointer, (...)) returns (bytes memory)``: ABI-encodes the revert data for ``errorPointer`` with the arguments found in the tuple. Performs a full type-check, ensuring the types match the error definition. Result equals ``abi.encodeWithSelector(errorPointer.selector, ...)`` .. note:: These encoding functions can be used to craft data for external function calls without actually diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index a7402ba40f60..f1e4f7f0d074 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2203,6 +2203,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( _functionType->kind() == FunctionType::Kind::ABIEncodePacked || _functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector || _functionType->kind() == FunctionType::Kind::ABIEncodeCall || + _functionType->kind() == FunctionType::Kind::ABIEncodeError || _functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature, "ABI function has unexpected FunctionType::Kind." ); @@ -2227,10 +2228,13 @@ void TypeChecker::typeCheckABIEncodeFunctions( // Perform standard function call type checking typeCheckFunctionGeneralChecks(_functionCall, _functionType); - // No further generic checks needed as we do a precise check for ABIEncodeCall - if (_functionType->kind() == FunctionType::Kind::ABIEncodeCall) + // No further generic checks needed as we do a precise check for ABIEncodeCall and ABIEncodeError + if ( + _functionType->kind() == FunctionType::Kind::ABIEncodeCall || + _functionType->kind() == FunctionType::Kind::ABIEncodeError + ) { - typeCheckABIEncodeCallFunction(_functionCall); + typeCheckABIEncodeCallFunctionOrError(_functionCall, _functionType); return; } @@ -2292,19 +2296,34 @@ void TypeChecker::typeCheckABIEncodeFunctions( } } -void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall) +void TypeChecker::typeCheckABIEncodeCallFunctionOrError( + FunctionCall const& _functionCall, + FunctionTypePointer _functionType +) { std::vector> const& arguments = _functionCall.arguments(); // Expecting first argument to be the function pointer and second to be a tuple. if (arguments.size() != 2) { - m_errorReporter.typeError( - 6219_error, - _functionCall.location(), - "Expected two arguments: a function pointer followed by a tuple." - ); - return; + switch (_functionType->kind()) { + case FunctionType::Kind::ABIEncodeCall: + m_errorReporter.typeError( + 6219_error, + _functionCall.location(), + "Expected two arguments: a function pointer followed by a tuple." + ); + return; + case FunctionType::Kind::ABIEncodeError: + m_errorReporter.typeError( + 6220_error, + _functionCall.location(), + "Expected two arguments: a custom error followed by a tuple." + ); + return; + default: + solAssert(false); + } } FunctionType const* externalFunctionType = nullptr; @@ -2316,17 +2335,32 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa } else { - m_errorReporter.typeError( - 5511_error, - arguments.front()->location(), - "Expected first argument to be a function pointer, not \"" + - type(*arguments.front())->humanReadableName() + - "\"." - ); - return; + switch (_functionType->kind()) { + case FunctionType::Kind::ABIEncodeCall: + m_errorReporter.typeError( + 5511_error, + arguments.front()->location(), + "Expected first argument to be a function pointer, not \"" + + type(*arguments.front())->humanReadableName() + + "\"." + ); + return; + case FunctionType::Kind::ABIEncodeError: + m_errorReporter.typeError( + 5512_error, + arguments.front()->location(), + "Expected first argument to be a custom error, not \"" + + type(*arguments.front())->humanReadableName() + + "\"." + ); + return; + default: + solAssert(false); + } } if ( + _functionType->kind() == FunctionType::Kind::ABIEncodeCall && externalFunctionType->kind() != FunctionType::Kind::External && externalFunctionType->kind() != FunctionType::Kind::Declaration ) @@ -2378,6 +2412,34 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa m_errorReporter.typeError(3509_error, arguments[0]->location(), ssl, msg); return; } + if ( + _functionType->kind() == FunctionType::Kind::ABIEncodeError && + externalFunctionType->kind() != FunctionType::Kind::Error + ) + { + std::string msg = "Expected an error type."; + + switch (externalFunctionType->kind()) + { + case FunctionType::Kind::Internal: + case FunctionType::Kind::External: + case FunctionType::Kind::Declaration: + case FunctionType::Kind::DelegateCall: + msg += " Cannot use functions for abi.encodeError."; + break; + case FunctionType::Kind::Creation: + msg += " Provided creation function."; + break; + case FunctionType::Kind::Event: + msg += " Cannot use events for abi.encodeError."; + break; + default: + msg += " Cannot use special function."; + } + + m_errorReporter.typeError(3510_error, arguments[0]->location(), msg); + return; + } solAssert(!externalFunctionType->takesArbitraryParameters(), "Function must have fixed parameters."); // Tuples with only one component become that component std::vector> callArguments; @@ -2386,7 +2448,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa if (tupleType) { if (TupleExpression const* argumentTuple = dynamic_cast(arguments[1].get())) - callArguments = decltype(callArguments){argumentTuple->components().begin(), argumentTuple->components().end()}; + callArguments = {argumentTuple->components().begin(), argumentTuple->components().end()}; else { m_errorReporter.typeError( @@ -2445,7 +2507,6 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa } } - void TypeChecker::typeCheckStringConcatFunction( FunctionCall const& _functionCall, FunctionType const* _functionType @@ -2903,6 +2964,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) case FunctionType::Kind::ABIEncodeWithSelector: case FunctionType::Kind::ABIEncodeWithSignature: case FunctionType::Kind::ABIEncodeCall: + case FunctionType::Kind::ABIEncodeError: { typeCheckABIEncodeFunctions(_functionCall, functionType); returnTypes = functionType->returnParameterTypes(); diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 2ef6b818be6e..e97839f7bd29 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -110,8 +110,11 @@ class TypeChecker: private ASTConstVisitor FunctionTypePointer _functionType ); - /// Performs checks specific to the ABI encode functions of type ABIEncodeCall - void typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall); + /// Performs checks specific to the ABI encode functions/errors of type ABIEncodeCall/AbiEncodeError + void typeCheckABIEncodeCallFunctionOrError( + FunctionCall const& _functionCall, + FunctionTypePointer _functionType + ); /// Performs general checks and checks specific to string concat function call void typeCheckStringConcatFunction( diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 3f6b954e75da..f800e03208f7 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -390,6 +390,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess) {MagicType::Kind::ABI, "encodePacked"}, {MagicType::Kind::ABI, "encodeWithSelector"}, {MagicType::Kind::ABI, "encodeCall"}, + {MagicType::Kind::ABI, "encodeError"}, {MagicType::Kind::ABI, "encodeWithSignature"}, {MagicType::Kind::Message, "data"}, {MagicType::Kind::Message, "sig"}, diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 028b7667326f..c90c2bef5412 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3075,6 +3075,7 @@ std::string FunctionType::richIdentifier() const case Kind::ABIEncodePacked: id += "abiencodepacked"; break; case Kind::ABIEncodeWithSelector: id += "abiencodewithselector"; break; case Kind::ABIEncodeCall: id += "abiencodecall"; break; + case Kind::ABIEncodeError: id += "abiencodeerror"; break; case Kind::ABIEncodeWithSignature: id += "abiencodewithsignature"; break; case Kind::ABIDecode: id += "abidecode"; break; case Kind::BlobHash: id += "blobhash"; break; @@ -3663,6 +3664,7 @@ bool FunctionType::isPure() const m_kind == Kind::ABIEncodePacked || m_kind == Kind::ABIEncodeWithSelector || m_kind == Kind::ABIEncodeCall || + m_kind == Kind::ABIEncodeError || m_kind == Kind::ABIEncodeWithSignature || m_kind == Kind::ABIDecode || m_kind == Kind::MetaType || @@ -4179,6 +4181,16 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const nullptr, FunctionType::Options::withArbitraryParameters() )}, + {"encodeError", TypeProvider::function( + TypePointers{}, + TypePointers{TypeProvider::array(DataLocation::Memory)}, + strings{}, + strings{1, ""}, + FunctionType::Kind::ABIEncodeError, + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() + )}, {"encodeWithSignature", TypeProvider::function( TypePointers{TypeProvider::array(DataLocation::Memory, true)}, TypePointers{TypeProvider::array(DataLocation::Memory)}, diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 3ab4a1d97ebc..cb92bd9a55c2 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1284,6 +1284,7 @@ class FunctionType: public Type ABIEncodePacked, ABIEncodeWithSelector, ABIEncodeCall, + ABIEncodeError, ABIEncodeWithSignature, ABIDecode, GasLeft, ///< gasleft() diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 54090f960437..1cc89ea6cb30 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1304,12 +1304,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case FunctionType::Kind::ABIEncodePacked: case FunctionType::Kind::ABIEncodeWithSelector: case FunctionType::Kind::ABIEncodeCall: + case FunctionType::Kind::ABIEncodeError: case FunctionType::Kind::ABIEncodeWithSignature: { bool const isPacked = function.kind() == FunctionType::Kind::ABIEncodePacked; bool const hasSelectorOrSignature = function.kind() == FunctionType::Kind::ABIEncodeWithSelector || function.kind() == FunctionType::Kind::ABIEncodeCall || + function.kind() == FunctionType::Kind::ABIEncodeError || function.kind() == FunctionType::Kind::ABIEncodeWithSignature; TypePointers argumentTypes; @@ -1317,7 +1319,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) ASTNode::listAccept(arguments, *this); - if (function.kind() == FunctionType::Kind::ABIEncodeCall) + if ( + function.kind() == FunctionType::Kind::ABIEncodeCall || + function.kind() == FunctionType::Kind::ABIEncodeError + ) { solAssert(arguments.size() == 2); @@ -1398,10 +1403,16 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) dataOnStack = TypeProvider::fixedBytes(32); } } - else if (function.kind() == FunctionType::Kind::ABIEncodeCall) + else if ( + function.kind() == FunctionType::Kind::ABIEncodeCall || + function.kind() == FunctionType::Kind::ABIEncodeError + ) { auto const& funType = dynamic_cast(*selectorType); - if (funType.kind() == FunctionType::Kind::Declaration) + if ( + funType.kind() == FunctionType::Kind::Declaration || + funType.kind() == FunctionType::Kind::Error + ) { solAssert(funType.hasDeclaration()); solAssert(selectorType->sizeOnStack() == 0); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 2464fefc434b..194c97bd0796 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1184,6 +1184,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::ABIEncodePacked: case FunctionType::Kind::ABIEncodeWithSelector: case FunctionType::Kind::ABIEncodeCall: + case FunctionType::Kind::ABIEncodeError: case FunctionType::Kind::ABIEncodeWithSignature: { bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked; @@ -1191,6 +1192,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) bool const hasSelectorOrSignature = functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector || functionType->kind() == FunctionType::Kind::ABIEncodeCall || + functionType->kind() == FunctionType::Kind::ABIEncodeError || functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature; TypePointers argumentTypes; @@ -1199,7 +1201,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) std::string selector; std::vector> argumentsOfEncodeFunction; - if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) + if ( + functionType->kind() == FunctionType::Kind::ABIEncodeCall || + functionType->kind() == FunctionType::Kind::ABIEncodeError + ) { solAssert(arguments.size() == 2); // Account for tuples with one component which become that component @@ -1227,7 +1232,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) argumentVars += IRVariable(*argument).stackSlots(); } - if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) + if ( + functionType->kind() == FunctionType::Kind::ABIEncodeCall || + functionType->kind() == FunctionType::Kind::ABIEncodeError + ) { auto encodedFunctionType = dynamic_cast(arguments.front()->annotation().type); solAssert(encodedFunctionType); @@ -1240,10 +1248,16 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) targetTypes.emplace_back(type(*argument).fullEncodingType(false, true, isPacked)); - if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) + if ( + functionType->kind() == FunctionType::Kind::ABIEncodeCall || + functionType->kind() == FunctionType::Kind::ABIEncodeError + ) { auto const& selectorType = dynamic_cast(type(*arguments.front())); - if (selectorType.kind() == FunctionType::Kind::Declaration) + if ( + selectorType.kind() == FunctionType::Kind::Declaration || + selectorType.kind() == FunctionType::Kind::Error + ) { solAssert(selectorType.hasDeclaration()); selector = formatNumber(selectorType.externalIdentifier() << (256 - 32)); @@ -1986,7 +2000,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) define(_memberAccess) << requestedValue << "\n"; } - else if (std::set{"encode", "encodePacked", "encodeWithSelector", "encodeCall", "encodeWithSignature", "decode"}.count(member)) + else if (std::set{"encode", "encodePacked", "encodeWithSelector", "encodeCall", "encodeError", "encodeWithSignature", "decode"}.count(member)) { // no-op } diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 61aad0e8f526..9557c5ec4b8f 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -659,6 +659,7 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) case FunctionType::Kind::ABIEncodePacked: case FunctionType::Kind::ABIEncodeWithSelector: case FunctionType::Kind::ABIEncodeCall: + case FunctionType::Kind::ABIEncodeError: case FunctionType::Kind::ABIEncodeWithSignature: visitABIFunction(_funCall); break; @@ -3111,6 +3112,7 @@ std::set> SMTEncoder::collectA case FunctionType::Kind::ABIEncodePacked: case FunctionType::Kind::ABIEncodeWithSelector: case FunctionType::Kind::ABIEncodeCall: + case FunctionType::Kind::ABIEncodeError: case FunctionType::Kind::ABIEncodeWithSignature: case FunctionType::Kind::ABIDecode: abiCalls.insert(&_funCall); diff --git a/test/libsolidity/semanticTests/errors/error_in_library_and_interface.sol b/test/libsolidity/semanticTests/errors/error_in_library_and_interface.sol index fad9d8bbfc2f..397d9000c9ad 100644 --- a/test/libsolidity/semanticTests/errors/error_in_library_and_interface.sol +++ b/test/libsolidity/semanticTests/errors/error_in_library_and_interface.sol @@ -15,8 +15,20 @@ contract C { function h() public pure { revert I.E(1, 2, 3); } + function encode_f() public pure returns (bytes memory) { + return abi.encodeError(E, (1)); + } + function encode_g() public pure returns (bytes memory) { + return abi.encodeError(L.E, (1, 2)); + } + function encode_h() public pure returns (bytes memory) { + return abi.encodeError(I.E, (1, 2, 3)); + } } // ---- // f() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001" // g() -> FAILURE, hex"85208890", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"0000000000000000000000000000000000000000000000000000000000000002" // h() -> FAILURE, hex"7924ea7c", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"0000000000000000000000000000000000000000000000000000000000000003" +// encode_f() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"00000000000000000000000000000000000000000000000000000000" +// encode_g() -> 0x20, 0x44, hex"85208890", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"00000000000000000000000000000000000000000000000000000000" +// encode_h() -> 0x20, 0x64, hex"7924ea7c", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"0000000000000000000000000000000000000000000000000000000000000003", hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/error_static_calldata_uint_array_and_dynamic_array.sol b/test/libsolidity/semanticTests/errors/error_static_calldata_uint_array_and_dynamic_array.sol index bfda3b1263f0..54b12083eb58 100644 --- a/test/libsolidity/semanticTests/errors/error_static_calldata_uint_array_and_dynamic_array.sol +++ b/test/libsolidity/semanticTests/errors/error_static_calldata_uint_array_and_dynamic_array.sol @@ -2,9 +2,13 @@ contract C { error E(uint[], uint[1]); // This case used to be affected by the buggy cleanup due to ABIEncoderV2HeadOverflowWithStaticArrayCleanup bug. - function f(uint[] memory a, uint[1] calldata b) public { + function f(uint[] memory a, uint[1] calldata b) public pure { revert E(a, b); } + function encode_f(uint[] memory a, uint[1] calldata b) public pure returns (bytes memory) { + return abi.encodeError(E, (a,b)); + } } // ---- // f(uint256[],uint256[1]): 0x40, 0xff, 1, 0xffff -> FAILURE, hex"f42f106d", 0x40, 0xff, 1, 0xffff +// encode_f(uint256[],uint256[1]): 0x40, 0xff, 1, 0xffff -> 0x20, 0x84, hex"f42f106d", 0x40, 0xff, 1, 0xffff, hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/named_parameters_shadowing_types.sol b/test/libsolidity/semanticTests/errors/named_parameters_shadowing_types.sol index 2f2b7c676b9b..76076f3e3f37 100644 --- a/test/libsolidity/semanticTests/errors/named_parameters_shadowing_types.sol +++ b/test/libsolidity/semanticTests/errors/named_parameters_shadowing_types.sol @@ -10,11 +10,11 @@ contract C { error E1(StructType StructType); error E2(EnumType StructType, StructType EnumType); - function f() public { + function f() public pure { revert E1({StructType: StructType(42)}); } - function g() public { + function g() public pure { revert E2({EnumType: StructType(42), StructType: EnumType.B}); } } diff --git a/test/libsolidity/semanticTests/errors/panic_via_import.sol b/test/libsolidity/semanticTests/errors/panic_via_import.sol index 94a6a7aaaf68..9d068f7c92d1 100644 --- a/test/libsolidity/semanticTests/errors/panic_via_import.sol +++ b/test/libsolidity/semanticTests/errors/panic_via_import.sol @@ -10,7 +10,15 @@ contract C { function b() public pure { revert E(1); } + function encode_a() public pure returns (bytes memory) { + return abi.encodeError(Panic, (1)); + } + function encode_b() public pure returns (bytes memory) { + return abi.encodeError(E, (1)); + } } // ---- // a() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001" // b() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001" +// encode_a() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"00000000000000000000000000000000000000000000000000000000" +// encode_b() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/revert_conversion.sol b/test/libsolidity/semanticTests/errors/revert_conversion.sol index bef34704fcf5..f37997d0d2eb 100644 --- a/test/libsolidity/semanticTests/errors/revert_conversion.sol +++ b/test/libsolidity/semanticTests/errors/revert_conversion.sol @@ -5,6 +5,11 @@ contract C { x.push(7); revert E("abc", x); } + function encode_f() public returns (bytes memory) { + x.push(7); + return abi.encodeError(E, ("abc", x)); + } } // ---- // f() -> FAILURE, hex"59e4d4df", 0x40, 0x80, 3, "abc", 1, 7 +// encode_f() -> 0x20, 0xc4, hex"59e4d4df", 0x40, 0x80, 3, "abc", 1, 7, hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/simple.sol b/test/libsolidity/semanticTests/errors/simple.sol index 809b10c57d0a..9f7d4491e528 100644 --- a/test/libsolidity/semanticTests/errors/simple.sol +++ b/test/libsolidity/semanticTests/errors/simple.sol @@ -3,6 +3,10 @@ contract C { function f() public pure { revert E(2, 7); } + function encode_f() public pure returns (bytes memory) { + return abi.encodeError(E, (2, 7)); + } } // ---- // f() -> FAILURE, hex"85208890", 2, 7 +// encode_f() -> 0x20, 0x44, hex"85208890", 2, 7, hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/using_structs.sol b/test/libsolidity/semanticTests/errors/using_structs.sol index e04e4b1c7a49..d8514909068c 100644 --- a/test/libsolidity/semanticTests/errors/using_structs.sol +++ b/test/libsolidity/semanticTests/errors/using_structs.sol @@ -12,7 +12,13 @@ contract C { revert E({b: 7, a: 2, s: S({b: "abc", a: 9})}); } } + function encode_f() public returns (bytes memory) { + s.a = 9; + s.b = "abc"; + return abi.encodeError(E, (2, s, 7)); + } } // ---- // f(bool): true -> FAILURE, hex"e96e07f0", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"0000000000000000000000000000000000000000000000000000000000000060", hex"0000000000000000000000000000000000000000000000000000000000000007", hex"0000000000000000000000000000000000000000000000000000000000000009", hex"0000000000000000000000000000000000000000000000000000000000000040", hex"0000000000000000000000000000000000000000000000000000000000000003", hex"6162630000000000000000000000000000000000000000000000000000000000" // f(bool): false -> FAILURE, hex"e96e07f0", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"0000000000000000000000000000000000000000000000000000000000000060", hex"0000000000000000000000000000000000000000000000000000000000000007", hex"0000000000000000000000000000000000000000000000000000000000000009", hex"0000000000000000000000000000000000000000000000000000000000000040", hex"0000000000000000000000000000000000000000000000000000000000000003", hex"6162630000000000000000000000000000000000000000000000000000000000" +// encode_f() -> 0x20, 0xe4, hex"e96e07f0", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"0000000000000000000000000000000000000000000000000000000000000060", hex"0000000000000000000000000000000000000000000000000000000000000007", hex"0000000000000000000000000000000000000000000000000000000000000009", hex"0000000000000000000000000000000000000000000000000000000000000040", hex"0000000000000000000000000000000000000000000000000000000000000003", hex"6162630000000000000000000000000000000000000000000000000000000000", hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/via_contract_type.sol b/test/libsolidity/semanticTests/errors/via_contract_type.sol index 09f60e6530d2..0af7be0540a9 100644 --- a/test/libsolidity/semanticTests/errors/via_contract_type.sol +++ b/test/libsolidity/semanticTests/errors/via_contract_type.sol @@ -6,11 +6,16 @@ contract X { } contract B is A { function f() public pure { revert E(1); } - function g() public pure { revert A.E(1); } + function g() public pure { revert A.E(1); } function h() public pure { revert X.E("abc"); } - + function encode_f() public pure returns (bytes memory) { return abi.encodeError(E, (1)); } + function encode_g() public pure returns (bytes memory) { return abi.encodeError(A.E, (1)); } + function encode_h() public pure returns (bytes memory) { return abi.encodeError(X.E, ("abc")); } } // ---- // f() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001" // g() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001" // h() -> FAILURE, hex"3e9992c9", hex"0000000000000000000000000000000000000000000000000000000000000020", hex"0000000000000000000000000000000000000000000000000000000000000003", hex"6162630000000000000000000000000000000000000000000000000000000000" +// encode_f() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"00000000000000000000000000000000000000000000000000000000" +// encode_g() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"00000000000000000000000000000000000000000000000000000000" +// encode_h() -> 0x20, 0x64, hex"3e9992c9", hex"0000000000000000000000000000000000000000000000000000000000000020", hex"0000000000000000000000000000000000000000000000000000000000000003", hex"6162630000000000000000000000000000000000000000000000000000000000", hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/via_import.sol b/test/libsolidity/semanticTests/errors/via_import.sol index eb54e5b4d71b..8ef31a7dbea3 100644 --- a/test/libsolidity/semanticTests/errors/via_import.sol +++ b/test/libsolidity/semanticTests/errors/via_import.sol @@ -7,17 +7,17 @@ import "s1.sol" as S; import "s2.sol" as T; import "s1.sol"; contract C { - function x() public pure { - revert E(1); - } - function y() public pure { - revert S.E(2); - } - function z() public pure { - revert T.S.E(3); - } + function x() public pure { revert E(1); } + function y() public pure { revert S.E(2); } + function z() public pure { revert T.S.E(3); } + function encode_x() public pure returns (bytes memory) { return abi.encodeError(E, (1)); } + function encode_y() public pure returns (bytes memory) { return abi.encodeError(S.E, (2)); } + function encode_z() public pure returns (bytes memory) { return abi.encodeError(T.S.E, (3)); } } // ---- // x() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001" // y() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000002" // z() -> FAILURE, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000003" +// encode_x() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000001", hex"00000000000000000000000000000000000000000000000000000000" +// encode_y() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"00000000000000000000000000000000000000000000000000000000" +// encode_z() -> 0x20, 0x24, hex"002ff067", hex"0000000000000000000000000000000000000000000000000000000000000003", hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/semanticTests/errors/weird_name.sol b/test/libsolidity/semanticTests/errors/weird_name.sol index 2466d6e20346..e090c9071efb 100644 --- a/test/libsolidity/semanticTests/errors/weird_name.sol +++ b/test/libsolidity/semanticTests/errors/weird_name.sol @@ -3,6 +3,10 @@ contract C { function f() public pure { revert error(2); } + function encode_f() public pure returns (bytes memory) { + return abi.encodeError(error, (2)); + } } // ---- // f() -> FAILURE, hex"b48fb6cf", hex"0000000000000000000000000000000000000000000000000000000000000002" +// encode_f() -> 0x20, 0x24, hex"b48fb6cf", hex"0000000000000000000000000000000000000000000000000000000000000002", hex"00000000000000000000000000000000000000000000000000000000" diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_error_free_function.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_error_free_function.sol new file mode 100644 index 000000000000..f5afcba28889 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_error_free_function.sol @@ -0,0 +1,6 @@ +error E(uint); + +function f() pure { + abi.encodeError(E, (1)); +} +// ---- diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_event_free_function.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_event_free_function.sol new file mode 100644 index 000000000000..d84473ab2353 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_event_free_function.sol @@ -0,0 +1,9 @@ +library L { + event E(uint); +} + +function f() { + abi.encodeError(L.E, (1)); +} +// ---- +// TypeError 3510: (69-72): Expected an error type. Cannot use events for abi.encodeError. diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_free_error.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_free_error.sol new file mode 100644 index 000000000000..deca6f97ce76 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_free_error.sol @@ -0,0 +1,6 @@ +error g(uint); + +function f() pure { + abi.encodeError(g, (1)); +} +// ---- diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_free_func.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_free_func.sol new file mode 100644 index 000000000000..374114459973 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_free_func.sol @@ -0,0 +1,7 @@ +function g(uint) {} + +function f() { + abi.encodeError(g, (1)); +} +// ---- +// TypeError 3510: (56-57): Expected an error type. Cannot use functions for abi.encodeError. diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_library_func.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_library_func.sol new file mode 100644 index 000000000000..872f532a00a7 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_library_func.sol @@ -0,0 +1,13 @@ +library L { + function g(uint) public {} + function h(uint) internal {} +} + +function f() { + abi.encodeError(L.g, (1)); + abi.encodeError(L.h, (1)); +} +// ---- +// TypeError 3510: (108-111): Expected an error type. Cannot use functions for abi.encodeError. +// TypeError 3510: (139-142): Expected an error type. Cannot use functions for abi.encodeError. + diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_on_lib_error_in_free_func.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_on_lib_error_in_free_func.sol new file mode 100644 index 000000000000..c949c0bea41f --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_on_lib_error_in_free_func.sol @@ -0,0 +1,8 @@ +library L { + error g(uint); +} + +function f() pure { + abi.encodeError(L.g, (1)); +} +// ---- diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_assignment_expression.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_assignment_expression.sol new file mode 100644 index 000000000000..26c8cd3ebdae --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_assignment_expression.sol @@ -0,0 +1,24 @@ +contract C { + function g0() internal pure {} + function g2() internal pure returns (uint, uint) { return (2, 3); } + + error e0(); + error e2(uint, uint); + + function h() public view { + uint a; + uint b; + + abi.encodeError(e0, () = g0()); + abi.encodeError(e0, () = ()); + abi.encodeError(e2, (a, b) = g2()); + abi.encodeError(e2, (a, b) = (2, 3)); + } +} +// ---- +// TypeError 5547: (256-258): Empty tuple on the left hand side. +// TypeError 9062: (256-265): Expected an inline tuple, not an expression of a tuple type. +// TypeError 5547: (296-298): Empty tuple on the left hand side. +// TypeError 9062: (296-303): Expected an inline tuple, not an expression of a tuple type. +// TypeError 9062: (334-347): Expected an inline tuple, not an expression of a tuple type. +// TypeError 9062: (378-393): Expected an inline tuple, not an expression of a tuple type. diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_conditional_ternary_expression.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_conditional_ternary_expression.sol new file mode 100644 index 000000000000..e68ed232a0c8 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_conditional_ternary_expression.sol @@ -0,0 +1,17 @@ +contract C { + function g0() internal pure {} + function g2() internal pure returns (uint, uint) { return (2, 3); } + + error e0(); + error e2(uint, uint); + + function h() public view { + abi.encodeError(e0, true ? g0() : g0()); + abi.encodeError(e2, true ? g2() : g2()); + abi.encodeError(e2, true ? (1, 2) : (3, 4)); + } +} +// ---- +// TypeError 9062: (223-241): Expected an inline tuple, not an expression of a tuple type. +// TypeError 9062: (272-290): Expected an inline tuple, not an expression of a tuple type. +// TypeError 9062: (321-343): Expected an inline tuple, not an expression of a tuple type. diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_error_event.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_error_event.sol new file mode 100644 index 000000000000..684cbd8d99e2 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_error_event.sol @@ -0,0 +1,16 @@ +contract C { + event Ev(); + error Er(); + + error e0(); + + function h() public view { + abi.encodeError(e0, Ev()); + abi.encodeError(e0, Er()); + abi.encodeError(e0, revert()); + } +} +// ---- +// TypeError 9062: (122-126): Expected an inline tuple, not an expression of a tuple type. +// TypeError 7515: (137-162): Expected a tuple with 0 components instead of a single non-tuple parameter. +// TypeError 9062: (192-200): Expected an inline tuple, not an expression of a tuple type. diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_invalid_operator.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_invalid_operator.sol new file mode 100644 index 000000000000..2d55471b5eb5 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_from_invalid_operator.sol @@ -0,0 +1,23 @@ +contract C { + event Ev(); + error Er(); + + function g0() internal pure {} + function g2() internal pure returns (uint, uint) { return (2, 3); } + + error e0(); + error e2(uint, uint); + + function h() public view { + abi.encodeError(e2, (1, 1) + (2, 2)); + abi.encodeError(e0, Ev() / Er()); + abi.encodeError(e0, !()); + } +} +// ---- +// TypeError 2271: (256-271): Built-in binary operator + cannot be applied to types tuple(int_const 1,int_const 1) and tuple(int_const 2,int_const 2). +// TypeError 9062: (256-271): Expected an inline tuple, not an expression of a tuple type. +// TypeError 2271: (302-313): Built-in binary operator / cannot be applied to types tuple() and error. +// TypeError 9062: (302-313): Expected an inline tuple, not an expression of a tuple type. +// TypeError 4907: (344-347): Built-in unary operator ! cannot be applied to type tuple(). +// TypeError 9062: (344-347): Expected an inline tuple, not an expression of a tuple type. diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_returned_from_function.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_returned_from_function.sol new file mode 100644 index 000000000000..fcd5288d747f --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_tuple_returned_from_function.sol @@ -0,0 +1,22 @@ +contract C { + function g0() internal pure {} + function g2() internal pure returns (uint, uint) { return (2, 3); } + + error e0(); + error e2(uint, uint); + + function h() public view { + abi.encodeError(e0, g0()); + abi.encodeError(e2, g2()); + + abi.encodeError(e0, (g0())); + abi.encodeError(e2, (g2())); + } +} +// ---- +// TypeError 9062: (223-227): Expected an inline tuple, not an expression of a tuple type. +// TypeError 9062: (258-262): Expected an inline tuple, not an expression of a tuple type. +// TypeError 6473: (295-299): Tuple component cannot be empty. +// TypeError 7788: (274-301): Expected 0 instead of 1 components for the tuple parameter. +// TypeError 7788: (311-338): Expected 2 instead of 1 components for the tuple parameter. +// TypeError 5407: (332-336): Cannot implicitly convert component at position 0 from "tuple(uint256,uint256)" to "uint256". diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_from_assignment_expression.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_from_assignment_expression.sol new file mode 100644 index 000000000000..9c6d54a28bee --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_from_assignment_expression.sol @@ -0,0 +1,13 @@ +contract C { + function g1() internal pure returns (uint) { return (1); } + + error e1(uint); + + function h() public pure { + uint a; + + abi.encodeError(e1, (a) = g1()); + abi.encodeError(e1, (a) = (1)); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_from_conditional_ternary_expression.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_from_conditional_ternary_expression.sol new file mode 100644 index 000000000000..588a1be402b5 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_from_conditional_ternary_expression.sol @@ -0,0 +1,11 @@ +contract C { + function g1() internal pure returns (uint) { return (1); } + + error e1(uint); + + function h() public pure { + abi.encodeError(e1, true ? (1) : (2)); + abi.encodeError(e1, true ? g1() : g1()); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_returned_from_function.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_returned_from_function.sol new file mode 100644 index 000000000000..229600e78264 --- /dev/null +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encodeError_unitary_tuple_returned_from_function.sol @@ -0,0 +1,14 @@ +contract C { + function g1() internal pure returns (uint) { return (1); } + function g2() internal pure returns (uint, uint) { return (2, 3); } + + error e1(uint); + error e2(uint, uint); + + function h() public pure { + abi.encodeError(e1, g1()); + abi.encodeError(e1, (g1())); + abi.encodeError(e2, (g1(), g1())); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions.sol index 71047858029a..6b1a5e0a9f15 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions.sol @@ -3,6 +3,9 @@ interface testInterface { function D(string calldata) external; function E(string memory) external; function F(address) external; + + error C2(function (string memory) external); + error F2(address); } contract testContract { @@ -29,7 +32,11 @@ contract testContract { abi.encodeCall(testInterface.F, (payable(address(0)))); abi.encodeCall(this.i, (s)); abi.encodeCall(this.j, (s)); + + abi.encodeError(testInterface.C2, (this.g)); + abi.encodeError(testInterface.C2, (this.h)); + abi.encodeError(testInterface.F2, (payable(address(0)))); } } // ---- -// Warning 6133: (860-914): Statement has no effect. +// Warning 6133: (933-987): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_address.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_address.sol index b5d53142c7ea..12e7ea1cab09 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_address.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_address.sol @@ -1,11 +1,14 @@ interface testInterface { function A(address payable) external; + error E(address payable); } contract testContract { function main() external view { abi.encodeCall(testInterface.A, (address(0))); + abi.encodeError(testInterface.E, (address(0))); } } // ---- -// TypeError 5407: (171-183): Cannot implicitly convert component at position 0 from "address" to "address payable". +// TypeError 5407: (201-213): Cannot implicitly convert component at position 0 from "address" to "address payable". +// TypeError 5407: (257-269): Cannot implicitly convert component at position 0 from "address" to "address payable". diff --git a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_function_pointers.sol b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_function_pointers.sol index 242eb61c7998..0af384051c91 100644 --- a/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_function_pointers.sol +++ b/test/libsolidity/syntaxTests/abiEncoder/abi_encode_conversions_function_pointers.sol @@ -1,5 +1,6 @@ interface testInterface { function B(function (string calldata) external) external; + error E(function (string calldata) external); } contract testContract { @@ -9,8 +10,12 @@ contract testContract { function main() external view { abi.encodeCall(testInterface.B, (this.g)); abi.encodeCall(testInterface.B, (this.h)); + abi.encodeError(testInterface.E, (this.g)); + abi.encodeError(testInterface.E, (this.h)); } } // ---- -// TypeError 5407: (278-286): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external". -// TypeError 5407: (329-337): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external". +// TypeError 5407: (328-336): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external". +// TypeError 5407: (379-387): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external". +// TypeError 5407: (431-439): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external". +// TypeError 5407: (483-491): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external". diff --git a/test/libsolidity/syntaxTests/errors/error_encodeerror_fail_args.sol b/test/libsolidity/syntaxTests/errors/error_encodeerror_fail_args.sol new file mode 100644 index 000000000000..71e8ea735ff6 --- /dev/null +++ b/test/libsolidity/syntaxTests/errors/error_encodeerror_fail_args.sol @@ -0,0 +1,39 @@ +contract C { + enum testEnum { choice1, choice2, choice3 } + + error e0(uint8, uint8); + error e1(uint32); + error e2(uint); + error e3(bytes); + error e4(bytes32); + error e5(string); + error e6(bool); + error e7(address); + error e8(address payable); + error e9(testEnum); + + function f() pure public { + abi.encodeError(e0, (this.f, this.f)); + abi.encodeError(e1, (this.f)); + abi.encodeError(e2, (this.f)); + abi.encodeError(e3, (this.f)); + abi.encodeError(e4, (this.f)); + abi.encodeError(e5, (this.f)); + abi.encodeError(e6, (this.f)); + abi.encodeError(e7, (this.f)); + abi.encodeError(e8, (this.f)); + abi.encodeError(e9, (this.f)); + } +} +// ---- +// TypeError 5407: (357-363): Cannot implicitly convert component at position 0 from "function () pure external" to "uint8". +// TypeError 5407: (365-371): Cannot implicitly convert component at position 1 from "function () pure external" to "uint8". +// TypeError 5407: (403-411): Cannot implicitly convert component at position 0 from "function () pure external" to "uint32". +// TypeError 5407: (442-450): Cannot implicitly convert component at position 0 from "function () pure external" to "uint256". +// TypeError 5407: (481-489): Cannot implicitly convert component at position 0 from "function () pure external" to "bytes memory". +// TypeError 5407: (520-528): Cannot implicitly convert component at position 0 from "function () pure external" to "bytes32". +// TypeError 5407: (559-567): Cannot implicitly convert component at position 0 from "function () pure external" to "string memory". +// TypeError 5407: (598-606): Cannot implicitly convert component at position 0 from "function () pure external" to "bool". +// TypeError 5407: (637-645): Cannot implicitly convert component at position 0 from "function () pure external" to "address". +// TypeError 5407: (676-684): Cannot implicitly convert component at position 0 from "function () pure external" to "address payable". +// TypeError 5407: (715-723): Cannot implicitly convert component at position 0 from "function () pure external" to "enum C.testEnum". diff --git a/test/libsolidity/syntaxTests/events/event_encodeCall_fail_args.sol b/test/libsolidity/syntaxTests/events/event_encodeCall_fail_args.sol new file mode 100644 index 000000000000..9137fd26f4c6 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_encodeCall_fail_args.sol @@ -0,0 +1,41 @@ +contract C { + event MyCustomEvent(uint); + + enum testEnum { choice1, choice2, choice3 } + + function f1(uint8, uint8) external {} + function f2(uint32) external {} + function f3(uint) external {} + function g1(bytes memory) external {} + function g2(bytes32) external {} + function h(string memory) external {} + function i(bool) external {} + function j(address) external {} + function k(address payable) external {} + function l(testEnum) external {} + + function f() pure public { + abi.encodeCall(this.f1, (MyCustomEvent, MyCustomEvent)); + abi.encodeCall(this.f2, (MyCustomEvent)); + abi.encodeCall(this.f3, (MyCustomEvent)); + abi.encodeCall(this.g1, (MyCustomEvent)); + abi.encodeCall(this.g2, (MyCustomEvent)); + abi.encodeCall(this.h, (MyCustomEvent)); + abi.encodeCall(this.i, (MyCustomEvent)); + abi.encodeCall(this.j, (MyCustomEvent)); + abi.encodeCall(this.k, (MyCustomEvent)); + abi.encodeCall(this.l, (MyCustomEvent)); + } +} +// ---- +// TypeError 5407: (542-555): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "uint8". +// TypeError 5407: (557-570): Cannot implicitly convert component at position 1 from "event MyCustomEvent(uint256)" to "uint8". +// TypeError 5407: (606-621): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "uint32". +// TypeError 5407: (656-671): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "uint256". +// TypeError 5407: (706-721): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "bytes memory". +// TypeError 5407: (756-771): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "bytes32". +// TypeError 5407: (805-820): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "string memory". +// TypeError 5407: (854-869): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "bool". +// TypeError 5407: (903-918): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "address". +// TypeError 5407: (952-967): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "address payable". +// TypeError 5407: (1001-1016): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "enum C.testEnum". diff --git a/test/libsolidity/syntaxTests/events/event_encodeError_fail_args.sol b/test/libsolidity/syntaxTests/events/event_encodeError_fail_args.sol new file mode 100644 index 000000000000..813c162db6b7 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_encodeError_fail_args.sol @@ -0,0 +1,41 @@ +contract C { + event MyCustomEvent(uint); + + enum testEnum { choice1, choice2, choice3 } + + error f1(uint8, uint8); + error f2(uint32); + error f3(uint); + error g1(bytes); + error g2(bytes32); + error h(string); + error i(bool); + error j(address); + error k(address payable); + error l(testEnum); + + function f() pure public { + abi.encodeError(f1, (MyCustomEvent, MyCustomEvent)); + abi.encodeError(f2, (MyCustomEvent)); + abi.encodeError(f3, (MyCustomEvent)); + abi.encodeError(g1, (MyCustomEvent)); + abi.encodeError(g2, (MyCustomEvent)); + abi.encodeError(h, (MyCustomEvent)); + abi.encodeError(i, (MyCustomEvent)); + abi.encodeError(j, (MyCustomEvent)); + abi.encodeError(k, (MyCustomEvent)); + abi.encodeError(l, (MyCustomEvent)); + } +} +// ---- +// TypeError 5407: (384-397): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "uint8". +// TypeError 5407: (399-412): Cannot implicitly convert component at position 1 from "event MyCustomEvent(uint256)" to "uint8". +// TypeError 5407: (444-459): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "uint32". +// TypeError 5407: (490-505): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "uint256". +// TypeError 5407: (536-551): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "bytes memory". +// TypeError 5407: (582-597): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "bytes32". +// TypeError 5407: (627-642): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "string memory". +// TypeError 5407: (672-687): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "bool". +// TypeError 5407: (717-732): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "address". +// TypeError 5407: (762-777): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "address payable". +// TypeError 5407: (807-822): Cannot implicitly convert component at position 0 from "event MyCustomEvent(uint256)" to "enum C.testEnum". diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodecall_fail_args_internal_struct_for_uint.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args_internal_struct_for_uint.sol similarity index 100% rename from test/libsolidity/syntaxTests/specialFunctions/encodecall_fail_args_internal_struct_for_uint.sol rename to test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args_internal_struct_for_uint.sol diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeError.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeError.sol new file mode 100644 index 000000000000..837a02a6ce7e --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeError.sol @@ -0,0 +1,45 @@ +interface I { + error IErr(uint256 p, string t); +} + +contract Other { + error OtherErr(uint); +} + +library L { + error LErr(uint256 p, string t); +} + +contract Base { + error BaseErr(uint); +} + +contract C is Base { + error Err(int a); + error Err2(int a, string b); + error Err4(); + + function successErrorArgsIntLiteralTuple() public pure returns(bytes memory) { + return abi.encodeError(Err, (1)); + } + function successErrorArgsIntLiteral() public pure returns(bytes memory) { + return abi.encodeError(Err, 1); + } + function successErrorArgsLiteralTuple() public pure returns(bytes memory) { + return abi.encodeError(Err2, (1, "test")); + } + function successErrorArgsEmptyTuple() public pure returns(bytes memory) { + return abi.encodeError(Err4, ()); + } + function viaDeclaration() public pure returns (bytes memory) { + return bytes.concat( + abi.encodeError(I.IErr, (1, "234")), + abi.encodeError(Other.OtherErr, (1)), + abi.encodeError(L.LErr, (1, "123")) + ); + } + function viaBaseDeclaration() public pure returns (bytes memory) { + return abi.encodeError(Base.BaseErr, (1)); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args.sol new file mode 100644 index 000000000000..cd0573ecf4e1 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args.sol @@ -0,0 +1,27 @@ +contract C { + error f(int a); + error f3(int a, int b); + + function failErrorArgsWrongType() public returns(bytes memory) { + return abi.encodeError(f, ("test")); + } + function failErrorArgsTooMany() public returns(bytes memory) { + return abi.encodeError(f, (1, 2)); + } + function failErrorArgsTooFew0() public returns(bytes memory) { + return abi.encodeError(f, ()); + } + function failErrorArgsTooFew1() public returns(bytes memory) { + return abi.encodeError(f); + } + function failErrorArgsArrayLiteral() public returns(bytes memory) { + return abi.encodeError(f3, [1, 2]); + } +} +// ---- +// TypeError 5407: (150-158): Cannot implicitly convert component at position 0 from "literal_string "test"" to "int256". +// TypeError 7788: (237-263): Expected 1 instead of 2 components for the tuple parameter. +// TypeError 7788: (341-363): Expected 1 instead of 0 components for the tuple parameter. +// TypeError 6220: (441-459): Expected two arguments: a custom error followed by a tuple. +// TypeError 7515: (542-569): Expected a tuple with 2 components instead of a single non-tuple parameter. +// TypeError 5407: (562-568): Cannot implicitly convert component at position 0 from "uint8[2] memory" to "int256". diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args_internal_function_pointer_for_uint.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args_internal_function_pointer_for_uint.sol new file mode 100644 index 000000000000..e83512222500 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args_internal_function_pointer_for_uint.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint) external {} + + function main() external view { + function () h; + abi.encodeCall(this.f, (h)); + } +} +// ---- +// TypeError 5407: (137-140): Cannot implicitly convert component at position 0 from "function ()" to "uint256". diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args_internal_struct_for_uint.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args_internal_struct_for_uint.sol new file mode 100644 index 000000000000..2a6f0373b490 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_args_internal_struct_for_uint.sol @@ -0,0 +1,43 @@ +struct S { + function () f; +} + +contract C { + enum testEnum { choice1, choice2, choice3 } + + error f1(uint8); + error f2(uint32); + error f3(uint); + error g1(bytes); + error g2(bytes32); + error h(string); + error i(bool); + error j(address); + error k(address payable); + error l(testEnum); + + function main() external pure { + S memory s; + abi.encodeError(f1, (s)); + abi.encodeError(f2, (s)); + abi.encodeError(f3, (s)); + abi.encodeError(g1, (s)); + abi.encodeError(g2, (s)); + abi.encodeError(h, (s)); + abi.encodeError(i, (s)); + abi.encodeError(j, (s)); + abi.encodeError(k, (s)); + abi.encodeError(l, (s)); + } +} +// ---- +// TypeError 5407: (402-405): Cannot implicitly convert component at position 0 from "struct S memory" to "uint8". +// TypeError 5407: (436-439): Cannot implicitly convert component at position 0 from "struct S memory" to "uint32". +// TypeError 5407: (470-473): Cannot implicitly convert component at position 0 from "struct S memory" to "uint256". +// TypeError 5407: (504-507): Cannot implicitly convert component at position 0 from "struct S memory" to "bytes memory". +// TypeError 5407: (538-541): Cannot implicitly convert component at position 0 from "struct S memory" to "bytes32". +// TypeError 5407: (571-574): Cannot implicitly convert component at position 0 from "struct S memory" to "string memory". +// TypeError 5407: (604-607): Cannot implicitly convert component at position 0 from "struct S memory" to "bool". +// TypeError 5407: (637-640): Cannot implicitly convert component at position 0 from "struct S memory" to "address". +// TypeError 5407: (670-673): Cannot implicitly convert component at position 0 from "struct S memory" to "address payable". +// TypeError 5407: (703-706): Cannot implicitly convert component at position 0 from "struct S memory" to "enum C.testEnum". diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_funType.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_funType.sol new file mode 100644 index 000000000000..961bd3ef6d15 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeError_fail_funType.sol @@ -0,0 +1,55 @@ +interface I { + error Err(uint256 p, string t); +} + +contract Other { + error Err(uint); +} + +library L { + error Err(uint256 p, string t); +} + +contract Base { + error BaseErr(uint); +} + +error fileLevel(uint); + +contract C is Base { + using L for uint256; + + error Err(int a); + + function failErrorPtrMissing() public returns(bytes memory) { + return abi.encodeError(1, Err); + } + function failErrorPtrWrongType() public returns(bytes memory) { + return abi.encodeError(abi.encodeCall, (1, 2, 3, "test")); + } + function viaBaseDeclaration() public pure returns (bytes memory) { + return abi.encodeError(C.Err, (1)); + } + function viaBaseDeclaration2() public pure returns (bytes memory) { + return abi.encodeError(Base.BaseErr, (1)); + } + function viaOther() public pure returns (bytes memory) { + return abi.encodeError(Other.Err, (1)); + } + function viaInterface() public pure returns (bytes memory) { + return abi.encodeError(I.Err, (1, "123")); + } + function viaLibrary() public pure returns (bytes memory) { + return abi.encodeError(L.Err, (1, "123")); + } + function fileLevelFunction() public pure returns (bytes memory) { + return abi.encodeError(fileLevel, (2)); + } + function createFunction() public pure returns (bytes memory) { + return abi.encodeError(new Other, (2)); + } +} +// ---- +// TypeError 5512: (353-354): Expected first argument to be a custom error, not "int_const 1". +// TypeError 3510: (455-469): Expected an error type. Cannot use special function. +// TypeError 3510: (1242-1251): Expected an error type. Provided creation function. diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeError_nested_tuple.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeError_nested_tuple.sol new file mode 100644 index 000000000000..3f12802bda77 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeError_nested_tuple.sol @@ -0,0 +1,9 @@ +contract C { + error e(int a, int b); + function failErrorArgsIntLiteralNestedTuple() public returns(bytes memory) { + return abi.encodeError(e, ((1,2))); + } +} +// ---- +// TypeError 7788: (124-151): Expected 2 instead of 1 components for the tuple parameter. +// TypeError 5407: (144-149): Cannot implicitly convert component at position 0 from "tuple(int_const 1,int_const 2)" to "int256". diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeError_tuple_incomplete.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeError_tuple_incomplete.sol new file mode 100644 index 000000000000..63dc3e2ab92a --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeError_tuple_incomplete.sol @@ -0,0 +1,8 @@ +contract C { + error e(int a); + function failErrorArgsIntLiteralTuple() public returns(bytes memory) { + return abi.encodeError(e, (1,)); + } +} +// ---- +// TypeError 8381: (130-134): Tuple component cannot be empty.