From 843171c70f6d0628f9b31ed83d7cfd8b6813e350 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Wed, 6 Oct 2021 14:15:30 +0200 Subject: [PATCH] Correctly name builtin functions in error messages. --- Changelog.md | 1 + libsolidity/analysis/GlobalContext.cpp | 66 ++--- libsolidity/ast/Types.cpp | 240 ++++++++++++------ libsolidity/ast/Types.h | 7 +- test/libsolidity/ASTJSON/used_errors.json | 2 +- .../concat/bytes_concat_empty_invalid.sol | 2 +- ...nction_parameter_disallowed_conversion.sol | 2 +- test/libsolidity/syntaxTests/errors/using.sol | 2 +- .../libsolidity/syntaxTests/errors/weird1.sol | 2 +- .../functionTypes/assign_builtin.sol | 2 +- .../functionTypes/event_convert_err.sol | 9 + .../493_builtin_keccak256_reject_gas.sol | 2 +- .../494_builtin_sha256_reject_gas.sol | 2 +- .../495_builtin_ripemd160_reject_gas.sol | 2 +- .../496_builtin_ecrecover_reject_gas.sol | 2 +- .../wrap_unwrap_assign_err.sol | 4 +- 16 files changed, 229 insertions(+), 118 deletions(-) create mode 100644 test/libsolidity/syntaxTests/functionTypes/event_convert_err.sol diff --git a/Changelog.md b/Changelog.md index ddfe1648e..00df32091 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Compiler Features: * SMTChecker: Output values for ``block.*``, ``msg.*`` and ``tx.*`` variables that are present in the called functions. * Standard JSON: Accept nested brackets in step sequences passed to ``settings.optimizer.details.yulDetails.optimizerSteps``. * Standard JSON: Add ``settings.debug.debugInfo`` option for selecting how much extra debug information should be included in the produced EVM assembly and Yul code. + * TypeChecker: Improve error message in implicit function type conversions failures from and to builtin function types. Bugfixes: diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 17d5b8c3e..e4364b58e 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -37,7 +37,7 @@ namespace solidity::frontend namespace { /// Magic variables get negative ids for easy differentiation -int magicVariableToID(std::string const& _name) +int magicVariableToID(std::string const& _name) // TODO(pr): I think that should be a FunctionType::Kind instead of string. { if (_name == "abi") return -1; else if (_name == "addmod") return -2; @@ -71,37 +71,45 @@ inline vector> constructMagicVariable return make_shared(magicVariableToID(_name), _name, _type); }; + static auto const magicFunDecl = [](FunctionType const* _type) -> shared_ptr { + auto const kind = _type->kind(); + return make_shared( + magicVariableToID(string(FunctionType::magicName(kind))), + ASTString(FunctionType::magicName(kind)), + _type + ); + }; + return { - magicVarDecl("abi", TypeProvider::magic(MagicType::Kind::ABI)), - magicVarDecl("addmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)), - magicVarDecl("assert", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)), - magicVarDecl("block", TypeProvider::magic(MagicType::Kind::Block)), - magicVarDecl("blockhash", TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)), - magicVarDecl("ecrecover", TypeProvider::function(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)), - magicVarDecl("gasleft", TypeProvider::function(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)), - magicVarDecl("keccak256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), - magicVarDecl("msg", TypeProvider::magic(MagicType::Kind::Message)), - magicVarDecl("mulmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)), - magicVarDecl("now", TypeProvider::uint256()), - magicVarDecl("require", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), - magicVarDecl("require", TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), - magicVarDecl("revert", TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), - magicVarDecl("revert", TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), - magicVarDecl("ripemd160", TypeProvider::function(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)), - magicVarDecl("selfdestruct", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), - magicVarDecl("sha256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)), - magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), - magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), - magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)), + // magic functions + magicFunDecl(TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)), + magicFunDecl(TypeProvider::function(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)), + magicFunDecl(TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)), + magicFunDecl(TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), + magicFunDecl(TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)), // Accepts a MagicType that can be any contract type or an Integer type and returns a // MagicType. The TypeChecker handles the correctness of the input and output types. - magicVarDecl("type", TypeProvider::function( - strings{}, - strings{}, - FunctionType::Kind::MetaType, - true, - StateMutability::Pure - )), + magicFunDecl(TypeProvider::function(strings{}, strings{}, FunctionType::Kind::MetaType, true, StateMutability::Pure)), + + // Aliases: sha3 and suicide() are an alias() to keccak256() and selfdestruct() + magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), + magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), + + // magic variables + magicVarDecl("abi", TypeProvider::magic(MagicType::Kind::ABI)), + magicVarDecl("block", TypeProvider::magic(MagicType::Kind::Block)), + magicVarDecl("msg", TypeProvider::magic(MagicType::Kind::Message)), + magicVarDecl("now", TypeProvider::uint256()), + magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)), }; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 70e3ec298..2c7bd0d94 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -467,19 +467,23 @@ bool AddressType::operator==(Type const& _other) const MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const { + auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member { + return {FunctionType::magicName(_functionType->kind()), _functionType}; + }; + MemberList::MemberMap members = { - {"balance", TypeProvider::uint256()}, - {"code", TypeProvider::array(DataLocation::Memory)}, - {"codehash", TypeProvider::fixedBytes(32)}, - {"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)}, - {"callcode", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)}, - {"delegatecall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false, StateMutability::NonPayable)}, - {"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)} + {"balance"sv, TypeProvider::uint256()}, + {"code"sv, TypeProvider::array(DataLocation::Memory)}, + {"codehash"sv, TypeProvider::fixedBytes(32)}, + magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)), + magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)), + magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false, StateMutability::NonPayable)), + magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)) }; if (m_stateMutability == StateMutability::Payable) { - members.emplace_back(MemberList::Member{"send", TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, false, StateMutability::NonPayable)}); - members.emplace_back(MemberList::Member{"transfer", TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, false, StateMutability::NonPayable)}); + members.emplace_back(magicFunc(TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, false, StateMutability::NonPayable))); + members.emplace_back(magicFunc(TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, false, StateMutability::NonPayable))); } return members; } @@ -1806,28 +1810,32 @@ MemberList::MemberMap ArrayType::nativeMembers(ASTNode const*) const members.emplace_back("length", TypeProvider::uint256()); if (isDynamicallySized() && location() == DataLocation::Storage) { + auto const magicBoundFunc = [](FunctionType const* _functionType) -> MemberList::Member { + return {FunctionType::magicName(_functionType->kind()), _functionType->asBoundFunction()}; + }; Type const* thisAsPointer = TypeProvider::withLocation(this, location(), true); - members.emplace_back("push", TypeProvider::function( + + members.emplace_back(magicBoundFunc(TypeProvider::function( TypePointers{thisAsPointer}, TypePointers{baseType()}, strings{string()}, strings{string()}, FunctionType::Kind::ArrayPush - )->asBoundFunction()); - members.emplace_back("push", TypeProvider::function( + ))); + members.emplace_back(magicBoundFunc(TypeProvider::function( TypePointers{thisAsPointer, baseType()}, TypePointers{}, strings{string(),string()}, strings{}, FunctionType::Kind::ArrayPush - )->asBoundFunction()); - members.emplace_back("pop", TypeProvider::function( + ))); + members.emplace_back(magicBoundFunc(TypeProvider::function( TypePointers{thisAsPointer}, TypePointers{}, strings{string()}, strings{}, FunctionType::Kind::ArrayPop - )->asBoundFunction()); + ))); } } return members; @@ -3030,22 +3038,96 @@ string FunctionType::canonicalName() const return "function"; } +string_view FunctionType::magicName(Kind _kind) // TODO(pr): maybe call it languageIdentifier(.) instead +{ + switch (_kind) + { + // magic funcs and vars + case Kind::AddMod: return "addmod"sv; + case Kind::Assert: return "assert"sv; + case Kind::BlockHash: return "blockhash"sv; + case Kind::ECRecover: return "ecrecover"sv; + case Kind::Require: return "require"sv; + case Kind::GasLeft: return "gasleft"sv; + case Kind::KECCAK256: return "keccak256"sv; // NB: sha3 is an alias to keccak256 + case Kind::MulMod: return "mulmod"sv; + case Kind::Revert: return "revert"sv; + case Kind::RIPEMD160: return "ripemd160"sv; + case Kind::Selfdestruct: return "selfdestruct"sv; // NB: suicide() is an alias to selfdestruct() + case Kind::SHA256: return "sha256"sv; + case Kind::MetaType: return "type"sv; + + // native members: ArrayType + case Kind::ArrayPop: return "pop"sv; + case Kind::ArrayPush: return "push"sv; + + // native members: AddressType + case Kind::BareCall: return "call"sv; + case Kind::BareCallCode: return "callcode"sv; + case Kind::BareDelegateCall: return "delegatecall"sv; + case Kind::BareStaticCall: return "staticcall"sv; + case Kind::Send: return "send"sv; + case Kind::Transfer: return "transfer"sv; + + // FunctionType + case Kind::SetValue: return "value"sv; + case Kind::SetGas: return "gas"sv; + + // TypeType + case Kind::Unwrap: return "unwrap"sv; + case Kind::Wrap: return "wrap"sv; + case Kind::BytesConcat: return "concat"sv; + + // MagicType + case Kind::ABIEncode: return "encode"sv; + case Kind::ABIDecode: return "decode"sv; + case Kind::ABIEncodePacked: return "encodePacked"sv; + case Kind::ABIEncodeWithSelector: return "encodeWithSelector"sv; + case Kind::ABIEncodeWithSignature: return "encodeWithSignature"sv; + + + // user defined + case Kind::Error: + case Kind::Event: + case Kind::Creation: + case Kind::Declaration: + case Kind::DelegateCall: + case Kind::External: + case Kind::Internal: + case Kind::ObjectCreation: + break; + } + + return ""sv; +} + string FunctionType::toString(bool _short) const { - string name = "function "; - if (m_kind == Kind::Declaration) + string name; + + if (m_kind == Kind::Event) + name += "event " + m_declaration->name(); + else if (m_kind == Kind::Error) + name += "error " + m_declaration->name(); + else if (magicName(m_kind) != "") + name += magicName(m_kind); + else if (m_kind == Kind::Declaration) { + name += "function "; auto const* functionDefinition = dynamic_cast(m_declaration); solAssert(functionDefinition, ""); if (auto const* contract = dynamic_cast(functionDefinition->scope())) name += *contract->annotation().canonicalName + "."; name += functionDefinition->name(); } + else + name += "function "; + name += '('; for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it) name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ","); name += ")"; - if (m_stateMutability != StateMutability::NonPayable) + if (m_stateMutability != StateMutability::NonPayable && m_kind != Kind::Error) name += " " + stateMutabilityToString(m_stateMutability); if (m_kind == Kind::External) name += " external"; @@ -3190,6 +3272,11 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const { + auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member { + return {FunctionType::magicName(_functionType->kind()), _functionType}; + }; + + switch (m_kind) { case Kind::Declaration: @@ -3229,40 +3316,34 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const if (m_kind != Kind::BareDelegateCall) { if (isPayable()) - members.emplace_back( - "value", - TypeProvider::function( - parseElementaryTypeVector({"uint"}), - TypePointers{copyAndSetCallOptions(false, true, false)}, - strings(1, ""), - strings(1, ""), - Kind::SetValue, - false, - StateMutability::Pure, - nullptr, - m_gasSet, - m_valueSet, - m_saltSet - ) - ); - } - if (m_kind != Kind::Creation) - members.emplace_back( - "gas", - TypeProvider::function( + members.emplace_back(magicFunc(TypeProvider::function( parseElementaryTypeVector({"uint"}), - TypePointers{copyAndSetCallOptions(true, false, false)}, + TypePointers{copyAndSetCallOptions(false, true, false)}, strings(1, ""), strings(1, ""), - Kind::SetGas, + Kind::SetValue, false, StateMutability::Pure, nullptr, m_gasSet, m_valueSet, m_saltSet - ) - ); + ))); + } + if (m_kind != Kind::Creation) + members.emplace_back(magicFunc(TypeProvider::function( + parseElementaryTypeVector({"uint"}), + TypePointers{copyAndSetCallOptions(true, false, false)}, + strings(1, ""), + strings(1, ""), + Kind::SetGas, + false, + StateMutability::Pure, + nullptr, + m_gasSet, + m_valueSet, + m_saltSet + ))); return members; } case Kind::DelegateCall: @@ -3720,6 +3801,11 @@ vector> TypeType::makeStackItems() const MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) const { + auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member { + return {FunctionType::magicName(_functionType->kind()), _functionType}; + }; + + MemberList::MemberMap members; if (m_actualType->category() == Category::Contract) { @@ -3794,8 +3880,7 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons else if (m_actualType->category() == Category::UserDefinedValueType) { auto& userDefined = dynamic_cast(*m_actualType); - members.emplace_back( - "wrap", + members.emplace_back(magicFunc( TypeProvider::function( TypePointers{&userDefined.underlyingType()}, TypePointers{&userDefined}, @@ -3805,9 +3890,8 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons false, /*_arbitraryParameters */ StateMutability::Pure ) - ); - members.emplace_back( - "unwrap", + )); + members.emplace_back(magicFunc( TypeProvider::function( TypePointers{&userDefined}, TypePointers{&userDefined.underlyingType()}, @@ -3817,13 +3901,13 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons false, /* _arbitraryParameters */ StateMutability::Pure ) - ); + )); } else if ( auto const* arrayType = dynamic_cast(m_actualType); arrayType && arrayType->isByteArray() ) - members.emplace_back("concat", TypeProvider::function( + members.emplace_back(magicFunc(TypeProvider::function( TypePointers{}, TypePointers{TypeProvider::bytesMemory()}, strings{}, @@ -3831,7 +3915,7 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons FunctionType::Kind::BytesConcat, /* _arbitraryParameters */ true, StateMutability::Pure - )); + ))); return members; } @@ -3947,35 +4031,39 @@ bool MagicType::operator==(Type const& _other) const MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const { + auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member { + return {FunctionType::magicName(_functionType->kind()), _functionType}; + }; + switch (m_kind) { case Kind::Block: return MemberList::MemberMap({ - {"coinbase", TypeProvider::payableAddress()}, - {"timestamp", TypeProvider::uint256()}, - {"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)}, - {"difficulty", TypeProvider::uint256()}, - {"number", TypeProvider::uint256()}, - {"gaslimit", TypeProvider::uint256()}, - {"chainid", TypeProvider::uint256()}, - {"basefee", TypeProvider::uint256()} + {"coinbase"sv, TypeProvider::payableAddress()}, + {"timestamp"sv, TypeProvider::uint256()}, + magicFunc(TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)), + {"difficulty"sv, TypeProvider::uint256()}, + {"number"sv, TypeProvider::uint256()}, + {"gaslimit"sv, TypeProvider::uint256()}, + {"chainid"sv, TypeProvider::uint256()}, + {"basefee"sv, TypeProvider::uint256()} }); case Kind::Message: return MemberList::MemberMap({ - {"sender", TypeProvider::address()}, - {"gas", TypeProvider::uint256()}, - {"value", TypeProvider::uint256()}, - {"data", TypeProvider::array(DataLocation::CallData)}, - {"sig", TypeProvider::fixedBytes(4)} + {"sender"sv, TypeProvider::address()}, + {"gas"sv, TypeProvider::uint256()}, + {"value"sv, TypeProvider::uint256()}, + {"data"sv, TypeProvider::array(DataLocation::CallData)}, + {"sig"sv, TypeProvider::fixedBytes(4)} }); case Kind::Transaction: return MemberList::MemberMap({ - {"origin", TypeProvider::address()}, - {"gasprice", TypeProvider::uint256()} + {"origin"sv, TypeProvider::address()}, + {"gasprice"sv, TypeProvider::uint256()} }); case Kind::ABI: return MemberList::MemberMap({ - {"encode", TypeProvider::function( + magicFunc(TypeProvider::function( TypePointers{}, TypePointers{TypeProvider::array(DataLocation::Memory)}, strings{}, @@ -3983,8 +4071,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const FunctionType::Kind::ABIEncode, true, StateMutability::Pure - )}, - {"encodePacked", TypeProvider::function( + )), + magicFunc(TypeProvider::function( TypePointers{}, TypePointers{TypeProvider::array(DataLocation::Memory)}, strings{}, @@ -3992,8 +4080,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const FunctionType::Kind::ABIEncodePacked, true, StateMutability::Pure - )}, - {"encodeWithSelector", TypeProvider::function( + )), + magicFunc(TypeProvider::function( TypePointers{TypeProvider::fixedBytes(4)}, TypePointers{TypeProvider::array(DataLocation::Memory)}, strings{1, ""}, @@ -4001,8 +4089,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const FunctionType::Kind::ABIEncodeWithSelector, true, StateMutability::Pure - )}, - {"encodeWithSignature", TypeProvider::function( + )), + magicFunc(TypeProvider::function( TypePointers{TypeProvider::array(DataLocation::Memory, true)}, TypePointers{TypeProvider::array(DataLocation::Memory)}, strings{1, ""}, @@ -4010,8 +4098,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const FunctionType::Kind::ABIEncodeWithSignature, true, StateMutability::Pure - )}, - {"decode", TypeProvider::function( + )), + magicFunc(TypeProvider::function( TypePointers(), TypePointers(), strings{}, @@ -4019,7 +4107,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const FunctionType::Kind::ABIDecode, true, StateMutability::Pure - )} + )) }); case Kind::MetaType: { diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 334e69ba1..d7459bcfd 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -101,7 +101,7 @@ public: struct Member { /// Manual constructor for members that are not taken from a declaration. - Member(char const* _name, Type const* _type): + Member(std::string_view _name, Type const* _type): name(_name), type(_type), declaration(nullptr) @@ -1245,6 +1245,11 @@ public: Declaration, }; + /// Returns the magic name of this function kind, if there is any. + /// + /// If there is no magic or native name for this function, an empty string is returned instead. + static std::string_view magicName(Kind _kind); + /// Creates the type of a function. /// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration. explicit FunctionType(FunctionDefinition const& _function, Kind _kind = Kind::Declaration); diff --git a/test/libsolidity/ASTJSON/used_errors.json b/test/libsolidity/ASTJSON/used_errors.json index a8ca24a28..503c3dd94 100644 --- a/test/libsolidity/ASTJSON/used_errors.json +++ b/test/libsolidity/ASTJSON/used_errors.json @@ -57,7 +57,7 @@ "typeDescriptions": { "typeIdentifier": "t_function_error_pure$__$returns$__$", - "typeString": "function () pure" + "typeString": "error ()" } }, "id": 6, diff --git a/test/libsolidity/syntaxTests/array/concat/bytes_concat_empty_invalid.sol b/test/libsolidity/syntaxTests/array/concat/bytes_concat_empty_invalid.sol index d956c4663..d567bcf1a 100644 --- a/test/libsolidity/syntaxTests/array/concat/bytes_concat_empty_invalid.sol +++ b/test/libsolidity/syntaxTests/array/concat/bytes_concat_empty_invalid.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 6359: (82-94): Return argument type function () pure returns (bytes memory) is not implicitly convertible to expected type (type of first return variable) bytes memory. +// TypeError 6359: (82-94): Return argument type concat() pure returns (bytes memory) is not implicitly convertible to expected type (type of first return variable) bytes memory. diff --git a/test/libsolidity/syntaxTests/constructor/constructor_function_parameter_disallowed_conversion.sol b/test/libsolidity/syntaxTests/constructor/constructor_function_parameter_disallowed_conversion.sol index c32dc60b5..fa7384f2c 100644 --- a/test/libsolidity/syntaxTests/constructor/constructor_function_parameter_disallowed_conversion.sol +++ b/test/libsolidity/syntaxTests/constructor/constructor_function_parameter_disallowed_conversion.sol @@ -53,7 +53,7 @@ contract C { // TypeError 9553: (415-428): Invalid type for argument in function call. Invalid implicit conversion from function () view external returns (uint256) to function () pure external returns (uint256) requested. // TypeError 9553: (465-481): Invalid type for argument in function call. Invalid implicit conversion from function () external returns (uint256) to function () pure external returns (uint256) requested. // TypeError 9553: (518-545): Invalid type for argument in function call. Invalid implicit conversion from function (uint256) pure external returns (uint256) to function () pure external returns (uint256) requested. -// TypeError 9553: (582-589): Invalid type for argument in function call. Invalid implicit conversion from function () view returns (uint256) to function () pure external returns (uint256) requested. Special functions can not be converted to function types. +// TypeError 9553: (582-589): Invalid type for argument in function call. Invalid implicit conversion from gasleft() view returns (uint256) to function () pure external returns (uint256) requested. Special functions can not be converted to function types. // TypeError 9553: (626-629): Invalid type for argument in function call. Invalid implicit conversion from function () pure returns (uint256) to function () pure external returns (uint256) requested. Special functions can not be converted to function types. // TypeError 9553: (666-686): Invalid type for argument in function call. Invalid implicit conversion from function () pure returns (uint256) to function () pure external returns (uint256) requested. Special functions can not be converted to function types. // TypeError 9582: (723-748): Member "testInternalFunction" not found or not visible after argument-dependent lookup in contract C. diff --git a/test/libsolidity/syntaxTests/errors/using.sol b/test/libsolidity/syntaxTests/errors/using.sol index 388fa52ab..ad5a43f86 100644 --- a/test/libsolidity/syntaxTests/errors/using.sol +++ b/test/libsolidity/syntaxTests/errors/using.sol @@ -9,4 +9,4 @@ contract C { } } // ---- -// TypeError 9582: (133-136): Member "f" not found or not visible after argument-dependent lookup in function (uint256) pure. +// TypeError 9582: (133-136): Member "f" not found or not visible after argument-dependent lookup in error E(uint256). diff --git a/test/libsolidity/syntaxTests/errors/weird1.sol b/test/libsolidity/syntaxTests/errors/weird1.sol index b57f34c22..e37a6892d 100644 --- a/test/libsolidity/syntaxTests/errors/weird1.sol +++ b/test/libsolidity/syntaxTests/errors/weird1.sol @@ -4,4 +4,4 @@ contract C { function() internal pure x = E; } // ---- -// TypeError 7407: (58-59): Type function () pure is not implicitly convertible to expected type function () pure. Special functions can not be converted to function types. +// TypeError 7407: (58-59): Type error E() is not implicitly convertible to expected type function () pure. Special functions can not be converted to function types. diff --git a/test/libsolidity/syntaxTests/functionTypes/assign_builtin.sol b/test/libsolidity/syntaxTests/functionTypes/assign_builtin.sol index cb795fede..27408fc39 100644 --- a/test/libsolidity/syntaxTests/functionTypes/assign_builtin.sol +++ b/test/libsolidity/syntaxTests/functionTypes/assign_builtin.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 9574: (42-103): Type function (uint256) view returns (bytes32) is not implicitly convertible to expected type function (uint256) view returns (bytes32). Special functions can not be converted to function types. +// TypeError 9574: (42-103): Type blockhash(uint256) view returns (bytes32) is not implicitly convertible to expected type function (uint256) view returns (bytes32). Special functions can not be converted to function types. diff --git a/test/libsolidity/syntaxTests/functionTypes/event_convert_err.sol b/test/libsolidity/syntaxTests/functionTypes/event_convert_err.sol new file mode 100644 index 000000000..f97096f48 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionTypes/event_convert_err.sol @@ -0,0 +1,9 @@ +contract C { + event That(uint a); + function f() public { + function (uint) pure g = That; + emit That(2); + } +} +// ---- +// TypeError 9574: (71-100): Type event That(uint256) is not implicitly convertible to expected type function (uint256) pure. Special functions can not be converted to function types. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/493_builtin_keccak256_reject_gas.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/493_builtin_keccak256_reject_gas.sol index 75a6ff5a9..cddd1c809 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/493_builtin_keccak256_reject_gas.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/493_builtin_keccak256_reject_gas.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 9582: (47-60): Member "gas" not found or not visible after argument-dependent lookup in function (bytes memory) pure returns (bytes32). +// TypeError 9582: (47-60): Member "gas" not found or not visible after argument-dependent lookup in keccak256(bytes memory) pure returns (bytes32). diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/494_builtin_sha256_reject_gas.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/494_builtin_sha256_reject_gas.sol index a418ef207..3660fbed8 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/494_builtin_sha256_reject_gas.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/494_builtin_sha256_reject_gas.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 9582: (47-57): Member "gas" not found or not visible after argument-dependent lookup in function (bytes memory) pure returns (bytes32). +// TypeError 9582: (47-57): Member "gas" not found or not visible after argument-dependent lookup in sha256(bytes memory) pure returns (bytes32). diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/495_builtin_ripemd160_reject_gas.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/495_builtin_ripemd160_reject_gas.sol index 17b0fc490..365d7d18d 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/495_builtin_ripemd160_reject_gas.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/495_builtin_ripemd160_reject_gas.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 9582: (47-60): Member "gas" not found or not visible after argument-dependent lookup in function (bytes memory) pure returns (bytes20). +// TypeError 9582: (47-60): Member "gas" not found or not visible after argument-dependent lookup in ripemd160(bytes memory) pure returns (bytes20). diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/496_builtin_ecrecover_reject_gas.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/496_builtin_ecrecover_reject_gas.sol index 007cb316a..66b724b1d 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/496_builtin_ecrecover_reject_gas.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/496_builtin_ecrecover_reject_gas.sol @@ -4,4 +4,4 @@ contract C { } } // ---- -// TypeError 9582: (47-60): Member "gas" not found or not visible after argument-dependent lookup in function (bytes32,uint8,bytes32,bytes32) pure returns (address). +// TypeError 9582: (47-60): Member "gas" not found or not visible after argument-dependent lookup in ecrecover(bytes32,uint8,bytes32,bytes32) pure returns (address). diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol index 15bc15fa0..daa7a3b44 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol @@ -4,5 +4,5 @@ function test() pure { function (int) returns (MyInt) g = MyInt.wrap; } // ---- -// TypeError 9574: (46-93): Type function (MyInt) pure returns (int256) is not implicitly convertible to expected type function (MyInt) returns (int256). Special functions can not be converted to function types. -// TypeError 9574: (99-144): Type function (int256) pure returns (MyInt) is not implicitly convertible to expected type function (int256) returns (MyInt). Special functions can not be converted to function types. +// TypeError 9574: (46-93): Type unwrap(MyInt) pure returns (int256) is not implicitly convertible to expected type function (MyInt) returns (int256). Special functions can not be converted to function types. +// TypeError 9574: (99-144): Type wrap(int256) pure returns (MyInt) is not implicitly convertible to expected type function (int256) returns (MyInt). Special functions can not be converted to function types.