mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12121 from ethereum/extend-using-statement
Extend using statement
This commit is contained in:
commit
3f6beaa0ad
@ -2,6 +2,7 @@
|
||||
|
||||
Language Features:
|
||||
* General: Allow annotating inline assembly as memory-safe to allow optimizations and stack limit evasion that rely on respecting Solidity's memory model.
|
||||
* General: ``using M for Type;`` is allowed at file level and ``M`` can now also be a brace-enclosed list of free functions or library functions.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
|
@ -6,71 +6,89 @@
|
||||
Using For
|
||||
*********
|
||||
|
||||
The directive ``using A for B;`` can be used to attach library
|
||||
functions (from the library ``A``) to any type (``B``)
|
||||
in the context of a contract.
|
||||
The directive ``using A for B;`` can be used to attach
|
||||
functions (``A``) as member functions to any type (``B``).
|
||||
These functions will receive the object they are called on
|
||||
as their first parameter (like the ``self`` variable in Python).
|
||||
|
||||
The effect of ``using A for *;`` is that the functions from
|
||||
the library ``A`` are attached to *any* type.
|
||||
It is valid either at file level or inside a contract,
|
||||
at contract level.
|
||||
|
||||
In both situations, *all* functions in the library are attached,
|
||||
The first part, ``A``, can be one of:
|
||||
|
||||
- a list of file-level or library functions (``using {f, g, h, L.t} for uint;``) -
|
||||
only those functions will be attached to the type.
|
||||
- the name of a library (``using L for uint;``) -
|
||||
all functions (both public and internal ones) of the library are attached to the type
|
||||
|
||||
At file level, the second part, ``B``, has to be an explicit type (without data location specifier).
|
||||
Inside contracts, you can also use ``using L for *;``,
|
||||
which has the effect that all functions of the library ``L``
|
||||
are attached to *all* types.
|
||||
|
||||
If you specify a library, *all* functions in the library are attached,
|
||||
even those where the type of the first parameter does not
|
||||
match the type of the object. The type is checked at the
|
||||
point the function is called and function overload
|
||||
resolution is performed.
|
||||
|
||||
If you use a list of functions (``using {f, g, h, L.t} for uint;``),
|
||||
then the type (``uint``) has to be implicitly convertible to the
|
||||
first parameter of each of these functions. This check is
|
||||
performed even if none of these functions are called.
|
||||
|
||||
The ``using A for B;`` directive is active only within the current
|
||||
contract, including within all of its functions, and has no effect
|
||||
outside of the contract in which it is used. The directive
|
||||
may only be used inside a contract, not inside any of its functions.
|
||||
scope (either the contract or the current module/source unit),
|
||||
including within all of its functions, and has no effect
|
||||
outside of the contract or module in which it is used.
|
||||
|
||||
Let us rewrite the set example from the
|
||||
:ref:`libraries` in this way:
|
||||
:ref:`libraries` section in this way, using file-level functions
|
||||
instead of library functions.
|
||||
|
||||
.. code-block:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.9.0;
|
||||
pragma solidity ^0.8.13;
|
||||
|
||||
|
||||
// This is the same code as before, just without comments
|
||||
struct Data { mapping(uint => bool) flags; }
|
||||
// Now we attach functions to the type.
|
||||
// The attached functions can be used throughout the rest of the module.
|
||||
// If you import the module, you have to
|
||||
// repeat the using directive there, for example as
|
||||
// import "flags.sol" as Flags;
|
||||
// using {Flags.insert, Flags.remove, Flags.contains}
|
||||
// for Flags.Data;
|
||||
using {insert, remove, contains} for Data;
|
||||
|
||||
library Set {
|
||||
function insert(Data storage self, uint value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
if (self.flags[value])
|
||||
return false; // already there
|
||||
self.flags[value] = true;
|
||||
return true;
|
||||
}
|
||||
function insert(Data storage self, uint value)
|
||||
returns (bool)
|
||||
{
|
||||
if (self.flags[value])
|
||||
return false; // already there
|
||||
self.flags[value] = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
function remove(Data storage self, uint value)
|
||||
public
|
||||
returns (bool)
|
||||
{
|
||||
if (!self.flags[value])
|
||||
return false; // not there
|
||||
self.flags[value] = false;
|
||||
return true;
|
||||
}
|
||||
function remove(Data storage self, uint value)
|
||||
returns (bool)
|
||||
{
|
||||
if (!self.flags[value])
|
||||
return false; // not there
|
||||
self.flags[value] = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function contains(Data storage self, uint value)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return self.flags[value];
|
||||
}
|
||||
function contains(Data storage self, uint value)
|
||||
public
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
return self.flags[value];
|
||||
}
|
||||
|
||||
|
||||
contract C {
|
||||
using Set for Data; // this is the crucial change
|
||||
Data knownValues;
|
||||
|
||||
function register(uint value) public {
|
||||
@ -82,12 +100,13 @@ Let us rewrite the set example from the
|
||||
}
|
||||
}
|
||||
|
||||
It is also possible to extend elementary types in that way:
|
||||
It is also possible to extend built-in types in that way.
|
||||
In this example, we will use a library.
|
||||
|
||||
.. code-block:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.8 <0.9.0;
|
||||
pragma solidity ^0.8.13;
|
||||
|
||||
library Search {
|
||||
function indexOf(uint[] storage self, uint value)
|
||||
@ -100,9 +119,9 @@ It is also possible to extend elementary types in that way:
|
||||
return type(uint).max;
|
||||
}
|
||||
}
|
||||
using Search for uint[];
|
||||
|
||||
contract C {
|
||||
using Search for uint[];
|
||||
uint[] data;
|
||||
|
||||
function append(uint value) public {
|
||||
|
@ -12,6 +12,7 @@ options { tokenVocab=SolidityLexer; }
|
||||
sourceUnit: (
|
||||
pragmaDirective
|
||||
| importDirective
|
||||
| usingDirective
|
||||
| contractDefinition
|
||||
| interfaceDefinition
|
||||
| libraryDefinition
|
||||
@ -311,10 +312,10 @@ errorDefinition:
|
||||
Semicolon;
|
||||
|
||||
/**
|
||||
* Using directive to bind library functions to types.
|
||||
* Can occur within contracts and libraries.
|
||||
* Using directive to bind library functions and free functions to types.
|
||||
* Can occur within contracts and libraries and at the file level.
|
||||
*/
|
||||
usingDirective: Using identifierPath For (Mul | typeName) Semicolon;
|
||||
usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Semicolon;
|
||||
/**
|
||||
* A type name can be an elementary type, a function type, a mapping type, a user-defined type
|
||||
* (e.g. a contract or struct) or an array type.
|
||||
|
@ -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);
|
||||
|
@ -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), "");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <libevmasm/Instruction.h>
|
||||
#include <libsolutil/FixedHash.h>
|
||||
#include <libsolutil/LazyInit.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
@ -630,9 +631,16 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* `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.
|
||||
* Using for directive:
|
||||
*
|
||||
* 1. `using LibraryName for T` attaches all functions from the library `LibraryName` to the type `T`
|
||||
* 2. `using LibraryName for *` attaches to all types.
|
||||
* 3. `using {f1, f2, ..., fn} for T` attaches the functions `f1`, `f2`, ...,
|
||||
* `fn`, respectively to `T`.
|
||||
*
|
||||
* For version 3, T has to be implicitly convertible to the first parameter type of
|
||||
* all functions, and this is checked at the point of the using statement. For versions 1 and
|
||||
* 2, this check is only done when a function is called.
|
||||
*/
|
||||
class UsingForDirective: public ASTNode
|
||||
{
|
||||
@ -640,23 +648,28 @@ public:
|
||||
UsingForDirective(
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
ASTPointer<IdentifierPath> _libraryName,
|
||||
std::vector<ASTPointer<IdentifierPath>> _functions,
|
||||
bool _usesBraces,
|
||||
ASTPointer<TypeName> _typeName
|
||||
):
|
||||
ASTNode(_id, _location), m_libraryName(std::move(_libraryName)), m_typeName(std::move(_typeName))
|
||||
ASTNode(_id, _location), m_functions(_functions), m_usesBraces(_usesBraces), m_typeName(std::move(_typeName))
|
||||
{
|
||||
solAssert(m_libraryName != nullptr, "Name cannot be null.");
|
||||
}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
IdentifierPath 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(); }
|
||||
|
||||
/// @returns a list of functions or the single library.
|
||||
std::vector<ASTPointer<IdentifierPath>> const& functionsOrLibrary() const { return m_functions; }
|
||||
bool usesBraces() const { return m_usesBraces; }
|
||||
|
||||
private:
|
||||
ASTPointer<IdentifierPath> m_libraryName;
|
||||
/// Either the single library or a list of functions.
|
||||
std::vector<ASTPointer<IdentifierPath>> m_functions;
|
||||
bool m_usesBraces;
|
||||
ASTPointer<TypeName> m_typeName;
|
||||
};
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <libsolutil/JSON.h>
|
||||
#include <libsolutil/UTF8.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
#include <libsolutil/Keccak256.h>
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
@ -311,10 +312,25 @@ bool ASTJsonConverter::visit(InheritanceSpecifier const& _node)
|
||||
|
||||
bool ASTJsonConverter::visit(UsingForDirective const& _node)
|
||||
{
|
||||
setJsonNode(_node, "UsingForDirective", {
|
||||
make_pair("libraryName", toJson(_node.libraryName())),
|
||||
vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue)
|
||||
});
|
||||
};
|
||||
if (_node.usesBraces())
|
||||
{
|
||||
Json::Value functionList;
|
||||
for (auto const& function: _node.functionsOrLibrary())
|
||||
{
|
||||
Json::Value functionNode;
|
||||
functionNode["function"] = toJson(*function);
|
||||
functionList.append(move(functionNode));
|
||||
}
|
||||
attributes.emplace_back("functionList", move(functionList));
|
||||
}
|
||||
else
|
||||
attributes.emplace_back("libraryName", toJson(*_node.functionsOrLibrary().front()));
|
||||
|
||||
setJsonNode(_node, "UsingForDirective", move(attributes));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -348,9 +348,17 @@ ASTPointer<InheritanceSpecifier> ASTJsonImporter::createInheritanceSpecifier(Jso
|
||||
|
||||
ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
|
||||
{
|
||||
vector<ASTPointer<IdentifierPath>> functions;
|
||||
if (_node.isMember("libraryName"))
|
||||
functions.emplace_back(createIdentifierPath(_node["libraryName"]));
|
||||
else if (_node.isMember("functionList"))
|
||||
for (Json::Value const& function: _node["functionList"])
|
||||
functions.emplace_back(createIdentifierPath(function["function"]));
|
||||
|
||||
return createASTNode<UsingForDirective>(
|
||||
_node,
|
||||
createIdentifierPath(member(_node, "libraryName")),
|
||||
move(functions),
|
||||
!_node.isMember("libraryName"),
|
||||
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"])
|
||||
);
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ void UsingForDirective::accept(ASTVisitor& _visitor)
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
m_libraryName->accept(_visitor);
|
||||
listAccept(functionsOrLibrary(), _visitor);
|
||||
if (m_typeName)
|
||||
m_typeName->accept(_visitor);
|
||||
}
|
||||
@ -205,7 +205,7 @@ void UsingForDirective::accept(ASTConstVisitor& _visitor) const
|
||||
{
|
||||
if (_visitor.visit(*this))
|
||||
{
|
||||
m_libraryName->accept(_visitor);
|
||||
listAccept(functionsOrLibrary(), _visitor);
|
||||
if (m_typeName)
|
||||
m_typeName->accept(_visitor);
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <libsolutil/Keccak256.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolutil/UTF8.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
@ -331,30 +332,48 @@ Type const* Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
|
||||
MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope)
|
||||
{
|
||||
vector<UsingForDirective const*> usingForDirectives;
|
||||
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope))
|
||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
||||
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
|
||||
usingForDirectives +=
|
||||
contract->usingForDirectives() +
|
||||
ASTNode::filteredNodes<UsingForDirective>(contract->sourceUnit().nodes());
|
||||
SourceUnit const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope);
|
||||
if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
|
||||
{
|
||||
sourceUnit = &contract->sourceUnit();
|
||||
usingForDirectives += contract->usingForDirectives();
|
||||
}
|
||||
else
|
||||
solAssert(false, "");
|
||||
solAssert(sourceUnit, "");
|
||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
||||
|
||||
// Normalise data location of type.
|
||||
DataLocation typeLocation = DataLocation::Storage;
|
||||
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
|
||||
typeLocation = refType->location();
|
||||
|
||||
set<Declaration const*> seenFunctions;
|
||||
MemberList::MemberMap members;
|
||||
|
||||
set<pair<string, Declaration const*>> seenFunctions;
|
||||
auto addFunction = [&](FunctionDefinition const& _function, optional<string> _name = {})
|
||||
{
|
||||
if (!_name)
|
||||
_name = _function.name();
|
||||
Type const* functionType =
|
||||
_function.libraryFunction() ? _function.typeViaContractName() : _function.type();
|
||||
solAssert(functionType, "");
|
||||
FunctionType const* asBoundFunction =
|
||||
dynamic_cast<FunctionType const&>(*functionType).asBoundFunction();
|
||||
solAssert(asBoundFunction, "");
|
||||
|
||||
if (_type.isImplicitlyConvertibleTo(*asBoundFunction->selfType()))
|
||||
if (seenFunctions.insert(make_pair(*_name, &_function)).second)
|
||||
members.emplace_back(&_function, asBoundFunction, *_name);
|
||||
};
|
||||
|
||||
for (UsingForDirective const* ufd: usingForDirectives)
|
||||
{
|
||||
// Convert both types to pointers for comparison to see if the `using for`
|
||||
// directive applies.
|
||||
// Further down, we check more detailed for each function if `_type` is
|
||||
// convertible to the function parameter type.
|
||||
if (ufd->typeName() &&
|
||||
if (
|
||||
ufd->typeName() &&
|
||||
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
||||
*TypeProvider::withLocationIfReference(
|
||||
typeLocation,
|
||||
@ -363,20 +382,28 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc
|
||||
)
|
||||
)
|
||||
continue;
|
||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
||||
*ufd->libraryName().annotation().referencedDeclaration
|
||||
);
|
||||
for (FunctionDefinition const* function: library.definedFunctions())
|
||||
|
||||
for (auto const& pathPointer: ufd->functionsOrLibrary())
|
||||
{
|
||||
if (!function->isOrdinary() || !function->isVisibleAsLibraryMember() || seenFunctions.count(function))
|
||||
continue;
|
||||
seenFunctions.insert(function);
|
||||
if (function->parameters().empty())
|
||||
continue;
|
||||
FunctionTypePointer fun =
|
||||
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
|
||||
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
||||
members.emplace_back(function, fun);
|
||||
solAssert(pathPointer);
|
||||
Declaration const* declaration = pathPointer->annotation().referencedDeclaration;
|
||||
solAssert(declaration);
|
||||
|
||||
if (ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(declaration))
|
||||
{
|
||||
solAssert(library->isLibrary());
|
||||
for (FunctionDefinition const* function: library->definedFunctions())
|
||||
{
|
||||
if (!function->isOrdinary() || !function->isVisibleAsLibraryMember() || function->parameters().empty())
|
||||
continue;
|
||||
addFunction(*function);
|
||||
}
|
||||
}
|
||||
else
|
||||
addFunction(
|
||||
dynamic_cast<FunctionDefinition const&>(*declaration),
|
||||
pathPointer->path().back()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,9 @@ ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream)
|
||||
case Token::Type:
|
||||
nodes.push_back(parseUserDefinedValueTypeDefinition());
|
||||
break;
|
||||
case Token::Using:
|
||||
nodes.push_back(parseUsingDirective());
|
||||
break;
|
||||
case Token::Function:
|
||||
nodes.push_back(parseFunctionDefinition(true));
|
||||
break;
|
||||
@ -962,7 +965,22 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
|
||||
expectToken(Token::Using);
|
||||
ASTPointer<IdentifierPath> library(parseIdentifierPath());
|
||||
|
||||
vector<ASTPointer<IdentifierPath>> functions;
|
||||
bool const usesBraces = m_scanner->currentToken() == Token::LBrace;
|
||||
if (usesBraces)
|
||||
{
|
||||
do
|
||||
{
|
||||
advance();
|
||||
functions.emplace_back(parseIdentifierPath());
|
||||
}
|
||||
while (m_scanner->currentToken() == Token::Comma);
|
||||
expectToken(Token::RBrace);
|
||||
}
|
||||
else
|
||||
functions.emplace_back(parseIdentifierPath());
|
||||
|
||||
ASTPointer<TypeName> typeName;
|
||||
expectToken(Token::For);
|
||||
if (m_scanner->currentToken() == Token::Mul)
|
||||
@ -971,7 +989,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||
typeName = parseTypeName();
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::Semicolon);
|
||||
return nodeFactory.createNode<UsingForDirective>(library, typeName);
|
||||
return nodeFactory.createNode<UsingForDirective>(move(functions), usesBraces, typeName);
|
||||
}
|
||||
|
||||
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
||||
|
@ -4,17 +4,51 @@
|
||||
{
|
||||
"C":
|
||||
[
|
||||
5
|
||||
13
|
||||
],
|
||||
"L":
|
||||
[
|
||||
1
|
||||
4
|
||||
],
|
||||
"f":
|
||||
[
|
||||
10
|
||||
]
|
||||
},
|
||||
"id": 6,
|
||||
"id": 14,
|
||||
"nodeType": "SourceUnit",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"functionList":
|
||||
[
|
||||
{
|
||||
"function":
|
||||
{
|
||||
"id": 1,
|
||||
"name": "f",
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 10,
|
||||
"src": "7:1:1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": 3,
|
||||
"nodeType": "UsingForDirective",
|
||||
"src": "0:19:1",
|
||||
"typeName":
|
||||
{
|
||||
"id": 2,
|
||||
"name": "uint",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "14:4:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_uint256",
|
||||
"typeString": "uint256"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"abstract": false,
|
||||
"baseContracts": [],
|
||||
@ -22,19 +56,86 @@
|
||||
"contractDependencies": [],
|
||||
"contractKind": "library",
|
||||
"fullyImplemented": true,
|
||||
"id": 1,
|
||||
"id": 4,
|
||||
"linearizedBaseContracts":
|
||||
[
|
||||
1
|
||||
4
|
||||
],
|
||||
"name": "L",
|
||||
"nameLocation": "8:1:1",
|
||||
"nameLocation": "28:1:1",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes": [],
|
||||
"scope": 6,
|
||||
"src": "0:12:1",
|
||||
"scope": 14,
|
||||
"src": "20:12:1",
|
||||
"usedErrors": []
|
||||
},
|
||||
{
|
||||
"body":
|
||||
{
|
||||
"id": 9,
|
||||
"nodeType": "Block",
|
||||
"src": "50:2:1",
|
||||
"statements": []
|
||||
},
|
||||
"id": 10,
|
||||
"implemented": true,
|
||||
"kind": "freeFunction",
|
||||
"modifiers": [],
|
||||
"name": "f",
|
||||
"nameLocation": "42:1:1",
|
||||
"nodeType": "FunctionDefinition",
|
||||
"parameters":
|
||||
{
|
||||
"id": 7,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 6,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 10,
|
||||
"src": "44:4:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_uint256",
|
||||
"typeString": "uint256"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 5,
|
||||
"name": "uint",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "44:4:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_uint256",
|
||||
"typeString": "uint256"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "43:6:1"
|
||||
},
|
||||
"returnParameters":
|
||||
{
|
||||
"id": 8,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters": [],
|
||||
"src": "50:0:1"
|
||||
},
|
||||
"scope": 14,
|
||||
"src": "33:19:1",
|
||||
"stateMutability": "nonpayable",
|
||||
"virtual": false,
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"abstract": false,
|
||||
"baseContracts": [],
|
||||
@ -42,46 +143,34 @@
|
||||
"contractDependencies": [],
|
||||
"contractKind": "contract",
|
||||
"fullyImplemented": true,
|
||||
"id": 5,
|
||||
"id": 13,
|
||||
"linearizedBaseContracts":
|
||||
[
|
||||
5
|
||||
13
|
||||
],
|
||||
"name": "C",
|
||||
"nameLocation": "22:1:1",
|
||||
"nameLocation": "62:1:1",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"id": 4,
|
||||
"id": 12,
|
||||
"libraryName":
|
||||
{
|
||||
"id": 2,
|
||||
"id": 11,
|
||||
"name": "L",
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 1,
|
||||
"src": "32:1:1"
|
||||
"referencedDeclaration": 4,
|
||||
"src": "72:1:1"
|
||||
},
|
||||
"nodeType": "UsingForDirective",
|
||||
"src": "26:17:1",
|
||||
"typeName":
|
||||
{
|
||||
"id": 3,
|
||||
"name": "uint",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "38:4:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_uint256",
|
||||
"typeString": "uint256"
|
||||
}
|
||||
}
|
||||
"src": "66:14:1"
|
||||
}
|
||||
],
|
||||
"scope": 6,
|
||||
"src": "13:32:1",
|
||||
"scope": 14,
|
||||
"src": "53:29:1",
|
||||
"usedErrors": []
|
||||
}
|
||||
],
|
||||
"src": "0:46:1"
|
||||
"src": "0:83:1"
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
library L {} contract C { using L for uint; }
|
||||
using {f} for uint;
|
||||
library L {}
|
||||
function f(uint) {}
|
||||
contract C { using L for *; }
|
||||
|
||||
// ----
|
||||
|
@ -1,57 +1,131 @@
|
||||
{
|
||||
"absolutePath": "a",
|
||||
"id": 6,
|
||||
"id": 14,
|
||||
"nodeType": "SourceUnit",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"functionList":
|
||||
[
|
||||
{
|
||||
"function":
|
||||
{
|
||||
"id": 1,
|
||||
"name": "f",
|
||||
"nodeType": "IdentifierPath",
|
||||
"src": "7:1:1"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": 3,
|
||||
"nodeType": "UsingForDirective",
|
||||
"src": "0:19:1",
|
||||
"typeName":
|
||||
{
|
||||
"id": 2,
|
||||
"name": "uint",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "14:4:1",
|
||||
"typeDescriptions": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"abstract": false,
|
||||
"baseContracts": [],
|
||||
"contractDependencies": [],
|
||||
"contractKind": "library",
|
||||
"id": 1,
|
||||
"id": 4,
|
||||
"name": "L",
|
||||
"nameLocation": "8:1:1",
|
||||
"nameLocation": "28:1:1",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes": [],
|
||||
"src": "0:12:1",
|
||||
"src": "20:12:1",
|
||||
"usedErrors": []
|
||||
},
|
||||
{
|
||||
"body":
|
||||
{
|
||||
"id": 9,
|
||||
"nodeType": "Block",
|
||||
"src": "50:2:1",
|
||||
"statements": []
|
||||
},
|
||||
"id": 10,
|
||||
"implemented": true,
|
||||
"kind": "freeFunction",
|
||||
"modifiers": [],
|
||||
"name": "f",
|
||||
"nameLocation": "42:1:1",
|
||||
"nodeType": "FunctionDefinition",
|
||||
"parameters":
|
||||
{
|
||||
"id": 7,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 6,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"src": "44:4:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions": {},
|
||||
"typeName":
|
||||
{
|
||||
"id": 5,
|
||||
"name": "uint",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "44:4:1",
|
||||
"typeDescriptions": {}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "43:6:1"
|
||||
},
|
||||
"returnParameters":
|
||||
{
|
||||
"id": 8,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters": [],
|
||||
"src": "50:0:1"
|
||||
},
|
||||
"src": "33:19:1",
|
||||
"stateMutability": "nonpayable",
|
||||
"virtual": false,
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"abstract": false,
|
||||
"baseContracts": [],
|
||||
"contractDependencies": [],
|
||||
"contractKind": "contract",
|
||||
"id": 5,
|
||||
"id": 13,
|
||||
"name": "C",
|
||||
"nameLocation": "22:1:1",
|
||||
"nameLocation": "62:1:1",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"id": 4,
|
||||
"id": 12,
|
||||
"libraryName":
|
||||
{
|
||||
"id": 2,
|
||||
"id": 11,
|
||||
"name": "L",
|
||||
"nodeType": "IdentifierPath",
|
||||
"src": "32:1:1"
|
||||
"src": "72:1:1"
|
||||
},
|
||||
"nodeType": "UsingForDirective",
|
||||
"src": "26:17:1",
|
||||
"typeName":
|
||||
{
|
||||
"id": 3,
|
||||
"name": "uint",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "38:4:1",
|
||||
"typeDescriptions": {}
|
||||
}
|
||||
"src": "66:14:1"
|
||||
}
|
||||
],
|
||||
"src": "13:32:1",
|
||||
"src": "53:29:1",
|
||||
"usedErrors": []
|
||||
}
|
||||
],
|
||||
"src": "0:46:1"
|
||||
"src": "0:83:1"
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
|
||||
contract C {
|
||||
function f(uint[] calldata arr) external returns (uint) {
|
||||
return arr.sum();
|
||||
}
|
||||
}
|
||||
|
||||
function sum(uint[] memory arr) returns (uint result) {
|
||||
for(uint i = 0; i < arr.length; i++) {
|
||||
result += arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
using {sum} for uint[];
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256[]): 0x20, 3, 1, 2, 8 -> 11
|
@ -0,0 +1,26 @@
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
function zero(uint) pure returns (uint) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f(uint z) pure external returns(uint) {
|
||||
return z.id();
|
||||
}
|
||||
|
||||
function g(uint z) pure external returns (uint) {
|
||||
return z.zero();
|
||||
}
|
||||
|
||||
using {id, zero} for uint;
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256): 10 -> 10
|
||||
// g(uint256): 10 -> 0
|
||||
// f(uint256): 256 -> 0x0100
|
||||
// g(uint256): 256 -> 0
|
27
test/libsolidity/semanticTests/using/free_function_multi.sol
Normal file
27
test/libsolidity/semanticTests/using/free_function_multi.sol
Normal file
@ -0,0 +1,27 @@
|
||||
contract C {
|
||||
function f(uint z) pure external returns(uint) {
|
||||
return z.id();
|
||||
}
|
||||
|
||||
using {id, zero, zero, id} for uint;
|
||||
|
||||
function g(uint z) pure external returns (uint) {
|
||||
return z.zero();
|
||||
}
|
||||
}
|
||||
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
function zero(uint) pure returns (uint) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256): 10 -> 10
|
||||
// g(uint256): 10 -> 0
|
||||
// f(uint256): 256 -> 0x0100
|
||||
// g(uint256): 256 -> 0
|
@ -0,0 +1,30 @@
|
||||
using {zero} for uint;
|
||||
|
||||
contract C {
|
||||
using {id} for uint;
|
||||
|
||||
function f(uint z) pure external returns(uint) {
|
||||
return z.id();
|
||||
}
|
||||
|
||||
function g(uint z) pure external returns (uint) {
|
||||
return z.zero();
|
||||
}
|
||||
}
|
||||
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
function zero(uint) pure returns (uint) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256): 10 -> 10
|
||||
// g(uint256): 10 -> 0
|
||||
// f(uint256): 256 -> 0x0100
|
||||
// g(uint256): 256 -> 0
|
19
test/libsolidity/semanticTests/using/imported_functions.sol
Normal file
19
test/libsolidity/semanticTests/using/imported_functions.sol
Normal file
@ -0,0 +1,19 @@
|
||||
==== Source: A ====
|
||||
function inc(uint x) pure returns (uint) {
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
contract C {
|
||||
function f(uint x) public returns (uint) {
|
||||
return x.f() + x.inc();
|
||||
}
|
||||
}
|
||||
using {A.inc, f} for uint;
|
||||
import {inc as f} from "A";
|
||||
import "A" as A;
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f(uint256): 5 -> 12
|
||||
// f(uint256): 10 -> 0x16
|
@ -0,0 +1,34 @@
|
||||
==== Source: A ====
|
||||
library L {
|
||||
function id(uint x) internal pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
function one_ext(uint) pure external returns(uint) {
|
||||
return 1;
|
||||
}
|
||||
function empty() pure internal {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
contract C {
|
||||
using M.L for uint;
|
||||
function f(uint x) public pure returns (uint) {
|
||||
return x.id();
|
||||
}
|
||||
function g(uint x) public pure returns (uint) {
|
||||
return x.one_ext();
|
||||
}
|
||||
}
|
||||
|
||||
import "A" as M;
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// library: "A":L
|
||||
// f(uint256): 5 -> 5
|
||||
// f(uint256): 10 -> 10
|
||||
// g(uint256): 5 -> 1
|
||||
// g(uint256): 10 -> 1
|
26
test/libsolidity/semanticTests/using/module_renamed.sol
Normal file
26
test/libsolidity/semanticTests/using/module_renamed.sol
Normal file
@ -0,0 +1,26 @@
|
||||
==== Source: A ====
|
||||
function f(uint x) pure returns (uint) {
|
||||
return x + 2;
|
||||
}
|
||||
function g(uint x) pure returns (uint) {
|
||||
return x + 8;
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
import {f as g, g as f} from "A";
|
||||
|
||||
==== Source: C ====
|
||||
contract C {
|
||||
function test(uint x, uint y) public pure returns (uint, uint) {
|
||||
return (x.f(), y.g());
|
||||
}
|
||||
}
|
||||
|
||||
using {M.g, M.f} for uint;
|
||||
|
||||
import "B" as M;
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test(uint256,uint256): 1, 1 -> 9, 3
|
@ -7,4 +7,4 @@ contract C {
|
||||
using S for S;
|
||||
}
|
||||
// ----
|
||||
// TypeError 4357: (113-114): Library name expected.
|
||||
// TypeError 4357: (113-114): Library name expected. If you want to attach a function, use '{...}'.
|
||||
|
@ -7,4 +7,4 @@ interface I {
|
||||
function g() external;
|
||||
}
|
||||
// ----
|
||||
// TypeError 9088: (60-76): The "using for" directive is not allowed inside interfaces.
|
||||
// SyntaxError 9088: (60-76): The "using for" directive is not allowed inside interfaces.
|
||||
|
@ -3,4 +3,4 @@ contract C {
|
||||
using D for uint;
|
||||
}
|
||||
// ----
|
||||
// TypeError 4357: (38-39): Library name expected.
|
||||
// TypeError 4357: (38-39): Library name expected. If you want to attach a function, use '{...}'.
|
||||
|
@ -7,4 +7,4 @@ library L {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 4357: (120-121): Library name expected.
|
||||
// TypeError 4357: (120-121): Library name expected. If you want to attach a function, use '{...}'.
|
||||
|
19
test/libsolidity/syntaxTests/using/double_asterisk.sol
Normal file
19
test/libsolidity/syntaxTests/using/double_asterisk.sol
Normal file
@ -0,0 +1,19 @@
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
function zero(address) pure returns (address) {
|
||||
return address(0);
|
||||
}
|
||||
|
||||
contract C {
|
||||
using * for *;
|
||||
function f(uint x) pure external returns (uint) {
|
||||
return x.id();
|
||||
}
|
||||
function g(address a) pure external returns (address) {
|
||||
return a.zero();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// ParserError 2314: (156-157): Expected identifier but got '*'
|
@ -0,0 +1,22 @@
|
||||
==== Source: A ====
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
// we check that the effect of this directive is
|
||||
// limited to this file.
|
||||
using {id} for uint;
|
||||
|
||||
function t() pure {
|
||||
uint y = 2;
|
||||
y = y.id();
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
import "A";
|
||||
|
||||
function f() pure {
|
||||
uint y = 2;
|
||||
y = y.id();
|
||||
}
|
||||
// ----
|
||||
// TypeError 9582: (B:57-61): Member "id" not found or not visible after argument-dependent lookup in uint256.
|
@ -0,0 +1,6 @@
|
||||
function id(uint16 x) pure returns(uint16) {
|
||||
return x;
|
||||
}
|
||||
contract C {
|
||||
using {id} for uint8;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
function id(uint16 x) pure returns(uint16) {
|
||||
return x;
|
||||
}
|
||||
contract C {
|
||||
using {id} for uint256;
|
||||
}
|
||||
// ----
|
||||
// TypeError 3100: (85-87): The function "id" cannot be bound to the type "uint256" because the type cannot be implicitly converted to the first argument of the function ("uint16").
|
@ -0,0 +1,12 @@
|
||||
function id(int8 x) pure returns(int8) {
|
||||
return x;
|
||||
}
|
||||
function id(uint256 x) pure returns(uint256) {
|
||||
return x;
|
||||
}
|
||||
|
||||
contract C {
|
||||
using {id} for uint256;
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 7920: (145-147): Identifier not found or not unique.
|
10
test/libsolidity/syntaxTests/using/free_overloads.sol
Normal file
10
test/libsolidity/syntaxTests/using/free_overloads.sol
Normal file
@ -0,0 +1,10 @@
|
||||
function f(uint8 x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
function f(int8 storage x) pure returns (int) {
|
||||
return x[0];
|
||||
}
|
||||
using {f} for uint8;
|
||||
using {f} for int;
|
||||
// ----
|
||||
// DeclarationError 7920: (132-133): Identifier not found or not unique.
|
@ -0,0 +1,9 @@
|
||||
function f(uint x, uint[] y) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
function f(uint x, uint y) pure returns (int) {
|
||||
return x;
|
||||
}
|
||||
using {f} for uint;
|
||||
// ----
|
||||
// DeclarationError 7920: (138-139): Identifier not found or not unique.
|
11
test/libsolidity/syntaxTests/using/free_reference_type.sol
Normal file
11
test/libsolidity/syntaxTests/using/free_reference_type.sol
Normal file
@ -0,0 +1,11 @@
|
||||
function f(uint[] memory x) pure returns (uint) {
|
||||
return x[0];
|
||||
}
|
||||
function g(uint[] storage x) view returns (uint) {
|
||||
return x[0];
|
||||
}
|
||||
function h(uint[] calldata x) pure returns (uint) {
|
||||
return x[0];
|
||||
}
|
||||
using {f, g, h} for uint[];
|
||||
// ----
|
16
test/libsolidity/syntaxTests/using/library_import_as.sol
Normal file
16
test/libsolidity/syntaxTests/using/library_import_as.sol
Normal file
@ -0,0 +1,16 @@
|
||||
==== Source: A ====
|
||||
library L {
|
||||
function id(uint x) pure internal returns (uint) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
import {L as M} from "A";
|
||||
|
||||
contract C {
|
||||
using M for uint;
|
||||
function f(uint x) public pure returns (uint) {
|
||||
return x.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
library L {
|
||||
function id_ext(uint x) external returns(uint) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
using L.id_ext for uint;
|
||||
function f(uint x) external {
|
||||
x.id_ext();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 7920: (115-123): Identifier not found or not unique.
|
@ -0,0 +1,13 @@
|
||||
library L {
|
||||
function id(uint x) internal pure returns(uint) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
using {L.id} for uint;
|
||||
function f(uint x) external pure {
|
||||
x.id();
|
||||
}
|
||||
}
|
||||
// ----
|
12
test/libsolidity/syntaxTests/using/module_1.sol
Normal file
12
test/libsolidity/syntaxTests/using/module_1.sol
Normal file
@ -0,0 +1,12 @@
|
||||
==== Source: A ====
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
import "A" as M;
|
||||
contract C {
|
||||
using M for uint;
|
||||
}
|
||||
// ----
|
||||
// TypeError 4357: (B:40-41): Library name expected. If you want to attach a function, use '{...}'.
|
14
test/libsolidity/syntaxTests/using/module_2.sol
Normal file
14
test/libsolidity/syntaxTests/using/module_2.sol
Normal file
@ -0,0 +1,14 @@
|
||||
==== Source: A ====
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
import {id as Id} from "A";
|
||||
|
||||
contract C {
|
||||
using { Id } for uint;
|
||||
function f(uint x) public pure returns (uint) {
|
||||
return x.Id();
|
||||
}
|
||||
}
|
14
test/libsolidity/syntaxTests/using/module_3.sol
Normal file
14
test/libsolidity/syntaxTests/using/module_3.sol
Normal file
@ -0,0 +1,14 @@
|
||||
==== Source: A ====
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
import "A" as M;
|
||||
|
||||
contract C {
|
||||
using {M.id} for uint;
|
||||
function f(uint x) public pure returns (uint) {
|
||||
return x.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
==== Source: A ====
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
==== Source: B ====
|
||||
import "A" as M;
|
||||
|
||||
contract C {
|
||||
using { id } for uint;
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 7920: (B:43-45): Identifier not found or not unique.
|
13
test/libsolidity/syntaxTests/using/using_contract_err.sol
Normal file
13
test/libsolidity/syntaxTests/using/using_contract_err.sol
Normal file
@ -0,0 +1,13 @@
|
||||
contract C {
|
||||
function f(uint) external {
|
||||
}
|
||||
}
|
||||
interface I {
|
||||
function f(uint) external;
|
||||
}
|
||||
|
||||
contract Test {
|
||||
using C for uint;
|
||||
}
|
||||
// ----
|
||||
// TypeError 4357: (127-128): Library name expected. If you want to attach a function, use '{...}'.
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
using {} for uint;
|
||||
}
|
||||
// ----
|
||||
// ParserError 2314: (24-25): Expected identifier but got '}'
|
@ -0,0 +1,3 @@
|
||||
using {} for uint;
|
||||
// ----
|
||||
// ParserError 2314: (7-8): Expected identifier but got '}'
|
@ -0,0 +1,7 @@
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
using {id} for *;
|
||||
// ----
|
||||
// SyntaxError 8118: (59-76): The type has to be specified explicitly at file level (cannot use '*').
|
16
test/libsolidity/syntaxTests/using/using_free_functions.sol
Normal file
16
test/libsolidity/syntaxTests/using/using_free_functions.sol
Normal file
@ -0,0 +1,16 @@
|
||||
function id(uint x) pure returns (uint) {
|
||||
return x;
|
||||
}
|
||||
|
||||
function zero(uint) pure returns (uint) {
|
||||
return 0;
|
||||
}
|
||||
using {id} for uint;
|
||||
contract C {
|
||||
using {zero} for uint;
|
||||
|
||||
function g(uint z) pure external {
|
||||
z.zero();
|
||||
z.id();
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
function one() pure returns(uint) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
using {one} for uint;
|
||||
// ----
|
||||
// TypeError 4731: (60-63): The function "one" does not have any parameters, and therefore cannot be bound to the type "uint256".
|
@ -0,0 +1,7 @@
|
||||
function f(uint) {}
|
||||
|
||||
contract C {
|
||||
using {f} for *;
|
||||
}
|
||||
// ----
|
||||
// SyntaxError 3349: (38-54): The type has to be specified explicitly when attaching specific functions.
|
@ -0,0 +1,3 @@
|
||||
using * for uint;
|
||||
// ----
|
||||
// ParserError 2314: (6-7): Expected identifier but got '*'
|
@ -0,0 +1,5 @@
|
||||
contract C {
|
||||
using * for uint;
|
||||
}
|
||||
// ----
|
||||
// ParserError 2314: (23-24): Expected identifier but got '*'
|
@ -0,0 +1,4 @@
|
||||
library L { }
|
||||
using L for *;
|
||||
// ----
|
||||
// SyntaxError 8118: (14-28): The type has to be specified explicitly at file level (cannot use '*').
|
@ -0,0 +1,3 @@
|
||||
library L { }
|
||||
using L for uint;
|
||||
// ----
|
@ -0,0 +1,9 @@
|
||||
contract C {
|
||||
using {f, g} for uint;
|
||||
|
||||
function f(uint) internal { }
|
||||
function g(uint) public { }
|
||||
}
|
||||
// ----
|
||||
// TypeError 4167: (24-25): Only file-level functions and library functions can be bound to a type in a "using" statement
|
||||
// TypeError 4167: (27-28): Only file-level functions and library functions can be bound to a type in a "using" statement
|
@ -0,0 +1,6 @@
|
||||
contract C {
|
||||
function() internal pure x;
|
||||
using {x} for uint;
|
||||
}
|
||||
// ----
|
||||
// TypeError 8187: (56-57): Expected function name.
|
Loading…
Reference in New Issue
Block a user