mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add bound functions to types.
This commit is contained in:
parent
d71cd3aa2b
commit
93b3237c6a
@ -267,6 +267,7 @@ public:
|
||||
|
||||
std::vector<ASTPointer<InheritanceSpecifier>> const& baseContracts() const { return m_baseContracts; }
|
||||
std::vector<ASTPointer<ASTNode>> const& subNodes() const { return m_subNodes; }
|
||||
std::vector<UsingForDirective const*> usingForDirectives() const { return filteredNodes<UsingForDirective>(m_subNodes); }
|
||||
std::vector<StructDefinition const*> definedStructs() const { return filteredNodes<StructDefinition>(m_subNodes); }
|
||||
std::vector<EnumDefinition const*> definedEnums() const { return filteredNodes<EnumDefinition>(m_subNodes); }
|
||||
std::vector<VariableDeclaration const*> stateVariables() const { return filteredNodes<VariableDeclaration>(m_subNodes); }
|
||||
|
@ -39,6 +39,7 @@ class ImportDirective;
|
||||
class Declaration;
|
||||
class ContractDefinition;
|
||||
class InheritanceSpecifier;
|
||||
class UsingForDirective;
|
||||
class StructDefinition;
|
||||
class EnumDefinition;
|
||||
class EnumValue;
|
||||
|
@ -86,6 +86,11 @@ MemberList& MemberList::operator=(MemberList&& _other)
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MemberList::combine(MemberList const & _other)
|
||||
{
|
||||
m_memberTypes += _other.m_memberTypes;
|
||||
}
|
||||
|
||||
std::pair<u256, unsigned> const* MemberList::memberStorageOffset(string const& _name) const
|
||||
{
|
||||
if (!m_storageOffsets)
|
||||
@ -185,7 +190,52 @@ TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
|
||||
return TypePointer();
|
||||
}
|
||||
|
||||
const MemberList Type::EmptyMemberList;
|
||||
MemberList const& Type::members(ContractDefinition const* _currentScope) const
|
||||
{
|
||||
if (!m_members[_currentScope])
|
||||
{
|
||||
MemberList::MemberMap members = nativeMembers(_currentScope);
|
||||
if (_currentScope)
|
||||
members += boundFunctions(*this, *_currentScope);
|
||||
m_members[_currentScope] = unique_ptr<MemberList>(new MemberList(move(members)));
|
||||
}
|
||||
return *m_members[_currentScope];
|
||||
}
|
||||
|
||||
MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition const& _scope)
|
||||
{
|
||||
// Normalise data location of type.
|
||||
TypePointer type = ReferenceType::copyForLocationIfReference(DataLocation::Storage, _type.shared_from_this());
|
||||
set<Declaration const*> seenFunctions;
|
||||
MemberList::MemberMap members;
|
||||
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
|
||||
for (UsingForDirective const* ufd: contract->usingForDirectives())
|
||||
{
|
||||
if (ufd->typeName() && *type != *ReferenceType::copyForLocationIfReference(
|
||||
DataLocation::Storage,
|
||||
ufd->typeName()->annotation().type
|
||||
))
|
||||
continue;
|
||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
||||
*ufd->libraryName().annotation().referencedDeclaration
|
||||
);
|
||||
for (auto const& it: library.interfaceFunctions())
|
||||
{
|
||||
FunctionType const& funType = *it.second;
|
||||
solAssert(funType.hasDeclaration(), "Tried to bind function without declaration.");
|
||||
if (seenFunctions.count(&funType.declaration()))
|
||||
continue;
|
||||
seenFunctions.insert(&funType.declaration());
|
||||
if (auto fun = funType.asMemberFunction(true, true))
|
||||
members.push_back(MemberList::Member(
|
||||
funType.declaration().name(),
|
||||
fun,
|
||||
&funType.declaration()
|
||||
));
|
||||
}
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
|
||||
m_bits(_bits), m_modifier(_modifier)
|
||||
@ -273,12 +323,18 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
|
||||
return commonType;
|
||||
}
|
||||
|
||||
const MemberList IntegerType::AddressMemberList({
|
||||
{"balance", make_shared<IntegerType >(256)},
|
||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true)},
|
||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
|
||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
|
||||
});
|
||||
MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) const
|
||||
{
|
||||
if (isAddress())
|
||||
return {
|
||||
{"balance", make_shared<IntegerType >(256)},
|
||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true)},
|
||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
|
||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
|
||||
};
|
||||
else
|
||||
return MemberList::MemberMap();
|
||||
}
|
||||
|
||||
bool IntegerConstantType::isValidLiteral(const Literal& _literal)
|
||||
{
|
||||
@ -858,26 +914,22 @@ string ArrayType::canonicalName(bool _addDataLocation) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
MemberList const& ArrayType::members(ContractDefinition const*) const
|
||||
MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
|
||||
{
|
||||
if (!m_members)
|
||||
MemberList::MemberMap members;
|
||||
if (!isString())
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
if (!isString())
|
||||
{
|
||||
members.push_back({"length", make_shared<IntegerType>(256)});
|
||||
if (isDynamicallySized() && location() == DataLocation::Storage)
|
||||
members.push_back({"push", make_shared<FunctionType>(
|
||||
TypePointers{baseType()},
|
||||
TypePointers{make_shared<IntegerType>(256)},
|
||||
strings{string()},
|
||||
strings{string()},
|
||||
isByteArray() ? FunctionType::Location::ByteArrayPush : FunctionType::Location::ArrayPush
|
||||
)});
|
||||
}
|
||||
m_members.reset(new MemberList(members));
|
||||
members.push_back({"length", make_shared<IntegerType>(256)});
|
||||
if (isDynamicallySized() && location() == DataLocation::Storage)
|
||||
members.push_back({"push", make_shared<FunctionType>(
|
||||
TypePointers{baseType()},
|
||||
TypePointers{make_shared<IntegerType>(256)},
|
||||
strings{string()},
|
||||
strings{string()},
|
||||
isByteArray() ? FunctionType::Location::ByteArrayPush : FunctionType::Location::ArrayPush
|
||||
)});
|
||||
}
|
||||
return *m_members;
|
||||
return members;
|
||||
}
|
||||
|
||||
TypePointer ArrayType::encodingType() const
|
||||
@ -956,55 +1008,47 @@ string ContractType::canonicalName(bool) const
|
||||
return m_contract.annotation().canonicalName;
|
||||
}
|
||||
|
||||
MemberList const& ContractType::members(ContractDefinition const*) const
|
||||
MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) const
|
||||
{
|
||||
// We need to lazy-initialize it because of recursive references.
|
||||
if (!m_members)
|
||||
// All address members and all interface functions
|
||||
MemberList::MemberMap members(IntegerType(120, IntegerType::Modifier::Address).nativeMembers(nullptr));
|
||||
if (m_super)
|
||||
{
|
||||
// All address members and all interface functions
|
||||
MemberList::MemberMap members(
|
||||
IntegerType::AddressMemberList.begin(),
|
||||
IntegerType::AddressMemberList.end()
|
||||
);
|
||||
if (m_super)
|
||||
{
|
||||
// add the most derived of all functions which are visible in derived contracts
|
||||
for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts)
|
||||
for (FunctionDefinition const* function: base->definedFunctions())
|
||||
// add the most derived of all functions which are visible in derived contracts
|
||||
for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts)
|
||||
for (FunctionDefinition const* function: base->definedFunctions())
|
||||
{
|
||||
if (!function->isVisibleInDerivedContracts())
|
||||
continue;
|
||||
auto functionType = make_shared<FunctionType>(*function, true);
|
||||
bool functionWithEqualArgumentsFound = false;
|
||||
for (auto const& member: members)
|
||||
{
|
||||
if (!function->isVisibleInDerivedContracts())
|
||||
if (member.name != function->name())
|
||||
continue;
|
||||
auto functionType = make_shared<FunctionType>(*function, true);
|
||||
bool functionWithEqualArgumentsFound = false;
|
||||
for (auto const& member: members)
|
||||
{
|
||||
if (member.name != function->name())
|
||||
continue;
|
||||
auto memberType = dynamic_cast<FunctionType const*>(member.type.get());
|
||||
solAssert(!!memberType, "Override changes type.");
|
||||
if (!memberType->hasEqualArgumentTypes(*functionType))
|
||||
continue;
|
||||
functionWithEqualArgumentsFound = true;
|
||||
break;
|
||||
}
|
||||
if (!functionWithEqualArgumentsFound)
|
||||
members.push_back(MemberList::Member(
|
||||
function->name(),
|
||||
functionType,
|
||||
function
|
||||
));
|
||||
auto memberType = dynamic_cast<FunctionType const*>(member.type.get());
|
||||
solAssert(!!memberType, "Override changes type.");
|
||||
if (!memberType->hasEqualArgumentTypes(*functionType))
|
||||
continue;
|
||||
functionWithEqualArgumentsFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
for (auto const& it: m_contract.interfaceFunctions())
|
||||
members.push_back(MemberList::Member(
|
||||
it.second->declaration().name(),
|
||||
it.second->asMemberFunction(m_contract.isLibrary()),
|
||||
&it.second->declaration()
|
||||
));
|
||||
m_members.reset(new MemberList(members));
|
||||
if (!functionWithEqualArgumentsFound)
|
||||
members.push_back(MemberList::Member(
|
||||
function->name(),
|
||||
functionType,
|
||||
function
|
||||
));
|
||||
}
|
||||
}
|
||||
return *m_members;
|
||||
else
|
||||
for (auto const& it: m_contract.interfaceFunctions())
|
||||
members.push_back(MemberList::Member(
|
||||
it.second->declaration().name(),
|
||||
it.second->asMemberFunction(m_contract.isLibrary()),
|
||||
&it.second->declaration()
|
||||
));
|
||||
return members;
|
||||
}
|
||||
|
||||
shared_ptr<FunctionType const> const& ContractType::constructorType() const
|
||||
@ -1099,27 +1143,22 @@ string StructType::toString(bool _short) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
MemberList const& StructType::members(ContractDefinition const*) const
|
||||
MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const
|
||||
{
|
||||
// We need to lazy-initialize it because of recursive references.
|
||||
if (!m_members)
|
||||
MemberList::MemberMap members;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
{
|
||||
TypePointer type = variable->annotation().type;
|
||||
// Skip all mapping members if we are not in storage.
|
||||
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
|
||||
continue;
|
||||
members.push_back(MemberList::Member(
|
||||
variable->name(),
|
||||
copyForLocationIfReference(type),
|
||||
variable.get())
|
||||
);
|
||||
}
|
||||
m_members.reset(new MemberList(members));
|
||||
TypePointer type = variable->annotation().type;
|
||||
// Skip all mapping members if we are not in storage.
|
||||
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
|
||||
continue;
|
||||
members.push_back(MemberList::Member(
|
||||
variable->name(),
|
||||
copyForLocationIfReference(type),
|
||||
variable.get())
|
||||
);
|
||||
}
|
||||
return *m_members;
|
||||
return members;
|
||||
}
|
||||
|
||||
TypePointer StructType::interfaceType(bool _inLibrary) const
|
||||
@ -1436,6 +1475,20 @@ FunctionType::FunctionType(const EventDefinition& _event):
|
||||
swap(paramNames, m_parameterNames);
|
||||
}
|
||||
|
||||
std::vector<string> FunctionType::parameterNames() const
|
||||
{
|
||||
if (!bound())
|
||||
return m_parameterNames;
|
||||
return vector<string>(m_parameterNames.cbegin() + 1, m_parameterNames.cend());
|
||||
}
|
||||
|
||||
TypePointers FunctionType::parameterTypes() const
|
||||
{
|
||||
if (!bound())
|
||||
return m_parameterTypes;
|
||||
return TypePointers(m_parameterTypes.cbegin() + 1, m_parameterTypes.cend());
|
||||
}
|
||||
|
||||
bool FunctionType::operator==(Type const& _other) const
|
||||
{
|
||||
if (_other.category() != category())
|
||||
@ -1504,6 +1557,8 @@ unsigned FunctionType::sizeOnStack() const
|
||||
size++;
|
||||
if (m_valueSet)
|
||||
size++;
|
||||
if (bound())
|
||||
size += m_parameterTypes.front()->sizeOnStack();
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -1533,7 +1588,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
||||
return make_shared<FunctionType>(paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_location, m_arbitraryParameters);
|
||||
}
|
||||
|
||||
MemberList const& FunctionType::members(ContractDefinition const*) const
|
||||
MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) const
|
||||
{
|
||||
switch (m_location)
|
||||
{
|
||||
@ -1544,52 +1599,50 @@ MemberList const& FunctionType::members(ContractDefinition const*) const
|
||||
case Location::RIPEMD160:
|
||||
case Location::Bare:
|
||||
case Location::BareCallCode:
|
||||
if (!m_members)
|
||||
{
|
||||
MemberList::MemberMap members{
|
||||
{
|
||||
"value",
|
||||
{
|
||||
MemberList::MemberMap members{
|
||||
{
|
||||
"value",
|
||||
make_shared<FunctionType>(
|
||||
parseElementaryTypeVector({"uint"}),
|
||||
TypePointers{copyAndSetGasOrValue(false, true)},
|
||||
strings(),
|
||||
strings(),
|
||||
Location::SetValue,
|
||||
false,
|
||||
nullptr,
|
||||
m_gasSet,
|
||||
m_valueSet
|
||||
)
|
||||
}
|
||||
};
|
||||
if (m_location != Location::Creation)
|
||||
members.push_back(
|
||||
MemberList::Member(
|
||||
"gas",
|
||||
make_shared<FunctionType>(
|
||||
parseElementaryTypeVector({"uint"}),
|
||||
TypePointers{copyAndSetGasOrValue(false, true)},
|
||||
TypePointers{copyAndSetGasOrValue(true, false)},
|
||||
strings(),
|
||||
strings(),
|
||||
Location::SetValue,
|
||||
Location::SetGas,
|
||||
false,
|
||||
nullptr,
|
||||
m_gasSet,
|
||||
m_valueSet
|
||||
)
|
||||
}
|
||||
};
|
||||
if (m_location != Location::Creation)
|
||||
members.push_back(
|
||||
MemberList::Member(
|
||||
"gas",
|
||||
make_shared<FunctionType>(
|
||||
parseElementaryTypeVector({"uint"}),
|
||||
TypePointers{copyAndSetGasOrValue(true, false)},
|
||||
strings(),
|
||||
strings(),
|
||||
Location::SetGas,
|
||||
false,
|
||||
nullptr,
|
||||
m_gasSet,
|
||||
m_valueSet
|
||||
)
|
||||
)
|
||||
);
|
||||
m_members.reset(new MemberList(members));
|
||||
}
|
||||
return *m_members;
|
||||
)
|
||||
);
|
||||
return members;
|
||||
}
|
||||
default:
|
||||
return EmptyMemberList;
|
||||
return MemberList::MemberMap();
|
||||
}
|
||||
}
|
||||
|
||||
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes) const
|
||||
{
|
||||
TypePointers const& paramTypes = parameterTypes();
|
||||
TypePointers paramTypes = parameterTypes();
|
||||
if (takesArbitraryParameters())
|
||||
return true;
|
||||
else if (_argumentTypes.size() != paramTypes.size())
|
||||
@ -1678,11 +1731,12 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
|
||||
m_arbitraryParameters,
|
||||
m_declaration,
|
||||
m_gasSet || _setGas,
|
||||
m_valueSet || _setValue
|
||||
m_valueSet || _setValue,
|
||||
m_bound
|
||||
);
|
||||
}
|
||||
|
||||
FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary) const
|
||||
FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) const
|
||||
{
|
||||
TypePointers parameterTypes;
|
||||
for (auto const& t: m_parameterTypes)
|
||||
@ -1712,14 +1766,15 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary) const
|
||||
m_arbitraryParameters,
|
||||
m_declaration,
|
||||
m_gasSet,
|
||||
m_valueSet
|
||||
m_valueSet,
|
||||
_bound
|
||||
);
|
||||
}
|
||||
|
||||
vector<string> const FunctionType::parameterTypeNames(bool _addDataLocation) const
|
||||
{
|
||||
vector<string> names;
|
||||
for (TypePointer const& t: m_parameterTypes)
|
||||
for (TypePointer const& t: parameterTypes())
|
||||
names.push_back(t->canonicalName(_addDataLocation));
|
||||
|
||||
return names;
|
||||
@ -1734,6 +1789,12 @@ vector<string> const FunctionType::returnParameterTypeNames(bool _addDataLocatio
|
||||
return names;
|
||||
}
|
||||
|
||||
TypePointer FunctionType::selfType() const
|
||||
{
|
||||
solAssert(bound(), "");
|
||||
return m_parameterTypes.at(0);
|
||||
}
|
||||
|
||||
ASTPointer<ASTString> FunctionType::documentation() const
|
||||
{
|
||||
auto function = dynamic_cast<Documented const*>(m_declaration);
|
||||
@ -1784,43 +1845,37 @@ unsigned TypeType::sizeOnStack() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
MemberList const& TypeType::members(ContractDefinition const* _currentScope) const
|
||||
MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _currentScope) const
|
||||
{
|
||||
// We need to lazy-initialize it because of recursive references.
|
||||
if (!m_members || m_cachedScope != _currentScope)
|
||||
MemberList::MemberMap members;
|
||||
if (m_actualType->category() == Category::Contract)
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
if (m_actualType->category() == Category::Contract)
|
||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).contractDefinition();
|
||||
if (contract.isLibrary())
|
||||
for (auto const& it: contract.interfaceFunctions())
|
||||
members.push_back(MemberList::Member(
|
||||
it.second->declaration().name(),
|
||||
it.second->asMemberFunction(true), // use callcode
|
||||
&it.second->declaration()
|
||||
));
|
||||
else if (_currentScope != nullptr)
|
||||
{
|
||||
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).contractDefinition();
|
||||
if (contract.isLibrary())
|
||||
for (auto const& it: contract.interfaceFunctions())
|
||||
members.push_back(MemberList::Member(
|
||||
it.second->declaration().name(),
|
||||
it.second->asMemberFunction(true), // use callcode
|
||||
&it.second->declaration()
|
||||
));
|
||||
else if (_currentScope != nullptr)
|
||||
{
|
||||
auto const& currentBases = _currentScope->annotation().linearizedBaseContracts;
|
||||
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
|
||||
// We are accessing the type of a base contract, so add all public and protected
|
||||
// members. Note that this does not add inherited functions on purpose.
|
||||
for (Declaration const* decl: contract.inheritableMembers())
|
||||
members.push_back(MemberList::Member(decl->name(), decl->type(), decl));
|
||||
}
|
||||
auto const& currentBases = _currentScope->annotation().linearizedBaseContracts;
|
||||
if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
|
||||
// We are accessing the type of a base contract, so add all public and protected
|
||||
// members. Note that this does not add inherited functions on purpose.
|
||||
for (Declaration const* decl: contract.inheritableMembers())
|
||||
members.push_back(MemberList::Member(decl->name(), decl->type(), decl));
|
||||
}
|
||||
else if (m_actualType->category() == Category::Enum)
|
||||
{
|
||||
EnumDefinition const& enumDef = dynamic_cast<EnumType const&>(*m_actualType).enumDefinition();
|
||||
auto enumType = make_shared<EnumType>(enumDef);
|
||||
for (ASTPointer<EnumValue> const& enumValue: enumDef.members())
|
||||
members.push_back(MemberList::Member(enumValue->name(), enumType));
|
||||
}
|
||||
m_members.reset(new MemberList(members));
|
||||
m_cachedScope = _currentScope;
|
||||
}
|
||||
return *m_members;
|
||||
else if (m_actualType->category() == Category::Enum)
|
||||
{
|
||||
EnumDefinition const& enumDef = dynamic_cast<EnumType const&>(*m_actualType).enumDefinition();
|
||||
auto enumType = make_shared<EnumType>(enumDef);
|
||||
for (ASTPointer<EnumValue> const& enumValue: enumDef.members())
|
||||
members.push_back(MemberList::Member(enumValue->name(), enumType));
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
ModifierType::ModifierType(const ModifierDefinition& _modifier)
|
||||
@ -1866,36 +1921,6 @@ string ModifierType::toString(bool _short) const
|
||||
MagicType::MagicType(MagicType::Kind _kind):
|
||||
m_kind(_kind)
|
||||
{
|
||||
switch (m_kind)
|
||||
{
|
||||
case Kind::Block:
|
||||
m_members = MemberList({
|
||||
{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
||||
{"timestamp", make_shared<IntegerType>(256)},
|
||||
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Location::BlockHash)},
|
||||
{"difficulty", make_shared<IntegerType>(256)},
|
||||
{"number", make_shared<IntegerType>(256)},
|
||||
{"gaslimit", make_shared<IntegerType>(256)}
|
||||
});
|
||||
break;
|
||||
case Kind::Message:
|
||||
m_members = MemberList({
|
||||
{"sender", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
||||
{"gas", make_shared<IntegerType>(256)},
|
||||
{"value", make_shared<IntegerType>(256)},
|
||||
{"data", make_shared<ArrayType>(DataLocation::CallData)},
|
||||
{"sig", make_shared<FixedBytesType>(4)}
|
||||
});
|
||||
break;
|
||||
case Kind::Transaction:
|
||||
m_members = MemberList({
|
||||
{"origin", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
||||
{"gasprice", make_shared<IntegerType>(256)}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));
|
||||
}
|
||||
}
|
||||
|
||||
bool MagicType::operator==(Type const& _other) const
|
||||
@ -1906,6 +1931,37 @@ bool MagicType::operator==(Type const& _other) const
|
||||
return other.m_kind == m_kind;
|
||||
}
|
||||
|
||||
MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
||||
{
|
||||
switch (m_kind)
|
||||
{
|
||||
case Kind::Block:
|
||||
return MemberList::MemberMap({
|
||||
{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
||||
{"timestamp", make_shared<IntegerType>(256)},
|
||||
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Location::BlockHash)},
|
||||
{"difficulty", make_shared<IntegerType>(256)},
|
||||
{"number", make_shared<IntegerType>(256)},
|
||||
{"gaslimit", make_shared<IntegerType>(256)}
|
||||
});
|
||||
case Kind::Message:
|
||||
return MemberList::MemberMap({
|
||||
{"sender", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
||||
{"gas", make_shared<IntegerType>(256)},
|
||||
{"value", make_shared<IntegerType>(256)},
|
||||
{"data", make_shared<ArrayType>(DataLocation::CallData)},
|
||||
{"sig", make_shared<FixedBytesType>(4)}
|
||||
});
|
||||
case Kind::Transaction:
|
||||
return MemberList::MemberMap({
|
||||
{"origin", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
|
||||
{"gasprice", make_shared<IntegerType>(256)}
|
||||
});
|
||||
default:
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));
|
||||
}
|
||||
}
|
||||
|
||||
string MagicType::toString(bool) const
|
||||
{
|
||||
switch (m_kind)
|
||||
|
@ -90,6 +90,7 @@ public:
|
||||
MemberList() {}
|
||||
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
|
||||
MemberList& operator=(MemberList&& _other);
|
||||
void combine(MemberList const& _other);
|
||||
TypePointer memberType(std::string const& _name) const
|
||||
{
|
||||
TypePointer type;
|
||||
@ -149,8 +150,6 @@ public:
|
||||
/// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
|
||||
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
|
||||
|
||||
/// Calculates the
|
||||
|
||||
virtual Category category() const = 0;
|
||||
virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
|
||||
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
@ -216,9 +215,9 @@ public:
|
||||
return _targetType->dataStoredIn(DataLocation::Storage) ? mobileType() : _targetType;
|
||||
}
|
||||
|
||||
/// Returns the list of all members of this type. Default implementation: no members.
|
||||
/// Returns the list of all members of this type. Default implementation: no members apart from bound.
|
||||
/// @param _currentScope scope in which the members are accessed.
|
||||
virtual MemberList const& members(ContractDefinition const* /*_currentScope*/) const { return EmptyMemberList; }
|
||||
MemberList const& members(ContractDefinition const* _currentScope) const;
|
||||
/// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
|
||||
TypePointer memberType(std::string const& _name, ContractDefinition const* _currentScope = nullptr) const
|
||||
{
|
||||
@ -251,9 +250,20 @@ public:
|
||||
/// are returned without modification.
|
||||
virtual TypePointer interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
|
||||
|
||||
private:
|
||||
/// @returns a member list containing all members added to this type by `using for` directives.
|
||||
static MemberList::MemberMap boundFunctions(Type const& _type, ContractDefinition const& _scope);
|
||||
|
||||
protected:
|
||||
/// Convenience object used when returning an empty member list.
|
||||
static const MemberList EmptyMemberList;
|
||||
/// @returns the members native to this type depending on the given context. This function
|
||||
/// is used (in conjunction with boundFunctions to fill m_members below.
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* /*_currentScope*/) const
|
||||
{
|
||||
return MemberList::MemberMap();
|
||||
}
|
||||
|
||||
/// List of member types (parameterised by scape), will be lazy-initialized.
|
||||
mutable std::map<ContractDefinition const*, std::unique_ptr<MemberList>> m_members;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -281,10 +291,7 @@ public:
|
||||
virtual unsigned storageBytes() const override { return m_bits / 8; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual MemberList const& members(ContractDefinition const* /*_currentScope*/) const override
|
||||
{
|
||||
return isAddress() ? AddressMemberList : EmptyMemberList;
|
||||
}
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
|
||||
virtual std::string toString(bool _short) const override;
|
||||
|
||||
@ -295,8 +302,6 @@ public:
|
||||
bool isAddress() const { return m_modifier == Modifier::Address; }
|
||||
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
||||
|
||||
static const MemberList AddressMemberList;
|
||||
|
||||
private:
|
||||
int m_bits;
|
||||
Modifier m_modifier;
|
||||
@ -517,7 +522,7 @@ public:
|
||||
virtual unsigned sizeOnStack() const override;
|
||||
virtual std::string toString(bool _short) const override;
|
||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
virtual TypePointer encodingType() const override;
|
||||
virtual TypePointer decodingType() const override;
|
||||
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
||||
@ -541,8 +546,6 @@ private:
|
||||
TypePointer m_baseType;
|
||||
bool m_hasDynamicLength = true;
|
||||
u256 m_length;
|
||||
/// List of member types, will be lazy-initialized because of recursive references.
|
||||
mutable std::unique_ptr<MemberList> m_members;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -570,7 +573,7 @@ public:
|
||||
virtual std::string toString(bool _short) const override;
|
||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||
|
||||
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
virtual TypePointer encodingType() const override
|
||||
{
|
||||
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
||||
@ -602,8 +605,6 @@ private:
|
||||
bool m_super = false;
|
||||
/// Type of the constructor, @see constructorType. Lazily initialized.
|
||||
mutable FunctionTypePointer m_constructorType;
|
||||
/// List of member types, will be lazy-initialized because of recursive references.
|
||||
mutable std::unique_ptr<MemberList> m_members;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -623,7 +624,7 @@ public:
|
||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||
virtual std::string toString(bool _short) const override;
|
||||
|
||||
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
virtual TypePointer encodingType() const override
|
||||
{
|
||||
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : TypePointer();
|
||||
@ -648,8 +649,6 @@ public:
|
||||
|
||||
private:
|
||||
StructDefinition const& m_struct;
|
||||
/// List of member types, will be lazy-initialized because of recursive references.
|
||||
mutable std::unique_ptr<MemberList> m_members;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -688,8 +687,6 @@ public:
|
||||
|
||||
private:
|
||||
EnumDefinition const& m_enum;
|
||||
/// List of member types, will be lazy-initialized because of recursive references.
|
||||
mutable std::unique_ptr<MemberList> m_members;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -791,7 +788,8 @@ public:
|
||||
bool _arbitraryParameters = false,
|
||||
Declaration const* _declaration = nullptr,
|
||||
bool _gasSet = false,
|
||||
bool _valueSet = false
|
||||
bool _valueSet = false,
|
||||
bool _bound = false
|
||||
):
|
||||
m_parameterTypes(_parameterTypes),
|
||||
m_returnParameterTypes(_returnParameterTypes),
|
||||
@ -801,15 +799,18 @@ public:
|
||||
m_arbitraryParameters(_arbitraryParameters),
|
||||
m_gasSet(_gasSet),
|
||||
m_valueSet(_valueSet),
|
||||
m_bound(_bound),
|
||||
m_declaration(_declaration)
|
||||
{}
|
||||
|
||||
TypePointers const& parameterTypes() const { return m_parameterTypes; }
|
||||
std::vector<std::string> const& parameterNames() const { return m_parameterNames; }
|
||||
TypePointers parameterTypes() const;
|
||||
std::vector<std::string> parameterNames() const;
|
||||
std::vector<std::string> const parameterTypeNames(bool _addDataLocation) const;
|
||||
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
||||
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
|
||||
std::vector<std::string> const returnParameterTypeNames(bool _addDataLocation) const;
|
||||
/// @returns the "self" parameter type for a bound function
|
||||
TypePointer selfType() const;
|
||||
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
virtual std::string toString(bool _short) const override;
|
||||
@ -817,7 +818,7 @@ public:
|
||||
virtual u256 storageSize() const override;
|
||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||
virtual unsigned sizeOnStack() const override;
|
||||
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
|
||||
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
|
||||
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
|
||||
@ -855,6 +856,7 @@ public:
|
||||
bool takesArbitraryParameters() const { return m_arbitraryParameters; }
|
||||
bool gasSet() const { return m_gasSet; }
|
||||
bool valueSet() const { return m_valueSet; }
|
||||
bool bound() const { return m_bound; }
|
||||
|
||||
/// @returns a copy of this type, where gas or value are set manually. This will never set one
|
||||
/// of the parameters to fals.
|
||||
@ -865,7 +867,8 @@ public:
|
||||
/// This is needed if external functions are called on other contracts, as they cannot return
|
||||
/// dynamic values.
|
||||
/// @param _inLibrary if true, uses CallCode as location.
|
||||
FunctionTypePointer asMemberFunction(bool _inLibrary) const;
|
||||
/// @param _bound if true, the argumenst are placed as `arg1.functionName(arg2, ..., argn)`.
|
||||
FunctionTypePointer asMemberFunction(bool _inLibrary, bool _bound = false) const;
|
||||
|
||||
private:
|
||||
static TypePointers parseElementaryTypeVector(strings const& _types);
|
||||
@ -879,8 +882,8 @@ private:
|
||||
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_valueSet = false; ///< true iff the value to be sent is on the stack
|
||||
bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn)
|
||||
bool m_isConstant = false;
|
||||
mutable std::unique_ptr<MemberList> m_members;
|
||||
Declaration const* m_declaration = nullptr;
|
||||
};
|
||||
|
||||
@ -935,13 +938,10 @@ public:
|
||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||
virtual unsigned sizeOnStack() const override;
|
||||
virtual std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
||||
virtual MemberList const& members(ContractDefinition const* _currentScope) const override;
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
|
||||
private:
|
||||
TypePointer m_actualType;
|
||||
/// List of member types, will be lazy-initialized because of recursive references.
|
||||
mutable std::unique_ptr<MemberList> m_members;
|
||||
mutable ContractDefinition const* m_cachedScope = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@ -988,14 +988,12 @@ public:
|
||||
virtual bool canBeStored() const override { return false; }
|
||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||
virtual unsigned sizeOnStack() const override { return 0; }
|
||||
virtual MemberList const& members(ContractDefinition const*) const override { return m_members; }
|
||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
|
||||
virtual std::string toString(bool _short) const override;
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
|
||||
MemberList m_members;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -672,7 +672,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
_functionCall.expression().accept(*this);
|
||||
solAssert(function.parameterTypes().size() == 1, "");
|
||||
solAssert(!!function.parameterTypes()[0], "");
|
||||
TypePointer const& paramType = function.parameterTypes()[0];
|
||||
TypePointer paramType = function.parameterTypes()[0];
|
||||
shared_ptr<ArrayType> arrayType =
|
||||
function.location() == Location::ArrayPush ?
|
||||
make_shared<ArrayType>(DataLocation::Storage, paramType) :
|
||||
|
@ -2551,6 +2551,99 @@ BOOST_AUTO_TEST_CASE(using_for_not_library)
|
||||
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(using_for_function_exists)
|
||||
{
|
||||
char const* text = R"(
|
||||
library D { function double(uint self) returns (uint) { return 2*self; } }
|
||||
contract C {
|
||||
using D for uint;
|
||||
function f(uint a) {
|
||||
a.double;
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(using_for_function_on_int)
|
||||
{
|
||||
char const* text = R"(
|
||||
library D { function double(uint self) returns (uint) { return 2*self; } }
|
||||
contract C {
|
||||
using D for uint;
|
||||
function f(uint a) returns (uint) {
|
||||
return a.double();
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(using_for_function_on_struct)
|
||||
{
|
||||
char const* text = R"(
|
||||
library D { struct s { uint a; } function mul(s storage self, uint x) returns (uint) { return self.a *= x; } }
|
||||
contract C {
|
||||
using D for D.s;
|
||||
D.s x;
|
||||
function f(uint a) returns (uint) {
|
||||
return x.mul(a);
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(using_for_overload)
|
||||
{
|
||||
char const* text = R"(
|
||||
library D {
|
||||
struct s { uint a; }
|
||||
function mul(s storage self, uint x) returns (uint) { return self.a *= x; }
|
||||
function mul(s storage self, bytes32 x) returns (bytes32) { }
|
||||
}
|
||||
contract C {
|
||||
using D for D.s;
|
||||
D.s x;
|
||||
function f(uint a) returns (uint) {
|
||||
return x.mul(a);
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(using_for_by_name)
|
||||
{
|
||||
char const* text = R"(
|
||||
library D { struct s { uint a; } function mul(s storage self, uint x) returns (uint) { return self.a *= x; } }
|
||||
contract C {
|
||||
using D for D.s;
|
||||
D.s x;
|
||||
function f(uint a) returns (uint) {
|
||||
return x.mul({x: a});
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(bound_function_in_var)
|
||||
{
|
||||
char const* text = R"(
|
||||
library D { struct s { uint a; } function mul(s storage self, uint x) returns (uint) { return self.a *= x; } }
|
||||
contract C {
|
||||
using D for D.s;
|
||||
D.s x;
|
||||
function f(uint a) returns (uint) {
|
||||
var g = x.mul;
|
||||
return g({x: a});
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(create_memory_arrays)
|
||||
{
|
||||
char const* text = R"(
|
||||
|
Loading…
Reference in New Issue
Block a user