mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Syntax for custom errors.
This commit is contained in:
+30
-3
@@ -174,6 +174,15 @@ vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() cons
|
||||
});
|
||||
}
|
||||
|
||||
vector<ErrorDefinition const*> ContractDefinition::interfaceErrors() const
|
||||
{
|
||||
set<ErrorDefinition const*, CompareByID> result;
|
||||
// TODO add all referenced errors
|
||||
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
||||
result += filteredNodes<ErrorDefinition>(contract->m_subNodes);
|
||||
return convertContainer<vector<ErrorDefinition const*>>(move(result));
|
||||
}
|
||||
|
||||
vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const
|
||||
{
|
||||
return m_interfaceFunctionList[_includeInheritedFunctions].init([&]{
|
||||
@@ -462,6 +471,24 @@ EventDefinitionAnnotation& EventDefinition::annotation() const
|
||||
return initAnnotation<EventDefinitionAnnotation>();
|
||||
}
|
||||
|
||||
Type const* ErrorDefinition::type() const
|
||||
{
|
||||
return TypeProvider::function(*this);
|
||||
}
|
||||
|
||||
FunctionTypePointer ErrorDefinition::functionType(bool _internal) const
|
||||
{
|
||||
if (_internal)
|
||||
return TypeProvider::function(*this);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ErrorDefinitionAnnotation& ErrorDefinition::annotation() const
|
||||
{
|
||||
return initAnnotation<ErrorDefinitionAnnotation>();
|
||||
}
|
||||
|
||||
SourceUnit const& Scopable::sourceUnit() const
|
||||
{
|
||||
ASTNode const* s = scope();
|
||||
@@ -504,10 +531,10 @@ bool Declaration::isStructMember() const
|
||||
return dynamic_cast<StructDefinition const*>(scope());
|
||||
}
|
||||
|
||||
bool Declaration::isEventParameter() const
|
||||
bool Declaration::isEventOrErrorParameter() const
|
||||
{
|
||||
solAssert(scope(), "");
|
||||
return dynamic_cast<EventDefinition const*>(scope());
|
||||
return dynamic_cast<EventDefinition const*>(scope()) || dynamic_cast<ErrorDefinition const*>(scope());
|
||||
}
|
||||
|
||||
DeclarationAnnotation& Declaration::annotation() const
|
||||
@@ -653,7 +680,7 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
|
||||
{
|
||||
using Location = VariableDeclaration::Location;
|
||||
|
||||
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
|
||||
if (!hasReferenceOrMappingType() || isStateVariable() || isEventOrErrorParameter())
|
||||
return set<Location>{ Location::Unspecified };
|
||||
else if (isCallableOrCatchParameter())
|
||||
{
|
||||
|
||||
+46
-2
@@ -272,7 +272,7 @@ public:
|
||||
/// @returns true if this is a declaration of a struct member.
|
||||
bool isStructMember() const;
|
||||
/// @returns true if this is a declaration of a parameter of an event.
|
||||
bool isEventParameter() const;
|
||||
bool isEventOrErrorParameter() const;
|
||||
|
||||
/// @returns the type of expressions referencing this declaration.
|
||||
/// This can only be called once types of variable declarations have already been resolved.
|
||||
@@ -513,6 +513,9 @@ public:
|
||||
std::vector<FunctionDefinition const*> definedFunctions() const { return filteredNodes<FunctionDefinition>(m_subNodes); }
|
||||
std::vector<EventDefinition const*> events() const { return filteredNodes<EventDefinition>(m_subNodes); }
|
||||
std::vector<EventDefinition const*> const& interfaceEvents() const;
|
||||
/// @returns all errors defined in this contract or any base contract
|
||||
/// and all errors referenced during execution.
|
||||
std::vector<ErrorDefinition const*> interfaceErrors() const;
|
||||
bool isInterface() const { return m_contractKind == ContractKind::Interface; }
|
||||
bool isLibrary() const { return m_contractKind == ContractKind::Library; }
|
||||
|
||||
@@ -740,7 +743,7 @@ private:
|
||||
|
||||
/**
|
||||
* Base class for all nodes that define function-like objects, i.e. FunctionDefinition,
|
||||
* EventDefinition and ModifierDefinition.
|
||||
* EventDefinition, ErrorDefinition and ModifierDefinition.
|
||||
*/
|
||||
class CallableDeclaration: public Declaration, public VariableScope
|
||||
{
|
||||
@@ -1159,6 +1162,47 @@ private:
|
||||
bool m_anonymous = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Definition of an error type usable in ``revert(MyError(x))``, ``require(condition, MyError(x))``
|
||||
* and ``catch MyError(_x)``.
|
||||
*/
|
||||
class ErrorDefinition: public CallableDeclaration, public StructurallyDocumented, public ScopeOpener
|
||||
{
|
||||
public:
|
||||
ErrorDefinition(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<ASTString> const& _name,
|
||||
SourceLocation _nameLocation,
|
||||
ASTPointer<StructuredDocumentation> const& _documentation,
|
||||
ASTPointer<ParameterList> const& _parameters
|
||||
):
|
||||
CallableDeclaration(_id, _location, _name, std::move(_nameLocation), Visibility::Default, _parameters),
|
||||
StructurallyDocumented(_documentation)
|
||||
{
|
||||
}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
Type const* type() const override;
|
||||
|
||||
FunctionTypePointer functionType(bool _internal) const override;
|
||||
|
||||
bool isVisibleInDerivedContracts() const override { return true; }
|
||||
bool isVisibleViaContractTypeAccess() const override { return true; }
|
||||
|
||||
ErrorDefinitionAnnotation& annotation() const override;
|
||||
|
||||
CallableDeclaration const& resolveVirtual(
|
||||
ContractDefinition const&,
|
||||
ContractDefinition const*
|
||||
) const override
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global
|
||||
* functions when such an identifier is encountered. Will never have a valid location in the source code
|
||||
|
||||
@@ -184,6 +184,11 @@ struct EventDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDoc
|
||||
{
|
||||
};
|
||||
|
||||
struct ErrorDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
struct ModifierDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation
|
||||
{
|
||||
};
|
||||
|
||||
@@ -57,6 +57,7 @@ class VariableDeclaration;
|
||||
class ModifierDefinition;
|
||||
class ModifierInvocation;
|
||||
class EventDefinition;
|
||||
class ErrorDefinition;
|
||||
class MagicVariableDeclaration;
|
||||
class TypeName;
|
||||
class ElementaryTypeName;
|
||||
|
||||
@@ -481,6 +481,17 @@ bool ASTJsonConverter::visit(EventDefinition const& _node)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTJsonConverter::visit(ErrorDefinition const& _node)
|
||||
{
|
||||
setJsonNode(_node, "ErrorDefinition", {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
|
||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("parameters", toJson(_node.parameterList()))
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTJsonConverter::visit(ElementaryTypeName const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
bool visit(ModifierDefinition const& _node) override;
|
||||
bool visit(ModifierInvocation const& _node) override;
|
||||
bool visit(EventDefinition const& _node) override;
|
||||
bool visit(ErrorDefinition const& _node) override;
|
||||
bool visit(ElementaryTypeName const& _node) override;
|
||||
bool visit(UserDefinedTypeName const& _node) override;
|
||||
bool visit(FunctionTypeName const& _node) override;
|
||||
|
||||
@@ -151,6 +151,8 @@ ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _js
|
||||
return createModifierInvocation(_json);
|
||||
if (nodeType == "EventDefinition")
|
||||
return createEventDefinition(_json);
|
||||
if (nodeType == "ErrorDefinition")
|
||||
return createErrorDefinition(_json);
|
||||
if (nodeType == "ElementaryTypeName")
|
||||
return createElementaryTypeName(_json);
|
||||
if (nodeType == "UserDefinedTypeName")
|
||||
@@ -539,6 +541,17 @@ ASTPointer<EventDefinition> ASTJsonImporter::createEventDefinition(Json::Value c
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ErrorDefinition> ASTJsonImporter::createErrorDefinition(Json::Value const& _node)
|
||||
{
|
||||
return createASTNode<ErrorDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
createNameSourceLocation(_node),
|
||||
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
|
||||
createParameterList(member(_node, "parameters"))
|
||||
);
|
||||
}
|
||||
|
||||
ASTPointer<ElementaryTypeName> ASTJsonImporter::createElementaryTypeName(Json::Value const& _node)
|
||||
{
|
||||
unsigned short firstNum;
|
||||
|
||||
@@ -88,6 +88,7 @@ private:
|
||||
ASTPointer<ModifierDefinition> createModifierDefinition(Json::Value const& _node);
|
||||
ASTPointer<ModifierInvocation> createModifierInvocation(Json::Value const& _node);
|
||||
ASTPointer<EventDefinition> createEventDefinition(Json::Value const& _node);
|
||||
ASTPointer<ErrorDefinition> createErrorDefinition(Json::Value const& _node);
|
||||
ASTPointer<ElementaryTypeName> createElementaryTypeName(Json::Value const& _node);
|
||||
ASTPointer<UserDefinedTypeName> createUserDefinedTypeName(Json::Value const& _node);
|
||||
ASTPointer<FunctionTypeName> createFunctionTypeName(Json::Value const& _node);
|
||||
|
||||
@@ -22,6 +22,12 @@ namespace solidity::frontend
|
||||
{
|
||||
|
||||
class VariableDeclaration;
|
||||
class Declaration;
|
||||
class Expression;
|
||||
|
||||
/// @returns the declaration referenced from the expression which has to be MemberAccess
|
||||
/// or Identifier. Returns nullptr otherwise.
|
||||
Declaration const* referencedDeclaration(Expression const& _expression);
|
||||
|
||||
/// Find the topmost referenced constant variable declaration when the given variable
|
||||
/// declaration value is an identifier. Works only for constant variable declarations.
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
virtual bool visit(ModifierDefinition& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ModifierInvocation& _node) { return visitNode(_node); }
|
||||
virtual bool visit(EventDefinition& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ErrorDefinition& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
|
||||
virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
|
||||
virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); }
|
||||
@@ -124,6 +125,7 @@ public:
|
||||
virtual void endVisit(ModifierDefinition& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ModifierInvocation& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(EventDefinition& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ErrorDefinition& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); }
|
||||
@@ -199,6 +201,7 @@ public:
|
||||
virtual bool visit(ModifierDefinition const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ModifierInvocation const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(EventDefinition const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ErrorDefinition const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
|
||||
virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); }
|
||||
@@ -252,6 +255,7 @@ public:
|
||||
virtual void endVisit(ModifierDefinition const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ModifierInvocation const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(EventDefinition const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ErrorDefinition const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
|
||||
virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); }
|
||||
|
||||
@@ -366,6 +366,28 @@ void EventDefinition::accept(ASTConstVisitor& _visitor) const
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
void ErrorDefinition::accept(ASTVisitor& _visitor)
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
if (m_documentation)
|
||||
m_documentation->accept(_visitor);
|
||||
m_parameters->accept(_visitor);
|
||||
}
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
void ErrorDefinition::accept(ASTConstVisitor& _visitor) const
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
if (m_documentation)
|
||||
m_documentation->accept(_visitor);
|
||||
m_parameters->accept(_visitor);
|
||||
}
|
||||
_visitor.endVisit(*this);
|
||||
}
|
||||
|
||||
void ElementaryTypeName::accept(ASTVisitor& _visitor)
|
||||
{
|
||||
_visitor.visit(*this);
|
||||
|
||||
@@ -431,6 +431,11 @@ FunctionType const* TypeProvider::function(EventDefinition const& _def)
|
||||
return createAndGet<FunctionType>(_def);
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::function(ErrorDefinition const& _def)
|
||||
{
|
||||
return createAndGet<FunctionType>(_def);
|
||||
}
|
||||
|
||||
FunctionType const* TypeProvider::function(FunctionTypeName const& _typeName)
|
||||
{
|
||||
return createAndGet<FunctionType>(_typeName);
|
||||
|
||||
@@ -139,6 +139,8 @@ public:
|
||||
/// @returns the function type of an event.
|
||||
static FunctionType const* function(EventDefinition const& _event);
|
||||
|
||||
static FunctionType const* function(ErrorDefinition const& _error);
|
||||
|
||||
/// @returns the type of a function type name.
|
||||
static FunctionType const* function(FunctionTypeName const& _typeName);
|
||||
|
||||
|
||||
@@ -2736,13 +2736,36 @@ FunctionType::FunctionType(EventDefinition const& _event):
|
||||
}
|
||||
|
||||
solAssert(
|
||||
m_parameterNames.size() == m_parameterTypes.size(),
|
||||
"Parameter names list must match parameter types list!"
|
||||
);
|
||||
m_parameterNames.size() == m_parameterTypes.size(),
|
||||
"Parameter names list must match parameter types list!"
|
||||
);
|
||||
solAssert(
|
||||
m_returnParameterNames.size() == m_returnParameterTypes.size(),
|
||||
"Return parameter names list must match return parameter types list!"
|
||||
);
|
||||
m_returnParameterNames.size() == 0 &&
|
||||
m_returnParameterTypes.size() == 0,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
FunctionType::FunctionType(ErrorDefinition const& _error):
|
||||
m_kind(Kind::Error),
|
||||
m_stateMutability(StateMutability::Pure),
|
||||
m_declaration(&_error)
|
||||
{
|
||||
for (ASTPointer<VariableDeclaration> const& var: _error.parameters())
|
||||
{
|
||||
m_parameterNames.push_back(var->name());
|
||||
m_parameterTypes.push_back(var->annotation().type);
|
||||
}
|
||||
|
||||
solAssert(
|
||||
m_parameterNames.size() == m_parameterTypes.size(),
|
||||
"Parameter names list must match parameter types list!"
|
||||
);
|
||||
solAssert(
|
||||
m_returnParameterNames.size() == 0 &&
|
||||
m_returnParameterTypes.size() == 0,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
||||
@@ -2870,6 +2893,7 @@ string FunctionType::richIdentifier() const
|
||||
case Kind::RIPEMD160: id += "ripemd160"; break;
|
||||
case Kind::GasLeft: id += "gasleft"; break;
|
||||
case Kind::Event: id += "event"; break;
|
||||
case Kind::Error: id += "error"; break;
|
||||
case Kind::SetGas: id += "setgas"; break;
|
||||
case Kind::SetValue: id += "setvalue"; break;
|
||||
case Kind::BlockHash: id += "blockhash"; break;
|
||||
@@ -3107,7 +3131,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
||||
// Note that m_declaration might also be a state variable!
|
||||
solAssert(m_declaration, "Declaration needed to determine interface function type.");
|
||||
bool isLibraryFunction = false;
|
||||
if (kind() != Kind::Event)
|
||||
if (kind() != Kind::Event && kind() != Kind::Error)
|
||||
if (auto const* contract = dynamic_cast<ContractDefinition const*>(m_declaration->scope()))
|
||||
isLibraryFunction = contract->isLibrary();
|
||||
|
||||
@@ -3230,6 +3254,8 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
|
||||
}
|
||||
return {};
|
||||
}
|
||||
case Kind::Error:
|
||||
return {{"selector", TypeProvider::fixedBytes(4)}};
|
||||
default:
|
||||
return MemberList::MemberMap();
|
||||
}
|
||||
@@ -3396,15 +3422,16 @@ string FunctionType::externalSignature() const
|
||||
case Kind::External:
|
||||
case Kind::DelegateCall:
|
||||
case Kind::Event:
|
||||
case Kind::Error:
|
||||
case Kind::Declaration:
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Invalid function type for requesting external signature.");
|
||||
}
|
||||
|
||||
// "inLibrary" is only relevant if this is not an event.
|
||||
// "inLibrary" is only relevant if this is neither an event nor an error.
|
||||
bool inLibrary = false;
|
||||
if (kind() != Kind::Event)
|
||||
if (kind() != Kind::Event && kind() != Kind::Error)
|
||||
if (auto const* contract = dynamic_cast<ContractDefinition const*>(m_declaration->scope()))
|
||||
inLibrary = contract->isLibrary();
|
||||
|
||||
|
||||
@@ -1151,6 +1151,7 @@ public:
|
||||
SHA256, ///< CALL to special contract for sha256
|
||||
RIPEMD160, ///< CALL to special contract for ripemd160
|
||||
Event, ///< syntactic sugar for LOG*
|
||||
Error, ///< creating an error instance in revert or require
|
||||
SetGas, ///< modify the default gas value for the function call
|
||||
SetValue, ///< modify the default value transfer for the function call
|
||||
BlockHash, ///< BLOCKHASH
|
||||
@@ -1182,6 +1183,7 @@ public:
|
||||
explicit FunctionType(VariableDeclaration const& _varDecl);
|
||||
/// Creates the function type of an event.
|
||||
explicit FunctionType(EventDefinition const& _event);
|
||||
explicit FunctionType(ErrorDefinition const& _error);
|
||||
/// Creates the type of a function type name.
|
||||
explicit FunctionType(FunctionTypeName const& _typeName);
|
||||
/// Function type constructor to be used for a plain type (not derived from a declaration).
|
||||
|
||||
Reference in New Issue
Block a user