mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
commit
e154d43176
@ -3,6 +3,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.
|
* 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.
|
||||||
|
* General: ``using ... for T global;`` is allowed at file level where the user-defined type ``T`` has been defined, resulting in the effect of the statement being available everywhere ``T`` is available.
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
@ -42,6 +42,13 @@ scope (either the contract or the current module/source unit),
|
|||||||
including within all of its functions, and has no effect
|
including within all of its functions, and has no effect
|
||||||
outside of the contract or module in which it is used.
|
outside of the contract or module in which it is used.
|
||||||
|
|
||||||
|
When the directive is used at file level and applied to a
|
||||||
|
user-defined type which was defined at file level in the same file,
|
||||||
|
the word ``global`` can be added at the end. This will have the
|
||||||
|
effect that the functions are attached to the type everywhere
|
||||||
|
the type is available (including other files), not only in the
|
||||||
|
scope of the using statement.
|
||||||
|
|
||||||
Let us rewrite the set example from the
|
Let us rewrite the set example from the
|
||||||
:ref:`libraries` section in this way, using file-level functions
|
:ref:`libraries` section in this way, using file-level functions
|
||||||
instead of library functions.
|
instead of library functions.
|
||||||
|
@ -47,6 +47,7 @@ FixedBytes:
|
|||||||
'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32';
|
'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32';
|
||||||
For: 'for';
|
For: 'for';
|
||||||
Function: 'function';
|
Function: 'function';
|
||||||
|
Global: 'global'; // not a real keyword
|
||||||
Hex: 'hex';
|
Hex: 'hex';
|
||||||
If: 'if';
|
If: 'if';
|
||||||
Immutable: 'immutable';
|
Immutable: 'immutable';
|
||||||
|
@ -315,7 +315,7 @@ errorDefinition:
|
|||||||
* Using directive to bind library functions and free functions to types.
|
* Using directive to bind library functions and free functions to types.
|
||||||
* Can occur within contracts and libraries and at the file level.
|
* Can occur within contracts and libraries and at the file level.
|
||||||
*/
|
*/
|
||||||
usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Semicolon;
|
usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Global? 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.
|
||||||
@ -389,7 +389,7 @@ inlineArrayExpression: LBrack (expression ( Comma expression)* ) RBrack;
|
|||||||
/**
|
/**
|
||||||
* Besides regular non-keyword Identifiers, some keywords like 'from' and 'error' can also be used as identifiers.
|
* Besides regular non-keyword Identifiers, some keywords like 'from' and 'error' can also be used as identifiers.
|
||||||
*/
|
*/
|
||||||
identifier: Identifier | From | Error | Revert;
|
identifier: Identifier | From | Error | Revert | Global;
|
||||||
|
|
||||||
literal: stringLiteral | numberLiteral | booleanLiteral | hexStringLiteral | unicodeStringLiteral;
|
literal: stringLiteral | numberLiteral | booleanLiteral | hexStringLiteral | unicodeStringLiteral;
|
||||||
booleanLiteral: True | False;
|
booleanLiteral: True | False;
|
||||||
|
@ -417,6 +417,18 @@ bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
|
|||||||
_usingFor.location(),
|
_usingFor.location(),
|
||||||
"The type has to be specified explicitly when attaching specific functions."
|
"The type has to be specified explicitly when attaching specific functions."
|
||||||
);
|
);
|
||||||
|
if (_usingFor.global() && !_usingFor.typeName())
|
||||||
|
m_errorReporter.syntaxError(
|
||||||
|
2854_error,
|
||||||
|
_usingFor.location(),
|
||||||
|
"Can only globally bind functions to specific types."
|
||||||
|
);
|
||||||
|
if (_usingFor.global() && m_currentContractKind)
|
||||||
|
m_errorReporter.syntaxError(
|
||||||
|
3367_error,
|
||||||
|
_usingFor.location(),
|
||||||
|
"\"global\" can only be used at file level."
|
||||||
|
);
|
||||||
if (m_currentContractKind == ContractKind::Interface)
|
if (m_currentContractKind == ContractKind::Interface)
|
||||||
m_errorReporter.syntaxError(
|
m_errorReporter.syntaxError(
|
||||||
9088_error,
|
9088_error,
|
||||||
|
@ -3656,6 +3656,28 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
|||||||
);
|
);
|
||||||
solAssert(normalizedType);
|
solAssert(normalizedType);
|
||||||
|
|
||||||
|
if (_usingFor.global())
|
||||||
|
{
|
||||||
|
if (m_currentContract)
|
||||||
|
solAssert(m_errorReporter.hasErrors());
|
||||||
|
if (Declaration const* typeDefinition = _usingFor.typeName()->annotation().type->typeDefinition())
|
||||||
|
{
|
||||||
|
if (typeDefinition->scope() != m_currentSourceUnit)
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
4117_error,
|
||||||
|
_usingFor.location(),
|
||||||
|
"Can only use \"global\" with types defined in the same source unit at file level."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
8841_error,
|
||||||
|
_usingFor.location(),
|
||||||
|
"Can only use \"global\" with user-defined types."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
for (ASTPointer<IdentifierPath> const& path: _usingFor.functionsOrLibrary())
|
for (ASTPointer<IdentifierPath> const& path: _usingFor.functionsOrLibrary())
|
||||||
{
|
{
|
||||||
solAssert(path->annotation().referencedDeclaration);
|
solAssert(path->annotation().referencedDeclaration);
|
||||||
|
@ -641,6 +641,10 @@ private:
|
|||||||
* For version 3, T has to be implicitly convertible to the first parameter type of
|
* 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
|
* 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.
|
* 2, this check is only done when a function is called.
|
||||||
|
*
|
||||||
|
* Finally, `using {f1, f2, ..., fn} for T global` is also valid at file level, as long as T is
|
||||||
|
* a user-defined type defined in the same file at file level. In this case, the methods are
|
||||||
|
* attached to all objects of that type regardless of scope.
|
||||||
*/
|
*/
|
||||||
class UsingForDirective: public ASTNode
|
class UsingForDirective: public ASTNode
|
||||||
{
|
{
|
||||||
@ -650,9 +654,14 @@ public:
|
|||||||
SourceLocation const& _location,
|
SourceLocation const& _location,
|
||||||
std::vector<ASTPointer<IdentifierPath>> _functions,
|
std::vector<ASTPointer<IdentifierPath>> _functions,
|
||||||
bool _usesBraces,
|
bool _usesBraces,
|
||||||
ASTPointer<TypeName> _typeName
|
ASTPointer<TypeName> _typeName,
|
||||||
|
bool _global
|
||||||
):
|
):
|
||||||
ASTNode(_id, _location), m_functions(_functions), m_usesBraces(_usesBraces), m_typeName(std::move(_typeName))
|
ASTNode(_id, _location),
|
||||||
|
m_functions(_functions),
|
||||||
|
m_usesBraces(_usesBraces),
|
||||||
|
m_typeName(std::move(_typeName)),
|
||||||
|
m_global{_global}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,12 +674,14 @@ public:
|
|||||||
/// @returns a list of functions or the single library.
|
/// @returns a list of functions or the single library.
|
||||||
std::vector<ASTPointer<IdentifierPath>> const& functionsOrLibrary() const { return m_functions; }
|
std::vector<ASTPointer<IdentifierPath>> const& functionsOrLibrary() const { return m_functions; }
|
||||||
bool usesBraces() const { return m_usesBraces; }
|
bool usesBraces() const { return m_usesBraces; }
|
||||||
|
bool global() const { return m_global; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Either the single library or a list of functions.
|
/// Either the single library or a list of functions.
|
||||||
std::vector<ASTPointer<IdentifierPath>> m_functions;
|
std::vector<ASTPointer<IdentifierPath>> m_functions;
|
||||||
bool m_usesBraces;
|
bool m_usesBraces;
|
||||||
ASTPointer<TypeName> m_typeName;
|
ASTPointer<TypeName> m_typeName;
|
||||||
|
bool m_global = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StructDefinition: public Declaration, public ScopeOpener
|
class StructDefinition: public Declaration, public ScopeOpener
|
||||||
|
@ -328,6 +328,7 @@ bool ASTJsonConverter::visit(UsingForDirective const& _node)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
attributes.emplace_back("libraryName", toJson(*_node.functionsOrLibrary().front()));
|
attributes.emplace_back("libraryName", toJson(*_node.functionsOrLibrary().front()));
|
||||||
|
attributes.emplace_back("global", _node.global());
|
||||||
|
|
||||||
setJsonNode(_node, "UsingForDirective", move(attributes));
|
setJsonNode(_node, "UsingForDirective", move(attributes));
|
||||||
|
|
||||||
|
@ -359,7 +359,8 @@ ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Val
|
|||||||
_node,
|
_node,
|
||||||
move(functions),
|
move(functions),
|
||||||
!_node.isMember("libraryName"),
|
!_node.isMember("libraryName"),
|
||||||
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"])
|
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"]),
|
||||||
|
memberAsBool(_node, "global")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +342,13 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc
|
|||||||
solAssert(sourceUnit, "");
|
solAssert(sourceUnit, "");
|
||||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
||||||
|
|
||||||
|
if (Declaration const* typeDefinition = _type.typeDefinition())
|
||||||
|
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(typeDefinition->scope()))
|
||||||
|
for (auto usingFor: ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes()))
|
||||||
|
// We do not yet compare the type name because of normalization.
|
||||||
|
if (usingFor->global() && usingFor->typeName())
|
||||||
|
usingForDirectives.emplace_back(usingFor);
|
||||||
|
|
||||||
// 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))
|
||||||
|
@ -987,9 +987,15 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
|||||||
advance();
|
advance();
|
||||||
else
|
else
|
||||||
typeName = parseTypeName();
|
typeName = parseTypeName();
|
||||||
|
bool global = false;
|
||||||
|
if (m_scanner->currentToken() == Token::Identifier && currentLiteral() == "global")
|
||||||
|
{
|
||||||
|
global = true;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::Semicolon);
|
expectToken(Token::Semicolon);
|
||||||
return nodeFactory.createNode<UsingForDirective>(move(functions), usesBraces, typeName);
|
return nodeFactory.createNode<UsingForDirective>(move(functions), usesBraces, typeName, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"global": false,
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"nodeType": "UsingForDirective",
|
"nodeType": "UsingForDirective",
|
||||||
"src": "0:19:1",
|
"src": "0:19:1",
|
||||||
@ -154,6 +155,7 @@
|
|||||||
"nodes":
|
"nodes":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"global": false,
|
||||||
"id": 12,
|
"id": 12,
|
||||||
"libraryName":
|
"libraryName":
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"global": false,
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"nodeType": "UsingForDirective",
|
"nodeType": "UsingForDirective",
|
||||||
"src": "0:19:1",
|
"src": "0:19:1",
|
||||||
@ -111,6 +112,7 @@
|
|||||||
"nodes":
|
"nodes":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"global": false,
|
||||||
"id": 12,
|
"id": 12,
|
||||||
"libraryName":
|
"libraryName":
|
||||||
{
|
{
|
||||||
|
25
test/libsolidity/semanticTests/using/recursive_import.sol
Normal file
25
test/libsolidity/semanticTests/using/recursive_import.sol
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
import {T as U} from "A";
|
||||||
|
import "A" as X;
|
||||||
|
|
||||||
|
type T is uint;
|
||||||
|
function f(T x) pure returns (T) { return T.wrap(T.unwrap(x) + 1); }
|
||||||
|
function g(T x) pure returns (uint) { return T.unwrap(x) + 10; }
|
||||||
|
|
||||||
|
using { f } for X.X.U global;
|
||||||
|
using { g } for T global;
|
||||||
|
|
||||||
|
function cr() pure returns (T) {}
|
||||||
|
|
||||||
|
==== Source: B ====
|
||||||
|
import { cr } from "A";
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
function f() public returns (uint) {
|
||||||
|
return cr().f().g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f() -> 11
|
@ -0,0 +1,20 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
type global is uint;
|
||||||
|
using { f } for global global;
|
||||||
|
function f(global x) pure returns (global) { return global.wrap(global.unwrap(x) + 1); }
|
||||||
|
==== Source: B ====
|
||||||
|
import { global } from "A";
|
||||||
|
|
||||||
|
function g(global x) pure returns (global) { return global.wrap(global.unwrap(x) + 10); }
|
||||||
|
|
||||||
|
contract C {
|
||||||
|
using { g } for global;
|
||||||
|
function f(global r) public pure returns (global) {
|
||||||
|
return r.f().g();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f(uint256): 100 -> 111
|
@ -0,0 +1,45 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
type T is uint;
|
||||||
|
using L for T global;
|
||||||
|
library L {
|
||||||
|
function inc(T x) internal pure returns (T) {
|
||||||
|
return T.wrap(T.unwrap(x) + 1);
|
||||||
|
}
|
||||||
|
function dec(T x) external pure returns (T) {
|
||||||
|
return T.wrap(T.unwrap(x) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
using {unwrap} for T global;
|
||||||
|
function unwrap(T x) pure returns (uint) {
|
||||||
|
return T.unwrap(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
==== Source: B ====
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns (T r1) {
|
||||||
|
r1 = r1.inc().inc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import {T} from "A";
|
||||||
|
|
||||||
|
==== Source: C ====
|
||||||
|
import {C} from "B";
|
||||||
|
|
||||||
|
contract D {
|
||||||
|
function test() public returns (uint) {
|
||||||
|
C c = new C();
|
||||||
|
// This tests that bound functions are available
|
||||||
|
// even if the type is not available by name.
|
||||||
|
// This is a regular function call, a
|
||||||
|
// public and an internal library call
|
||||||
|
// and a free function call.
|
||||||
|
return c.f().inc().inc().dec().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// library: "A":L
|
||||||
|
// test() -> 3
|
||||||
|
// gas legacy: 130369
|
@ -0,0 +1,27 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
type T is uint;
|
||||||
|
using L for T global;
|
||||||
|
library L {
|
||||||
|
function inc(T x) internal pure returns (T) {
|
||||||
|
return T.wrap(T.unwrap(x) + 1);
|
||||||
|
}
|
||||||
|
function dec(T x) external pure returns (T) {
|
||||||
|
return T.wrap(T.unwrap(x) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
==== Source: B ====
|
||||||
|
contract C {
|
||||||
|
function f() public pure returns (T r1, T r2) {
|
||||||
|
r1 = r1.inc().inc();
|
||||||
|
r2 = r1.dec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import {T} from "A";
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// library: "A":L
|
||||||
|
// f() -> 2, 1
|
21
test/libsolidity/syntaxTests/using/global_and_local.sol
Normal file
21
test/libsolidity/syntaxTests/using/global_and_local.sol
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
using {f} for S global;
|
||||||
|
struct S { uint x; }
|
||||||
|
function gen() pure returns (S memory) {}
|
||||||
|
function f(S memory _x) pure returns (uint) { return _x.x; }
|
||||||
|
==== Source: B ====
|
||||||
|
contract C {
|
||||||
|
using {fun} for S;
|
||||||
|
// Adds the same function again with the same name,
|
||||||
|
// so it's fine.
|
||||||
|
using {A.f} for S;
|
||||||
|
|
||||||
|
function test() pure public
|
||||||
|
{
|
||||||
|
uint p = g().f();
|
||||||
|
p = g().fun();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
import {gen as g, f as fun, S} from "A";
|
||||||
|
import "A" as A;
|
||||||
|
// ----
|
@ -0,0 +1,5 @@
|
|||||||
|
using {f} for * global;
|
||||||
|
function f(uint) pure{}
|
||||||
|
// ----
|
||||||
|
// SyntaxError 8118: (0-23): The type has to be specified explicitly at file level (cannot use '*').
|
||||||
|
// SyntaxError 2854: (0-23): Can only globally bind functions to specific types.
|
@ -0,0 +1,4 @@
|
|||||||
|
using {f} for uint global;
|
||||||
|
function f(uint) pure{}
|
||||||
|
// ----
|
||||||
|
// TypeError 8841: (0-26): Can only use "global" with user-defined types.
|
@ -0,0 +1,7 @@
|
|||||||
|
using {f} for L.S global;
|
||||||
|
function f(L.S memory) pure{}
|
||||||
|
library L {
|
||||||
|
struct S { uint x; }
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 4117: (0-25): Can only use "global" with types defined in the same source unit at file level.
|
@ -0,0 +1,14 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
struct S { uint x; }
|
||||||
|
==== Source: B ====
|
||||||
|
|
||||||
|
using {f} for S global;
|
||||||
|
using {f} for A.S global;
|
||||||
|
|
||||||
|
function f(S memory) pure{}
|
||||||
|
|
||||||
|
import {S} from "A";
|
||||||
|
import "A" as A;
|
||||||
|
// ----
|
||||||
|
// TypeError 4117: (B:1-24): Can only use "global" with types defined in the same source unit at file level.
|
||||||
|
// TypeError 4117: (B:25-50): Can only use "global" with types defined in the same source unit at file level.
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
using {f} for uint global;
|
||||||
|
}
|
||||||
|
function f(uint) pure{}
|
||||||
|
// ----
|
||||||
|
// SyntaxError 3367: (17-43): "global" can only be used at file level.
|
||||||
|
// TypeError 8841: (17-43): Can only use "global" with user-defined types.
|
21
test/libsolidity/syntaxTests/using/global_local_clash.sol
Normal file
21
test/libsolidity/syntaxTests/using/global_local_clash.sol
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
using {f} for S global;
|
||||||
|
struct S { uint x; }
|
||||||
|
function gen() pure returns (S memory) {}
|
||||||
|
function f(S memory _x) pure returns (uint) { return _x.x; }
|
||||||
|
function f1(S memory _x) pure returns (uint) { return _x.x + 1; }
|
||||||
|
==== Source: B ====
|
||||||
|
contract C {
|
||||||
|
// Here, f points to f1, so we end up with two different functions
|
||||||
|
// bound as S.f
|
||||||
|
using {f} for S;
|
||||||
|
|
||||||
|
function test() pure public
|
||||||
|
{
|
||||||
|
uint p = g().f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
import {gen as g, f1 as f, S} from "A";
|
||||||
|
import "A" as A;
|
||||||
|
// ----
|
||||||
|
// TypeError 6675: (B:181-186): Member "f" not unique after argument-dependent lookup in struct S memory.
|
17
test/libsolidity/syntaxTests/using/global_nonglobal.sol
Normal file
17
test/libsolidity/syntaxTests/using/global_nonglobal.sol
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
using {f} for S global;
|
||||||
|
using {g} for S;
|
||||||
|
struct S { uint x; }
|
||||||
|
function gen() pure returns (S memory) {}
|
||||||
|
function f(S memory _x) pure { _x.g(); }
|
||||||
|
function g(S memory _x) pure { }
|
||||||
|
==== Source: B ====
|
||||||
|
import "A";
|
||||||
|
function test() pure
|
||||||
|
{
|
||||||
|
gen().f();
|
||||||
|
gen().g();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
// TypeError 9582: (B:54-61): Member "g" not found or not visible after argument-dependent lookup in struct S memory.
|
15
test/libsolidity/syntaxTests/using/global_working.sol
Normal file
15
test/libsolidity/syntaxTests/using/global_working.sol
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
==== Source: A ====
|
||||||
|
using {f} for S global;
|
||||||
|
// this should not conflict
|
||||||
|
using {f} for S;
|
||||||
|
struct S { uint x; }
|
||||||
|
function gen() pure returns (S memory) {}
|
||||||
|
function f(S memory _x) pure returns (uint) { return _x.x; }
|
||||||
|
==== Source: B ====
|
||||||
|
function test() pure
|
||||||
|
{
|
||||||
|
uint p = g().f();
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
import {gen as g} from "A";
|
||||||
|
// ----
|
Loading…
Reference in New Issue
Block a user