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. * 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: 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. * 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: Bugfixes:

View File

@ -37,7 +37,7 @@ namespace solidity::frontend
namespace namespace
{ {
/// Magic variables get negative ids for easy differentiation /// 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; if (_name == "abi") return -1;
else if (_name == "addmod") return -2; 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); 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 { return {
magicVarDecl("abi", TypeProvider::magic(MagicType::Kind::ABI)), // magic functions
magicVarDecl("addmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)), magicFunDecl(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)), magicFunDecl(TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
magicVarDecl("block", TypeProvider::magic(MagicType::Kind::Block)), magicFunDecl(TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
magicVarDecl("blockhash", 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)),
magicVarDecl("ecrecover", 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)),
magicVarDecl("gasleft", 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)),
magicVarDecl("keccak256", 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)),
magicVarDecl("msg", TypeProvider::magic(MagicType::Kind::Message)), magicFunDecl(TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
magicVarDecl("mulmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)), magicFunDecl(TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)),
magicVarDecl("now", TypeProvider::uint256()), magicFunDecl(TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
magicVarDecl("require", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), magicFunDecl(TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
magicVarDecl("require", TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), magicFunDecl(TypeProvider::function(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
magicVarDecl("revert", TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), magicFunDecl(TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
magicVarDecl("revert", TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), magicFunDecl(TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, 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)),
// Accepts a MagicType that can be any contract type or an Integer type and returns a // 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. // MagicType. The TypeChecker handles the correctness of the input and output types.
magicVarDecl("type", TypeProvider::function( magicFunDecl(TypeProvider::function(strings{}, strings{}, FunctionType::Kind::MetaType, true, StateMutability::Pure)),
strings{},
strings{}, // Aliases: sha3 and suicide() are an alias() to keccak256() and selfdestruct()
FunctionType::Kind::MetaType, magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
true, magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
StateMutability::Pure
)), // 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 MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const
{ {
auto const magicFunc = [](FunctionType const* _functionType) -> MemberList::Member {
return {FunctionType::magicName(_functionType->kind()), _functionType};
};
MemberList::MemberMap members = { MemberList::MemberMap members = {
{"balance", TypeProvider::uint256()}, {"balance"sv, TypeProvider::uint256()},
{"code", TypeProvider::array(DataLocation::Memory)}, {"code"sv, TypeProvider::array(DataLocation::Memory)},
{"codehash", TypeProvider::fixedBytes(32)}, {"codehash"sv, TypeProvider::fixedBytes(32)},
{"call", 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::BareCall, false, StateMutability::Payable)),
{"callcode", 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::BareCallCode, false, StateMutability::Payable)),
{"delegatecall", 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::BareDelegateCall, false, StateMutability::NonPayable)),
{"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)} magicFunc(TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View))
}; };
if (m_stateMutability == StateMutability::Payable) 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(magicFunc(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(), FunctionType::Kind::Transfer, false, StateMutability::NonPayable)));
} }
return members; return members;
} }
@ -1806,28 +1810,32 @@ MemberList::MemberMap ArrayType::nativeMembers(ASTNode const*) const
members.emplace_back("length", TypeProvider::uint256()); members.emplace_back("length", TypeProvider::uint256());
if (isDynamicallySized() && location() == DataLocation::Storage) 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); Type const* thisAsPointer = TypeProvider::withLocation(this, location(), true);
members.emplace_back("push", TypeProvider::function(
members.emplace_back(magicBoundFunc(TypeProvider::function(
TypePointers{thisAsPointer}, TypePointers{thisAsPointer},
TypePointers{baseType()}, TypePointers{baseType()},
strings{string()}, strings{string()},
strings{string()}, strings{string()},
FunctionType::Kind::ArrayPush FunctionType::Kind::ArrayPush
)->asBoundFunction()); )));
members.emplace_back("push", TypeProvider::function( members.emplace_back(magicBoundFunc(TypeProvider::function(
TypePointers{thisAsPointer, baseType()}, TypePointers{thisAsPointer, baseType()},
TypePointers{}, TypePointers{},
strings{string(),string()}, strings{string(),string()},
strings{}, strings{},
FunctionType::Kind::ArrayPush FunctionType::Kind::ArrayPush
)->asBoundFunction()); )));
members.emplace_back("pop", TypeProvider::function( members.emplace_back(magicBoundFunc(TypeProvider::function(
TypePointers{thisAsPointer}, TypePointers{thisAsPointer},
TypePointers{}, TypePointers{},
strings{string()}, strings{string()},
strings{}, strings{},
FunctionType::Kind::ArrayPop FunctionType::Kind::ArrayPop
)->asBoundFunction()); )));
} }
} }
return members; return members;
@ -3030,22 +3038,96 @@ string FunctionType::canonicalName() const
return "function"; 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 FunctionType::toString(bool _short) const
{ {
string name = "function "; string name;
if (m_kind == Kind::Declaration)
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); auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(m_declaration);
solAssert(functionDefinition, ""); solAssert(functionDefinition, "");
if (auto const* contract = dynamic_cast<ContractDefinition const*>(functionDefinition->scope())) if (auto const* contract = dynamic_cast<ContractDefinition const*>(functionDefinition->scope()))
name += *contract->annotation().canonicalName + "."; name += *contract->annotation().canonicalName + ".";
name += functionDefinition->name(); name += functionDefinition->name();
} }
else
name += "function ";
name += '('; name += '(';
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it) for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ","); name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
name += ")"; name += ")";
if (m_stateMutability != StateMutability::NonPayable) if (m_stateMutability != StateMutability::NonPayable && m_kind != Kind::Error)
name += " " + stateMutabilityToString(m_stateMutability); name += " " + stateMutabilityToString(m_stateMutability);
if (m_kind == Kind::External) if (m_kind == Kind::External)
name += " external"; name += " external";
@ -3190,6 +3272,11 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) 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) switch (m_kind)
{ {
case Kind::Declaration: case Kind::Declaration:
@ -3229,40 +3316,34 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
if (m_kind != Kind::BareDelegateCall) if (m_kind != Kind::BareDelegateCall)
{ {
if (isPayable()) if (isPayable())
members.emplace_back( members.emplace_back(magicFunc(TypeProvider::function(
"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(
parseElementaryTypeVector({"uint"}), parseElementaryTypeVector({"uint"}),
TypePointers{copyAndSetCallOptions(true, false, false)}, TypePointers{copyAndSetCallOptions(false, true, false)},
strings(1, ""), strings(1, ""),
strings(1, ""), strings(1, ""),
Kind::SetGas, Kind::SetValue,
false, false,
StateMutability::Pure, StateMutability::Pure,
nullptr, nullptr,
m_gasSet, m_gasSet,
m_valueSet, m_valueSet,
m_saltSet 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; return members;
} }
case Kind::DelegateCall: case Kind::DelegateCall:
@ -3720,6 +3801,11 @@ vector<tuple<string, Type const*>> TypeType::makeStackItems() const
MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) 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; MemberList::MemberMap members;
if (m_actualType->category() == Category::Contract) 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) else if (m_actualType->category() == Category::UserDefinedValueType)
{ {
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(*m_actualType); auto& userDefined = dynamic_cast<UserDefinedValueType const&>(*m_actualType);
members.emplace_back( members.emplace_back(magicFunc(
"wrap",
TypeProvider::function( TypeProvider::function(
TypePointers{&userDefined.underlyingType()}, TypePointers{&userDefined.underlyingType()},
TypePointers{&userDefined}, TypePointers{&userDefined},
@ -3805,9 +3890,8 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
false, /*_arbitraryParameters */ false, /*_arbitraryParameters */
StateMutability::Pure StateMutability::Pure
) )
); ));
members.emplace_back( members.emplace_back(magicFunc(
"unwrap",
TypeProvider::function( TypeProvider::function(
TypePointers{&userDefined}, TypePointers{&userDefined},
TypePointers{&userDefined.underlyingType()}, TypePointers{&userDefined.underlyingType()},
@ -3817,13 +3901,13 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
false, /* _arbitraryParameters */ false, /* _arbitraryParameters */
StateMutability::Pure StateMutability::Pure
) )
); ));
} }
else if ( else if (
auto const* arrayType = dynamic_cast<ArrayType const*>(m_actualType); auto const* arrayType = dynamic_cast<ArrayType const*>(m_actualType);
arrayType && arrayType->isByteArray() arrayType && arrayType->isByteArray()
) )
members.emplace_back("concat", TypeProvider::function( members.emplace_back(magicFunc(TypeProvider::function(
TypePointers{}, TypePointers{},
TypePointers{TypeProvider::bytesMemory()}, TypePointers{TypeProvider::bytesMemory()},
strings{}, strings{},
@ -3831,7 +3915,7 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons
FunctionType::Kind::BytesConcat, FunctionType::Kind::BytesConcat,
/* _arbitraryParameters */ true, /* _arbitraryParameters */ true,
StateMutability::Pure StateMutability::Pure
)); )));
return members; return members;
} }
@ -3947,35 +4031,39 @@ bool MagicType::operator==(Type const& _other) const
MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) 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) switch (m_kind)
{ {
case Kind::Block: case Kind::Block:
return MemberList::MemberMap({ return MemberList::MemberMap({
{"coinbase", TypeProvider::payableAddress()}, {"coinbase"sv, TypeProvider::payableAddress()},
{"timestamp", TypeProvider::uint256()}, {"timestamp"sv, TypeProvider::uint256()},
{"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)}, magicFunc(TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
{"difficulty", TypeProvider::uint256()}, {"difficulty"sv, TypeProvider::uint256()},
{"number", TypeProvider::uint256()}, {"number"sv, TypeProvider::uint256()},
{"gaslimit", TypeProvider::uint256()}, {"gaslimit"sv, TypeProvider::uint256()},
{"chainid", TypeProvider::uint256()}, {"chainid"sv, TypeProvider::uint256()},
{"basefee", TypeProvider::uint256()} {"basefee"sv, TypeProvider::uint256()}
}); });
case Kind::Message: case Kind::Message:
return MemberList::MemberMap({ return MemberList::MemberMap({
{"sender", TypeProvider::address()}, {"sender"sv, TypeProvider::address()},
{"gas", TypeProvider::uint256()}, {"gas"sv, TypeProvider::uint256()},
{"value", TypeProvider::uint256()}, {"value"sv, TypeProvider::uint256()},
{"data", TypeProvider::array(DataLocation::CallData)}, {"data"sv, TypeProvider::array(DataLocation::CallData)},
{"sig", TypeProvider::fixedBytes(4)} {"sig"sv, TypeProvider::fixedBytes(4)}
}); });
case Kind::Transaction: case Kind::Transaction:
return MemberList::MemberMap({ return MemberList::MemberMap({
{"origin", TypeProvider::address()}, {"origin"sv, TypeProvider::address()},
{"gasprice", TypeProvider::uint256()} {"gasprice"sv, TypeProvider::uint256()}
}); });
case Kind::ABI: case Kind::ABI:
return MemberList::MemberMap({ return MemberList::MemberMap({
{"encode", TypeProvider::function( magicFunc(TypeProvider::function(
TypePointers{}, TypePointers{},
TypePointers{TypeProvider::array(DataLocation::Memory)}, TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{}, strings{},
@ -3983,8 +4071,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncode, FunctionType::Kind::ABIEncode,
true, true,
StateMutability::Pure StateMutability::Pure
)}, )),
{"encodePacked", TypeProvider::function( magicFunc(TypeProvider::function(
TypePointers{}, TypePointers{},
TypePointers{TypeProvider::array(DataLocation::Memory)}, TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{}, strings{},
@ -3992,8 +4080,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncodePacked, FunctionType::Kind::ABIEncodePacked,
true, true,
StateMutability::Pure StateMutability::Pure
)}, )),
{"encodeWithSelector", TypeProvider::function( magicFunc(TypeProvider::function(
TypePointers{TypeProvider::fixedBytes(4)}, TypePointers{TypeProvider::fixedBytes(4)},
TypePointers{TypeProvider::array(DataLocation::Memory)}, TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{1, ""}, strings{1, ""},
@ -4001,8 +4089,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncodeWithSelector, FunctionType::Kind::ABIEncodeWithSelector,
true, true,
StateMutability::Pure StateMutability::Pure
)}, )),
{"encodeWithSignature", TypeProvider::function( magicFunc(TypeProvider::function(
TypePointers{TypeProvider::array(DataLocation::Memory, true)}, TypePointers{TypeProvider::array(DataLocation::Memory, true)},
TypePointers{TypeProvider::array(DataLocation::Memory)}, TypePointers{TypeProvider::array(DataLocation::Memory)},
strings{1, ""}, strings{1, ""},
@ -4010,8 +4098,8 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIEncodeWithSignature, FunctionType::Kind::ABIEncodeWithSignature,
true, true,
StateMutability::Pure StateMutability::Pure
)}, )),
{"decode", TypeProvider::function( magicFunc(TypeProvider::function(
TypePointers(), TypePointers(),
TypePointers(), TypePointers(),
strings{}, strings{},
@ -4019,7 +4107,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
FunctionType::Kind::ABIDecode, FunctionType::Kind::ABIDecode,
true, true,
StateMutability::Pure StateMutability::Pure
)} ))
}); });
case Kind::MetaType: case Kind::MetaType:
{ {

View File

@ -101,7 +101,7 @@ public:
struct Member struct Member
{ {
/// Manual constructor for members that are not taken from a declaration. /// 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), name(_name),
type(_type), type(_type),
declaration(nullptr) declaration(nullptr)
@ -1245,6 +1245,11 @@ public:
Declaration, 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. /// Creates the type of a function.
/// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration. /// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration.
explicit FunctionType(FunctionDefinition const& _function, Kind _kind = Kind::Declaration); explicit FunctionType(FunctionDefinition const& _function, Kind _kind = Kind::Declaration);

View File

@ -57,7 +57,7 @@
"typeDescriptions": "typeDescriptions":
{ {
"typeIdentifier": "t_function_error_pure$__$returns$__$", "typeIdentifier": "t_function_error_pure$__$returns$__$",
"typeString": "function () pure" "typeString": "error ()"
} }
}, },
"id": 6, "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: (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: (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: (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: (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 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. // 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; 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; 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: (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 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: (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.