Correctly name builtin functions in error messages.

This commit is contained in:
Christian Parpart 2021-10-06 14:15:30 +02:00
parent 3fb42f60b4
commit 843171c70f
16 changed files with 229 additions and 118 deletions

View File

@ -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:

View File

@ -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<shared_ptr<MagicVariableDeclaration const>> constructMagicVariable
return make_shared<MagicVariableDeclaration>(magicVariableToID(_name), _name, _type);
};
static auto const magicFunDecl = [](FunctionType const* _type) -> shared_ptr<MagicVariableDeclaration> {
auto const kind = _type->kind();
return make_shared<MagicVariableDeclaration>(
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)),
};
}

View File

@ -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<FunctionDefinition const*>(m_declaration);
solAssert(functionDefinition, "");
if (auto const* contract = dynamic_cast<ContractDefinition const*>(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<tuple<string, Type const*>> 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<UserDefinedValueType const&>(*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<ArrayType const*>(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:
{

View File

@ -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);

View File

@ -57,7 +57,7 @@
"typeDescriptions":
{
"typeIdentifier": "t_function_error_pure$__$returns$__$",
"typeString": "function () pure"
"typeString": "error ()"
}
},
"id": 6,

View File

@ -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.

View File

@ -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.

View File

@ -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).

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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).

View File

@ -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).

View File

@ -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).

View File

@ -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).

View File

@ -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.