Extend using-for.

This commit is contained in:
hrkrshnn
2022-03-14 12:33:44 +01:00
committed by chriseth
parent db30f4d495
commit 672951ccc7
55 changed files with 992 additions and 150 deletions
@@ -25,6 +25,7 @@
#include <liblangutil/ErrorReporter.h>
#include <libsolutil/Algorithms.h>
#include <libsolutil/Visitor.h>
#include <range/v3/view/transform.hpp>
@@ -451,12 +452,39 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
bool DeclarationTypeChecker::visit(UsingForDirective const& _usingFor)
{
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
_usingFor.libraryName().annotation().referencedDeclaration
);
if (_usingFor.usesBraces())
{
for (ASTPointer<IdentifierPath> const& function: _usingFor.functionsOrLibrary())
if (auto functionDefinition = dynamic_cast<FunctionDefinition const*>(function->annotation().referencedDeclaration))
{
if (!functionDefinition->isFree() && !(
dynamic_cast<ContractDefinition const*>(functionDefinition->scope()) &&
dynamic_cast<ContractDefinition const*>(functionDefinition->scope())->isLibrary()
))
m_errorReporter.typeError(
4167_error,
function->location(),
"Only file-level functions and library functions can be bound to a type in a \"using\" statement"
);
}
else
m_errorReporter.fatalTypeError(8187_error, function->location(), "Expected function name." );
}
else
{
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
_usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration
);
if (!library || !library->isLibrary())
m_errorReporter.fatalTypeError(
4357_error,
_usingFor.functionsOrLibrary().front()->location(),
"Library name expected. If you want to attach a function, use '{...}'."
);
}
if (!library || !library->isLibrary())
m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected.");
// We do not visit _usingFor.functions() because it will lead to an error since
// library names cannot be mentioned stand-alone.
if (_usingFor.typeName())
_usingFor.typeName()->accept(*this);
+24
View File
@@ -403,6 +403,30 @@ void SyntaxChecker::endVisit(ContractDefinition const&)
m_currentContractKind = std::nullopt;
}
bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
{
if (!m_currentContractKind && !_usingFor.typeName())
m_errorReporter.syntaxError(
8118_error,
_usingFor.location(),
"The type has to be specified explicitly at file level (cannot use '*')."
);
else if (_usingFor.usesBraces() && !_usingFor.typeName())
m_errorReporter.syntaxError(
3349_error,
_usingFor.location(),
"The type has to be specified explicitly when attaching specific functions."
);
if (m_currentContractKind == ContractKind::Interface)
m_errorReporter.syntaxError(
9088_error,
_usingFor.location(),
"The \"using for\" directive is not allowed inside interfaces."
);
return true;
}
bool SyntaxChecker::visit(FunctionDefinition const& _function)
{
solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), "");
+3
View File
@@ -88,6 +88,9 @@ private:
bool visit(ContractDefinition const& _contract) override;
void endVisit(ContractDefinition const& _contract) override;
bool visit(UsingForDirective const& _usingFor) override;
bool visit(FunctionDefinition const& _function) override;
bool visit(FunctionTypeName const& _node) override;
+61 -5
View File
@@ -35,6 +35,7 @@
#include <libsolutil/Algorithms.h>
#include <libsolutil/StringUtils.h>
#include <libsolutil/Views.h>
#include <libsolutil/Visitor.h>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp>
@@ -3626,12 +3627,67 @@ void TypeChecker::endVisit(Literal const& _literal)
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
{
if (m_currentContract->isInterface())
m_errorReporter.typeError(
9088_error,
_usingFor.location(),
"The \"using for\" directive is not allowed inside interfaces."
if (!_usingFor.usesBraces())
{
solAssert(_usingFor.functionsOrLibrary().size() == 1);
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
_usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration
);
solAssert(library && library->isLibrary());
// No type checking for libraries
return;
}
if (!_usingFor.typeName())
{
solAssert(m_errorReporter.hasErrors());
return;
}
solAssert(_usingFor.typeName()->annotation().type);
Type const* normalizedType = TypeProvider::withLocationIfReference(
DataLocation::Storage,
_usingFor.typeName()->annotation().type
);
solAssert(normalizedType);
for (ASTPointer<IdentifierPath> const& path: _usingFor.functionsOrLibrary())
{
solAssert(path->annotation().referencedDeclaration);
FunctionDefinition const& functionDefinition =
dynamic_cast<FunctionDefinition const&>(*path->annotation().referencedDeclaration);
solAssert(functionDefinition.type());
if (functionDefinition.parameters().empty())
m_errorReporter.fatalTypeError(
4731_error,
path->location(),
"The function \"" + joinHumanReadable(path->path(), ".") + "\" " +
"does not have any parameters, and therefore cannot be bound to the type \"" +
(normalizedType ? normalizedType->toString(true) : "*") + "\"."
);
FunctionType const* functionType = dynamic_cast<FunctionType const&>(*functionDefinition.type()).asBoundFunction();
solAssert(functionType && functionType->selfType(), "");
BoolResult result = normalizedType->isImplicitlyConvertibleTo(
*TypeProvider::withLocationIfReference(DataLocation::Storage, functionType->selfType())
);
if (!result)
m_errorReporter.typeError(
3100_error,
path->location(),
"The function \"" + joinHumanReadable(path->path(), ".") + "\" "+
"cannot be bound to the type \"" + _usingFor.typeName()->annotation().type->toString() +
"\" because the type cannot be implicitly converted to the first argument" +
" of the function (\"" + functionType->selfType()->toString() + "\")" +
(
result.message().empty() ?
"." :
": " + result.message()
)
);
}
}
void TypeChecker::checkErrorAndEventParameters(CallableDeclaration const& _callable)