mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Extend using-for.
This commit is contained in:
parent
db30f4d495
commit
672951ccc7
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Language Features:
|
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: 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:
|
Compiler Features:
|
||||||
|
@ -6,71 +6,89 @@
|
|||||||
Using For
|
Using For
|
||||||
*********
|
*********
|
||||||
|
|
||||||
The directive ``using A for B;`` can be used to attach library
|
The directive ``using A for B;`` can be used to attach
|
||||||
functions (from the library ``A``) to any type (``B``)
|
functions (``A``) as member functions to any type (``B``).
|
||||||
in the context of a contract.
|
|
||||||
These functions will receive the object they are called on
|
These functions will receive the object they are called on
|
||||||
as their first parameter (like the ``self`` variable in Python).
|
as their first parameter (like the ``self`` variable in Python).
|
||||||
|
|
||||||
The effect of ``using A for *;`` is that the functions from
|
It is valid either at file level or inside a contract,
|
||||||
the library ``A`` are attached to *any* type.
|
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
|
even those where the type of the first parameter does not
|
||||||
match the type of the object. The type is checked at the
|
match the type of the object. The type is checked at the
|
||||||
point the function is called and function overload
|
point the function is called and function overload
|
||||||
resolution is performed.
|
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
|
The ``using A for B;`` directive is active only within the current
|
||||||
contract, including within all of its functions, and has no effect
|
scope (either the contract or the current module/source unit),
|
||||||
outside of the contract in which it is used. The directive
|
including within all of its functions, and has no effect
|
||||||
may only be used inside a contract, not inside any of its functions.
|
outside of the contract or module in which it is used.
|
||||||
|
|
||||||
Let us rewrite the set example from the
|
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
|
.. code-block:: solidity
|
||||||
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// 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; }
|
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)
|
||||||
function insert(Data storage self, uint value)
|
returns (bool)
|
||||||
public
|
{
|
||||||
returns (bool)
|
if (self.flags[value])
|
||||||
{
|
return false; // already there
|
||||||
if (self.flags[value])
|
self.flags[value] = true;
|
||||||
return false; // already there
|
return true;
|
||||||
self.flags[value] = true;
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove(Data storage self, uint value)
|
function remove(Data storage self, uint value)
|
||||||
public
|
returns (bool)
|
||||||
returns (bool)
|
{
|
||||||
{
|
if (!self.flags[value])
|
||||||
if (!self.flags[value])
|
return false; // not there
|
||||||
return false; // not there
|
self.flags[value] = false;
|
||||||
self.flags[value] = false;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function contains(Data storage self, uint value)
|
function contains(Data storage self, uint value)
|
||||||
public
|
public
|
||||||
view
|
view
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
return self.flags[value];
|
return self.flags[value];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
contract C {
|
contract C {
|
||||||
using Set for Data; // this is the crucial change
|
|
||||||
Data knownValues;
|
Data knownValues;
|
||||||
|
|
||||||
function register(uint value) public {
|
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
|
.. code-block:: solidity
|
||||||
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
pragma solidity >=0.6.8 <0.9.0;
|
pragma solidity ^0.8.13;
|
||||||
|
|
||||||
library Search {
|
library Search {
|
||||||
function indexOf(uint[] storage self, uint value)
|
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;
|
return type(uint).max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
using Search for uint[];
|
||||||
|
|
||||||
contract C {
|
contract C {
|
||||||
using Search for uint[];
|
|
||||||
uint[] data;
|
uint[] data;
|
||||||
|
|
||||||
function append(uint value) public {
|
function append(uint value) public {
|
||||||
|
@ -12,6 +12,7 @@ options { tokenVocab=SolidityLexer; }
|
|||||||
sourceUnit: (
|
sourceUnit: (
|
||||||
pragmaDirective
|
pragmaDirective
|
||||||
| importDirective
|
| importDirective
|
||||||
|
| usingDirective
|
||||||
| contractDefinition
|
| contractDefinition
|
||||||
| interfaceDefinition
|
| interfaceDefinition
|
||||||
| libraryDefinition
|
| libraryDefinition
|
||||||
@ -311,10 +312,10 @@ errorDefinition:
|
|||||||
Semicolon;
|
Semicolon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Using directive to bind library functions to types.
|
* Using directive to bind library functions and free functions to types.
|
||||||
* Can occur within contracts and libraries.
|
* 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
|
* 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.
|
* (e.g. a contract or struct) or an array type.
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <liblangutil/ErrorReporter.h>
|
#include <liblangutil/ErrorReporter.h>
|
||||||
|
|
||||||
#include <libsolutil/Algorithms.h>
|
#include <libsolutil/Algorithms.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
#include <range/v3/view/transform.hpp>
|
#include <range/v3/view/transform.hpp>
|
||||||
|
|
||||||
@ -451,12 +452,39 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
|||||||
|
|
||||||
bool DeclarationTypeChecker::visit(UsingForDirective const& _usingFor)
|
bool DeclarationTypeChecker::visit(UsingForDirective const& _usingFor)
|
||||||
{
|
{
|
||||||
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
|
if (_usingFor.usesBraces())
|
||||||
_usingFor.libraryName().annotation().referencedDeclaration
|
{
|
||||||
);
|
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())
|
// We do not visit _usingFor.functions() because it will lead to an error since
|
||||||
m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected.");
|
// library names cannot be mentioned stand-alone.
|
||||||
|
|
||||||
if (_usingFor.typeName())
|
if (_usingFor.typeName())
|
||||||
_usingFor.typeName()->accept(*this);
|
_usingFor.typeName()->accept(*this);
|
||||||
|
@ -403,6 +403,30 @@ void SyntaxChecker::endVisit(ContractDefinition const&)
|
|||||||
m_currentContractKind = std::nullopt;
|
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)
|
bool SyntaxChecker::visit(FunctionDefinition const& _function)
|
||||||
{
|
{
|
||||||
solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), "");
|
solAssert(_function.isFree() == (m_currentContractKind == std::nullopt), "");
|
||||||
|
@ -88,6 +88,9 @@ private:
|
|||||||
|
|
||||||
bool visit(ContractDefinition const& _contract) override;
|
bool visit(ContractDefinition const& _contract) override;
|
||||||
void endVisit(ContractDefinition const& _contract) override;
|
void endVisit(ContractDefinition const& _contract) override;
|
||||||
|
|
||||||
|
bool visit(UsingForDirective const& _usingFor) override;
|
||||||
|
|
||||||
bool visit(FunctionDefinition const& _function) override;
|
bool visit(FunctionDefinition const& _function) override;
|
||||||
bool visit(FunctionTypeName const& _node) override;
|
bool visit(FunctionTypeName const& _node) override;
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <libsolutil/Algorithms.h>
|
#include <libsolutil/Algorithms.h>
|
||||||
#include <libsolutil/StringUtils.h>
|
#include <libsolutil/StringUtils.h>
|
||||||
#include <libsolutil/Views.h>
|
#include <libsolutil/Views.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
@ -3626,12 +3627,67 @@ void TypeChecker::endVisit(Literal const& _literal)
|
|||||||
|
|
||||||
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||||
{
|
{
|
||||||
if (m_currentContract->isInterface())
|
if (!_usingFor.usesBraces())
|
||||||
m_errorReporter.typeError(
|
{
|
||||||
9088_error,
|
solAssert(_usingFor.functionsOrLibrary().size() == 1);
|
||||||
_usingFor.location(),
|
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
|
||||||
"The \"using for\" directive is not allowed inside interfaces."
|
_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)
|
void TypeChecker::checkErrorAndEventParameters(CallableDeclaration const& _callable)
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <libevmasm/Instruction.h>
|
#include <libevmasm/Instruction.h>
|
||||||
#include <libsolutil/FixedHash.h>
|
#include <libsolutil/FixedHash.h>
|
||||||
#include <libsolutil/LazyInit.h>
|
#include <libsolutil/LazyInit.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
@ -630,9 +631,16 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `using LibraryName for uint` will attach all functions from the library LibraryName
|
* Using for directive:
|
||||||
* to `uint` if the first parameter matches the type. `using LibraryName for *` attaches
|
*
|
||||||
* the function to any matching type.
|
* 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
|
class UsingForDirective: public ASTNode
|
||||||
{
|
{
|
||||||
@ -640,23 +648,28 @@ public:
|
|||||||
UsingForDirective(
|
UsingForDirective(
|
||||||
int64_t _id,
|
int64_t _id,
|
||||||
SourceLocation const& _location,
|
SourceLocation const& _location,
|
||||||
ASTPointer<IdentifierPath> _libraryName,
|
std::vector<ASTPointer<IdentifierPath>> _functions,
|
||||||
|
bool _usesBraces,
|
||||||
ASTPointer<TypeName> _typeName
|
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(ASTVisitor& _visitor) override;
|
||||||
void accept(ASTConstVisitor& _visitor) const 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 `*`.
|
/// @returns the type name the library is attached to, null for `*`.
|
||||||
TypeName const* typeName() const { return m_typeName.get(); }
|
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:
|
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;
|
ASTPointer<TypeName> m_typeName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <libsolutil/JSON.h>
|
#include <libsolutil/JSON.h>
|
||||||
#include <libsolutil/UTF8.h>
|
#include <libsolutil/UTF8.h>
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
#include <libsolutil/Keccak256.h>
|
#include <libsolutil/Keccak256.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
@ -311,10 +312,25 @@ bool ASTJsonConverter::visit(InheritanceSpecifier const& _node)
|
|||||||
|
|
||||||
bool ASTJsonConverter::visit(UsingForDirective const& _node)
|
bool ASTJsonConverter::visit(UsingForDirective const& _node)
|
||||||
{
|
{
|
||||||
setJsonNode(_node, "UsingForDirective", {
|
vector<pair<string, Json::Value>> attributes = {
|
||||||
make_pair("libraryName", toJson(_node.libraryName())),
|
|
||||||
make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,9 +348,17 @@ ASTPointer<InheritanceSpecifier> ASTJsonImporter::createInheritanceSpecifier(Jso
|
|||||||
|
|
||||||
ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
|
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>(
|
return createASTNode<UsingForDirective>(
|
||||||
_node,
|
_node,
|
||||||
createIdentifierPath(member(_node, "libraryName")),
|
move(functions),
|
||||||
|
!_node.isMember("libraryName"),
|
||||||
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"])
|
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ void UsingForDirective::accept(ASTVisitor& _visitor)
|
|||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
{
|
{
|
||||||
m_libraryName->accept(_visitor);
|
listAccept(functionsOrLibrary(), _visitor);
|
||||||
if (m_typeName)
|
if (m_typeName)
|
||||||
m_typeName->accept(_visitor);
|
m_typeName->accept(_visitor);
|
||||||
}
|
}
|
||||||
@ -205,7 +205,7 @@ void UsingForDirective::accept(ASTConstVisitor& _visitor) const
|
|||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
{
|
{
|
||||||
m_libraryName->accept(_visitor);
|
listAccept(functionsOrLibrary(), _visitor);
|
||||||
if (m_typeName)
|
if (m_typeName)
|
||||||
m_typeName->accept(_visitor);
|
m_typeName->accept(_visitor);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <libsolutil/Keccak256.h>
|
#include <libsolutil/Keccak256.h>
|
||||||
#include <libsolutil/StringUtils.h>
|
#include <libsolutil/StringUtils.h>
|
||||||
#include <libsolutil/UTF8.h>
|
#include <libsolutil/UTF8.h>
|
||||||
|
#include <libsolutil/Visitor.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/algorithm/string/classification.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)
|
MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope)
|
||||||
{
|
{
|
||||||
vector<UsingForDirective const*> usingForDirectives;
|
vector<UsingForDirective const*> usingForDirectives;
|
||||||
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope))
|
SourceUnit const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope);
|
||||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
|
||||||
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
|
{
|
||||||
usingForDirectives +=
|
sourceUnit = &contract->sourceUnit();
|
||||||
contract->usingForDirectives() +
|
usingForDirectives += contract->usingForDirectives();
|
||||||
ASTNode::filteredNodes<UsingForDirective>(contract->sourceUnit().nodes());
|
}
|
||||||
else
|
else
|
||||||
solAssert(false, "");
|
solAssert(sourceUnit, "");
|
||||||
|
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
||||||
|
|
||||||
// Normalise data location of type.
|
// Normalise data location of type.
|
||||||
DataLocation typeLocation = DataLocation::Storage;
|
DataLocation typeLocation = DataLocation::Storage;
|
||||||
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
|
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
|
||||||
typeLocation = refType->location();
|
typeLocation = refType->location();
|
||||||
|
|
||||||
set<Declaration const*> seenFunctions;
|
|
||||||
MemberList::MemberMap members;
|
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)
|
for (UsingForDirective const* ufd: usingForDirectives)
|
||||||
{
|
{
|
||||||
// Convert both types to pointers for comparison to see if the `using for`
|
// Convert both types to pointers for comparison to see if the `using for`
|
||||||
// directive applies.
|
// directive applies.
|
||||||
// Further down, we check more detailed for each function if `_type` is
|
// Further down, we check more detailed for each function if `_type` is
|
||||||
// convertible to the function parameter type.
|
// convertible to the function parameter type.
|
||||||
if (ufd->typeName() &&
|
if (
|
||||||
|
ufd->typeName() &&
|
||||||
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
||||||
*TypeProvider::withLocationIfReference(
|
*TypeProvider::withLocationIfReference(
|
||||||
typeLocation,
|
typeLocation,
|
||||||
@ -363,20 +382,28 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
continue;
|
continue;
|
||||||
auto const& library = dynamic_cast<ContractDefinition const&>(
|
|
||||||
*ufd->libraryName().annotation().referencedDeclaration
|
for (auto const& pathPointer: ufd->functionsOrLibrary())
|
||||||
);
|
|
||||||
for (FunctionDefinition const* function: library.definedFunctions())
|
|
||||||
{
|
{
|
||||||
if (!function->isOrdinary() || !function->isVisibleAsLibraryMember() || seenFunctions.count(function))
|
solAssert(pathPointer);
|
||||||
continue;
|
Declaration const* declaration = pathPointer->annotation().referencedDeclaration;
|
||||||
seenFunctions.insert(function);
|
solAssert(declaration);
|
||||||
if (function->parameters().empty())
|
|
||||||
continue;
|
if (ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
FunctionTypePointer fun =
|
{
|
||||||
dynamic_cast<FunctionType const&>(*function->typeViaContractName()).asBoundFunction();
|
solAssert(library->isLibrary());
|
||||||
if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
|
for (FunctionDefinition const* function: library->definedFunctions())
|
||||||
members.emplace_back(function, fun);
|
{
|
||||||
|
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:
|
case Token::Type:
|
||||||
nodes.push_back(parseUserDefinedValueTypeDefinition());
|
nodes.push_back(parseUserDefinedValueTypeDefinition());
|
||||||
break;
|
break;
|
||||||
|
case Token::Using:
|
||||||
|
nodes.push_back(parseUsingDirective());
|
||||||
|
break;
|
||||||
case Token::Function:
|
case Token::Function:
|
||||||
nodes.push_back(parseFunctionDefinition(true));
|
nodes.push_back(parseFunctionDefinition(true));
|
||||||
break;
|
break;
|
||||||
@ -962,7 +965,22 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
|||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
|
|
||||||
expectToken(Token::Using);
|
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;
|
ASTPointer<TypeName> typeName;
|
||||||
expectToken(Token::For);
|
expectToken(Token::For);
|
||||||
if (m_scanner->currentToken() == Token::Mul)
|
if (m_scanner->currentToken() == Token::Mul)
|
||||||
@ -971,7 +989,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
|||||||
typeName = parseTypeName();
|
typeName = parseTypeName();
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::Semicolon);
|
expectToken(Token::Semicolon);
|
||||||
return nodeFactory.createNode<UsingForDirective>(library, typeName);
|
return nodeFactory.createNode<UsingForDirective>(move(functions), usesBraces, typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
||||||
|
@ -4,17 +4,51 @@
|
|||||||
{
|
{
|
||||||
"C":
|
"C":
|
||||||
[
|
[
|
||||||
5
|
13
|
||||||
],
|
],
|
||||||
"L":
|
"L":
|
||||||
[
|
[
|
||||||
1
|
4
|
||||||
|
],
|
||||||
|
"f":
|
||||||
|
[
|
||||||
|
10
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"id": 6,
|
"id": 14,
|
||||||
"nodeType": "SourceUnit",
|
"nodeType": "SourceUnit",
|
||||||
"nodes":
|
"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,
|
"abstract": false,
|
||||||
"baseContracts": [],
|
"baseContracts": [],
|
||||||
@ -22,19 +56,86 @@
|
|||||||
"contractDependencies": [],
|
"contractDependencies": [],
|
||||||
"contractKind": "library",
|
"contractKind": "library",
|
||||||
"fullyImplemented": true,
|
"fullyImplemented": true,
|
||||||
"id": 1,
|
"id": 4,
|
||||||
"linearizedBaseContracts":
|
"linearizedBaseContracts":
|
||||||
[
|
[
|
||||||
1
|
4
|
||||||
],
|
],
|
||||||
"name": "L",
|
"name": "L",
|
||||||
"nameLocation": "8:1:1",
|
"nameLocation": "28:1:1",
|
||||||
"nodeType": "ContractDefinition",
|
"nodeType": "ContractDefinition",
|
||||||
"nodes": [],
|
"nodes": [],
|
||||||
"scope": 6,
|
"scope": 14,
|
||||||
"src": "0:12:1",
|
"src": "20:12:1",
|
||||||
"usedErrors": []
|
"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,
|
"abstract": false,
|
||||||
"baseContracts": [],
|
"baseContracts": [],
|
||||||
@ -42,46 +143,34 @@
|
|||||||
"contractDependencies": [],
|
"contractDependencies": [],
|
||||||
"contractKind": "contract",
|
"contractKind": "contract",
|
||||||
"fullyImplemented": true,
|
"fullyImplemented": true,
|
||||||
"id": 5,
|
"id": 13,
|
||||||
"linearizedBaseContracts":
|
"linearizedBaseContracts":
|
||||||
[
|
[
|
||||||
5
|
13
|
||||||
],
|
],
|
||||||
"name": "C",
|
"name": "C",
|
||||||
"nameLocation": "22:1:1",
|
"nameLocation": "62:1:1",
|
||||||
"nodeType": "ContractDefinition",
|
"nodeType": "ContractDefinition",
|
||||||
"nodes":
|
"nodes":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 12,
|
||||||
"libraryName":
|
"libraryName":
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 11,
|
||||||
"name": "L",
|
"name": "L",
|
||||||
"nodeType": "IdentifierPath",
|
"nodeType": "IdentifierPath",
|
||||||
"referencedDeclaration": 1,
|
"referencedDeclaration": 4,
|
||||||
"src": "32:1:1"
|
"src": "72:1:1"
|
||||||
},
|
},
|
||||||
"nodeType": "UsingForDirective",
|
"nodeType": "UsingForDirective",
|
||||||
"src": "26:17:1",
|
"src": "66:14:1"
|
||||||
"typeName":
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"name": "uint",
|
|
||||||
"nodeType": "ElementaryTypeName",
|
|
||||||
"src": "38:4:1",
|
|
||||||
"typeDescriptions":
|
|
||||||
{
|
|
||||||
"typeIdentifier": "t_uint256",
|
|
||||||
"typeString": "uint256"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scope": 6,
|
"scope": 14,
|
||||||
"src": "13:32:1",
|
"src": "53:29:1",
|
||||||
"usedErrors": []
|
"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",
|
"absolutePath": "a",
|
||||||
"id": 6,
|
"id": 14,
|
||||||
"nodeType": "SourceUnit",
|
"nodeType": "SourceUnit",
|
||||||
"nodes":
|
"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,
|
"abstract": false,
|
||||||
"baseContracts": [],
|
"baseContracts": [],
|
||||||
"contractDependencies": [],
|
"contractDependencies": [],
|
||||||
"contractKind": "library",
|
"contractKind": "library",
|
||||||
"id": 1,
|
"id": 4,
|
||||||
"name": "L",
|
"name": "L",
|
||||||
"nameLocation": "8:1:1",
|
"nameLocation": "28:1:1",
|
||||||
"nodeType": "ContractDefinition",
|
"nodeType": "ContractDefinition",
|
||||||
"nodes": [],
|
"nodes": [],
|
||||||
"src": "0:12:1",
|
"src": "20:12:1",
|
||||||
"usedErrors": []
|
"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,
|
"abstract": false,
|
||||||
"baseContracts": [],
|
"baseContracts": [],
|
||||||
"contractDependencies": [],
|
"contractDependencies": [],
|
||||||
"contractKind": "contract",
|
"contractKind": "contract",
|
||||||
"id": 5,
|
"id": 13,
|
||||||
"name": "C",
|
"name": "C",
|
||||||
"nameLocation": "22:1:1",
|
"nameLocation": "62:1:1",
|
||||||
"nodeType": "ContractDefinition",
|
"nodeType": "ContractDefinition",
|
||||||
"nodes":
|
"nodes":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 12,
|
||||||
"libraryName":
|
"libraryName":
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 11,
|
||||||
"name": "L",
|
"name": "L",
|
||||||
"nodeType": "IdentifierPath",
|
"nodeType": "IdentifierPath",
|
||||||
"src": "32:1:1"
|
"src": "72:1:1"
|
||||||
},
|
},
|
||||||
"nodeType": "UsingForDirective",
|
"nodeType": "UsingForDirective",
|
||||||
"src": "26:17:1",
|
"src": "66:14:1"
|
||||||
"typeName":
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"name": "uint",
|
|
||||||
"nodeType": "ElementaryTypeName",
|
|
||||||
"src": "38:4:1",
|
|
||||||
"typeDescriptions": {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"src": "13:32:1",
|
"src": "53:29:1",
|
||||||
"usedErrors": []
|
"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;
|
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;
|
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;
|
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