mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #1792 from ethereum/function-kind
Rename FunctionType::Location to Kind
This commit is contained in:
commit
245c8914cf
@ -39,39 +39,39 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared<
|
|||||||
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
|
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
|
||||||
make_shared<MagicVariableDeclaration>("now", make_shared<IntegerType>(256)),
|
make_shared<MagicVariableDeclaration>("now", make_shared<IntegerType>(256)),
|
||||||
make_shared<MagicVariableDeclaration>("suicide",
|
make_shared<MagicVariableDeclaration>("suicide",
|
||||||
make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Location::Selfdestruct)),
|
make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||||
make_shared<MagicVariableDeclaration>("selfdestruct",
|
make_shared<MagicVariableDeclaration>("selfdestruct",
|
||||||
make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Location::Selfdestruct)),
|
make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||||
make_shared<MagicVariableDeclaration>("addmod",
|
make_shared<MagicVariableDeclaration>("addmod",
|
||||||
make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Location::AddMod)),
|
make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod)),
|
||||||
make_shared<MagicVariableDeclaration>("mulmod",
|
make_shared<MagicVariableDeclaration>("mulmod",
|
||||||
make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Location::MulMod)),
|
make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod)),
|
||||||
make_shared<MagicVariableDeclaration>("sha3",
|
make_shared<MagicVariableDeclaration>("sha3",
|
||||||
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)),
|
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true)),
|
||||||
make_shared<MagicVariableDeclaration>("keccak256",
|
make_shared<MagicVariableDeclaration>("keccak256",
|
||||||
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)),
|
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true)),
|
||||||
make_shared<MagicVariableDeclaration>("log0",
|
make_shared<MagicVariableDeclaration>("log0",
|
||||||
make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Location::Log0)),
|
make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Kind::Log0)),
|
||||||
make_shared<MagicVariableDeclaration>("log1",
|
make_shared<MagicVariableDeclaration>("log1",
|
||||||
make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Location::Log1)),
|
make_shared<FunctionType>(strings{"bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log1)),
|
||||||
make_shared<MagicVariableDeclaration>("log2",
|
make_shared<MagicVariableDeclaration>("log2",
|
||||||
make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Location::Log2)),
|
make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log2)),
|
||||||
make_shared<MagicVariableDeclaration>("log3",
|
make_shared<MagicVariableDeclaration>("log3",
|
||||||
make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Location::Log3)),
|
make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log3)),
|
||||||
make_shared<MagicVariableDeclaration>("log4",
|
make_shared<MagicVariableDeclaration>("log4",
|
||||||
make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Location::Log4)),
|
make_shared<FunctionType>(strings{"bytes32", "bytes32", "bytes32", "bytes32", "bytes32"}, strings{}, FunctionType::Kind::Log4)),
|
||||||
make_shared<MagicVariableDeclaration>("sha256",
|
make_shared<MagicVariableDeclaration>("sha256",
|
||||||
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA256, true)),
|
make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA256, true)),
|
||||||
make_shared<MagicVariableDeclaration>("ecrecover",
|
make_shared<MagicVariableDeclaration>("ecrecover",
|
||||||
make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Location::ECRecover)),
|
make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover)),
|
||||||
make_shared<MagicVariableDeclaration>("ripemd160",
|
make_shared<MagicVariableDeclaration>("ripemd160",
|
||||||
make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Location::RIPEMD160, true)),
|
make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Kind::RIPEMD160, true)),
|
||||||
make_shared<MagicVariableDeclaration>("assert",
|
make_shared<MagicVariableDeclaration>("assert",
|
||||||
make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Assert)),
|
make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Assert)),
|
||||||
make_shared<MagicVariableDeclaration>("require",
|
make_shared<MagicVariableDeclaration>("require",
|
||||||
make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Require)),
|
make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Require)),
|
||||||
make_shared<MagicVariableDeclaration>("revert",
|
make_shared<MagicVariableDeclaration>("revert",
|
||||||
make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Revert))})
|
make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert))})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,7 +582,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
|||||||
void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
||||||
{
|
{
|
||||||
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
|
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
|
||||||
if (fun.location() == FunctionType::Location::External)
|
if (fun.kind() == FunctionType::Kind::External)
|
||||||
if (!fun.canBeUsedExternally(false))
|
if (!fun.canBeUsedExternally(false))
|
||||||
typeError(_funType.location(), "External function type uses internal types.");
|
typeError(_funType.location(), "External function type uses internal types.");
|
||||||
}
|
}
|
||||||
@ -886,15 +886,14 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
|||||||
{
|
{
|
||||||
if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression()).get()))
|
if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression()).get()))
|
||||||
{
|
{
|
||||||
using Location = FunctionType::Location;
|
auto kind = callType->kind();
|
||||||
Location location = callType->location();
|
|
||||||
if (
|
if (
|
||||||
location == Location::Bare ||
|
kind == FunctionType::Kind::Bare ||
|
||||||
location == Location::BareCallCode ||
|
kind == FunctionType::Kind::BareCallCode ||
|
||||||
location == Location::BareDelegateCall
|
kind == FunctionType::Kind::BareDelegateCall
|
||||||
)
|
)
|
||||||
warning(_statement.location(), "Return value of low-level calls not used.");
|
warning(_statement.location(), "Return value of low-level calls not used.");
|
||||||
else if (location == Location::Send)
|
else if (kind == FunctionType::Kind::Send)
|
||||||
warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead.");
|
warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1387,7 +1386,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
|||||||
TypePointers{type},
|
TypePointers{type},
|
||||||
strings(),
|
strings(),
|
||||||
strings(),
|
strings(),
|
||||||
FunctionType::Location::ObjectCreation
|
FunctionType::Kind::ObjectCreation
|
||||||
);
|
);
|
||||||
_newExpression.annotation().isPure = true;
|
_newExpression.annotation().isPure = true;
|
||||||
}
|
}
|
||||||
|
@ -462,11 +462,11 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons
|
|||||||
if (isAddress())
|
if (isAddress())
|
||||||
return {
|
return {
|
||||||
{"balance", make_shared<IntegerType >(256)},
|
{"balance", make_shared<IntegerType >(256)},
|
||||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true, false, true)},
|
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::Bare, true, false, true)},
|
||||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true, false, true)},
|
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, false, true)},
|
||||||
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareDelegateCall, true)},
|
{"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)},
|
||||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)},
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
|
||||||
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Location::Transfer)}
|
{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
|
||||||
};
|
};
|
||||||
else
|
else
|
||||||
return MemberList::MemberMap();
|
return MemberList::MemberMap();
|
||||||
@ -1466,7 +1466,7 @@ MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
|
|||||||
TypePointers{make_shared<IntegerType>(256)},
|
TypePointers{make_shared<IntegerType>(256)},
|
||||||
strings{string()},
|
strings{string()},
|
||||||
strings{string()},
|
strings{string()},
|
||||||
isByteArray() ? FunctionType::Location::ByteArrayPush : FunctionType::Location::ArrayPush
|
isByteArray() ? FunctionType::Kind::ByteArrayPush : FunctionType::Kind::ArrayPush
|
||||||
)});
|
)});
|
||||||
}
|
}
|
||||||
return members;
|
return members;
|
||||||
@ -1766,7 +1766,7 @@ FunctionTypePointer StructType::constructorType() const
|
|||||||
TypePointers{copyForLocation(DataLocation::Memory, false)},
|
TypePointers{copyForLocation(DataLocation::Memory, false)},
|
||||||
paramNames,
|
paramNames,
|
||||||
strings(),
|
strings(),
|
||||||
FunctionType::Location::Internal
|
FunctionType::Kind::Internal
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1967,7 +1967,7 @@ TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
|
FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
|
||||||
m_location(_isInternal ? Location::Internal : Location::External),
|
m_kind(_isInternal ? Kind::Internal : Kind::External),
|
||||||
m_isConstant(_function.isDeclaredConst()),
|
m_isConstant(_function.isDeclaredConst()),
|
||||||
m_isPayable(_isInternal ? false : _function.isPayable()),
|
m_isPayable(_isInternal ? false : _function.isPayable()),
|
||||||
m_declaration(&_function)
|
m_declaration(&_function)
|
||||||
@ -1998,7 +1998,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
||||||
m_location(Location::External), m_isConstant(true), m_declaration(&_varDecl)
|
m_kind(Kind::External), m_isConstant(true), m_declaration(&_varDecl)
|
||||||
{
|
{
|
||||||
TypePointers paramTypes;
|
TypePointers paramTypes;
|
||||||
vector<string> paramNames;
|
vector<string> paramNames;
|
||||||
@ -2058,7 +2058,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionType::FunctionType(EventDefinition const& _event):
|
FunctionType::FunctionType(EventDefinition const& _event):
|
||||||
m_location(Location::Event), m_isConstant(true), m_declaration(&_event)
|
m_kind(Kind::Event), m_isConstant(true), m_declaration(&_event)
|
||||||
{
|
{
|
||||||
TypePointers params;
|
TypePointers params;
|
||||||
vector<string> paramNames;
|
vector<string> paramNames;
|
||||||
@ -2074,19 +2074,19 @@ FunctionType::FunctionType(EventDefinition const& _event):
|
|||||||
}
|
}
|
||||||
|
|
||||||
FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
||||||
m_location(_typeName.visibility() == VariableDeclaration::Visibility::External ? Location::External : Location::Internal),
|
m_kind(_typeName.visibility() == VariableDeclaration::Visibility::External ? Kind::External : Kind::Internal),
|
||||||
m_isConstant(_typeName.isDeclaredConst()),
|
m_isConstant(_typeName.isDeclaredConst()),
|
||||||
m_isPayable(_typeName.isPayable())
|
m_isPayable(_typeName.isPayable())
|
||||||
{
|
{
|
||||||
if (_typeName.isPayable())
|
if (_typeName.isPayable())
|
||||||
{
|
{
|
||||||
solAssert(m_location == Location::External, "Internal payable function type used.");
|
solAssert(m_kind == Kind::External, "Internal payable function type used.");
|
||||||
solAssert(!m_isConstant, "Payable constant function");
|
solAssert(!m_isConstant, "Payable constant function");
|
||||||
}
|
}
|
||||||
for (auto const& t: _typeName.parameterTypes())
|
for (auto const& t: _typeName.parameterTypes())
|
||||||
{
|
{
|
||||||
solAssert(t->annotation().type, "Type not set for parameter.");
|
solAssert(t->annotation().type, "Type not set for parameter.");
|
||||||
if (m_location == Location::External)
|
if (m_kind == Kind::External)
|
||||||
solAssert(
|
solAssert(
|
||||||
t->annotation().type->canBeUsedExternally(false),
|
t->annotation().type->canBeUsedExternally(false),
|
||||||
"Internal type used as parameter for external function."
|
"Internal type used as parameter for external function."
|
||||||
@ -2096,7 +2096,7 @@ FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
|||||||
for (auto const& t: _typeName.returnParameterTypes())
|
for (auto const& t: _typeName.returnParameterTypes())
|
||||||
{
|
{
|
||||||
solAssert(t->annotation().type, "Type not set for return parameter.");
|
solAssert(t->annotation().type, "Type not set for return parameter.");
|
||||||
if (m_location == Location::External)
|
if (m_kind == Kind::External)
|
||||||
solAssert(
|
solAssert(
|
||||||
t->annotation().type->canBeUsedExternally(false),
|
t->annotation().type->canBeUsedExternally(false),
|
||||||
"Internal type used as return parameter for external function."
|
"Internal type used as return parameter for external function."
|
||||||
@ -2126,7 +2126,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
|
|||||||
TypePointers{make_shared<ContractType>(_contract)},
|
TypePointers{make_shared<ContractType>(_contract)},
|
||||||
parameterNames,
|
parameterNames,
|
||||||
strings{""},
|
strings{""},
|
||||||
Location::Creation,
|
Kind::Creation,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
false,
|
||||||
@ -2151,38 +2151,38 @@ TypePointers FunctionType::parameterTypes() const
|
|||||||
string FunctionType::identifier() const
|
string FunctionType::identifier() const
|
||||||
{
|
{
|
||||||
string id = "t_function_";
|
string id = "t_function_";
|
||||||
switch (location())
|
switch (m_kind)
|
||||||
{
|
{
|
||||||
case Location::Internal: id += "internal"; break;
|
case Kind::Internal: id += "internal"; break;
|
||||||
case Location::External: id += "external"; break;
|
case Kind::External: id += "external"; break;
|
||||||
case Location::CallCode: id += "callcode"; break;
|
case Kind::CallCode: id += "callcode"; break;
|
||||||
case Location::DelegateCall: id += "delegatecall"; break;
|
case Kind::DelegateCall: id += "delegatecall"; break;
|
||||||
case Location::Bare: id += "bare"; break;
|
case Kind::Bare: id += "bare"; break;
|
||||||
case Location::BareCallCode: id += "barecallcode"; break;
|
case Kind::BareCallCode: id += "barecallcode"; break;
|
||||||
case Location::BareDelegateCall: id += "baredelegatecall"; break;
|
case Kind::BareDelegateCall: id += "baredelegatecall"; break;
|
||||||
case Location::Creation: id += "creation"; break;
|
case Kind::Creation: id += "creation"; break;
|
||||||
case Location::Send: id += "send"; break;
|
case Kind::Send: id += "send"; break;
|
||||||
case Location::Transfer: id += "transfer"; break;
|
case Kind::Transfer: id += "transfer"; break;
|
||||||
case Location::SHA3: id += "sha3"; break;
|
case Kind::SHA3: id += "sha3"; break;
|
||||||
case Location::Selfdestruct: id += "selfdestruct"; break;
|
case Kind::Selfdestruct: id += "selfdestruct"; break;
|
||||||
case Location::Revert: id += "revert"; break;
|
case Kind::Revert: id += "revert"; break;
|
||||||
case Location::ECRecover: id += "ecrecover"; break;
|
case Kind::ECRecover: id += "ecrecover"; break;
|
||||||
case Location::SHA256: id += "sha256"; break;
|
case Kind::SHA256: id += "sha256"; break;
|
||||||
case Location::RIPEMD160: id += "ripemd160"; break;
|
case Kind::RIPEMD160: id += "ripemd160"; break;
|
||||||
case Location::Log0: id += "log0"; break;
|
case Kind::Log0: id += "log0"; break;
|
||||||
case Location::Log1: id += "log1"; break;
|
case Kind::Log1: id += "log1"; break;
|
||||||
case Location::Log2: id += "log2"; break;
|
case Kind::Log2: id += "log2"; break;
|
||||||
case Location::Log3: id += "log3"; break;
|
case Kind::Log3: id += "log3"; break;
|
||||||
case Location::Log4: id += "log4"; break;
|
case Kind::Log4: id += "log4"; break;
|
||||||
case Location::Event: id += "event"; break;
|
case Kind::Event: id += "event"; break;
|
||||||
case Location::SetGas: id += "setgas"; break;
|
case Kind::SetGas: id += "setgas"; break;
|
||||||
case Location::SetValue: id += "setvalue"; break;
|
case Kind::SetValue: id += "setvalue"; break;
|
||||||
case Location::BlockHash: id += "blockhash"; break;
|
case Kind::BlockHash: id += "blockhash"; break;
|
||||||
case Location::AddMod: id += "addmod"; break;
|
case Kind::AddMod: id += "addmod"; break;
|
||||||
case Location::MulMod: id += "mulmod"; break;
|
case Kind::MulMod: id += "mulmod"; break;
|
||||||
case Location::ArrayPush: id += "arraypush"; break;
|
case Kind::ArrayPush: id += "arraypush"; break;
|
||||||
case Location::ByteArrayPush: id += "bytearraypush"; break;
|
case Kind::ByteArrayPush: id += "bytearraypush"; break;
|
||||||
case Location::ObjectCreation: id += "objectcreation"; break;
|
case Kind::ObjectCreation: id += "objectcreation"; break;
|
||||||
default: solAssert(false, "Unknown function location."); break;
|
default: solAssert(false, "Unknown function location."); break;
|
||||||
}
|
}
|
||||||
if (isConstant())
|
if (isConstant())
|
||||||
@ -2203,7 +2203,7 @@ bool FunctionType::operator==(Type const& _other) const
|
|||||||
return false;
|
return false;
|
||||||
FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
|
FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
|
||||||
|
|
||||||
if (m_location != other.m_location)
|
if (m_kind != other.m_kind)
|
||||||
return false;
|
return false;
|
||||||
if (m_isConstant != other.isConstant())
|
if (m_isConstant != other.isConstant())
|
||||||
return false;
|
return false;
|
||||||
@ -2231,7 +2231,7 @@ bool FunctionType::operator==(Type const& _other) const
|
|||||||
|
|
||||||
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
if (m_location == Location::External && _convertTo.category() == Category::Integer)
|
if (m_kind == Kind::External && _convertTo.category() == Category::Integer)
|
||||||
{
|
{
|
||||||
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
|
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
|
||||||
if (convertTo.isAddress())
|
if (convertTo.isAddress())
|
||||||
@ -2249,7 +2249,7 @@ TypePointer FunctionType::unaryOperatorResult(Token::Value _operator) const
|
|||||||
|
|
||||||
string FunctionType::canonicalName(bool) const
|
string FunctionType::canonicalName(bool) const
|
||||||
{
|
{
|
||||||
solAssert(m_location == Location::External, "");
|
solAssert(m_kind == Kind::External, "");
|
||||||
return "function";
|
return "function";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2263,7 +2263,7 @@ string FunctionType::toString(bool _short) const
|
|||||||
name += " constant";
|
name += " constant";
|
||||||
if (m_isPayable)
|
if (m_isPayable)
|
||||||
name += " payable";
|
name += " payable";
|
||||||
if (m_location == Location::External)
|
if (m_kind == Kind::External)
|
||||||
name += " external";
|
name += " external";
|
||||||
if (!m_returnParameterTypes.empty())
|
if (!m_returnParameterTypes.empty())
|
||||||
{
|
{
|
||||||
@ -2285,7 +2285,7 @@ unsigned FunctionType::calldataEncodedSize(bool _padded) const
|
|||||||
|
|
||||||
u256 FunctionType::storageSize() const
|
u256 FunctionType::storageSize() const
|
||||||
{
|
{
|
||||||
if (m_location == Location::External || m_location == Location::Internal)
|
if (m_kind == Kind::External || m_kind == Kind::Internal)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
@ -2295,9 +2295,9 @@ u256 FunctionType::storageSize() const
|
|||||||
|
|
||||||
unsigned FunctionType::storageBytes() const
|
unsigned FunctionType::storageBytes() const
|
||||||
{
|
{
|
||||||
if (m_location == Location::External)
|
if (m_kind == Kind::External)
|
||||||
return 20 + 4;
|
return 20 + 4;
|
||||||
else if (m_location == Location::Internal)
|
else if (m_kind == Kind::Internal)
|
||||||
return 8; // it should really not be possible to create larger programs
|
return 8; // it should really not be possible to create larger programs
|
||||||
else
|
else
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
@ -2307,21 +2307,21 @@ unsigned FunctionType::storageBytes() const
|
|||||||
|
|
||||||
unsigned FunctionType::sizeOnStack() const
|
unsigned FunctionType::sizeOnStack() const
|
||||||
{
|
{
|
||||||
Location location = m_location;
|
Kind kind = m_kind;
|
||||||
if (m_location == Location::SetGas || m_location == Location::SetValue)
|
if (m_kind == Kind::SetGas || m_kind == Kind::SetValue)
|
||||||
{
|
{
|
||||||
solAssert(m_returnParameterTypes.size() == 1, "");
|
solAssert(m_returnParameterTypes.size() == 1, "");
|
||||||
location = dynamic_cast<FunctionType const&>(*m_returnParameterTypes.front()).m_location;
|
kind = dynamic_cast<FunctionType const&>(*m_returnParameterTypes.front()).m_kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
if (location == Location::External || location == Location::CallCode || location == Location::DelegateCall)
|
if (kind == Kind::External || kind == Kind::CallCode || kind == Kind::DelegateCall)
|
||||||
size = 2;
|
size = 2;
|
||||||
else if (location == Location::Bare || location == Location::BareCallCode || location == Location::BareDelegateCall)
|
else if (kind == Kind::Bare || kind == Kind::BareCallCode || kind == Kind::BareDelegateCall)
|
||||||
size = 1;
|
size = 1;
|
||||||
else if (location == Location::Internal)
|
else if (kind == Kind::Internal)
|
||||||
size = 1;
|
size = 1;
|
||||||
else if (location == Location::ArrayPush || location == Location::ByteArrayPush)
|
else if (kind == Kind::ArrayPush || kind == Kind::ByteArrayPush)
|
||||||
size = 1;
|
size = 1;
|
||||||
if (m_gasSet)
|
if (m_gasSet)
|
||||||
size++;
|
size++;
|
||||||
@ -2362,26 +2362,26 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
|||||||
return make_shared<FunctionType>(
|
return make_shared<FunctionType>(
|
||||||
paramTypes, retParamTypes,
|
paramTypes, retParamTypes,
|
||||||
m_parameterNames, m_returnParameterNames,
|
m_parameterNames, m_returnParameterNames,
|
||||||
m_location, m_arbitraryParameters,
|
m_kind, m_arbitraryParameters,
|
||||||
m_declaration, m_isConstant, m_isPayable
|
m_declaration, m_isConstant, m_isPayable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) const
|
MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) const
|
||||||
{
|
{
|
||||||
switch (m_location)
|
switch (m_kind)
|
||||||
{
|
{
|
||||||
case Location::External:
|
case Kind::External:
|
||||||
case Location::Creation:
|
case Kind::Creation:
|
||||||
case Location::ECRecover:
|
case Kind::ECRecover:
|
||||||
case Location::SHA256:
|
case Kind::SHA256:
|
||||||
case Location::RIPEMD160:
|
case Kind::RIPEMD160:
|
||||||
case Location::Bare:
|
case Kind::Bare:
|
||||||
case Location::BareCallCode:
|
case Kind::BareCallCode:
|
||||||
case Location::BareDelegateCall:
|
case Kind::BareDelegateCall:
|
||||||
{
|
{
|
||||||
MemberList::MemberMap members;
|
MemberList::MemberMap members;
|
||||||
if (m_location != Location::BareDelegateCall && m_location != Location::DelegateCall)
|
if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall)
|
||||||
{
|
{
|
||||||
if (m_isPayable)
|
if (m_isPayable)
|
||||||
members.push_back(MemberList::Member(
|
members.push_back(MemberList::Member(
|
||||||
@ -2391,7 +2391,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
TypePointers{copyAndSetGasOrValue(false, true)},
|
TypePointers{copyAndSetGasOrValue(false, true)},
|
||||||
strings(),
|
strings(),
|
||||||
strings(),
|
strings(),
|
||||||
Location::SetValue,
|
Kind::SetValue,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
false,
|
||||||
@ -2401,7 +2401,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
)
|
)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (m_location != Location::Creation)
|
if (m_kind != Kind::Creation)
|
||||||
members.push_back(MemberList::Member(
|
members.push_back(MemberList::Member(
|
||||||
"gas",
|
"gas",
|
||||||
make_shared<FunctionType>(
|
make_shared<FunctionType>(
|
||||||
@ -2409,7 +2409,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
TypePointers{copyAndSetGasOrValue(true, false)},
|
TypePointers{copyAndSetGasOrValue(true, false)},
|
||||||
strings(),
|
strings(),
|
||||||
strings(),
|
strings(),
|
||||||
Location::SetGas,
|
Kind::SetGas,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
false,
|
||||||
@ -2428,7 +2428,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
TypePointer FunctionType::encodingType() const
|
TypePointer FunctionType::encodingType() const
|
||||||
{
|
{
|
||||||
// Only external functions can be encoded, internal functions cannot leave code boundaries.
|
// Only external functions can be encoded, internal functions cannot leave code boundaries.
|
||||||
if (m_location == Location::External)
|
if (m_kind == Kind::External)
|
||||||
return shared_from_this();
|
return shared_from_this();
|
||||||
else
|
else
|
||||||
return TypePointer();
|
return TypePointer();
|
||||||
@ -2436,7 +2436,7 @@ TypePointer FunctionType::encodingType() const
|
|||||||
|
|
||||||
TypePointer FunctionType::interfaceType(bool /*_inLibrary*/) const
|
TypePointer FunctionType::interfaceType(bool /*_inLibrary*/) const
|
||||||
{
|
{
|
||||||
if (m_location == Location::External)
|
if (m_kind == Kind::External)
|
||||||
return shared_from_this();
|
return shared_from_this();
|
||||||
else
|
else
|
||||||
return TypePointer();
|
return TypePointer();
|
||||||
@ -2478,14 +2478,14 @@ bool FunctionType::hasEqualArgumentTypes(FunctionType const& _other) const
|
|||||||
|
|
||||||
bool FunctionType::isBareCall() const
|
bool FunctionType::isBareCall() const
|
||||||
{
|
{
|
||||||
switch (m_location)
|
switch (m_kind)
|
||||||
{
|
{
|
||||||
case Location::Bare:
|
case Kind::Bare:
|
||||||
case Location::BareCallCode:
|
case Kind::BareCallCode:
|
||||||
case Location::BareDelegateCall:
|
case Kind::BareDelegateCall:
|
||||||
case Location::ECRecover:
|
case Kind::ECRecover:
|
||||||
case Location::SHA256:
|
case Kind::SHA256:
|
||||||
case Location::RIPEMD160:
|
case Kind::RIPEMD160:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -2520,13 +2520,13 @@ u256 FunctionType::externalIdentifier() const
|
|||||||
bool FunctionType::isPure() const
|
bool FunctionType::isPure() const
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
m_location == Location::SHA3 ||
|
m_kind == Kind::SHA3 ||
|
||||||
m_location == Location::ECRecover ||
|
m_kind == Kind::ECRecover ||
|
||||||
m_location == Location::SHA256 ||
|
m_kind == Kind::SHA256 ||
|
||||||
m_location == Location::RIPEMD160 ||
|
m_kind == Kind::RIPEMD160 ||
|
||||||
m_location == Location::AddMod ||
|
m_kind == Kind::AddMod ||
|
||||||
m_location == Location::MulMod ||
|
m_kind == Kind::MulMod ||
|
||||||
m_location == Location::ObjectCreation;
|
m_kind == Kind::ObjectCreation;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
|
TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
|
||||||
@ -2545,7 +2545,7 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
|
|||||||
m_returnParameterTypes,
|
m_returnParameterTypes,
|
||||||
m_parameterNames,
|
m_parameterNames,
|
||||||
m_returnParameterNames,
|
m_returnParameterNames,
|
||||||
m_location,
|
m_kind,
|
||||||
m_arbitraryParameters,
|
m_arbitraryParameters,
|
||||||
m_declaration,
|
m_declaration,
|
||||||
m_isConstant,
|
m_isConstant,
|
||||||
@ -2571,18 +2571,18 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound)
|
|||||||
parameterTypes.push_back(t);
|
parameterTypes.push_back(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
Location location = m_location;
|
Kind kind = m_kind;
|
||||||
if (_inLibrary)
|
if (_inLibrary)
|
||||||
{
|
{
|
||||||
solAssert(!!m_declaration, "Declaration has to be available.");
|
solAssert(!!m_declaration, "Declaration has to be available.");
|
||||||
if (!m_declaration->isPublic())
|
if (!m_declaration->isPublic())
|
||||||
location = Location::Internal; // will be inlined
|
kind = Kind::Internal; // will be inlined
|
||||||
else
|
else
|
||||||
location = Location::DelegateCall;
|
kind = Kind::DelegateCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointers returnParameterTypes = m_returnParameterTypes;
|
TypePointers returnParameterTypes = m_returnParameterTypes;
|
||||||
if (location != Location::Internal)
|
if (kind != Kind::Internal)
|
||||||
{
|
{
|
||||||
// Alter dynamic types to be non-accessible.
|
// Alter dynamic types to be non-accessible.
|
||||||
for (auto& param: returnParameterTypes)
|
for (auto& param: returnParameterTypes)
|
||||||
@ -2595,7 +2595,7 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound)
|
|||||||
returnParameterTypes,
|
returnParameterTypes,
|
||||||
m_parameterNames,
|
m_parameterNames,
|
||||||
m_returnParameterNames,
|
m_returnParameterNames,
|
||||||
location,
|
kind,
|
||||||
m_arbitraryParameters,
|
m_arbitraryParameters,
|
||||||
m_declaration,
|
m_declaration,
|
||||||
m_isConstant,
|
m_isConstant,
|
||||||
@ -2821,7 +2821,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
|||||||
return MemberList::MemberMap({
|
return MemberList::MemberMap({
|
||||||
{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
||||||
{"timestamp", make_shared<IntegerType>(256)},
|
{"timestamp", make_shared<IntegerType>(256)},
|
||||||
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Location::BlockHash)},
|
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash)},
|
||||||
{"difficulty", make_shared<IntegerType>(256)},
|
{"difficulty", make_shared<IntegerType>(256)},
|
||||||
{"number", make_shared<IntegerType>(256)},
|
{"number", make_shared<IntegerType>(256)},
|
||||||
{"gaslimit", make_shared<IntegerType>(256)}
|
{"gaslimit", make_shared<IntegerType>(256)}
|
||||||
|
@ -817,8 +817,7 @@ class FunctionType: public Type
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// How this function is invoked on the EVM.
|
/// How this function is invoked on the EVM.
|
||||||
/// @todo This documentation is outdated, and Location should rather be named "Type"
|
enum class Kind
|
||||||
enum class Location
|
|
||||||
{
|
{
|
||||||
Internal, ///< stack-call using plain JUMP
|
Internal, ///< stack-call using plain JUMP
|
||||||
External, ///< external call using CALL
|
External, ///< external call using CALL
|
||||||
@ -868,7 +867,7 @@ public:
|
|||||||
FunctionType(
|
FunctionType(
|
||||||
strings const& _parameterTypes,
|
strings const& _parameterTypes,
|
||||||
strings const& _returnParameterTypes,
|
strings const& _returnParameterTypes,
|
||||||
Location _location = Location::Internal,
|
Kind _kind = Kind::Internal,
|
||||||
bool _arbitraryParameters = false,
|
bool _arbitraryParameters = false,
|
||||||
bool _constant = false,
|
bool _constant = false,
|
||||||
bool _payable = false
|
bool _payable = false
|
||||||
@ -877,7 +876,7 @@ public:
|
|||||||
parseElementaryTypeVector(_returnParameterTypes),
|
parseElementaryTypeVector(_returnParameterTypes),
|
||||||
strings(),
|
strings(),
|
||||||
strings(),
|
strings(),
|
||||||
_location,
|
_kind,
|
||||||
_arbitraryParameters,
|
_arbitraryParameters,
|
||||||
nullptr,
|
nullptr,
|
||||||
_constant,
|
_constant,
|
||||||
@ -895,7 +894,7 @@ public:
|
|||||||
TypePointers const& _returnParameterTypes,
|
TypePointers const& _returnParameterTypes,
|
||||||
strings _parameterNames = strings(),
|
strings _parameterNames = strings(),
|
||||||
strings _returnParameterNames = strings(),
|
strings _returnParameterNames = strings(),
|
||||||
Location _location = Location::Internal,
|
Kind _kind = Kind::Internal,
|
||||||
bool _arbitraryParameters = false,
|
bool _arbitraryParameters = false,
|
||||||
Declaration const* _declaration = nullptr,
|
Declaration const* _declaration = nullptr,
|
||||||
bool _isConstant = false,
|
bool _isConstant = false,
|
||||||
@ -908,7 +907,7 @@ public:
|
|||||||
m_returnParameterTypes(_returnParameterTypes),
|
m_returnParameterTypes(_returnParameterTypes),
|
||||||
m_parameterNames(_parameterNames),
|
m_parameterNames(_parameterNames),
|
||||||
m_returnParameterNames(_returnParameterNames),
|
m_returnParameterNames(_returnParameterNames),
|
||||||
m_location(_location),
|
m_kind(_kind),
|
||||||
m_arbitraryParameters(_arbitraryParameters),
|
m_arbitraryParameters(_arbitraryParameters),
|
||||||
m_gasSet(_gasSet),
|
m_gasSet(_gasSet),
|
||||||
m_valueSet(_valueSet),
|
m_valueSet(_valueSet),
|
||||||
@ -937,11 +936,11 @@ public:
|
|||||||
virtual std::string canonicalName(bool /*_addDataLocation*/) const override;
|
virtual std::string canonicalName(bool /*_addDataLocation*/) const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual unsigned calldataEncodedSize(bool _padded) const override;
|
virtual unsigned calldataEncodedSize(bool _padded) const override;
|
||||||
virtual bool canBeStored() const override { return m_location == Location::Internal || m_location == Location::External; }
|
virtual bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||||
virtual u256 storageSize() const override;
|
virtual u256 storageSize() const override;
|
||||||
virtual unsigned storageBytes() const override;
|
virtual unsigned storageBytes() const override;
|
||||||
virtual bool isValueType() const override { return true; }
|
virtual bool isValueType() const override { return true; }
|
||||||
virtual bool canLiveOutsideStorage() const override { return m_location == Location::Internal || m_location == Location::External; }
|
virtual bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||||
virtual TypePointer encodingType() const override;
|
virtual TypePointer encodingType() const override;
|
||||||
@ -964,7 +963,7 @@ public:
|
|||||||
|
|
||||||
/// @returns true if the ABI is used for this call (only meaningful for external calls)
|
/// @returns true if the ABI is used for this call (only meaningful for external calls)
|
||||||
bool isBareCall() const;
|
bool isBareCall() const;
|
||||||
Location const& location() const { return m_location; }
|
Kind const& kind() const { return m_kind; }
|
||||||
/// @returns the external signature of this function type given the function name
|
/// @returns the external signature of this function type given the function name
|
||||||
std::string externalSignature() const;
|
std::string externalSignature() const;
|
||||||
/// @returns the external identifier of this function (the hash of the signature).
|
/// @returns the external identifier of this function (the hash of the signature).
|
||||||
@ -986,7 +985,7 @@ public:
|
|||||||
ASTPointer<ASTString> documentation() const;
|
ASTPointer<ASTString> documentation() const;
|
||||||
|
|
||||||
/// true iff arguments are to be padded to multiples of 32 bytes for external calls
|
/// true iff arguments are to be padded to multiples of 32 bytes for external calls
|
||||||
bool padArguments() const { return !(m_location == Location::SHA3 || m_location == Location::SHA256 || m_location == Location::RIPEMD160); }
|
bool padArguments() const { return !(m_kind == Kind::SHA3 || m_kind == Kind::SHA256 || m_kind == Kind::RIPEMD160); }
|
||||||
bool takesArbitraryParameters() const { return m_arbitraryParameters; }
|
bool takesArbitraryParameters() const { return m_arbitraryParameters; }
|
||||||
bool gasSet() const { return m_gasSet; }
|
bool gasSet() const { return m_gasSet; }
|
||||||
bool valueSet() const { return m_valueSet; }
|
bool valueSet() const { return m_valueSet; }
|
||||||
@ -1012,7 +1011,7 @@ private:
|
|||||||
TypePointers m_returnParameterTypes;
|
TypePointers m_returnParameterTypes;
|
||||||
std::vector<std::string> m_parameterNames;
|
std::vector<std::string> m_parameterNames;
|
||||||
std::vector<std::string> m_returnParameterNames;
|
std::vector<std::string> m_returnParameterNames;
|
||||||
Location const m_location;
|
Kind const m_kind;
|
||||||
/// true if the function takes an arbitrary number of arguments of arbitrary types
|
/// true if the function takes an arbitrary number of arguments of arbitrary types
|
||||||
bool const m_arbitraryParameters = false;
|
bool const m_arbitraryParameters = false;
|
||||||
bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
|
bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
|
||||||
|
@ -135,7 +135,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
|
|||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
_type.category() == Type::Category::Function &&
|
_type.category() == Type::Category::Function &&
|
||||||
dynamic_cast<FunctionType const&>(_type).location() == FunctionType::Location::External
|
dynamic_cast<FunctionType const&>(_type).kind() == FunctionType::Kind::External
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(_padToWordBoundaries, "Non-padded store for function not implemented.");
|
solUnimplementedAssert(_padToWordBoundaries, "Non-padded store for function not implemented.");
|
||||||
@ -795,7 +795,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
|
|||||||
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_targetType);
|
IntegerType const& targetType = dynamic_cast<IntegerType const&>(_targetType);
|
||||||
solAssert(targetType.isAddress(), "Function type can only be converted to address.");
|
solAssert(targetType.isAddress(), "Function type can only be converted to address.");
|
||||||
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
|
||||||
solAssert(typeOnStack.location() == FunctionType::Location::External, "Only external function type can be converted.");
|
solAssert(typeOnStack.kind() == FunctionType::Kind::External, "Only external function type can be converted.");
|
||||||
|
|
||||||
// stack: <address> <function_id>
|
// stack: <address> <function_id>
|
||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
@ -820,7 +820,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
|
|||||||
{
|
{
|
||||||
if (auto const* funType = dynamic_cast<FunctionType const*>(&_type))
|
if (auto const* funType = dynamic_cast<FunctionType const*>(&_type))
|
||||||
{
|
{
|
||||||
if (funType->location() == FunctionType::Location::Internal)
|
if (funType->kind() == FunctionType::Kind::Internal)
|
||||||
{
|
{
|
||||||
m_context << m_context.lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) {
|
m_context << m_context.lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) {
|
||||||
_context.appendInvalid();
|
_context.appendInvalid();
|
||||||
@ -983,7 +983,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
|
|||||||
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
|
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
|
||||||
bool isExternalFunctionType = false;
|
bool isExternalFunctionType = false;
|
||||||
if (auto const* funType = dynamic_cast<FunctionType const*>(&_type))
|
if (auto const* funType = dynamic_cast<FunctionType const*>(&_type))
|
||||||
if (funType->location() == FunctionType::Location::External)
|
if (funType->kind() == FunctionType::Kind::External)
|
||||||
isExternalFunctionType = true;
|
isExternalFunctionType = true;
|
||||||
if (numBytes == 0)
|
if (numBytes == 0)
|
||||||
{
|
{
|
||||||
|
@ -434,7 +434,6 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
|
|||||||
bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||||
{
|
{
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, _functionCall);
|
CompilerContext::LocationSetter locationSetter(m_context, _functionCall);
|
||||||
using Location = FunctionType::Location;
|
|
||||||
if (_functionCall.annotation().isTypeConversion)
|
if (_functionCall.annotation().isTypeConversion)
|
||||||
{
|
{
|
||||||
solAssert(_functionCall.arguments().size() == 1, "");
|
solAssert(_functionCall.arguments().size() == 1, "");
|
||||||
@ -499,10 +498,10 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
FunctionType const& function = *functionType;
|
FunctionType const& function = *functionType;
|
||||||
if (function.bound())
|
if (function.bound())
|
||||||
// Only delegatecall and internal functions can be bound, this might be lifted later.
|
// Only delegatecall and internal functions can be bound, this might be lifted later.
|
||||||
solAssert(function.location() == Location::DelegateCall || function.location() == Location::Internal, "");
|
solAssert(function.kind() == FunctionType::Kind::DelegateCall || function.kind() == FunctionType::Kind::Internal, "");
|
||||||
switch (function.location())
|
switch (function.kind())
|
||||||
{
|
{
|
||||||
case Location::Internal:
|
case FunctionType::Kind::Internal:
|
||||||
{
|
{
|
||||||
// Calling convention: Caller pushes return address and arguments
|
// Calling convention: Caller pushes return address and arguments
|
||||||
// Callee removes them and pushes return values
|
// Callee removes them and pushes return values
|
||||||
@ -538,16 +537,16 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context.adjustStackOffset(returnParametersSize - parameterSize - 1);
|
m_context.adjustStackOffset(returnParametersSize - parameterSize - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::External:
|
case FunctionType::Kind::External:
|
||||||
case Location::CallCode:
|
case FunctionType::Kind::CallCode:
|
||||||
case Location::DelegateCall:
|
case FunctionType::Kind::DelegateCall:
|
||||||
case Location::Bare:
|
case FunctionType::Kind::Bare:
|
||||||
case Location::BareCallCode:
|
case FunctionType::Kind::BareCallCode:
|
||||||
case Location::BareDelegateCall:
|
case FunctionType::Kind::BareDelegateCall:
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
appendExternalFunctionCall(function, arguments);
|
appendExternalFunctionCall(function, arguments);
|
||||||
break;
|
break;
|
||||||
case Location::Creation:
|
case FunctionType::Kind::Creation:
|
||||||
{
|
{
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
solAssert(!function.gasSet(), "Gas limit set for contract creation.");
|
solAssert(!function.gasSet(), "Gas limit set for contract creation.");
|
||||||
@ -592,7 +591,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << swapInstruction(1) << Instruction::POP;
|
m_context << swapInstruction(1) << Instruction::POP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::SetGas:
|
case FunctionType::Kind::SetGas:
|
||||||
{
|
{
|
||||||
// stack layout: contract_address function_id [gas] [value]
|
// stack layout: contract_address function_id [gas] [value]
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
@ -608,7 +607,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::SetValue:
|
case FunctionType::Kind::SetValue:
|
||||||
// stack layout: contract_address function_id [gas] [value]
|
// stack layout: contract_address function_id [gas] [value]
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
// Note that function is not the original function, but the ".value" function.
|
// Note that function is not the original function, but the ".value" function.
|
||||||
@ -617,8 +616,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
break;
|
break;
|
||||||
case Location::Send:
|
case FunctionType::Kind::Send:
|
||||||
case Location::Transfer:
|
case FunctionType::Kind::Transfer:
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
// Provide the gas stipend manually at first because we may send zero ether.
|
// Provide the gas stipend manually at first because we may send zero ether.
|
||||||
// Will be zeroed if we send more than zero ether.
|
// Will be zeroed if we send more than zero ether.
|
||||||
@ -637,7 +636,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
TypePointers{},
|
TypePointers{},
|
||||||
strings(),
|
strings(),
|
||||||
strings(),
|
strings(),
|
||||||
Location::Bare,
|
FunctionType::Kind::Bare,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
nullptr,
|
||||||
false,
|
false,
|
||||||
@ -647,24 +646,24 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
),
|
),
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
if (function.location() == Location::Transfer)
|
if (function.kind() == FunctionType::Kind::Transfer)
|
||||||
{
|
{
|
||||||
// Check if zero (out of stack or not enough balance).
|
// Check if zero (out of stack or not enough balance).
|
||||||
m_context << Instruction::ISZERO;
|
m_context << Instruction::ISZERO;
|
||||||
m_context.appendConditionalInvalid();
|
m_context.appendConditionalInvalid();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Location::Selfdestruct:
|
case FunctionType::Kind::Selfdestruct:
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true);
|
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true);
|
||||||
m_context << Instruction::SELFDESTRUCT;
|
m_context << Instruction::SELFDESTRUCT;
|
||||||
break;
|
break;
|
||||||
case Location::Revert:
|
case FunctionType::Kind::Revert:
|
||||||
// memory offset returned - zero length
|
// memory offset returned - zero length
|
||||||
m_context << u256(0) << u256(0);
|
m_context << u256(0) << u256(0);
|
||||||
m_context << Instruction::REVERT;
|
m_context << Instruction::REVERT;
|
||||||
break;
|
break;
|
||||||
case Location::SHA3:
|
case FunctionType::Kind::SHA3:
|
||||||
{
|
{
|
||||||
TypePointers argumentTypes;
|
TypePointers argumentTypes;
|
||||||
for (auto const& arg: arguments)
|
for (auto const& arg: arguments)
|
||||||
@ -678,13 +677,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << Instruction::SHA3;
|
m_context << Instruction::SHA3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::Log0:
|
case FunctionType::Kind::Log0:
|
||||||
case Location::Log1:
|
case FunctionType::Kind::Log1:
|
||||||
case Location::Log2:
|
case FunctionType::Kind::Log2:
|
||||||
case Location::Log3:
|
case FunctionType::Kind::Log3:
|
||||||
case Location::Log4:
|
case FunctionType::Kind::Log4:
|
||||||
{
|
{
|
||||||
unsigned logNumber = int(function.location()) - int(Location::Log0);
|
unsigned logNumber = int(function.kind()) - int(FunctionType::Kind::Log0);
|
||||||
for (unsigned arg = logNumber; arg > 0; --arg)
|
for (unsigned arg = logNumber; arg > 0; --arg)
|
||||||
{
|
{
|
||||||
arguments[arg]->accept(*this);
|
arguments[arg]->accept(*this);
|
||||||
@ -701,7 +700,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << logInstruction(logNumber);
|
m_context << logInstruction(logNumber);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::Event:
|
case FunctionType::Kind::Event:
|
||||||
{
|
{
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
auto const& event = dynamic_cast<EventDefinition const&>(function.declaration());
|
auto const& event = dynamic_cast<EventDefinition const&>(function.declaration());
|
||||||
@ -755,50 +754,50 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << logInstruction(numIndexed);
|
m_context << logInstruction(numIndexed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::BlockHash:
|
case FunctionType::Kind::BlockHash:
|
||||||
{
|
{
|
||||||
arguments[0]->accept(*this);
|
arguments[0]->accept(*this);
|
||||||
utils().convertType(*arguments[0]->annotation().type, *function.parameterTypes()[0], true);
|
utils().convertType(*arguments[0]->annotation().type, *function.parameterTypes()[0], true);
|
||||||
m_context << Instruction::BLOCKHASH;
|
m_context << Instruction::BLOCKHASH;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::AddMod:
|
case FunctionType::Kind::AddMod:
|
||||||
case Location::MulMod:
|
case FunctionType::Kind::MulMod:
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < 3; i ++)
|
for (unsigned i = 0; i < 3; i ++)
|
||||||
{
|
{
|
||||||
arguments[2 - i]->accept(*this);
|
arguments[2 - i]->accept(*this);
|
||||||
utils().convertType(*arguments[2 - i]->annotation().type, IntegerType(256));
|
utils().convertType(*arguments[2 - i]->annotation().type, IntegerType(256));
|
||||||
}
|
}
|
||||||
if (function.location() == Location::AddMod)
|
if (function.kind() == FunctionType::Kind::AddMod)
|
||||||
m_context << Instruction::ADDMOD;
|
m_context << Instruction::ADDMOD;
|
||||||
else
|
else
|
||||||
m_context << Instruction::MULMOD;
|
m_context << Instruction::MULMOD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::ECRecover:
|
case FunctionType::Kind::ECRecover:
|
||||||
case Location::SHA256:
|
case FunctionType::Kind::SHA256:
|
||||||
case Location::RIPEMD160:
|
case FunctionType::Kind::RIPEMD160:
|
||||||
{
|
{
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
static const map<Location, u256> contractAddresses{{Location::ECRecover, 1},
|
static const map<FunctionType::Kind, u256> contractAddresses{{FunctionType::Kind::ECRecover, 1},
|
||||||
{Location::SHA256, 2},
|
{FunctionType::Kind::SHA256, 2},
|
||||||
{Location::RIPEMD160, 3}};
|
{FunctionType::Kind::RIPEMD160, 3}};
|
||||||
m_context << contractAddresses.find(function.location())->second;
|
m_context << contractAddresses.find(function.kind())->second;
|
||||||
for (unsigned i = function.sizeOnStack(); i > 0; --i)
|
for (unsigned i = function.sizeOnStack(); i > 0; --i)
|
||||||
m_context << swapInstruction(i);
|
m_context << swapInstruction(i);
|
||||||
appendExternalFunctionCall(function, arguments);
|
appendExternalFunctionCall(function, arguments);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::ByteArrayPush:
|
case FunctionType::Kind::ByteArrayPush:
|
||||||
case Location::ArrayPush:
|
case FunctionType::Kind::ArrayPush:
|
||||||
{
|
{
|
||||||
_functionCall.expression().accept(*this);
|
_functionCall.expression().accept(*this);
|
||||||
solAssert(function.parameterTypes().size() == 1, "");
|
solAssert(function.parameterTypes().size() == 1, "");
|
||||||
solAssert(!!function.parameterTypes()[0], "");
|
solAssert(!!function.parameterTypes()[0], "");
|
||||||
TypePointer paramType = function.parameterTypes()[0];
|
TypePointer paramType = function.parameterTypes()[0];
|
||||||
shared_ptr<ArrayType> arrayType =
|
shared_ptr<ArrayType> arrayType =
|
||||||
function.location() == Location::ArrayPush ?
|
function.kind() == FunctionType::Kind::ArrayPush ?
|
||||||
make_shared<ArrayType>(DataLocation::Storage, paramType) :
|
make_shared<ArrayType>(DataLocation::Storage, paramType) :
|
||||||
make_shared<ArrayType>(DataLocation::Storage);
|
make_shared<ArrayType>(DataLocation::Storage);
|
||||||
// get the current length
|
// get the current length
|
||||||
@ -822,13 +821,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
utils().moveToStackTop(1 + type->sizeOnStack());
|
utils().moveToStackTop(1 + type->sizeOnStack());
|
||||||
utils().moveToStackTop(1 + type->sizeOnStack());
|
utils().moveToStackTop(1 + type->sizeOnStack());
|
||||||
// stack: newLength argValue storageSlot slotOffset
|
// stack: newLength argValue storageSlot slotOffset
|
||||||
if (function.location() == Location::ArrayPush)
|
if (function.kind() == FunctionType::Kind::ArrayPush)
|
||||||
StorageItem(m_context, *paramType).storeValue(*type, _functionCall.location(), true);
|
StorageItem(m_context, *paramType).storeValue(*type, _functionCall.location(), true);
|
||||||
else
|
else
|
||||||
StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true);
|
StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::ObjectCreation:
|
case FunctionType::Kind::ObjectCreation:
|
||||||
{
|
{
|
||||||
// Will allocate at the end of memory (MSIZE) and not write at all unless the base
|
// Will allocate at the end of memory (MSIZE) and not write at all unless the base
|
||||||
// type is dynamically sized.
|
// type is dynamically sized.
|
||||||
@ -878,15 +877,15 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
m_context << Instruction::POP;
|
m_context << Instruction::POP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Location::Assert:
|
case FunctionType::Kind::Assert:
|
||||||
case Location::Require:
|
case FunctionType::Kind::Require:
|
||||||
{
|
{
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), false);
|
utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), false);
|
||||||
// jump if condition was met
|
// jump if condition was met
|
||||||
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
m_context << Instruction::ISZERO << Instruction::ISZERO;
|
||||||
auto success = m_context.appendConditionalJump();
|
auto success = m_context.appendConditionalJump();
|
||||||
if (function.location() == Location::Assert)
|
if (function.kind() == FunctionType::Kind::Assert)
|
||||||
// condition was not met, flag an error
|
// condition was not met, flag an error
|
||||||
m_context << Instruction::INVALID;
|
m_context << Instruction::INVALID;
|
||||||
else
|
else
|
||||||
@ -922,7 +921,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
*funType->selfType(),
|
*funType->selfType(),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
if (funType->location() == FunctionType::Location::Internal)
|
if (funType->kind() == FunctionType::Kind::Internal)
|
||||||
{
|
{
|
||||||
FunctionDefinition const& funDef = dynamic_cast<decltype(funDef)>(funType->declaration());
|
FunctionDefinition const& funDef = dynamic_cast<decltype(funDef)>(funType->declaration());
|
||||||
utils().pushCombinedFunctionEntryLabel(funDef);
|
utils().pushCombinedFunctionEntryLabel(funDef);
|
||||||
@ -930,7 +929,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(funType->location() == FunctionType::Location::DelegateCall, "");
|
solAssert(funType->kind() == FunctionType::Kind::DelegateCall, "");
|
||||||
auto contract = dynamic_cast<ContractDefinition const*>(funType->declaration().scope());
|
auto contract = dynamic_cast<ContractDefinition const*>(funType->declaration().scope());
|
||||||
solAssert(contract && contract->isLibrary(), "");
|
solAssert(contract && contract->isLibrary(), "");
|
||||||
m_context.appendLibraryAddress(contract->fullyQualifiedName());
|
m_context.appendLibraryAddress(contract->fullyQualifiedName());
|
||||||
@ -949,9 +948,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
|
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
|
||||||
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
||||||
{
|
{
|
||||||
switch (funType->location())
|
switch (funType->kind())
|
||||||
{
|
{
|
||||||
case FunctionType::Location::Internal:
|
case FunctionType::Kind::Internal:
|
||||||
// We do not visit the expression here on purpose, because in the case of an
|
// We do not visit the expression here on purpose, because in the case of an
|
||||||
// internal library function call, this would push the library address forcing
|
// internal library function call, this would push the library address forcing
|
||||||
// us to link against it although we actually do not need it.
|
// us to link against it although we actually do not need it.
|
||||||
@ -960,31 +959,31 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
|
|||||||
else
|
else
|
||||||
solAssert(false, "Function not found in member access");
|
solAssert(false, "Function not found in member access");
|
||||||
break;
|
break;
|
||||||
case FunctionType::Location::Event:
|
case FunctionType::Kind::Event:
|
||||||
if (!dynamic_cast<EventDefinition const*>(_memberAccess.annotation().referencedDeclaration))
|
if (!dynamic_cast<EventDefinition const*>(_memberAccess.annotation().referencedDeclaration))
|
||||||
solAssert(false, "event not found");
|
solAssert(false, "event not found");
|
||||||
// no-op, because the parent node will do the job
|
// no-op, because the parent node will do the job
|
||||||
break;
|
break;
|
||||||
case FunctionType::Location::External:
|
case FunctionType::Kind::External:
|
||||||
case FunctionType::Location::Creation:
|
case FunctionType::Kind::Creation:
|
||||||
case FunctionType::Location::DelegateCall:
|
case FunctionType::Kind::DelegateCall:
|
||||||
case FunctionType::Location::CallCode:
|
case FunctionType::Kind::CallCode:
|
||||||
case FunctionType::Location::Send:
|
case FunctionType::Kind::Send:
|
||||||
case FunctionType::Location::Bare:
|
case FunctionType::Kind::Bare:
|
||||||
case FunctionType::Location::BareCallCode:
|
case FunctionType::Kind::BareCallCode:
|
||||||
case FunctionType::Location::BareDelegateCall:
|
case FunctionType::Kind::BareDelegateCall:
|
||||||
case FunctionType::Location::Transfer:
|
case FunctionType::Kind::Transfer:
|
||||||
_memberAccess.expression().accept(*this);
|
_memberAccess.expression().accept(*this);
|
||||||
m_context << funType->externalIdentifier();
|
m_context << funType->externalIdentifier();
|
||||||
break;
|
break;
|
||||||
case FunctionType::Location::Log0:
|
case FunctionType::Kind::Log0:
|
||||||
case FunctionType::Location::Log1:
|
case FunctionType::Kind::Log1:
|
||||||
case FunctionType::Location::Log2:
|
case FunctionType::Kind::Log2:
|
||||||
case FunctionType::Location::Log3:
|
case FunctionType::Kind::Log3:
|
||||||
case FunctionType::Location::Log4:
|
case FunctionType::Kind::Log4:
|
||||||
case FunctionType::Location::ECRecover:
|
case FunctionType::Kind::ECRecover:
|
||||||
case FunctionType::Location::SHA256:
|
case FunctionType::Kind::SHA256:
|
||||||
case FunctionType::Location::RIPEMD160:
|
case FunctionType::Kind::RIPEMD160:
|
||||||
default:
|
default:
|
||||||
solAssert(false, "unsupported member function");
|
solAssert(false, "unsupported member function");
|
||||||
}
|
}
|
||||||
@ -1372,7 +1371,7 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
|
|||||||
{
|
{
|
||||||
if (FunctionType const* funType = dynamic_cast<decltype(funType)>(&_type))
|
if (FunctionType const* funType = dynamic_cast<decltype(funType)>(&_type))
|
||||||
{
|
{
|
||||||
if (funType->location() == FunctionType::Location::Internal)
|
if (funType->kind() == FunctionType::Kind::Internal)
|
||||||
{
|
{
|
||||||
// We have to remove the upper bits (construction time value) because they might
|
// We have to remove the upper bits (construction time value) because they might
|
||||||
// be "unknown" in one of the operands and not in the other.
|
// be "unknown" in one of the operands and not in the other.
|
||||||
@ -1555,11 +1554,10 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
if (_functionType.bound())
|
if (_functionType.bound())
|
||||||
utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
|
utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack());
|
||||||
|
|
||||||
using FunctionKind = FunctionType::Location;
|
auto funKind = _functionType.kind();
|
||||||
FunctionKind funKind = _functionType.location();
|
bool returnSuccessCondition = funKind == FunctionType::Kind::Bare || funKind == FunctionType::Kind::BareCallCode;
|
||||||
bool returnSuccessCondition = funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode;
|
bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode;
|
||||||
bool isCallCode = funKind == FunctionKind::BareCallCode || funKind == FunctionKind::CallCode;
|
bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall;
|
||||||
bool isDelegateCall = funKind == FunctionKind::BareDelegateCall || funKind == FunctionKind::DelegateCall;
|
|
||||||
|
|
||||||
unsigned retSize = 0;
|
unsigned retSize = 0;
|
||||||
if (returnSuccessCondition)
|
if (returnSuccessCondition)
|
||||||
@ -1576,7 +1574,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
TypePointers parameterTypes = _functionType.parameterTypes();
|
TypePointers parameterTypes = _functionType.parameterTypes();
|
||||||
bool manualFunctionId = false;
|
bool manualFunctionId = false;
|
||||||
if (
|
if (
|
||||||
(funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode || funKind == FunctionKind::BareDelegateCall) &&
|
(funKind == FunctionType::Kind::Bare || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall) &&
|
||||||
!_arguments.empty()
|
!_arguments.empty()
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -1611,7 +1609,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
argumentTypes.push_back(_arguments[i]->annotation().type);
|
argumentTypes.push_back(_arguments[i]->annotation().type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (funKind == FunctionKind::ECRecover)
|
if (funKind == FunctionType::Kind::ECRecover)
|
||||||
{
|
{
|
||||||
// Clears 32 bytes of currently free memory and advances free memory pointer.
|
// Clears 32 bytes of currently free memory and advances free memory pointer.
|
||||||
// Output area will be "start of input area" - 32.
|
// Output area will be "start of input area" - 32.
|
||||||
@ -1667,7 +1665,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
|
// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
|
||||||
m_context << u256(retSize);
|
m_context << u256(retSize);
|
||||||
utils().fetchFreeMemoryPointer(); // This is the start of input
|
utils().fetchFreeMemoryPointer(); // This is the start of input
|
||||||
if (funKind == FunctionKind::ECRecover)
|
if (funKind == FunctionType::Kind::ECRecover)
|
||||||
{
|
{
|
||||||
// In this case, output is 32 bytes before input and has already been cleared.
|
// In this case, output is 32 bytes before input and has already been cleared.
|
||||||
m_context << u256(32) << Instruction::DUP2 << Instruction::SUB << Instruction::SWAP1;
|
m_context << u256(32) << Instruction::DUP2 << Instruction::SUB << Instruction::SWAP1;
|
||||||
@ -1693,7 +1691,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
|
|
||||||
bool existenceChecked = false;
|
bool existenceChecked = false;
|
||||||
// Check the the target contract exists (has code) for non-low-level calls.
|
// Check the the target contract exists (has code) for non-low-level calls.
|
||||||
if (funKind == FunctionKind::External || funKind == FunctionKind::CallCode || funKind == FunctionKind::DelegateCall)
|
if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::CallCode || funKind == FunctionType::Kind::DelegateCall)
|
||||||
{
|
{
|
||||||
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO;
|
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO;
|
||||||
m_context.appendConditionalInvalid();
|
m_context.appendConditionalInvalid();
|
||||||
@ -1741,14 +1739,14 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
{
|
{
|
||||||
// already there
|
// already there
|
||||||
}
|
}
|
||||||
else if (funKind == FunctionKind::RIPEMD160)
|
else if (funKind == FunctionType::Kind::RIPEMD160)
|
||||||
{
|
{
|
||||||
// fix: built-in contract returns right-aligned data
|
// fix: built-in contract returns right-aligned data
|
||||||
utils().fetchFreeMemoryPointer();
|
utils().fetchFreeMemoryPointer();
|
||||||
utils().loadFromMemoryDynamic(IntegerType(160), false, true, false);
|
utils().loadFromMemoryDynamic(IntegerType(160), false, true, false);
|
||||||
utils().convertType(IntegerType(160), FixedBytesType(20));
|
utils().convertType(IntegerType(160), FixedBytesType(20));
|
||||||
}
|
}
|
||||||
else if (funKind == FunctionKind::ECRecover)
|
else if (funKind == FunctionType::Kind::ECRecover)
|
||||||
{
|
{
|
||||||
// Output is 32 bytes before input / free mem pointer.
|
// Output is 32 bytes before input / free mem pointer.
|
||||||
// Failing ecrecover cannot be detected, so we clear output before the call.
|
// Failing ecrecover cannot be detected, so we clear output before the call.
|
||||||
|
@ -199,7 +199,7 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const
|
|||||||
}
|
}
|
||||||
else if (FunctionType const* fun = dynamic_cast<decltype(fun)>(m_dataType))
|
else if (FunctionType const* fun = dynamic_cast<decltype(fun)>(m_dataType))
|
||||||
{
|
{
|
||||||
if (fun->location() == FunctionType::Location::External)
|
if (fun->kind() == FunctionType::Kind::External)
|
||||||
{
|
{
|
||||||
CompilerUtils(m_context).splitExternalFunctionType(false);
|
CompilerUtils(m_context).splitExternalFunctionType(false);
|
||||||
cleaned = true;
|
cleaned = true;
|
||||||
@ -256,7 +256,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
|||||||
if (FunctionType const* fun = dynamic_cast<decltype(fun)>(m_dataType))
|
if (FunctionType const* fun = dynamic_cast<decltype(fun)>(m_dataType))
|
||||||
{
|
{
|
||||||
solAssert(_sourceType == *m_dataType, "function item stored but target is not equal to source");
|
solAssert(_sourceType == *m_dataType, "function item stored but target is not equal to source");
|
||||||
if (fun->location() == FunctionType::Location::External)
|
if (fun->kind() == FunctionType::Kind::External)
|
||||||
// Combine the two-item function type into a single stack slot.
|
// Combine the two-item function type into a single stack slot.
|
||||||
utils.combineExternalFunctionType(false);
|
utils.combineExternalFunctionType(false);
|
||||||
else
|
else
|
||||||
|
@ -588,14 +588,14 @@ bool Why3Translator::visit(FunctionCall const& _node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
FunctionType const& function = dynamic_cast<FunctionType const&>(*_node.expression().annotation().type);
|
FunctionType const& function = dynamic_cast<FunctionType const&>(*_node.expression().annotation().type);
|
||||||
switch (function.location())
|
switch (function.kind())
|
||||||
{
|
{
|
||||||
case FunctionType::Location::AddMod:
|
case FunctionType::Kind::AddMod:
|
||||||
case FunctionType::Location::MulMod:
|
case FunctionType::Kind::MulMod:
|
||||||
{
|
{
|
||||||
//@todo require that third parameter is not zero
|
//@todo require that third parameter is not zero
|
||||||
add("(of_int (mod (Int.(");
|
add("(of_int (mod (Int.(");
|
||||||
add(function.location() == FunctionType::Location::AddMod ? "+" : "*");
|
add(function.kind() == FunctionType::Kind::AddMod ? "+" : "*");
|
||||||
add(") (to_int ");
|
add(") (to_int ");
|
||||||
_node.arguments().at(0)->accept(*this);
|
_node.arguments().at(0)->accept(*this);
|
||||||
add(") (to_int ");
|
add(") (to_int ");
|
||||||
@ -605,7 +605,7 @@ bool Why3Translator::visit(FunctionCall const& _node)
|
|||||||
add(")))");
|
add(")))");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case FunctionType::Location::Internal:
|
case FunctionType::Kind::Internal:
|
||||||
{
|
{
|
||||||
if (!_node.names().empty())
|
if (!_node.names().empty())
|
||||||
{
|
{
|
||||||
@ -626,7 +626,7 @@ bool Why3Translator::visit(FunctionCall const& _node)
|
|||||||
add(")");
|
add(")");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case FunctionType::Location::Bare:
|
case FunctionType::Kind::Bare:
|
||||||
{
|
{
|
||||||
if (!_node.arguments().empty())
|
if (!_node.arguments().empty())
|
||||||
{
|
{
|
||||||
@ -654,7 +654,7 @@ bool Why3Translator::visit(FunctionCall const& _node)
|
|||||||
add(")");
|
add(")");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case FunctionType::Location::SetValue:
|
case FunctionType::Kind::SetValue:
|
||||||
{
|
{
|
||||||
add("let amount = ");
|
add("let amount = ");
|
||||||
solAssert(_node.arguments().size() == 1, "");
|
solAssert(_node.arguments().size() == 1, "");
|
||||||
|
@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
|
|||||||
TupleType t({e.type(), s.type(), stringArray, nullptr});
|
TupleType t({e.type(), s.type(), stringArray, nullptr});
|
||||||
BOOST_CHECK_EQUAL(t.identifier(), "t_tuple$_t_type$_t_enum$_Enum_$4_$_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_t_array$_t_string_storage_$20_storage_ptr_$__$");
|
BOOST_CHECK_EQUAL(t.identifier(), "t_tuple$_t_type$_t_enum$_Enum_$4_$_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_t_array$_t_string_storage_$20_storage_ptr_$__$");
|
||||||
|
|
||||||
TypePointer sha3fun = make_shared<FunctionType>(strings{}, strings{}, FunctionType::Location::SHA3);
|
TypePointer sha3fun = make_shared<FunctionType>(strings{}, strings{}, FunctionType::Kind::SHA3);
|
||||||
BOOST_CHECK_EQUAL(sha3fun->identifier(), "t_function_sha3$__$returns$__$");
|
BOOST_CHECK_EQUAL(sha3fun->identifier(), "t_function_sha3$__$returns$__$");
|
||||||
|
|
||||||
FunctionType metaFun(TypePointers{sha3fun}, TypePointers{s.type()});
|
FunctionType metaFun(TypePointers{sha3fun}, TypePointers{s.type()});
|
||||||
|
Loading…
Reference in New Issue
Block a user