mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #251 from chriseth/bind2
Bind library functions to types.
This commit is contained in:
commit
e9c7837c15
@ -160,8 +160,8 @@ private:
|
|||||||
void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
|
void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
|
||||||
|
|
||||||
std::map<ASTNode const*, DeclarationContainer>& m_scopes;
|
std::map<ASTNode const*, DeclarationContainer>& m_scopes;
|
||||||
Declaration const* m_currentScope;
|
Declaration const* m_currentScope = nullptr;
|
||||||
VariableScope* m_currentFunction;
|
VariableScope* m_currentFunction = nullptr;
|
||||||
ErrorList& m_errors;
|
ErrorList& m_errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,28 +31,6 @@ using namespace dev;
|
|||||||
using namespace dev::solidity;
|
using namespace dev::solidity;
|
||||||
|
|
||||||
|
|
||||||
bool ReferencesResolver::visit(Return const& _return)
|
|
||||||
{
|
|
||||||
_return.annotation().functionReturnParameters = m_returnParameters;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReferencesResolver::endVisit(NewExpression const& _new)
|
|
||||||
{
|
|
||||||
typeFor(_new.typeName());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
|
|
||||||
{
|
|
||||||
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
|
|
||||||
if (!declaration)
|
|
||||||
fatalDeclarationError(_typeName.location(), "Identifier not found or not unique.");
|
|
||||||
|
|
||||||
_typeName.annotation().referencedDeclaration = declaration;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReferencesResolver::resolve(ASTNode const& _root)
|
bool ReferencesResolver::resolve(ASTNode const& _root)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -79,6 +57,67 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
|
||||||
|
{
|
||||||
|
_typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
||||||
|
{
|
||||||
|
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());
|
||||||
|
if (!declaration)
|
||||||
|
fatalDeclarationError(_typeName.location(), "Identifier not found or not unique.");
|
||||||
|
|
||||||
|
_typeName.annotation().referencedDeclaration = declaration;
|
||||||
|
|
||||||
|
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
|
||||||
|
_typeName.annotation().type = make_shared<StructType>(*structDef);
|
||||||
|
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
|
||||||
|
_typeName.annotation().type = make_shared<EnumType>(*enumDef);
|
||||||
|
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
|
_typeName.annotation().type = make_shared<ContractType>(*contract);
|
||||||
|
else
|
||||||
|
fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReferencesResolver::endVisit(Mapping const& _typeName)
|
||||||
|
{
|
||||||
|
TypePointer keyType = _typeName.keyType().annotation().type;
|
||||||
|
TypePointer valueType = _typeName.valueType().annotation().type;
|
||||||
|
// Convert key type to memory.
|
||||||
|
keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
|
||||||
|
// Convert value type to storage reference.
|
||||||
|
valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
|
||||||
|
_typeName.annotation().type = make_shared<MappingType>(keyType, valueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
||||||
|
{
|
||||||
|
TypePointer baseType = _typeName.baseType().annotation().type;
|
||||||
|
if (baseType->storageBytes() == 0)
|
||||||
|
fatalTypeError(_typeName.baseType().location(), "Illegal base type of storage size zero for array.");
|
||||||
|
if (Expression const* length = _typeName.length())
|
||||||
|
{
|
||||||
|
if (!length->annotation().type)
|
||||||
|
ConstantEvaluator e(*length);
|
||||||
|
|
||||||
|
auto const* lengthType = dynamic_cast<IntegerConstantType const*>(length->annotation().type.get());
|
||||||
|
if (!lengthType)
|
||||||
|
fatalTypeError(length->location(), "Invalid array length.");
|
||||||
|
else
|
||||||
|
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReferencesResolver::visit(Return const& _return)
|
||||||
|
{
|
||||||
|
_return.annotation().functionReturnParameters = m_returnParameters;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
||||||
{
|
{
|
||||||
if (_variable.annotation().type)
|
if (_variable.annotation().type)
|
||||||
@ -87,7 +126,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
TypePointer type;
|
TypePointer type;
|
||||||
if (_variable.typeName())
|
if (_variable.typeName())
|
||||||
{
|
{
|
||||||
type = typeFor(*_variable.typeName());
|
type = _variable.typeName()->annotation().type;
|
||||||
using Location = VariableDeclaration::Location;
|
using Location = VariableDeclaration::Location;
|
||||||
Location loc = _variable.referenceLocation();
|
Location loc = _variable.referenceLocation();
|
||||||
// References are forced to calldata for external function parameters (not return)
|
// References are forced to calldata for external function parameters (not return)
|
||||||
@ -167,61 +206,6 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
_variable.annotation().type = type;
|
_variable.annotation().type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer ReferencesResolver::typeFor(TypeName const& _typeName)
|
|
||||||
{
|
|
||||||
if (_typeName.annotation().type)
|
|
||||||
return _typeName.annotation().type;
|
|
||||||
|
|
||||||
TypePointer type;
|
|
||||||
if (auto elemTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName))
|
|
||||||
type = Type::fromElementaryTypeName(elemTypeName->typeName());
|
|
||||||
else if (auto typeName = dynamic_cast<UserDefinedTypeName const*>(&_typeName))
|
|
||||||
{
|
|
||||||
Declaration const* declaration = typeName->annotation().referencedDeclaration;
|
|
||||||
solAssert(!!declaration, "");
|
|
||||||
|
|
||||||
if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
|
|
||||||
type = make_shared<StructType>(*structDef);
|
|
||||||
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
|
|
||||||
type = make_shared<EnumType>(*enumDef);
|
|
||||||
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
|
|
||||||
type = make_shared<ContractType>(*contract);
|
|
||||||
else
|
|
||||||
fatalTypeError(typeName->location(), "Name has to refer to a struct, enum or contract.");
|
|
||||||
}
|
|
||||||
else if (auto mapping = dynamic_cast<Mapping const*>(&_typeName))
|
|
||||||
{
|
|
||||||
TypePointer keyType = typeFor(mapping->keyType());
|
|
||||||
TypePointer valueType = typeFor(mapping->valueType());
|
|
||||||
// Convert key type to memory.
|
|
||||||
keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType);
|
|
||||||
// Convert value type to storage reference.
|
|
||||||
valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType);
|
|
||||||
type = make_shared<MappingType>(keyType, valueType);
|
|
||||||
}
|
|
||||||
else if (auto arrayType = dynamic_cast<ArrayTypeName const*>(&_typeName))
|
|
||||||
{
|
|
||||||
TypePointer baseType = typeFor(arrayType->baseType());
|
|
||||||
if (baseType->storageBytes() == 0)
|
|
||||||
fatalTypeError(arrayType->baseType().location(), "Illegal base type of storage size zero for array.");
|
|
||||||
if (Expression const* length = arrayType->length())
|
|
||||||
{
|
|
||||||
if (!length->annotation().type)
|
|
||||||
ConstantEvaluator e(*length);
|
|
||||||
|
|
||||||
auto const* lengthType = dynamic_cast<IntegerConstantType const*>(length->annotation().type.get());
|
|
||||||
if (!lengthType)
|
|
||||||
fatalTypeError(length->location(), "Invalid array length.");
|
|
||||||
else
|
|
||||||
type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
type = make_shared<ArrayType>(DataLocation::Storage, baseType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _typeName.annotation().type = move(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReferencesResolver::typeError(SourceLocation const& _location, string const& _description)
|
void ReferencesResolver::typeError(SourceLocation const& _location, string const& _description)
|
||||||
{
|
{
|
||||||
auto err = make_shared<Error>(Error::Type::TypeError);
|
auto err = make_shared<Error>(Error::Type::TypeError);
|
||||||
|
@ -60,13 +60,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
virtual bool visit(Block const&) override { return m_resolveInsideCode; }
|
virtual bool visit(Block const&) override { return m_resolveInsideCode; }
|
||||||
virtual bool visit(Identifier const& _identifier) override;
|
virtual bool visit(Identifier const& _identifier) override;
|
||||||
virtual bool visit(UserDefinedTypeName const& _typeName) override;
|
virtual bool visit(ElementaryTypeName const& _typeName) override;
|
||||||
|
virtual void endVisit(UserDefinedTypeName const& _typeName) override;
|
||||||
|
virtual void endVisit(Mapping const& _typeName) override;
|
||||||
|
virtual void endVisit(ArrayTypeName const& _typeName) override;
|
||||||
virtual bool visit(Return const& _return) override;
|
virtual bool visit(Return const& _return) override;
|
||||||
virtual void endVisit(NewExpression const& _new) override;
|
|
||||||
virtual void endVisit(VariableDeclaration const& _variable) override;
|
virtual void endVisit(VariableDeclaration const& _variable) override;
|
||||||
|
|
||||||
TypePointer typeFor(TypeName const& _typeName);
|
|
||||||
|
|
||||||
/// Adds a new error to the list of errors.
|
/// Adds a new error to the list of errors.
|
||||||
void typeError(SourceLocation const& _location, std::string const& _description);
|
void typeError(SourceLocation const& _location, std::string const& _description);
|
||||||
|
|
||||||
|
@ -359,6 +359,15 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||||
|
{
|
||||||
|
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
|
||||||
|
_usingFor.libraryName().annotation().referencedDeclaration
|
||||||
|
);
|
||||||
|
if (!library || !library->isLibrary())
|
||||||
|
typeError(_usingFor.libraryName().location(), "Library name expected.");
|
||||||
|
}
|
||||||
|
|
||||||
bool TypeChecker::visit(StructDefinition const& _struct)
|
bool TypeChecker::visit(StructDefinition const& _struct)
|
||||||
{
|
{
|
||||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||||
@ -1119,7 +1128,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
for (auto it = possibleMembers.begin(); it != possibleMembers.end();)
|
for (auto it = possibleMembers.begin(); it != possibleMembers.end();)
|
||||||
if (
|
if (
|
||||||
it->type->category() == Type::Category::Function &&
|
it->type->category() == Type::Category::Function &&
|
||||||
!dynamic_cast<FunctionType const&>(*it->type).canTakeArguments(*argumentTypes)
|
!dynamic_cast<FunctionType const&>(*it->type).canTakeArguments(*argumentTypes, exprType)
|
||||||
)
|
)
|
||||||
it = possibleMembers.erase(it);
|
it = possibleMembers.erase(it);
|
||||||
else
|
else
|
||||||
@ -1154,6 +1163,15 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
auto& annotation = _memberAccess.annotation();
|
auto& annotation = _memberAccess.annotation();
|
||||||
annotation.referencedDeclaration = possibleMembers.front().declaration;
|
annotation.referencedDeclaration = possibleMembers.front().declaration;
|
||||||
annotation.type = possibleMembers.front().type;
|
annotation.type = possibleMembers.front().type;
|
||||||
|
|
||||||
|
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type.get()))
|
||||||
|
if (funType->bound() && !exprType->isImplicitlyConvertibleTo(*funType->selfType()))
|
||||||
|
typeError(
|
||||||
|
_memberAccess.location(),
|
||||||
|
"Function \"" + memberName + "\" cannot be called on an object of type " +
|
||||||
|
exprType->toString() + " (expected " + funType->selfType()->toString() + ")"
|
||||||
|
);
|
||||||
|
|
||||||
if (exprType->category() == Type::Category::Struct)
|
if (exprType->category() == Type::Category::Struct)
|
||||||
annotation.isLValue = true;
|
annotation.isLValue = true;
|
||||||
else if (exprType->category() == Type::Category::Array)
|
else if (exprType->category() == Type::Category::Array)
|
||||||
|
@ -76,6 +76,7 @@ private:
|
|||||||
void checkLibraryRequirements(ContractDefinition const& _contract);
|
void checkLibraryRequirements(ContractDefinition const& _contract);
|
||||||
|
|
||||||
virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
|
virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
|
||||||
|
virtual void endVisit(UsingForDirective const& _usingFor) override;
|
||||||
virtual bool visit(StructDefinition const& _struct) override;
|
virtual bool visit(StructDefinition const& _struct) override;
|
||||||
virtual bool visit(FunctionDefinition const& _function) override;
|
virtual bool visit(FunctionDefinition const& _function) override;
|
||||||
virtual bool visit(VariableDeclaration const& _variable) override;
|
virtual bool visit(VariableDeclaration const& _variable) override;
|
||||||
|
@ -267,6 +267,7 @@ public:
|
|||||||
|
|
||||||
std::vector<ASTPointer<InheritanceSpecifier>> const& baseContracts() const { return m_baseContracts; }
|
std::vector<ASTPointer<InheritanceSpecifier>> const& baseContracts() const { return m_baseContracts; }
|
||||||
std::vector<ASTPointer<ASTNode>> const& subNodes() const { return m_subNodes; }
|
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<StructDefinition const*> definedStructs() const { return filteredNodes<StructDefinition>(m_subNodes); }
|
||||||
std::vector<EnumDefinition const*> definedEnums() const { return filteredNodes<EnumDefinition>(m_subNodes); }
|
std::vector<EnumDefinition const*> definedEnums() const { return filteredNodes<EnumDefinition>(m_subNodes); }
|
||||||
std::vector<VariableDeclaration const*> stateVariables() const { return filteredNodes<VariableDeclaration>(m_subNodes); }
|
std::vector<VariableDeclaration const*> stateVariables() const { return filteredNodes<VariableDeclaration>(m_subNodes); }
|
||||||
@ -335,6 +336,33 @@ private:
|
|||||||
std::vector<ASTPointer<Expression>> m_arguments;
|
std::vector<ASTPointer<Expression>> m_arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `using LibraryName for uint` will attach all functions from the library LibraryName
|
||||||
|
* to `uint` if the first parameter matches the type. `using LibraryName for *` attaches
|
||||||
|
* the function to any matching type.
|
||||||
|
*/
|
||||||
|
class UsingForDirective: public ASTNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UsingForDirective(
|
||||||
|
SourceLocation const& _location,
|
||||||
|
ASTPointer<Identifier> const& _libraryName,
|
||||||
|
ASTPointer<TypeName> const& _typeName
|
||||||
|
):
|
||||||
|
ASTNode(_location), m_libraryName(_libraryName), m_typeName(_typeName) {}
|
||||||
|
|
||||||
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
|
Identifier const& libraryName() const { return *m_libraryName; }
|
||||||
|
/// @returns the type name the library is attached to, null for `*`.
|
||||||
|
TypeName const* typeName() const { return m_typeName.get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ASTPointer<Identifier> m_libraryName;
|
||||||
|
ASTPointer<TypeName> m_typeName;
|
||||||
|
};
|
||||||
|
|
||||||
class StructDefinition: public Declaration
|
class StructDefinition: public Declaration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -39,6 +39,7 @@ class ImportDirective;
|
|||||||
class Declaration;
|
class Declaration;
|
||||||
class ContractDefinition;
|
class ContractDefinition;
|
||||||
class InheritanceSpecifier;
|
class InheritanceSpecifier;
|
||||||
|
class UsingForDirective;
|
||||||
class StructDefinition;
|
class StructDefinition;
|
||||||
class EnumDefinition;
|
class EnumDefinition;
|
||||||
class EnumValue;
|
class EnumValue;
|
||||||
|
@ -47,6 +47,7 @@ public:
|
|||||||
virtual bool visit(ImportDirective& _node) { return visitNode(_node); }
|
virtual bool visit(ImportDirective& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(ContractDefinition& _node) { return visitNode(_node); }
|
virtual bool visit(ContractDefinition& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(InheritanceSpecifier& _node) { return visitNode(_node); }
|
virtual bool visit(InheritanceSpecifier& _node) { return visitNode(_node); }
|
||||||
|
virtual bool visit(UsingForDirective& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(StructDefinition& _node) { return visitNode(_node); }
|
virtual bool visit(StructDefinition& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(EnumDefinition& _node) { return visitNode(_node); }
|
virtual bool visit(EnumDefinition& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(EnumValue& _node) { return visitNode(_node); }
|
virtual bool visit(EnumValue& _node) { return visitNode(_node); }
|
||||||
@ -88,6 +89,7 @@ public:
|
|||||||
virtual void endVisit(ImportDirective& _node) { endVisitNode(_node); }
|
virtual void endVisit(ImportDirective& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(ContractDefinition& _node) { endVisitNode(_node); }
|
virtual void endVisit(ContractDefinition& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(InheritanceSpecifier& _node) { endVisitNode(_node); }
|
virtual void endVisit(InheritanceSpecifier& _node) { endVisitNode(_node); }
|
||||||
|
virtual void endVisit(UsingForDirective& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(StructDefinition& _node) { endVisitNode(_node); }
|
virtual void endVisit(StructDefinition& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(EnumDefinition& _node) { endVisitNode(_node); }
|
virtual void endVisit(EnumDefinition& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(EnumValue& _node) { endVisitNode(_node); }
|
virtual void endVisit(EnumValue& _node) { endVisitNode(_node); }
|
||||||
@ -142,6 +144,7 @@ public:
|
|||||||
virtual bool visit(ContractDefinition const& _node) { return visitNode(_node); }
|
virtual bool visit(ContractDefinition const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(InheritanceSpecifier const& _node) { return visitNode(_node); }
|
virtual bool visit(InheritanceSpecifier const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(StructDefinition const& _node) { return visitNode(_node); }
|
virtual bool visit(StructDefinition const& _node) { return visitNode(_node); }
|
||||||
|
virtual bool visit(UsingForDirective const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(EnumDefinition const& _node) { return visitNode(_node); }
|
virtual bool visit(EnumDefinition const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(EnumValue const& _node) { return visitNode(_node); }
|
virtual bool visit(EnumValue const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(ParameterList const& _node) { return visitNode(_node); }
|
virtual bool visit(ParameterList const& _node) { return visitNode(_node); }
|
||||||
@ -182,6 +185,7 @@ public:
|
|||||||
virtual void endVisit(ImportDirective const& _node) { endVisitNode(_node); }
|
virtual void endVisit(ImportDirective const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(ContractDefinition const& _node) { endVisitNode(_node); }
|
virtual void endVisit(ContractDefinition const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(InheritanceSpecifier const& _node) { endVisitNode(_node); }
|
virtual void endVisit(InheritanceSpecifier const& _node) { endVisitNode(_node); }
|
||||||
|
virtual void endVisit(UsingForDirective const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(StructDefinition const& _node) { endVisitNode(_node); }
|
virtual void endVisit(StructDefinition const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(EnumDefinition const& _node) { endVisitNode(_node); }
|
virtual void endVisit(EnumDefinition const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(EnumValue const& _node) { endVisitNode(_node); }
|
virtual void endVisit(EnumValue const& _node) { endVisitNode(_node); }
|
||||||
|
@ -123,6 +123,28 @@ void EnumValue::accept(ASTConstVisitor& _visitor) const
|
|||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UsingForDirective::accept(ASTVisitor& _visitor)
|
||||||
|
{
|
||||||
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
|
m_libraryName->accept(_visitor);
|
||||||
|
if (m_typeName)
|
||||||
|
m_typeName->accept(_visitor);
|
||||||
|
}
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsingForDirective::accept(ASTConstVisitor& _visitor) const
|
||||||
|
{
|
||||||
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
|
m_libraryName->accept(_visitor);
|
||||||
|
if (m_typeName)
|
||||||
|
m_typeName->accept(_visitor);
|
||||||
|
}
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void StructDefinition::accept(ASTVisitor& _visitor)
|
void StructDefinition::accept(ASTVisitor& _visitor)
|
||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
|
@ -86,6 +86,11 @@ MemberList& MemberList::operator=(MemberList&& _other)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemberList::combine(MemberList const & _other)
|
||||||
|
{
|
||||||
|
m_memberTypes += _other.m_memberTypes;
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<u256, unsigned> const* MemberList::memberStorageOffset(string const& _name) const
|
std::pair<u256, unsigned> const* MemberList::memberStorageOffset(string const& _name) const
|
||||||
{
|
{
|
||||||
if (!m_storageOffsets)
|
if (!m_storageOffsets)
|
||||||
@ -185,7 +190,52 @@ TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
|
|||||||
return TypePointer();
|
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):
|
IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
|
||||||
m_bits(_bits), m_modifier(_modifier)
|
m_bits(_bits), m_modifier(_modifier)
|
||||||
@ -273,12 +323,18 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
|
|||||||
return commonType;
|
return commonType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MemberList IntegerType::AddressMemberList({
|
MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) const
|
||||||
|
{
|
||||||
|
if (isAddress())
|
||||||
|
return {
|
||||||
{"balance", make_shared<IntegerType >(256)},
|
{"balance", make_shared<IntegerType >(256)},
|
||||||
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true)},
|
{"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true)},
|
||||||
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
|
{"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
|
||||||
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
|
{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
|
||||||
});
|
};
|
||||||
|
else
|
||||||
|
return MemberList::MemberMap();
|
||||||
|
}
|
||||||
|
|
||||||
bool IntegerConstantType::isValidLiteral(const Literal& _literal)
|
bool IntegerConstantType::isValidLiteral(const Literal& _literal)
|
||||||
{
|
{
|
||||||
@ -858,10 +914,8 @@ string ArrayType::canonicalName(bool _addDataLocation) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList const& ArrayType::members(ContractDefinition const*) const
|
MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
|
||||||
{
|
{
|
||||||
if (!m_members)
|
|
||||||
{
|
|
||||||
MemberList::MemberMap members;
|
MemberList::MemberMap members;
|
||||||
if (!isString())
|
if (!isString())
|
||||||
{
|
{
|
||||||
@ -875,9 +929,7 @@ MemberList const& ArrayType::members(ContractDefinition const*) const
|
|||||||
isByteArray() ? FunctionType::Location::ByteArrayPush : FunctionType::Location::ArrayPush
|
isByteArray() ? FunctionType::Location::ByteArrayPush : FunctionType::Location::ArrayPush
|
||||||
)});
|
)});
|
||||||
}
|
}
|
||||||
m_members.reset(new MemberList(members));
|
return members;
|
||||||
}
|
|
||||||
return *m_members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer ArrayType::encodingType() const
|
TypePointer ArrayType::encodingType() const
|
||||||
@ -956,16 +1008,10 @@ string ContractType::canonicalName(bool) const
|
|||||||
return m_contract.annotation().canonicalName;
|
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
|
// All address members and all interface functions
|
||||||
MemberList::MemberMap members(
|
MemberList::MemberMap members(IntegerType(120, IntegerType::Modifier::Address).nativeMembers(nullptr));
|
||||||
IntegerType::AddressMemberList.begin(),
|
|
||||||
IntegerType::AddressMemberList.end()
|
|
||||||
);
|
|
||||||
if (m_super)
|
if (m_super)
|
||||||
{
|
{
|
||||||
// add the most derived of all functions which are visible in derived contracts
|
// add the most derived of all functions which are visible in derived contracts
|
||||||
@ -1002,9 +1048,7 @@ MemberList const& ContractType::members(ContractDefinition const*) const
|
|||||||
it.second->asMemberFunction(m_contract.isLibrary()),
|
it.second->asMemberFunction(m_contract.isLibrary()),
|
||||||
&it.second->declaration()
|
&it.second->declaration()
|
||||||
));
|
));
|
||||||
m_members.reset(new MemberList(members));
|
return members;
|
||||||
}
|
|
||||||
return *m_members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<FunctionType const> const& ContractType::constructorType() const
|
shared_ptr<FunctionType const> const& ContractType::constructorType() const
|
||||||
@ -1099,11 +1143,8 @@ string StructType::toString(bool _short) const
|
|||||||
return ret;
|
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;
|
MemberList::MemberMap members;
|
||||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||||
{
|
{
|
||||||
@ -1117,9 +1158,7 @@ MemberList const& StructType::members(ContractDefinition const*) const
|
|||||||
variable.get())
|
variable.get())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
m_members.reset(new MemberList(members));
|
return members;
|
||||||
}
|
|
||||||
return *m_members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointer StructType::interfaceType(bool _inLibrary) const
|
TypePointer StructType::interfaceType(bool _inLibrary) const
|
||||||
@ -1436,6 +1475,20 @@ FunctionType::FunctionType(const EventDefinition& _event):
|
|||||||
swap(paramNames, m_parameterNames);
|
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
|
bool FunctionType::operator==(Type const& _other) const
|
||||||
{
|
{
|
||||||
if (_other.category() != category())
|
if (_other.category() != category())
|
||||||
@ -1504,6 +1557,8 @@ unsigned FunctionType::sizeOnStack() const
|
|||||||
size++;
|
size++;
|
||||||
if (m_valueSet)
|
if (m_valueSet)
|
||||||
size++;
|
size++;
|
||||||
|
if (bound())
|
||||||
|
size += m_parameterTypes.front()->sizeOnStack();
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1533,7 +1588,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
|||||||
return make_shared<FunctionType>(paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_location, m_arbitraryParameters);
|
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)
|
switch (m_location)
|
||||||
{
|
{
|
||||||
@ -1544,7 +1599,6 @@ MemberList const& FunctionType::members(ContractDefinition const*) const
|
|||||||
case Location::RIPEMD160:
|
case Location::RIPEMD160:
|
||||||
case Location::Bare:
|
case Location::Bare:
|
||||||
case Location::BareCallCode:
|
case Location::BareCallCode:
|
||||||
if (!m_members)
|
|
||||||
{
|
{
|
||||||
MemberList::MemberMap members{
|
MemberList::MemberMap members{
|
||||||
{
|
{
|
||||||
@ -1579,17 +1633,19 @@ MemberList const& FunctionType::members(ContractDefinition const*) const
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
m_members.reset(new MemberList(members));
|
return members;
|
||||||
}
|
}
|
||||||
return *m_members;
|
|
||||||
default:
|
default:
|
||||||
return EmptyMemberList;
|
return MemberList::MemberMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes) const
|
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePointer const& _selfType) const
|
||||||
{
|
{
|
||||||
TypePointers const& paramTypes = parameterTypes();
|
solAssert(!bound() || _selfType, "");
|
||||||
|
if (bound() && !_selfType->isImplicitlyConvertibleTo(*selfType()))
|
||||||
|
return false;
|
||||||
|
TypePointers paramTypes = parameterTypes();
|
||||||
if (takesArbitraryParameters())
|
if (takesArbitraryParameters())
|
||||||
return true;
|
return true;
|
||||||
else if (_argumentTypes.size() != paramTypes.size())
|
else if (_argumentTypes.size() != paramTypes.size())
|
||||||
@ -1678,11 +1734,12 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
|
|||||||
m_arbitraryParameters,
|
m_arbitraryParameters,
|
||||||
m_declaration,
|
m_declaration,
|
||||||
m_gasSet || _setGas,
|
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;
|
TypePointers parameterTypes;
|
||||||
for (auto const& t: m_parameterTypes)
|
for (auto const& t: m_parameterTypes)
|
||||||
@ -1712,14 +1769,15 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary) const
|
|||||||
m_arbitraryParameters,
|
m_arbitraryParameters,
|
||||||
m_declaration,
|
m_declaration,
|
||||||
m_gasSet,
|
m_gasSet,
|
||||||
m_valueSet
|
m_valueSet,
|
||||||
|
_bound
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> const FunctionType::parameterTypeNames(bool _addDataLocation) const
|
vector<string> const FunctionType::parameterTypeNames(bool _addDataLocation) const
|
||||||
{
|
{
|
||||||
vector<string> names;
|
vector<string> names;
|
||||||
for (TypePointer const& t: m_parameterTypes)
|
for (TypePointer const& t: parameterTypes())
|
||||||
names.push_back(t->canonicalName(_addDataLocation));
|
names.push_back(t->canonicalName(_addDataLocation));
|
||||||
|
|
||||||
return names;
|
return names;
|
||||||
@ -1734,6 +1792,12 @@ vector<string> const FunctionType::returnParameterTypeNames(bool _addDataLocatio
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePointer FunctionType::selfType() const
|
||||||
|
{
|
||||||
|
solAssert(bound(), "");
|
||||||
|
return m_parameterTypes.at(0);
|
||||||
|
}
|
||||||
|
|
||||||
ASTPointer<ASTString> FunctionType::documentation() const
|
ASTPointer<ASTString> FunctionType::documentation() const
|
||||||
{
|
{
|
||||||
auto function = dynamic_cast<Documented const*>(m_declaration);
|
auto function = dynamic_cast<Documented const*>(m_declaration);
|
||||||
@ -1784,11 +1848,8 @@ unsigned TypeType::sizeOnStack() const
|
|||||||
return 0;
|
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;
|
MemberList::MemberMap members;
|
||||||
if (m_actualType->category() == Category::Contract)
|
if (m_actualType->category() == Category::Contract)
|
||||||
{
|
{
|
||||||
@ -1817,10 +1878,7 @@ MemberList const& TypeType::members(ContractDefinition const* _currentScope) con
|
|||||||
for (ASTPointer<EnumValue> const& enumValue: enumDef.members())
|
for (ASTPointer<EnumValue> const& enumValue: enumDef.members())
|
||||||
members.push_back(MemberList::Member(enumValue->name(), enumType));
|
members.push_back(MemberList::Member(enumValue->name(), enumType));
|
||||||
}
|
}
|
||||||
m_members.reset(new MemberList(members));
|
return members;
|
||||||
m_cachedScope = _currentScope;
|
|
||||||
}
|
|
||||||
return *m_members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModifierType::ModifierType(const ModifierDefinition& _modifier)
|
ModifierType::ModifierType(const ModifierDefinition& _modifier)
|
||||||
@ -1866,36 +1924,6 @@ string ModifierType::toString(bool _short) const
|
|||||||
MagicType::MagicType(MagicType::Kind _kind):
|
MagicType::MagicType(MagicType::Kind _kind):
|
||||||
m_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
|
bool MagicType::operator==(Type const& _other) const
|
||||||
@ -1906,6 +1934,37 @@ bool MagicType::operator==(Type const& _other) const
|
|||||||
return other.m_kind == m_kind;
|
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
|
string MagicType::toString(bool) const
|
||||||
{
|
{
|
||||||
switch (m_kind)
|
switch (m_kind)
|
||||||
|
@ -90,6 +90,7 @@ public:
|
|||||||
MemberList() {}
|
MemberList() {}
|
||||||
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
|
explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
|
||||||
MemberList& operator=(MemberList&& _other);
|
MemberList& operator=(MemberList&& _other);
|
||||||
|
void combine(MemberList const& _other);
|
||||||
TypePointer memberType(std::string const& _name) const
|
TypePointer memberType(std::string const& _name) const
|
||||||
{
|
{
|
||||||
TypePointer type;
|
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
|
/// @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);
|
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
|
||||||
|
|
||||||
/// Calculates the
|
|
||||||
|
|
||||||
virtual Category category() const = 0;
|
virtual Category category() const = 0;
|
||||||
virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
|
virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
|
||||||
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
|
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
@ -216,9 +215,9 @@ public:
|
|||||||
return _targetType->dataStoredIn(DataLocation::Storage) ? mobileType() : _targetType;
|
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.
|
/// @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.
|
/// 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, ContractDefinition const* _currentScope = nullptr) const
|
||||||
{
|
{
|
||||||
@ -251,9 +250,20 @@ public:
|
|||||||
/// are returned without modification.
|
/// are returned without modification.
|
||||||
virtual TypePointer interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
|
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:
|
protected:
|
||||||
/// Convenience object used when returning an empty member list.
|
/// @returns the members native to this type depending on the given context. This function
|
||||||
static const MemberList EmptyMemberList;
|
/// 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 unsigned storageBytes() const override { return m_bits / 8; }
|
||||||
virtual bool isValueType() const override { return true; }
|
virtual bool isValueType() const override { return true; }
|
||||||
|
|
||||||
virtual MemberList const& members(ContractDefinition const* /*_currentScope*/) const override
|
virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||||
{
|
|
||||||
return isAddress() ? AddressMemberList : EmptyMemberList;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
|
|
||||||
@ -295,8 +302,6 @@ public:
|
|||||||
bool isAddress() const { return m_modifier == Modifier::Address; }
|
bool isAddress() const { return m_modifier == Modifier::Address; }
|
||||||
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
||||||
|
|
||||||
static const MemberList AddressMemberList;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_bits;
|
int m_bits;
|
||||||
Modifier m_modifier;
|
Modifier m_modifier;
|
||||||
@ -517,7 +522,7 @@ public:
|
|||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) 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 encodingType() const override;
|
||||||
virtual TypePointer decodingType() const override;
|
virtual TypePointer decodingType() const override;
|
||||||
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
||||||
@ -541,8 +546,6 @@ private:
|
|||||||
TypePointer m_baseType;
|
TypePointer m_baseType;
|
||||||
bool m_hasDynamicLength = true;
|
bool m_hasDynamicLength = true;
|
||||||
u256 m_length;
|
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 toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) 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 encodingType() const override
|
||||||
{
|
{
|
||||||
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
|
||||||
@ -602,8 +605,6 @@ private:
|
|||||||
bool m_super = false;
|
bool m_super = false;
|
||||||
/// Type of the constructor, @see constructorType. Lazily initialized.
|
/// Type of the constructor, @see constructorType. Lazily initialized.
|
||||||
mutable FunctionTypePointer m_constructorType;
|
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 bool canLiveOutsideStorage() const override { return true; }
|
||||||
virtual std::string toString(bool _short) const override;
|
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
|
virtual TypePointer encodingType() const override
|
||||||
{
|
{
|
||||||
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : TypePointer();
|
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : TypePointer();
|
||||||
@ -648,8 +649,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
StructDefinition const& m_struct;
|
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:
|
private:
|
||||||
EnumDefinition const& m_enum;
|
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,
|
bool _arbitraryParameters = false,
|
||||||
Declaration const* _declaration = nullptr,
|
Declaration const* _declaration = nullptr,
|
||||||
bool _gasSet = false,
|
bool _gasSet = false,
|
||||||
bool _valueSet = false
|
bool _valueSet = false,
|
||||||
|
bool _bound = false
|
||||||
):
|
):
|
||||||
m_parameterTypes(_parameterTypes),
|
m_parameterTypes(_parameterTypes),
|
||||||
m_returnParameterTypes(_returnParameterTypes),
|
m_returnParameterTypes(_returnParameterTypes),
|
||||||
@ -801,15 +799,18 @@ public:
|
|||||||
m_arbitraryParameters(_arbitraryParameters),
|
m_arbitraryParameters(_arbitraryParameters),
|
||||||
m_gasSet(_gasSet),
|
m_gasSet(_gasSet),
|
||||||
m_valueSet(_valueSet),
|
m_valueSet(_valueSet),
|
||||||
|
m_bound(_bound),
|
||||||
m_declaration(_declaration)
|
m_declaration(_declaration)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TypePointers const& parameterTypes() const { return m_parameterTypes; }
|
TypePointers parameterTypes() const;
|
||||||
std::vector<std::string> const& parameterNames() const { return m_parameterNames; }
|
std::vector<std::string> parameterNames() const;
|
||||||
std::vector<std::string> const parameterTypeNames(bool _addDataLocation) const;
|
std::vector<std::string> const parameterTypeNames(bool _addDataLocation) const;
|
||||||
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
||||||
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
|
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
|
||||||
std::vector<std::string> const returnParameterTypeNames(bool _addDataLocation) const;
|
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 bool operator==(Type const& _other) const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
@ -817,7 +818,7 @@ public:
|
|||||||
virtual u256 storageSize() const override;
|
virtual u256 storageSize() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
virtual unsigned sizeOnStack() const override;
|
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
|
/// @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
|
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
|
||||||
@ -828,7 +829,9 @@ public:
|
|||||||
|
|
||||||
/// @returns true if this function can take the given argument types (possibly
|
/// @returns true if this function can take the given argument types (possibly
|
||||||
/// after implicit conversion).
|
/// after implicit conversion).
|
||||||
bool canTakeArguments(TypePointers const& _arguments) const;
|
/// @param _selfType if the function is bound, this has to be supplied and is the type of the
|
||||||
|
/// expression the function is called on.
|
||||||
|
bool canTakeArguments(TypePointers const& _arguments, TypePointer const& _selfType = TypePointer()) const;
|
||||||
/// @returns true if the types of parameters are equal (does't check return parameter types)
|
/// @returns true if the types of parameters are equal (does't check return parameter types)
|
||||||
bool hasEqualArgumentTypes(FunctionType const& _other) const;
|
bool hasEqualArgumentTypes(FunctionType const& _other) const;
|
||||||
|
|
||||||
@ -855,6 +858,7 @@ public:
|
|||||||
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; }
|
||||||
|
bool bound() const { return m_bound; }
|
||||||
|
|
||||||
/// @returns a copy of this type, where gas or value are set manually. This will never set one
|
/// @returns a copy of this type, where gas or value are set manually. This will never set one
|
||||||
/// of the parameters to fals.
|
/// of the parameters to fals.
|
||||||
@ -865,7 +869,8 @@ public:
|
|||||||
/// This is needed if external functions are called on other contracts, as they cannot return
|
/// This is needed if external functions are called on other contracts, as they cannot return
|
||||||
/// dynamic values.
|
/// dynamic values.
|
||||||
/// @param _inLibrary if true, uses CallCode as location.
|
/// @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:
|
private:
|
||||||
static TypePointers parseElementaryTypeVector(strings const& _types);
|
static TypePointers parseElementaryTypeVector(strings const& _types);
|
||||||
@ -879,8 +884,8 @@ private:
|
|||||||
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
|
||||||
bool const m_valueSet = false; ///< true iff the value to be sent 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;
|
bool m_isConstant = false;
|
||||||
mutable std::unique_ptr<MemberList> m_members;
|
|
||||||
Declaration const* m_declaration = nullptr;
|
Declaration const* m_declaration = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -935,13 +940,10 @@ public:
|
|||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
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:
|
private:
|
||||||
TypePointer m_actualType;
|
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 +990,12 @@ public:
|
|||||||
virtual bool canBeStored() const override { return false; }
|
virtual bool canBeStored() const override { return false; }
|
||||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||||
virtual unsigned sizeOnStack() const override { return 0; }
|
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;
|
virtual std::string toString(bool _short) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
|
|
||||||
MemberList m_members;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -672,7 +672,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
_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 const& paramType = function.parameterTypes()[0];
|
TypePointer paramType = function.parameterTypes()[0];
|
||||||
shared_ptr<ArrayType> arrayType =
|
shared_ptr<ArrayType> arrayType =
|
||||||
function.location() == Location::ArrayPush ?
|
function.location() == Location::ArrayPush ?
|
||||||
make_shared<ArrayType>(DataLocation::Storage, paramType) :
|
make_shared<ArrayType>(DataLocation::Storage, paramType) :
|
||||||
|
@ -168,6 +168,8 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary)
|
|||||||
subNodes.push_back(parseModifierDefinition());
|
subNodes.push_back(parseModifierDefinition());
|
||||||
else if (currentTokenValue == Token::Event)
|
else if (currentTokenValue == Token::Event)
|
||||||
subNodes.push_back(parseEventDefinition());
|
subNodes.push_back(parseEventDefinition());
|
||||||
|
else if (currentTokenValue == Token::Using)
|
||||||
|
subNodes.push_back(parseUsingDirective());
|
||||||
else
|
else
|
||||||
fatalParserError(std::string("Function, variable, struct or modifier declaration expected."));
|
fatalParserError(std::string("Function, variable, struct or modifier declaration expected."));
|
||||||
}
|
}
|
||||||
@ -475,6 +477,24 @@ ASTPointer<EventDefinition> Parser::parseEventDefinition()
|
|||||||
return nodeFactory.createNode<EventDefinition>(name, docstring, parameters, anonymous);
|
return nodeFactory.createNode<EventDefinition>(name, docstring, parameters, anonymous);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||||
|
{
|
||||||
|
ASTNodeFactory nodeFactory(*this);
|
||||||
|
|
||||||
|
expectToken(Token::Using);
|
||||||
|
//@todo this should actually parse a full path.
|
||||||
|
ASTPointer<Identifier> library(parseIdentifier());
|
||||||
|
ASTPointer<TypeName> typeName;
|
||||||
|
expectToken(Token::For);
|
||||||
|
if (m_scanner->currentToken() == Token::Mul)
|
||||||
|
m_scanner->next();
|
||||||
|
else
|
||||||
|
typeName = parseTypeName(false);
|
||||||
|
nodeFactory.markEndPosition();
|
||||||
|
expectToken(Token::Semicolon);
|
||||||
|
return nodeFactory.createNode<UsingForDirective>(library, typeName);
|
||||||
|
}
|
||||||
|
|
||||||
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
|
@ -74,6 +74,7 @@ private:
|
|||||||
);
|
);
|
||||||
ASTPointer<ModifierDefinition> parseModifierDefinition();
|
ASTPointer<ModifierDefinition> parseModifierDefinition();
|
||||||
ASTPointer<EventDefinition> parseEventDefinition();
|
ASTPointer<EventDefinition> parseEventDefinition();
|
||||||
|
ASTPointer<UsingForDirective> parseUsingDirective();
|
||||||
ASTPointer<ModifierInvocation> parseModifierInvocation();
|
ASTPointer<ModifierInvocation> parseModifierInvocation();
|
||||||
ASTPointer<Identifier> parseIdentifier();
|
ASTPointer<Identifier> parseIdentifier();
|
||||||
ASTPointer<TypeName> parseTypeName(bool _allowVar);
|
ASTPointer<TypeName> parseTypeName(bool _allowVar);
|
||||||
|
@ -2529,6 +2529,166 @@ BOOST_AUTO_TEST_CASE(member_access_parser_ambiguity)
|
|||||||
BOOST_CHECK(success(text));
|
BOOST_CHECK(success(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(using_for_library)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
library D { }
|
||||||
|
contract C {
|
||||||
|
using D for uint;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(using_for_not_library)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract D { }
|
||||||
|
contract C {
|
||||||
|
using D for uint;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
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(using_for_mismatch)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
library D { function double(bytes32 self) returns (uint) { return 2; } }
|
||||||
|
contract C {
|
||||||
|
using D for uint;
|
||||||
|
function f(uint a) returns (uint) {
|
||||||
|
return a.double();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(using_for_not_used)
|
||||||
|
{
|
||||||
|
// This is an error because the function is only bound to uint.
|
||||||
|
// Had it been bound to *, it would have worked.
|
||||||
|
char const* text = R"(
|
||||||
|
library D { function double(uint self) returns (uint) { return 2; } }
|
||||||
|
contract C {
|
||||||
|
using D for uint;
|
||||||
|
function f(uint16 a) returns (uint) {
|
||||||
|
return a.double();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(using_for_arbitrary_mismatch)
|
||||||
|
{
|
||||||
|
// Bound to a, but self type does not match.
|
||||||
|
char const* text = R"(
|
||||||
|
library D { function double(bytes32 self) returns (uint) { return 2; } }
|
||||||
|
contract C {
|
||||||
|
using D for *;
|
||||||
|
function f(uint a) returns (uint) {
|
||||||
|
return a.double();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
BOOST_AUTO_TEST_CASE(create_memory_arrays)
|
||||||
{
|
{
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
|
@ -1032,6 +1032,21 @@ BOOST_AUTO_TEST_CASE(member_access_parser_ambiguity)
|
|||||||
BOOST_CHECK(successParse(text));
|
BOOST_CHECK(successParse(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(using_for)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
struct s { uint a; }
|
||||||
|
using LibraryName for uint;
|
||||||
|
using Library2 for *;
|
||||||
|
using Lib for s;
|
||||||
|
function f() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(successParse(text));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user