mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow library external functions to be bound with using for
This commit is contained in:
@@ -195,16 +195,23 @@ Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector<ASTString> c
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Declaration const*> NameAndTypeResolver::pathFromCurrentScopeWithAllDeclarations(std::vector<ASTString> const& _path) const
|
||||
std::vector<Declaration const*> NameAndTypeResolver::pathFromCurrentScopeWithAllDeclarations(
|
||||
std::vector<ASTString> const& _path,
|
||||
bool _includeInvisibles
|
||||
) const
|
||||
{
|
||||
solAssert(!_path.empty(), "");
|
||||
vector<Declaration const*> pathDeclarations;
|
||||
|
||||
ResolvingSettings settings;
|
||||
settings.recursive = true;
|
||||
settings.alsoInvisible = false;
|
||||
settings.alsoInvisible = _includeInvisibles;
|
||||
settings.onlyVisibleAsUnqualifiedNames = true;
|
||||
vector<Declaration const*> candidates = m_currentScope->resolveName(_path.front(), std::move(settings));
|
||||
vector<Declaration const*> candidates = m_currentScope->resolveName(_path.front(), settings);
|
||||
|
||||
// inside the loop, use default settings, except for alsoInvisible
|
||||
settings.recursive = false;
|
||||
settings.onlyVisibleAsUnqualifiedNames = false;
|
||||
|
||||
for (size_t i = 1; i < _path.size() && candidates.size() == 1; i++)
|
||||
{
|
||||
@@ -213,7 +220,7 @@ std::vector<Declaration const*> NameAndTypeResolver::pathFromCurrentScopeWithAll
|
||||
|
||||
pathDeclarations.push_back(candidates.front());
|
||||
|
||||
candidates = m_scopes.at(candidates.front())->resolveName(_path[i]);
|
||||
candidates = m_scopes.at(candidates.front())->resolveName(_path[i], settings);
|
||||
}
|
||||
if (candidates.size() == 1)
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
/// Resolves a path starting from the "current" scope, but also searches parent scopes.
|
||||
/// Should only be called during the initial resolving phase.
|
||||
/// @note Returns an empty vector if any component in the path was non-unique or not found. Otherwise, all declarations along the path are returned.
|
||||
std::vector<Declaration const*> pathFromCurrentScopeWithAllDeclarations(std::vector<ASTString> const& _path) const;
|
||||
std::vector<Declaration const*> pathFromCurrentScopeWithAllDeclarations(std::vector<ASTString> const& _path, bool _includeInvisibles = false) const;
|
||||
|
||||
/// Generate and store warnings about declarations with the same name.
|
||||
void warnHomonymDeclarations() const;
|
||||
|
||||
@@ -173,6 +173,7 @@ void ReferencesResolver::endVisit(ModifierDefinition const&)
|
||||
|
||||
void ReferencesResolver::endVisit(IdentifierPath const& _path)
|
||||
{
|
||||
// Note that library/functions names in "using {} for" directive are resolved separately in visit(UsingForDirective)
|
||||
std::vector<Declaration const*> declarations = m_resolver.pathFromCurrentScopeWithAllDeclarations(_path.path());
|
||||
if (declarations.empty())
|
||||
{
|
||||
@@ -184,6 +185,38 @@ void ReferencesResolver::endVisit(IdentifierPath const& _path)
|
||||
_path.annotation().pathDeclarations = std::move(declarations);
|
||||
}
|
||||
|
||||
bool ReferencesResolver::visit(UsingForDirective const& _usingFor)
|
||||
{
|
||||
for (ASTPointer<IdentifierPath> const& path: _usingFor.functionsOrLibrary())
|
||||
{
|
||||
// _includeInvisibles is enabled here because external library functions are marked invisible.
|
||||
// As unintended side-effects other invisible names (eg.: super, this) may be returned as well.
|
||||
// DeclarationTypeChecker should detect and report such situations.
|
||||
vector<Declaration const*> declarations = m_resolver.pathFromCurrentScopeWithAllDeclarations(path->path(), true /* _includeInvisibles */);
|
||||
if (declarations.empty())
|
||||
{
|
||||
string libraryOrFunctionNameErrorMessage =
|
||||
_usingFor.usesBraces() ?
|
||||
"Identifier is not a function name or not unique." :
|
||||
"Identifier is not a library name.";
|
||||
m_errorReporter.fatalDeclarationError(
|
||||
9589_error,
|
||||
path->location(),
|
||||
libraryOrFunctionNameErrorMessage
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
path->annotation().referencedDeclaration = declarations.back();
|
||||
path->annotation().pathDeclarations = std::move(declarations);
|
||||
}
|
||||
|
||||
if (_usingFor.typeName())
|
||||
_usingFor.typeName()->accept(*this);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
m_yulAnnotation = &_inlineAssembly.annotation();
|
||||
|
||||
@@ -84,6 +84,7 @@ private:
|
||||
void endVisit(IdentifierPath const& _path) override;
|
||||
bool visit(InlineAssembly const& _inlineAssembly) override;
|
||||
bool visit(Return const& _return) override;
|
||||
bool visit(UsingForDirective const& _usingFor) override;
|
||||
|
||||
void operator()(yul::FunctionDefinition const& _function) override;
|
||||
void operator()(yul::Identifier const& _identifier) override;
|
||||
|
||||
@@ -3826,7 +3826,13 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
FunctionDefinition const& functionDefinition =
|
||||
dynamic_cast<FunctionDefinition const&>(*path->annotation().referencedDeclaration);
|
||||
|
||||
solAssert(functionDefinition.type());
|
||||
FunctionType const* functionType = dynamic_cast<FunctionType const*>(
|
||||
functionDefinition.libraryFunction() ?
|
||||
functionDefinition.typeViaContractName() :
|
||||
functionDefinition.type()
|
||||
);
|
||||
|
||||
solAssert(functionType);
|
||||
|
||||
if (functionDefinition.parameters().empty())
|
||||
m_errorReporter.fatalTypeError(
|
||||
@@ -3864,21 +3870,25 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
);
|
||||
}
|
||||
|
||||
FunctionType const* functionType = dynamic_cast<FunctionType const&>(*functionDefinition.type()).withBoundFirstArgument();
|
||||
solAssert(functionType && functionType->selfType(), "");
|
||||
FunctionType const* functionTypeWithBoundFirstArgument = functionType->withBoundFirstArgument();
|
||||
solAssert(functionTypeWithBoundFirstArgument && functionTypeWithBoundFirstArgument->selfType(), "");
|
||||
BoolResult result = normalizedType->isImplicitlyConvertibleTo(
|
||||
*TypeProvider::withLocationIfReference(DataLocation::Storage, functionType->selfType())
|
||||
*TypeProvider::withLocationIfReference(DataLocation::Storage, functionTypeWithBoundFirstArgument->selfType())
|
||||
);
|
||||
if (!result)
|
||||
m_errorReporter.typeError(
|
||||
3100_error,
|
||||
path->location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Function defined here:",
|
||||
functionDefinition.location()
|
||||
),
|
||||
fmt::format(
|
||||
"The function \"{}\" cannot be attached to the type \"{}\" because the type cannot "
|
||||
"be implicitly converted to the first argument of the function (\"{}\"){}",
|
||||
joinHumanReadable(path->path(), "."),
|
||||
usingForType->toString(true /* withoutDataLocation */),
|
||||
functionType->selfType()->humanReadableName(),
|
||||
functionTypeWithBoundFirstArgument->selfType()->humanReadableName(),
|
||||
result.message().empty() ? "." : ": " + result.message()
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user