diff --git a/Changelog.md b/Changelog.md index 26ba5965d..b547c2aaa 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ Compiler Features: Bugfixes: + * Type Checker: Properly check restrictions of ``using ... global`` in conjunction with libraries. * Assembly-Json: Fix assembly json export to store jump types of operations in `jumpType` field instead of `value`. * TypeChecker: Convert parameters of function type to how they would be called for ``abi.encodeCall``. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index d83253b29..ed9875fce 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3638,11 +3638,36 @@ void TypeChecker::endVisit(Literal const& _literal) void TypeChecker::endVisit(UsingForDirective const& _usingFor) { + if (_usingFor.global()) + { + if (m_currentContract || !_usingFor.typeName()) + { + solAssert(m_errorReporter.hasErrors()); + return; + } + solAssert(_usingFor.typeName()->annotation().type); + 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." + ); + } + if (!_usingFor.usesBraces()) { solAssert(_usingFor.functionsOrLibrary().size() == 1); ContractDefinition const* library = dynamic_cast( - _usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration + _usingFor.functionsOrLibrary().front()->annotation().referencedDeclaration ); solAssert(library && library->isLibrary()); // No type checking for libraries @@ -3662,28 +3687,6 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor) ); 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 const& path: _usingFor.functionsOrLibrary()) { solAssert(path->annotation().referencedDeclaration); diff --git a/test/libsolidity/semanticTests/using/library_on_interface.sol b/test/libsolidity/semanticTests/using/library_on_interface.sol new file mode 100644 index 000000000..ff716dadb --- /dev/null +++ b/test/libsolidity/semanticTests/using/library_on_interface.sol @@ -0,0 +1,18 @@ +using L for I; +interface I { function f() external pure returns (uint); } +library L { + function execute(I i) internal pure returns (uint) { + return i.f(); + } +} +contract C is I { + function x() public view returns (uint) { + I i = this; + return i.execute(); + } + function f() public pure returns (uint) { return 7; } +} +// ==== +// compileViaYul: also +// ---- +// x() -> 7 diff --git a/test/libsolidity/semanticTests/using/using_global_all_the_types.sol b/test/libsolidity/semanticTests/using/using_global_all_the_types.sol new file mode 100644 index 000000000..b4f071fa2 --- /dev/null +++ b/test/libsolidity/semanticTests/using/using_global_all_the_types.sol @@ -0,0 +1,38 @@ +==== Source: A ==== +enum E {A, B} +struct S { uint x; } +type T is uint; +using L for E global; +using L for S global; +using L for T global; +library L { + function f(E e) internal pure returns (uint) { + return uint(e); + } + function f(S memory s) internal pure returns (uint) { + return s.x; + } + function f(T t) internal pure returns (uint) { + return T.unwrap(t); + } +} + +==== Source: B ==== +contract C { + function f() public pure returns (uint a, uint b, uint c) { + E e = E.B; + a = e.f(); + S memory s; + s.x = 7; + b = s.f(); + T t = T.wrap(9); + c = t.f(); + } +} + +import {E, S, T} from "A"; + +// ==== +// compileViaYul: also +// ---- +// f() -> 1, 7, 9 diff --git a/test/libsolidity/syntaxTests/using/global_inside_contract.sol b/test/libsolidity/syntaxTests/using/global_inside_contract.sol index edaeea922..54c01f99c 100644 --- a/test/libsolidity/syntaxTests/using/global_inside_contract.sol +++ b/test/libsolidity/syntaxTests/using/global_inside_contract.sol @@ -4,4 +4,3 @@ contract C { 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. diff --git a/test/libsolidity/syntaxTests/using/global_library_for_builtin.sol b/test/libsolidity/syntaxTests/using/global_library_for_builtin.sol new file mode 100644 index 000000000..7ff956941 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_library_for_builtin.sol @@ -0,0 +1,9 @@ +using L for uint global; +using L for uint[] global; +using L for function() returns (uint) global; +library L { +} +// ---- +// TypeError 8841: (0-24): Can only use "global" with user-defined types. +// TypeError 8841: (25-51): Can only use "global" with user-defined types. +// TypeError 8841: (52-97): Can only use "global" with user-defined types. diff --git a/test/libsolidity/syntaxTests/using/global_library_for_defined_elsewhere.sol b/test/libsolidity/syntaxTests/using/global_library_for_defined_elsewhere.sol new file mode 100644 index 000000000..f3f65890f --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_library_for_defined_elsewhere.sol @@ -0,0 +1,6 @@ +using L for L.S global; +library L { + struct S { uint x; } +} +// ---- +// TypeError 4117: (0-23): Can only use "global" with types defined in the same source unit at file level. diff --git a/test/libsolidity/syntaxTests/using/global_library_for_interface.sol b/test/libsolidity/syntaxTests/using/global_library_for_interface.sol new file mode 100644 index 000000000..06a644634 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_library_for_interface.sol @@ -0,0 +1,6 @@ +interface I {} +using L for I global; +library L { +} +// ---- +// TypeError 8841: (15-36): Can only use "global" with user-defined types. diff --git a/test/libsolidity/syntaxTests/using/global_library_foreign.sol b/test/libsolidity/syntaxTests/using/global_library_foreign.sol new file mode 100644 index 000000000..9eacc2c4b --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_library_foreign.sol @@ -0,0 +1,8 @@ +==== Source: A ==== +struct S { uint x; } +==== Source: B ==== +library L {} +using L for S global; +import {S} from "A"; +// ---- +// TypeError 4117: (B:13-34): Can only use "global" with types defined in the same source unit at file level. diff --git a/test/libsolidity/syntaxTests/using/global_library_with_asterisk.sol b/test/libsolidity/syntaxTests/using/global_library_with_asterisk.sol new file mode 100644 index 000000000..49ac6824d --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_library_with_asterisk.sol @@ -0,0 +1,5 @@ +using L for * global; +library L {} +// ---- +// SyntaxError 8118: (0-21): The type has to be specified explicitly at file level (cannot use '*'). +// SyntaxError 2854: (0-21): Can only globally bind functions to specific types. diff --git a/test/libsolidity/syntaxTests/using/global_with_asterisk.sol b/test/libsolidity/syntaxTests/using/global_with_asterisk.sol new file mode 100644 index 000000000..b5f6d8827 --- /dev/null +++ b/test/libsolidity/syntaxTests/using/global_with_asterisk.sol @@ -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.