Prepare for allowing bound functions and using for everywhere.

This commit is contained in:
chriseth 2020-06-15 19:11:03 +02:00
parent b9c9535647
commit 645c3508a8
2 changed files with 77 additions and 59 deletions

View File

@ -311,10 +311,15 @@ TypePointer Type::commonType(Type const* _a, Type const* _b)
return nullptr;
}
MemberList const& Type::members(ContractDefinition const* _currentScope) const
MemberList const& Type::members(ASTNode const* _currentScope) const
{
if (!m_members[_currentScope])
{
solAssert(
_currentScope == nullptr ||
dynamic_cast<SourceUnit const*>(_currentScope) ||
dynamic_cast<ContractDefinition const*>(_currentScope),
"");
MemberList::MemberMap members = nativeMembers(_currentScope);
if (_currentScope)
members += boundFunctions(*this, *_currentScope);
@ -344,8 +349,20 @@ TypePointer Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
return encodingType;
}
MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition const& _scope)
MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope)
{
vector<UsingForDirective const*> usingForDirectives;
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope))
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
{
for (ContractDefinition const* contract: contract->annotation().linearizedBaseContracts)
usingForDirectives += contract->usingForDirectives();
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(contract->sourceUnit().nodes());
}
else
solAssert(false, "");
// Normalise data location of type.
DataLocation typeLocation = DataLocation::Storage;
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
@ -353,38 +370,39 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
set<Declaration const*> seenFunctions;
MemberList::MemberMap members;
for (ContractDefinition const* contract: _scope.annotation().linearizedBaseContracts)
for (UsingForDirective const* ufd: contract->usingForDirectives())
{
// Convert both types to pointers for comparison to see if the `using for`
// directive applies.
// Further down, we check more detailed for each function if `_type` is
// convertible to the function parameter type.
if (ufd->typeName() &&
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
*TypeProvider::withLocationIfReference(
typeLocation,
ufd->typeName()->annotation().type,
true
)
for (UsingForDirective const* ufd: usingForDirectives)
{
// Convert both types to pointers for comparison to see if the `using for`
// directive applies.
// Further down, we check more detailed for each function if `_type` is
// convertible to the function parameter type.
if (ufd->typeName() &&
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
*TypeProvider::withLocationIfReference(
typeLocation,
ufd->typeName()->annotation().type,
true
)
)
continue;
auto const& library = dynamic_cast<ContractDefinition const&>(
*ufd->libraryName().annotation().referencedDeclaration
);
for (FunctionDefinition const* function: library.definedFunctions())
{
if (!function->isVisibleAsLibraryMember() || seenFunctions.count(function))
continue;
auto const& library = dynamic_cast<ContractDefinition const&>(
*ufd->libraryName().annotation().referencedDeclaration
);
for (FunctionDefinition const* function: library.definedFunctions())
{
if (!function->isVisibleAsLibraryMember() || seenFunctions.count(function))
continue;
seenFunctions.insert(function);
if (function->parameters().empty())
continue;
FunctionTypePointer fun =
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
members.emplace_back(function->name(), fun, function);
}
seenFunctions.insert(function);
if (function->parameters().empty())
continue;
FunctionTypePointer fun =
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
members.emplace_back(function->name(), fun, function);
}
}
return members;
}
@ -464,7 +482,7 @@ bool AddressType::operator==(Type const& _other) const
return other.m_stateMutability == m_stateMutability;
}
MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members = {
{"balance", TypeProvider::uint256()},
@ -1400,7 +1418,7 @@ TypeResult FixedBytesType::binaryOperatorResult(Token _operator, Type const* _ot
return nullptr;
}
MemberList::MemberMap FixedBytesType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap FixedBytesType::nativeMembers(ASTNode const*) const
{
return MemberList::MemberMap{MemberList::Member{"length", TypeProvider::uint(8)}};
}
@ -1856,7 +1874,7 @@ string ArrayType::signatureInExternalFunction(bool _structsByName) const
}
}
MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap ArrayType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members;
if (!isString())
@ -2029,10 +2047,9 @@ string ContractType::canonicalName() const
return m_contract.annotation().canonicalName;
}
MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _contract) const
MemberList::MemberMap ContractType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members;
solAssert(_contract, "");
if (m_super)
{
// add the most derived of all functions which are visible in derived contracts
@ -2063,14 +2080,13 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con
}
}
else if (!m_contract.isLibrary())
{
for (auto const& it: m_contract.interfaceFunctions())
members.emplace_back(
it.second->declaration().name(),
it.second->asExternallyCallableFunction(m_contract.isLibrary()),
&it.second->declaration()
);
}
return members;
}
@ -2241,7 +2257,7 @@ string StructType::toString(bool _short) const
return ret;
}
MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap StructType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap members;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
@ -3146,7 +3162,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
);
}
MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const* _scope) const
MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
{
switch (m_kind)
{
@ -3165,7 +3181,8 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const* _sco
functionDefinition->isPartOfExternalInterface()
)
{
solAssert(_scope->derivesFrom(*functionDefinition->annotation().contract), "");
auto const* contractScope = dynamic_cast<ContractDefinition const*>(_scope);
solAssert(contractScope && contractScope->derivesFrom(*functionDefinition->annotation().contract), "");
return {{"selector", TypeProvider::fixedBytes(4)}};
}
else
@ -3640,13 +3657,14 @@ vector<tuple<string, TypePointer>> TypeType::makeStackItems() const
return {};
}
MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _currentScope) const
MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) const
{
MemberList::MemberMap members;
if (m_actualType->category() == Category::Contract)
{
auto const* contractScope = dynamic_cast<ContractDefinition const*>(_currentScope);
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).contractDefinition();
bool inDerivingScope = _currentScope && _currentScope->derivesFrom(contract);
bool inDerivingScope = contractScope && contractScope->derivesFrom(contract);
for (auto const* declaration: contract.declarations())
{
@ -3748,7 +3766,7 @@ bool ModuleType::operator==(Type const& _other) const
return &m_sourceUnit == &dynamic_cast<ModuleType const&>(_other).m_sourceUnit;
}
MemberList::MemberMap ModuleType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap ModuleType::nativeMembers(ASTNode const*) const
{
MemberList::MemberMap symbols;
for (auto const& symbolName: m_sourceUnit.annotation().exportedSymbols)
@ -3789,7 +3807,7 @@ bool MagicType::operator==(Type const& _other) const
return other.m_kind == m_kind;
}
MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const
{
switch (m_kind)
{

View File

@ -315,9 +315,9 @@ public:
/// 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.
MemberList const& members(ContractDefinition const* _currentScope) const;
MemberList const& members(ASTNode 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
TypePointer memberType(std::string const& _name, ASTNode const* _currentScope = nullptr) const
{
return members(_currentScope).memberType(_name);
}
@ -361,12 +361,12 @@ public:
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);
static MemberList::MemberMap boundFunctions(Type const& _type, ASTNode const& _scope);
protected:
/// @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
virtual MemberList::MemberMap nativeMembers(ASTNode const* /*_currentScope*/) const
{
return MemberList::MemberMap();
}
@ -379,7 +379,7 @@ protected:
/// List of member types (parameterised by scape), will be lazy-initialized.
mutable std::map<ContractDefinition const*, std::unique_ptr<MemberList>> m_members;
mutable std::map<ASTNode const*, std::unique_ptr<MemberList>> m_members;
mutable std::optional<std::vector<std::tuple<std::string, TypePointer>>> m_stackItems;
mutable std::optional<size_t> m_stackSize;
};
@ -408,7 +408,7 @@ public:
bool isValueType() const override { return true; }
bool nameable() const override { return true; }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
std::string toString(bool _short) const override;
std::string canonicalName() const override;
@ -649,7 +649,7 @@ public:
bool nameable() const override { return true; }
std::string toString(bool) const override { return "bytes" + util::toString(m_bytes); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
TypePointer encodingType() const override { return this; }
TypeResult interfaceType(bool) const override { return this; }
@ -786,7 +786,7 @@ public:
std::string toString(bool _short) const override;
std::string canonicalName() const override;
std::string signatureInExternalFunction(bool _structsByName) const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
TypePointer encodingType() const override;
TypePointer decodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
@ -889,7 +889,7 @@ public:
std::string toString(bool _short) const override;
std::string canonicalName() const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
Type const* encodingType() const override;
@ -949,7 +949,7 @@ public:
bool nameable() const override { return true; }
std::string toString(bool _short) const override;
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
Type const* encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
@ -1220,7 +1220,7 @@ public:
bool nameable() const override;
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
bool hasSimpleZeroValueInMemory() const override { return false; }
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
TypePointer encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
@ -1389,7 +1389,7 @@ public:
bool canLiveOutsideStorage() const override { return false; }
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override;
protected:
@ -1441,7 +1441,7 @@ public:
bool canBeStored() const override { return false; }
bool canLiveOutsideStorage() const override { return true; }
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
std::string toString(bool _short) const override;
@ -1481,7 +1481,7 @@ public:
bool canBeStored() const override { return false; }
bool canLiveOutsideStorage() const override { return true; }
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
std::string toString(bool _short) const override;