From 0fe5811459bb25078e471ceeec475eaf49374d21 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 24 Jan 2022 11:56:27 +0100 Subject: [PATCH 01/28] Fixed a ICE on calldata to struct member copy --- Changelog.md | 1 + .../codegen/ir/IRGeneratorForStatements.cpp | 7 +- .../structs/copy_from_calldata.sol | 38 ++++++++ .../structs/copy_from_storage.sol | 24 +++++ .../copy_struct_array_from_storage.sol | 96 +++++++++++++++++++ .../structs/function_type_copy.sol | 44 +++++++++ .../msg_data_to_struct_member_copy.sol | 45 +++++++++ .../array/copy_from_function_type.sol | 9 ++ 8 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/structs/copy_from_calldata.sol create mode 100644 test/libsolidity/semanticTests/structs/copy_from_storage.sol create mode 100644 test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol create mode 100644 test/libsolidity/semanticTests/structs/function_type_copy.sol create mode 100644 test/libsolidity/semanticTests/structs/msg_data_to_struct_member_copy.sol create mode 100644 test/libsolidity/syntaxTests/array/copy_from_function_type.sol diff --git a/Changelog.md b/Changelog.md index 510feae9f..a49aedea4 100644 --- a/Changelog.md +++ b/Changelog.md @@ -18,6 +18,7 @@ Bugfixes: * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. * IR Generator: Add missing cleanup during the conversion of fixed bytes types to smaller fixed bytes types. * IR Generator: Add missing cleanup for indexed event arguments of value type. + * IR Generator: Fix internal error when copying reference types in calldata and storage to struct or array members in memory. * IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions. * Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different. * TypeChecker: Fix ICE when a constant variable declaration forward references a struct. diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index cf48df470..d68bc39c6 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -2985,8 +2985,11 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable { solAssert(_lvalue.type.sizeOnStack() == 1); auto const* valueReferenceType = dynamic_cast(&_value.type()); - solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory)); - appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n"; + solAssert(valueReferenceType); + if (valueReferenceType->dataStoredIn(DataLocation::Memory)) + appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n"; + else + appendCode() << "mstore(" + _memory.address + ", " + m_utils.conversionFunction(_value.type(), _lvalue.type) + "(" + _value.commaSeparatedList() + "))\n"; } }, [&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); }, diff --git a/test/libsolidity/semanticTests/structs/copy_from_calldata.sol b/test/libsolidity/semanticTests/structs/copy_from_calldata.sol new file mode 100644 index 000000000..bfe6fc949 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_from_calldata.sol @@ -0,0 +1,38 @@ +// Example from https://github.com/ethereum/solidity/issues/12558 +pragma abicoder v2; +contract C { + function f(uint[] calldata a) external returns (uint[][] memory) { + uint[][] memory m = new uint[][](2); + m[0] = a; + + return m; + } +} +contract Test { + C immutable c = new C(); + + function test() external returns (bool) { + uint[] memory arr = new uint[](4); + + arr[0] = 13; + arr[1] = 14; + arr[2] = 15; + arr[3] = 16; + + uint[][] memory ret = c.f(arr); + assert(ret.length == 2); + assert(ret[0].length == 4); + assert(ret[0][0] == 13); + assert(ret[0][1] == 14); + assert(ret[0][2] == 15); + assert(ret[0][3] == 16); + assert(ret[1].length == 0); + + return true; + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: also +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/structs/copy_from_storage.sol b/test/libsolidity/semanticTests/structs/copy_from_storage.sol new file mode 100644 index 000000000..d4a970bdc --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_from_storage.sol @@ -0,0 +1,24 @@ +pragma abicoder v2; +// Example from https://github.com/ethereum/solidity/issues/12558 +struct S { + uint x; +} + +contract C { + S sStorage; + constructor() { + sStorage.x = 13; + } + + function f() external returns (S[] memory) { + S[] memory sMemory = new S[](1); + + sMemory[0] = sStorage; + + return sMemory; + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0x20, 1, 13 diff --git a/test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol b/test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol new file mode 100644 index 000000000..7bbe495ce --- /dev/null +++ b/test/libsolidity/semanticTests/structs/copy_struct_array_from_storage.sol @@ -0,0 +1,96 @@ +pragma abicoder v2; + +struct S { uint value; } + +contract Test { + S[][] a; + S[] b; + + constructor() { + a.push(); + a[0].push(S(1)); + a[0].push(S(2)); + a[0].push(S(3)); + + b.push(S(4)); + b.push(S(5)); + b.push(S(6)); + b.push(S(7)); + } + + function test1() external returns (bool) { + a.push(); + a[1] = b; + + assert(a.length == 2); + assert(a[0].length == 3); + assert(a[1].length == 4); + assert(a[1][0].value == 4); + assert(a[1][1].value == 5); + assert(a[1][2].value == 6); + assert(a[1][3].value == 7); + + return true; + } + + function test2() external returns (bool) { + S[][] memory temp = new S[][](2); + + temp = a; + + assert(temp.length == 2); + assert(temp[0].length == 3); + assert(temp[1].length == 4); + assert(temp[1][0].value == 4); + assert(temp[1][1].value == 5); + assert(temp[1][2].value == 6); + assert(temp[1][3].value == 7); + + return true; + } + + function test3() external returns (bool) { + S[][] memory temp = new S[][](2); + + temp[0] = a[0]; + temp[1] = a[1]; + + assert(temp.length == 2); + assert(temp[0].length == 3); + assert(temp[1].length == 4); + assert(temp[1][0].value == 4); + assert(temp[1][1].value == 5); + assert(temp[1][2].value == 6); + assert(temp[1][3].value == 7); + + return true; + } + + function test4() external returns (bool) { + S[][] memory temp = new S[][](2); + + temp[0] = a[0]; + temp[1] = b; + + assert(temp.length == 2); + assert(temp[0].length == 3); + assert(temp[1].length == 4); + assert(temp[1][0].value == 4); + assert(temp[1][1].value == 5); + assert(temp[1][2].value == 6); + assert(temp[1][3].value == 7); + + return true; + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: also +// ---- +// test1() -> true +// gas irOptimized: 150618 +// gas legacy: 150266 +// gas legacyOptimized: 149875 +// test2() -> true +// test3() -> true +// test4() -> true diff --git a/test/libsolidity/semanticTests/structs/function_type_copy.sol b/test/libsolidity/semanticTests/structs/function_type_copy.sol new file mode 100644 index 000000000..79fe5ef4c --- /dev/null +++ b/test/libsolidity/semanticTests/structs/function_type_copy.sol @@ -0,0 +1,44 @@ +pragma abicoder v2; +struct S { + function () external[] functions; +} + +contract C { + function f(function () external[] calldata functions) external returns (S memory) { + S memory s; + s.functions = functions; + return s; + } +} + +contract Test { + C immutable c = new C(); + + function test() external returns (bool) { + function() external[] memory functions = new function() external[](3); + + functions[0] = this.random1; + functions[1] = this.random2; + functions[2] = this.random3; + + S memory ret = c.f(functions); + + assert(ret.functions.length == 3); + assert(ret.functions[0] == this.random1); + assert(ret.functions[1] == this.random2); + assert(ret.functions[2] == this.random3); + + return true; + } + function random1() external { + } + function random2() external { + } + function random3() external { + } +} +// ==== +// EVMVersion: >homestead +// compileViaYul: also +// ---- +// test() -> true diff --git a/test/libsolidity/semanticTests/structs/msg_data_to_struct_member_copy.sol b/test/libsolidity/semanticTests/structs/msg_data_to_struct_member_copy.sol new file mode 100644 index 000000000..f28bbf477 --- /dev/null +++ b/test/libsolidity/semanticTests/structs/msg_data_to_struct_member_copy.sol @@ -0,0 +1,45 @@ +pragma abicoder v2; + +struct St0 { + bytes el0; +} +contract C { + function f() external returns (St0 memory) { + St0 memory x; + x.el0 = msg.data; + return x; + } + + function g() external returns (St0 memory) { + bytes memory temp = msg.data; + St0 memory x; + x.el0 = temp; + return x; + } + + function hashes() external returns (bytes4, bytes4) { + return (this.f.selector, this.g.selector); + } + + function large(uint256, uint256, uint256, uint256) external returns (St0 memory) { + St0 memory x; + x.el0 = msg.data; + return x; + } + + function another_large(uint256, uint256, uint256, uint256) external returns (St0 memory) { + bytes memory temp = msg.data; + St0 memory x; + x.el0 = temp; + return x; + } + +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0x20, 0x20, 4, 0x26121ff000000000000000000000000000000000000000000000000000000000 +// g() -> 0x20, 0x20, 4, 0xe2179b8e00000000000000000000000000000000000000000000000000000000 +// hashes() -> 0x26121ff000000000000000000000000000000000000000000000000000000000, 0xe2179b8e00000000000000000000000000000000000000000000000000000000 +// large(uint256,uint256,uint256,uint256): 1, 2, 3, 4 -> 0x20, 0x20, 0x84, 0xe02492f800000000000000000000000000000000000000000000000000000000, 0x100000000000000000000000000000000000000000000000000000000, 0x200000000000000000000000000000000000000000000000000000000, 0x300000000000000000000000000000000000000000000000000000000, 0x400000000000000000000000000000000000000000000000000000000 +// another_large(uint256,uint256,uint256,uint256): 1, 2, 3, 4 -> 0x20, 0x20, 0x84, 0x2a46f85a00000000000000000000000000000000000000000000000000000000, 0x100000000000000000000000000000000000000000000000000000000, 0x200000000000000000000000000000000000000000000000000000000, 0x300000000000000000000000000000000000000000000000000000000, 0x400000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/syntaxTests/array/copy_from_function_type.sol b/test/libsolidity/syntaxTests/array/copy_from_function_type.sol new file mode 100644 index 000000000..b79509468 --- /dev/null +++ b/test/libsolidity/syntaxTests/array/copy_from_function_type.sol @@ -0,0 +1,9 @@ +// Example from https://github.com/ethereum/solidity/issues/12558 +pragma abicoder v2; +contract C { + function() external[1][] s0; + constructor(function() external[1][] memory i0) + { + i0[0] = s0[1]; + } +} From f1ce1528bb988fe3d51f3cc98e16dd1b5eaa9d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 28 Jan 2022 21:46:01 +0100 Subject: [PATCH 02/28] Update the release checklist to use the build+publish commands for solc-js --- ReleaseChecklist.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md index b95ea32a9..39a3d9a32 100644 --- a/ReleaseChecklist.md +++ b/ReleaseChecklist.md @@ -66,7 +66,8 @@ ### Release solc-js - [ ] Wait until solc-bin was properly deployed. You can test this via remix - a test run through remix is advisable anyway. - [ ] Increment the version number, create a pull request for that, merge it after tests succeeded. - - [ ] Run ``npm run updateBinary && npm publish`` in the updated ``solc-js`` repository. + - [ ] Run ``npm run build:tarball`` in the updated ``solc-js`` repository to create ``solc-.tgz``. Inspect the tarball to ensure that it contains an up to date compiler binary. + - [ ] Run ``npm run publish:tarball`` to publish the newly created tarball. - [ ] Create a tag using ``git tag --annotate v$VERSION`` and push it with ``git push --tags``. ### Post-release From 8728971354c15b1a8147726fa8c3efe8c801f0ee Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 31 Jan 2022 19:07:01 +0100 Subject: [PATCH 03/28] Correct type of address.code --- docs/types/value-types.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 215a18cee..30a857796 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -331,7 +331,9 @@ on ``call``. * ``code`` and ``codehash`` -You can query the deployed code for any smart contract. Use ``code`` to get the EVM bytecode as a string, which might be empty. Use ``codehash`` get the Keccak-256 hash of that code. +You can query the deployed code for any smart contract. Use ``.code`` to get the EVM bytecode as a +``bytes memory``, which might be empty. Use ``.codehash`` get the Keccak-256 hash of that code +(as a ``bytes32``). Note that ``addr.codehash`` is cheaper than using ``keccak256(addr.code)``. .. note:: All contracts can be converted to ``address`` type, so it is possible to query the balance of the From 4259e1bb7021d28931bf3d3f5973e32431f2c837 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 31 Jan 2022 19:18:32 +0100 Subject: [PATCH 04/28] Fix changelog --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index a49aedea4..e75e2c710 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,7 +15,7 @@ Bugfixes: * Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots. * Code Generator: Fix ICE when doing an explicit conversion from ``string calldata`` to ``bytes``. * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. - * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. + * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the derived contract contains immutable variables. * IR Generator: Add missing cleanup during the conversion of fixed bytes types to smaller fixed bytes types. * IR Generator: Add missing cleanup for indexed event arguments of value type. * IR Generator: Fix internal error when copying reference types in calldata and storage to struct or array members in memory. From 73470aed6afb172f189a550b79e310c9cac8c680 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 3 Nov 2021 16:10:14 +0100 Subject: [PATCH 05/28] Fix util::valueOrDefault. --- libsolutil/CommonData.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libsolutil/CommonData.h b/libsolutil/CommonData.h index 0d5a75282..b117c2772 100644 --- a/libsolutil/CommonData.h +++ b/libsolutil/CommonData.h @@ -267,17 +267,22 @@ template< typename MapType, typename KeyType, typename ValueType = std::decay_t().find(std::declval())->second)> const&, - typename AllowCopyType = void* + typename AllowCopyType = std::conditional_t || std::is_pointer_v, detail::allow_copy, void*> > -decltype(auto) valueOrDefault(MapType&& _map, KeyType const& _key, ValueType&& _defaultValue = {}, AllowCopyType = nullptr) +decltype(auto) valueOrDefault( + MapType&& _map, + KeyType const& _key, + ValueType&& _defaultValue = {}, + AllowCopyType = {} +) { auto it = _map.find(_key); static_assert( std::is_same_v || - std::is_reference_vsecond)>, + std::is_reference_v(_defaultValue) : it->second)>, "valueOrDefault does not allow copies by default. Pass allow_copy as additional argument, if you want to allow copies." ); - return (it == _map.end()) ? _defaultValue : it->second; + return (it == _map.end()) ? std::forward(_defaultValue) : it->second; } namespace detail From 8bcc4ee7d1a65f4732549f31cd7d5e8194c6c260 Mon Sep 17 00:00:00 2001 From: franzihei Date: Mon, 31 Jan 2022 15:32:49 +0100 Subject: [PATCH 06/28] Adding a few resources --- docs/resources.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/resources.rst b/docs/resources.rst index 5b8d0013a..a3b8d17e0 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -14,7 +14,7 @@ General Resources * `Solidity Compiler Developers Chat `_ * `Awesome Solidity `_ * `Solidity by Example `_ - +* `Solidity Documentation Community Translations `_ Integrated (Ethereum) Development Environments ============================================== @@ -28,15 +28,15 @@ Integrated (Ethereum) Development Environments * `Embark `_ Developer platform for building and deploying decentralized applications. + * `Foundry `_ + Fast, portable and modular toolkit for Ethereum application development written in Rust. + * `Hardhat `_ Ethereum development environment with local Ethereum network, debugging features and plugin ecosystem. * `Remix `_ Browser-based IDE with integrated compiler and Solidity runtime environment without server-side components. - * `Scaffold-ETH `_ - Ethereum development stack focused on fast product iterations. - * `Truffle `_ Ethereum development framework. @@ -112,6 +112,9 @@ Solidity Tools * `PIET `_ A tool to develop, audit and use Solidity smart contracts through a simple graphical interface. +* `Scaffold-ETH `_ + Forkable Ethereum development stack focused on fast product iterations. + * `sol2uml `_ Unified Modeling Language (UML) class diagram generator for Solidity contracts. @@ -130,6 +133,9 @@ Solidity Tools * `Solhint `_ Solidity linter that provides security, style guide and best practice rules for smart contract validation. +* `Sourcify `_ + Decentralized automated contract verification service and public repository of contract metadata. + * `Sūrya `_ Utility tool for smart contract systems, offering a number of visual outputs and information about the contracts' structure. Also supports querying the function call graph. From e2711b7fabcbf3af0c15e415778d821c1581d913 Mon Sep 17 00:00:00 2001 From: nishant-sachdeva Date: Tue, 25 Jan 2022 20:31:01 +0530 Subject: [PATCH 07/28] Corresponding code in the .cpp file has been commented instead of begin removed pending preliminary reviews Code generators needed fixing of the cleanup process during typecasting of bytes and integers --- .../codegen/ir/IRGeneratorForStatements.cpp | 37 ++++++++++++------- .../codegen/ir/IRGeneratorForStatements.h | 30 +++++++++++---- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index d68bc39c6..86d00dbc9 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -805,8 +805,8 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) if (auto type = dynamic_cast(commonType)) isSigned = type->isSigned(); - string args = expressionAsType(_binOp.leftExpression(), *commonType, true); - args += ", " + expressionAsType(_binOp.rightExpression(), *commonType, true); + string args = expressionAsCleanedType(_binOp.leftExpression(), *commonType); + args += ", " + expressionAsCleanedType(_binOp.rightExpression(), *commonType); auto functionType = dynamic_cast(commonType); solAssert(functionType ? (op == Token::Equal || op == Token::NotEqual) : true, "Invalid function pointer comparison!"); @@ -1037,7 +1037,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) else { solAssert(parameterTypes[i]->sizeOnStack() == 1, ""); - indexedArgs.emplace_back(convert(arg, *paramTypes[i], true)); + indexedArgs.emplace_back(convertAndCleanup(arg, *parameterTypes[i])); } } else @@ -2727,32 +2727,43 @@ void IRGeneratorForStatements::assignInternalFunctionIDIfNotCalledDirectly( m_context.addToInternalDispatch(_referencedFunction); } -IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const& _to, bool _forceCleanup) +IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const& _to) { - if (_from.type() == _to && !_forceCleanup) + if (_from.type() == _to) return _from; else { IRVariable converted(m_context.newYulVariable(), _to); - define(converted, _from, _forceCleanup); + define(converted, _from); return converted; } } -std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup) +IRVariable IRGeneratorForStatements::convertAndCleanup(IRVariable const& _from, Type const& _to) +{ + IRVariable converted(m_context.newYulVariable(), _to); + defineAndCleanup(converted, _from); + return converted; +} + +std::string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to) { IRVariable from(_expression); if (from.type() == _to) - { - if (_forceCleanup) - return m_utils.cleanupFunction(_to) + "(" + from.commaSeparatedList() + ")"; - else - return from.commaSeparatedList(); - } + return from.commaSeparatedList(); else return m_utils.conversionFunction(from.type(), _to) + "(" + from.commaSeparatedList() + ")"; } +std::string IRGeneratorForStatements::expressionAsCleanedType(Expression const& _expression, Type const& _to) +{ + IRVariable from(_expression); + if (from.type() == _to) + return m_utils.cleanupFunction(_to) + "(" + expressionAsType(_expression, _to) + ")"; + else + return expressionAsType(_expression, _to) ; +} + std::ostream& IRGeneratorForStatements::define(IRVariable const& _var) { if (_var.type().sizeOnStack() > 0) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 10e8f0b5e..11f8b3c84 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -86,10 +86,19 @@ public: IRVariable evaluateExpression(Expression const& _expression, Type const& _to); /// Defines @a _var using the value of @a _value while performing type conversions, if required. - /// If @a _forceCleanup is set to true, it also cleans the value of the variable after the conversion. - void define(IRVariable const& _var, IRVariable const& _value, bool _forceCleanup = false) + void define(IRVariable const& _var, IRVariable const& _value) { - declareAssign(_var, _value, true, _forceCleanup); + bool _declare = true; + declareAssign(_var, _value, _declare); + } + + /// Defines @a _var using the value of @a _value while performing type conversions, if required. + /// It also cleans the value of the variable. + void defineAndCleanup(IRVariable const& _var, IRVariable const& _value) + { + bool _forceCleanup = true; + bool _declare = true; + declareAssign(_var, _value, _declare, _forceCleanup); } /// @returns the name of a function that computes the value of the given constant @@ -166,13 +175,20 @@ private: ); /// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable - /// If @a _forceCleanup is set to true, it also cleans the value of the variable after the conversion. - IRVariable convert(IRVariable const& _variable, Type const& _to, bool _forceCleanup = false); + IRVariable convert(IRVariable const& _variable, Type const& _to); + + /// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable + /// It also cleans the value of the variable. + IRVariable convertAndCleanup(IRVariable const& _from, Type const& _to); /// @returns a Yul expression representing the current value of @a _expression, /// converted to type @a _to if it does not yet have that type. - /// If @a _forceCleanup is set to true, it also cleans the value, in case it already has type @a _to. - std::string expressionAsType(Expression const& _expression, Type const& _to, bool _forceCleanup = false); + std::string expressionAsType(Expression const& _expression, Type const& _to); + + /// @returns a Yul expression representing the current value of @a _expression, + /// converted to type @a _to if it does not yet have that type. + /// It also cleans the value, in case it already has type @a _to. + std::string expressionAsCleanedType(Expression const& _expression, Type const& _to); /// @returns an output stream that can be used to define @a _var using a function call or /// single stack slot expression. From 1528d4b9e4e8de6771ce15da90341e96d08dba86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 1 Feb 2022 14:34:03 +0100 Subject: [PATCH 08/28] perpetual-pools: Switch the test to our fork (original repo is gone) --- test/externalTests/perpetual-pools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/externalTests/perpetual-pools.sh b/test/externalTests/perpetual-pools.sh index 6c4af4937..e1ee9af8f 100755 --- a/test/externalTests/perpetual-pools.sh +++ b/test/externalTests/perpetual-pools.sh @@ -34,7 +34,7 @@ function test_fn { yarn test; } function perpetual_pools_test { - local repo="https://github.com/tracer-protocol/perpetual-pools-contracts" + local repo="https://github.com/solidity-external-tests/perpetual-pools-contracts" local ref_type=branch local ref=pools-v2 local config_file="hardhat.config.ts" From 6788f77541729e3ab2bc9e41dda66c2c06540b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 1 Feb 2022 15:25:13 +0100 Subject: [PATCH 09/28] Add missing SELECTED_PRESETS argument to some of the recently added external tests --- test/externalTests/bleeps.sh | 1 + test/externalTests/elementfi.sh | 1 + test/externalTests/trident.sh | 1 + test/externalTests/uniswap.sh | 1 + 4 files changed, 4 insertions(+) diff --git a/test/externalTests/bleeps.sh b/test/externalTests/bleeps.sh index df0e5e39e..a4d1efa62 100755 --- a/test/externalTests/bleeps.sh +++ b/test/externalTests/bleeps.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { npm run compile; } function test_fn { npm run test; } diff --git a/test/externalTests/elementfi.sh b/test/externalTests/elementfi.sh index 7227ce37e..f52a13ca6 100755 --- a/test/externalTests/elementfi.sh +++ b/test/externalTests/elementfi.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { npm run build; } function test_fn { npm run test; } diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index 26c3d3810..8e6f35ae3 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { yarn build; } diff --git a/test/externalTests/uniswap.sh b/test/externalTests/uniswap.sh index b3baad1a3..96a5d2b63 100755 --- a/test/externalTests/uniswap.sh +++ b/test/externalTests/uniswap.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { yarn compile; } function test_fn { UPDATE_SNAPSHOT=1 npx hardhat test; } From 57800529d1f54daa5d5c961532362dd50a62405d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 1 Feb 2022 16:40:08 +0100 Subject: [PATCH 10/28] bleeps: Switch to the main branch --- test/externalTests/bleeps.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/externalTests/bleeps.sh b/test/externalTests/bleeps.sh index a4d1efa62..70f69d460 100755 --- a/test/externalTests/bleeps.sh +++ b/test/externalTests/bleeps.sh @@ -35,8 +35,8 @@ function test_fn { npm run test; } function bleeps_test { local repo="https://github.com/wighawag/bleeps" - local ref_type=tag - local ref=bleeps_migrations # TODO: There's a 0.4.19 contract in 'main' that would need patching for the latest compiler. + local ref_type=branch + local ref=main local config_file="hardhat.config.ts" local config_var=config From e1a90b829e395d5356812d461322e465506c501e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 1 Feb 2022 16:40:28 +0100 Subject: [PATCH 11/28] bleeps: Patch WETH9.sol for 0.8.x --- test/externalTests/bleeps.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/externalTests/bleeps.sh b/test/externalTests/bleeps.sh index 70f69d460..d005cf8ef 100755 --- a/test/externalTests/bleeps.sh +++ b/test/externalTests/bleeps.sh @@ -66,6 +66,12 @@ function bleeps_test pushd "contracts/" sed -i 's|"bleeps-common": "workspace:\*",|"bleeps-common": "file:../common-lib/",|g' package.json + sed -i 's/function() public/fallback() external/g' src/externals/WETH9.sol + sed -i 's/this\.balance/address(this).balance/g' src/externals/WETH9.sol + sed -i 's/uint(-1)/type(uint).max/g' src/externals/WETH9.sol + sed -i 's/msg\.sender\.transfer(/payable(msg.sender).transfer(/g' src/externals/WETH9.sol + sed -i 's/^\s*\(Deposit\|Withdrawal\|Approval\|Transfer\)(/emit \1(/g' src/externals/WETH9.sol + neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" From 1e0a695d241dcf430c485dfdfb1d9e2b454fdb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 1 Feb 2022 17:01:10 +0100 Subject: [PATCH 12/28] Disable bleeps external test until it gets fixed upstream --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 143a692fd..44b44bb01 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1468,7 +1468,8 @@ workflows: - t_ems_ext: *job_native_test_ext_trident - t_ems_ext: *job_native_test_ext_euler - t_ems_ext: *job_native_test_ext_yield_liquidator - - t_ems_ext: *job_native_test_ext_bleeps + # Disabled until we have a fix for https://github.com/wighawag/bleeps/issues/2 + #-t_ems_ext: *job_native_test_ext_bleeps - t_ems_ext: *job_native_test_ext_pool_together - t_ems_ext: *job_native_test_ext_perpetual_pools - t_ems_ext: *job_native_test_ext_uniswap From 9043621747de80cfb6b4a5e890f062d6e962d27d Mon Sep 17 00:00:00 2001 From: nishant-sachdeva Date: Fri, 28 Jan 2022 23:27:05 +0530 Subject: [PATCH 13/28] Changed occurences of isByteArray() to isByteArrayOrString(). The idea is to, in a future commit, replace such occurences of isByteArrayOrString() which are required to return True only for Bytes type with a new isByteArray() function. --- .../analysis/DeclarationTypeChecker.cpp | 2 +- libsolidity/analysis/TypeChecker.cpp | 4 +- libsolidity/ast/Types.cpp | 26 ++++---- libsolidity/ast/Types.h | 8 +-- libsolidity/codegen/ABIFunctions.cpp | 24 +++---- libsolidity/codegen/ArrayUtils.cpp | 58 ++++++++-------- libsolidity/codegen/CompilerUtils.cpp | 12 ++-- libsolidity/codegen/ExpressionCompiler.cpp | 14 ++-- libsolidity/codegen/YulUtilFunctions.cpp | 66 +++++++++---------- libsolidity/codegen/ir/IRGenerator.cpp | 4 +- .../codegen/ir/IRGeneratorForStatements.cpp | 6 +- libsolidity/formal/SMTEncoder.cpp | 10 +-- libsolidity/formal/SymbolicTypes.cpp | 2 +- libsolidity/interface/ABI.cpp | 2 +- libsolidity/interface/StorageLayout.cpp | 2 +- 15 files changed, 120 insertions(+), 120 deletions(-) diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index 7a4aa9942..ba989972c 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -441,7 +441,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) { bool allowed = false; if (auto arrayType = dynamic_cast(type)) - allowed = arrayType->isByteArray(); + allowed = arrayType->isByteArrayOrString(); if (!allowed) m_errorReporter.fatalTypeError(9259_error, _variable.location(), "Only constants of value type and byte array type are implemented."); } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index f3ba2884b..1a07d6ded 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1783,7 +1783,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( ( ( resultArrayType->isPointer() || - (argArrayType->isByteArray() && resultArrayType->isByteArray()) + (argArrayType->isByteArrayOrString() && resultArrayType->isByteArrayOrString()) ) && resultArrayType->location() == DataLocation::Storage ), @@ -1791,7 +1791,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( ); else solAssert( - argArrayType->isByteArray() && !argArrayType->isString() && resultType->category() == Type::Category::FixedBytes, + argArrayType->isByteArrayOrString() && !argArrayType->isString() && resultType->category() == Type::Category::FixedBytes, "" ); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index fb31a9303..f50210ff5 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1206,7 +1206,7 @@ BoolResult StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) ); return arrayType->location() != DataLocation::CallData && - arrayType->isByteArray() && + arrayType->isByteArrayOrString() && !(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer()); } else @@ -1530,7 +1530,7 @@ BoolResult ArrayType::isImplicitlyConvertibleTo(Type const& _convertTo) const if (_convertTo.category() != category()) return false; auto& convertTo = dynamic_cast(_convertTo); - if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString()) + if (convertTo.isByteArrayOrString() != isByteArrayOrString() || convertTo.isString() != isString()) return false; // memory/calldata to storage can be converted, but only to a direct storage reference if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer()) @@ -1571,11 +1571,11 @@ BoolResult ArrayType::isExplicitlyConvertibleTo(Type const& _convertTo) const return true; // allow conversion bytes <-> string and bytes -> bytesNN if (_convertTo.category() != category()) - return isByteArray() && !isString() && _convertTo.category() == Type::Category::FixedBytes; + return isByteArrayOrString() && !isString() && _convertTo.category() == Type::Category::FixedBytes; auto& convertTo = dynamic_cast(_convertTo); if (convertTo.location() != location()) return false; - if (!isByteArray() || !convertTo.isByteArray()) + if (!isByteArrayOrString() || !convertTo.isByteArrayOrString()) return false; return true; } @@ -1585,7 +1585,7 @@ string ArrayType::richIdentifier() const string id; if (isString()) id = "t_string"; - else if (isByteArray()) + else if (isByteArrayOrString()) id = "t_bytes"; else { @@ -1608,7 +1608,7 @@ bool ArrayType::operator==(Type const& _other) const ArrayType const& other = dynamic_cast(_other); if ( !ReferenceType::operator==(other) || - other.isByteArray() != isByteArray() || + other.isByteArrayOrString() != isByteArrayOrString() || other.isString() != isString() || other.isDynamicallySized() != isDynamicallySized() ) @@ -1751,7 +1751,7 @@ string ArrayType::toString(bool _short) const string ret; if (isString()) ret = "string"; - else if (isByteArray()) + else if (isByteArrayOrString()) ret = "bytes"; else { @@ -1770,7 +1770,7 @@ string ArrayType::canonicalName() const string ret; if (isString()) ret = "string"; - else if (isByteArray()) + else if (isByteArrayOrString()) ret = "bytes"; else { @@ -1784,7 +1784,7 @@ string ArrayType::canonicalName() const string ArrayType::signatureInExternalFunction(bool _structsByName) const { - if (isByteArray()) + if (isByteArrayOrString()) return canonicalName(); else { @@ -1899,7 +1899,7 @@ u256 ArrayType::memoryDataSize() const { solAssert(!isDynamicallySized(), ""); solAssert(m_location == DataLocation::Memory, ""); - solAssert(!isByteArray(), ""); + solAssert(!isByteArrayOrString(), ""); bigint size = bigint(m_length) * m_baseType->memoryHeadSize(); solAssert(size <= numeric_limits::max(), "Array size does not fit u256."); return u256(size); @@ -2701,7 +2701,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): } else if (auto arrayType = dynamic_cast(returnType)) { - if (arrayType->isByteArray()) + if (arrayType->isByteArrayOrString()) // Return byte arrays as whole. break; returnType = arrayType->baseType(); @@ -2720,7 +2720,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): if (member.type->category() != Category::Mapping) { if (auto arrayType = dynamic_cast(member.type)) - if (!arrayType->isByteArray()) + if (!arrayType->isByteArrayOrString()) continue; m_returnParameterTypes.push_back(TypeProvider::withLocationIfReference( DataLocation::Memory, @@ -3813,7 +3813,7 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons } else if ( auto const* arrayType = dynamic_cast(m_actualType); - arrayType && arrayType->isByteArray() + arrayType && arrayType->isByteArrayOrString() ) members.emplace_back("concat", TypeProvider::function( TypePointers{}, diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index f15da58ab..e34c11405 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -838,7 +838,7 @@ public: BoolResult validForLocation(DataLocation _loc) const override; /// @returns true if this is a byte array or a string - bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; } + bool isByteArrayOrString() const { return m_arrayKind != ArrayKind::Ordinary; } /// @returns true if this is a string bool isString() const { return m_arrayKind == ArrayKind::String; } Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; } @@ -849,11 +849,11 @@ public: std::unique_ptr copyForLocation(DataLocation _location, bool _isPointer) const override; /// The offset to advance in calldata to move from one array element to the next. - unsigned calldataStride() const { return isByteArray() ? 1 : m_baseType->calldataHeadSize(); } + unsigned calldataStride() const { return isByteArrayOrString() ? 1 : m_baseType->calldataHeadSize(); } /// The offset to advance in memory to move from one array element to the next. - unsigned memoryStride() const { return isByteArray() ? 1 : m_baseType->memoryHeadSize(); } + unsigned memoryStride() const { return isByteArrayOrString() ? 1 : m_baseType->memoryHeadSize(); } /// The offset to advance in storage to move from one array element to the next. - unsigned storageStride() const { return isByteArray() ? 1 : m_baseType->storageBytes(); } + unsigned storageStride() const { return isByteArrayOrString() ? 1 : m_baseType->storageBytes(); } void clearCache() const override; diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 97cf3425d..65f9e1723 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -312,7 +312,7 @@ string ABIFunctions::abiEncodingFunction( { case DataLocation::CallData: if ( - fromArray->isByteArray() || + fromArray->isByteArrayOrString() || *fromArray->baseType() == *TypeProvider::uint256() || *fromArray->baseType() == FixedBytesType(32) ) @@ -320,7 +320,7 @@ string ABIFunctions::abiEncodingFunction( else return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); case DataLocation::Memory: - if (fromArray->isByteArray()) + if (fromArray->isByteArrayOrString()) return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options); else return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options); @@ -448,7 +448,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup( solAssert(fromArrayType.location() == DataLocation::CallData, ""); solAssert( - fromArrayType.isByteArray() || + fromArrayType.isByteArrayOrString() || *fromArrayType.baseType() == *TypeProvider::uint256() || *fromArrayType.baseType() == FixedBytesType(32), "" @@ -468,7 +468,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup( _to.identifier() + _options.toFunctionNameSuffix(); return createFunction(functionName, [&]() { - bool needsPadding = _options.padded && fromArrayType.isByteArray(); + bool needsPadding = _options.padded && fromArrayType.isByteArrayOrString(); if (fromArrayType.isDynamicallySized()) { Whiskers templ(R"( @@ -482,7 +482,7 @@ string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup( )"); templ("storeLength", arrayStoreLengthForEncodingFunction(toArrayType, _options)); templ("functionName", functionName); - if (fromArrayType.isByteArray() || fromArrayType.calldataStride() == 1) + if (fromArrayType.isByteArrayOrString() || fromArrayType.calldataStride() == 1) templ("scaleLengthByStride", ""); else templ("scaleLengthByStride", @@ -536,7 +536,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray( solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), ""); solAssert(_from.length() == _to.length(), ""); - solAssert(!_from.isByteArray(), ""); + solAssert(!_from.isByteArrayOrString(), ""); if (_from.dataStoredIn(DataLocation::Storage)) solAssert(_from.baseType()->storageBytes() > 16, ""); @@ -647,10 +647,10 @@ string ABIFunctions::abiEncodingFunctionMemoryByteArray( solAssert(_from.isDynamicallySized() == _to.isDynamicallySized(), ""); solAssert(_from.length() == _to.length(), ""); solAssert(_from.dataStoredIn(DataLocation::Memory), ""); - solAssert(_from.isByteArray(), ""); + solAssert(_from.isByteArrayOrString(), ""); return createFunction(functionName, [&]() { - solAssert(_to.isByteArray(), ""); + solAssert(_to.isByteArrayOrString(), ""); Whiskers templ(R"( function (value, pos) -> end { let length := (value) @@ -686,9 +686,9 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray( solAssert(_from.dataStoredIn(DataLocation::Storage), ""); return createFunction(functionName, [&]() { - if (_from.isByteArray()) + if (_from.isByteArrayOrString()) { - solAssert(_to.isByteArray(), ""); + solAssert(_to.isByteArrayOrString(), ""); Whiskers templ(R"( // -> function (value, pos) -> ret { @@ -1168,7 +1168,7 @@ string ABIFunctions::abiDecodingFunctionArray(ArrayType const& _type, bool _from string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory) { solAssert(_type.dataStoredIn(DataLocation::Memory), ""); - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) return abiDecodingFunctionByteArrayAvailableLength(_type, _fromMemory); solAssert(_type.calldataStride() > 0, ""); @@ -1275,7 +1275,7 @@ string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _type) string ABIFunctions::abiDecodingFunctionByteArrayAvailableLength(ArrayType const& _type, bool _fromMemory) { solAssert(_type.dataStoredIn(DataLocation::Memory), ""); - solAssert(_type.isByteArray(), ""); + solAssert(_type.isByteArrayOrString(), ""); string functionName = "abi_decode_available_length_" + diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 27afe1498..d2691c877 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -50,8 +50,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons solAssert(_targetType.location() == DataLocation::Storage, ""); Type const* uint256 = TypeProvider::uint256(); - Type const* targetBaseType = _targetType.isByteArray() ? uint256 : _targetType.baseType(); - Type const* sourceBaseType = _sourceType.isByteArray() ? uint256 : _sourceType.baseType(); + Type const* targetBaseType = _targetType.isByteArrayOrString() ? uint256 : _targetType.baseType(); + Type const* sourceBaseType = _sourceType.isByteArrayOrString() ? uint256 : _sourceType.baseType(); // TODO unroll loop for small sizes @@ -97,7 +97,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // stack: target_ref source_ref source_length target_ref target_length if (_targetType.isDynamicallySized()) // store new target length - if (!_targetType.isByteArray()) + if (!_targetType.isByteArrayOrString()) // Otherwise, length will be stored below. _context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE; if (sourceBaseType->category() == Type::Category::Mapping) @@ -126,7 +126,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons evmasm::AssemblyItem copyLoopEndWithoutByteOffset = _context.newTag(); // special case for short byte arrays: Store them together with their length. - if (_targetType.isByteArray()) + if (_targetType.isByteArrayOrString()) { // stack: target_ref target_data_end source_length target_data_pos source_ref _context << Instruction::DUP3; @@ -141,7 +141,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons _context << Instruction::DUP3 << u256(31) << Instruction::LT; evmasm::AssemblyItem longByteArray = _context.appendConditionalJump(); // store the short byte array - solAssert(_sourceType.isByteArray(), ""); + solAssert(_sourceType.isByteArrayOrString(), ""); if (_sourceType.location() == DataLocation::Storage) { // just copy the slot, it contains length and data @@ -323,7 +323,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord { if (!_sourceType.isDynamicallySized()) m_context << _sourceType.length(); - if (!_sourceType.isByteArray()) + if (!_sourceType.isByteArrayOrString()) convertLengthToSize(_sourceType); string routine = "calldatacopy(target, source, len)\n"; @@ -375,14 +375,14 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD; m_context << Instruction::SWAP1; } - if (!_sourceType.isByteArray()) + if (!_sourceType.isByteArrayOrString()) convertLengthToSize(_sourceType); // stack: m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4; // We can resort to copying full 32 bytes only if // - the length is known to be a multiple of 32 or // - we will pad to full 32 bytes later anyway. - if (!_sourceType.isByteArray() || _padToWordBoundaries) + if (!_sourceType.isByteArrayOrString() || _padToWordBoundaries) utils.memoryCopy32(); else utils.memoryCopy(); @@ -390,7 +390,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord m_context << Instruction::SWAP1 << Instruction::POP; // stack: - bool paddingNeeded = _padToWordBoundaries && _sourceType.isByteArray(); + bool paddingNeeded = _padToWordBoundaries && _sourceType.isByteArrayOrString(); if (paddingNeeded) { @@ -446,7 +446,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord m_context << Instruction::DUP1 << Instruction::ISZERO; evmasm::AssemblyItem loopEnd = m_context.appendConditionalJump(); // Special case for tightly-stored byte arrays - if (_sourceType.isByteArray()) + if (_sourceType.isByteArrayOrString()) { // stack here: memory_offset storage_offset length m_context << Instruction::DUP1 << u256(31) << Instruction::LT; @@ -482,14 +482,14 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord } // stack here: memory_end_offset storage_data_offset memory_offset - bool haveByteOffset = !_sourceType.isByteArray() && storageBytes <= 16; + bool haveByteOffset = !_sourceType.isByteArrayOrString() && storageBytes <= 16; if (haveByteOffset) m_context << u256(0) << Instruction::SWAP1; // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset evmasm::AssemblyItem loopStart = m_context.newTag(); m_context << loopStart; // load and store - if (_sourceType.isByteArray()) + if (_sourceType.isByteArrayOrString()) { // Packed both in storage and memory. m_context << Instruction::DUP2 << Instruction::SLOAD; @@ -528,12 +528,12 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset if (haveByteOffset) m_context << Instruction::SWAP1 << Instruction::POP; - if (!_sourceType.isByteArray()) + if (!_sourceType.isByteArrayOrString()) { solAssert(_sourceType.calldataStride() % 32 == 0, ""); solAssert(_sourceType.memoryStride() % 32 == 0, ""); } - if (_padToWordBoundaries && _sourceType.isByteArray()) + if (_padToWordBoundaries && _sourceType.isByteArrayOrString()) { // memory_end_offset - start is the actual length (we want to compute the ceil of). // memory_offset - start is its next multiple of 32, but it might be off by 32. @@ -624,7 +624,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const m_context << u256(0) << Instruction::DUP3 << Instruction::SSTORE; // Special case: short byte arrays are stored togeher with their length evmasm::AssemblyItem endTag = m_context.newTag(); - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) { // stack: ref old_length m_context << Instruction::DUP1 << u256(31) << Instruction::LT; @@ -664,7 +664,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const ArrayType const& _type = dynamic_cast(*type); solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.isDynamicallySized(), ""); - if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32) + if (!_type.isByteArrayOrString() && _type.baseType()->storageBytes() < 32) solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type."); unsigned stackHeightStart = _context.stackHeight(); @@ -677,7 +677,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const solAssert(_context.stackHeight() - stackHeightStart == 3 - 2, "2"); // Special case for short byte arrays, they are stored together with their length - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) { evmasm::AssemblyItem regularPath = _context.newTag(); // We start by a large case-distinction about the old and new length of the byte array. @@ -766,7 +766,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _typeIn) const // stack: ref new_length old_length // store new length _context << Instruction::DUP2; - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) // For a "long" byte array, store length as 2*length+1 _context << Instruction::DUP1 << Instruction::ADD << u256(1) << Instruction::ADD; _context << Instruction::DUP4 << Instruction::SSTORE; @@ -806,10 +806,10 @@ void ArrayUtils::incrementDynamicArraySize(ArrayType const& _type) const { solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.isDynamicallySized(), ""); - if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32) + if (!_type.isByteArrayOrString() && _type.baseType()->storageBytes() < 32) solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type."); - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) { // We almost always just add 2 (length of byte arrays is shifted left by one) // except for the case where we transition from a short byte array @@ -850,10 +850,10 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const { solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.isDynamicallySized(), ""); - if (!_type.isByteArray() && _type.baseType()->storageBytes() < 32) + if (!_type.isByteArrayOrString() && _type.baseType()->storageBytes() < 32) solAssert(_type.baseType()->isValueType(), "Invalid storage size for non-value type."); - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) { m_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::DUP1; m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1); @@ -999,7 +999,7 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con } else { - if (!_arrayType.isByteArray()) + if (!_arrayType.isByteArrayOrString()) { if (_arrayType.location() == DataLocation::Memory) m_context << _arrayType.memoryStride(); @@ -1031,7 +1031,7 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType, unsigned _stackDept break; case DataLocation::Storage: m_context << Instruction::SLOAD; - if (_arrayType.isByteArray()) + if (_arrayType.isByteArrayOrString()) m_context.callYulFunction(m_context.utilFunctions().extractByteArrayLengthFunction(), 1, 1); break; } @@ -1062,7 +1062,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b { case DataLocation::Memory: // stack: - if (!_arrayType.isByteArray()) + if (!_arrayType.isByteArrayOrString()) m_context << u256(_arrayType.memoryHeadSize()) << Instruction::MUL; if (_arrayType.isDynamicallySized()) m_context << u256(32) << Instruction::ADD; @@ -1071,7 +1071,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b m_context << Instruction::ADD; break; case DataLocation::CallData: - if (!_arrayType.isByteArray()) + if (!_arrayType.isByteArrayOrString()) { m_context << _arrayType.calldataStride(); m_context << Instruction::MUL; @@ -1090,7 +1090,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b // stack: [] evmasm::AssemblyItem endTag = m_context.newTag(); - if (_arrayType.isByteArray()) + if (_arrayType.isByteArrayOrString()) { // Special case of short byte arrays. m_context << Instruction::SWAP1; @@ -1153,7 +1153,7 @@ void ArrayUtils::accessCallDataArrayElement(ArrayType const& _arrayType, bool _d { solAssert(_arrayType.baseType()->storageBytes() <= 32, ""); if ( - !_arrayType.isByteArray() && + !_arrayType.isByteArrayOrString() && _arrayType.baseType()->storageBytes() < 32 && m_context.useABICoderV2() ) @@ -1165,7 +1165,7 @@ void ArrayUtils::accessCallDataArrayElement(ArrayType const& _arrayType, bool _d CompilerUtils(m_context).loadFromMemoryDynamic( *_arrayType.baseType(), true, - !_arrayType.isByteArray(), + !_arrayType.isByteArrayOrString(), false ); } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 1876b6ac0..ba678878f 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -970,7 +970,7 @@ void CompilerUtils::convertType( else if (targetTypeCategory == Type::Category::Array) { auto const& arrayType = dynamic_cast(_targetType); - solAssert(arrayType.isByteArray()); + solAssert(arrayType.isByteArrayOrString()); size_t storageSize = 32 + ((data.size() + 31) / 32) * 32; allocateMemory(storageSize); // stack: mempos @@ -992,7 +992,7 @@ void CompilerUtils::convertType( if (_targetType.category() == Type::Category::FixedBytes) { solAssert( - typeOnStack.isByteArray() && !typeOnStack.isString(), + typeOnStack.isByteArrayOrString() && !typeOnStack.isString(), "Array types other than bytes not convertible to bytesNN." ); solAssert(typeOnStack.isDynamicallySized()); @@ -1019,7 +1019,7 @@ void CompilerUtils::convertType( case DataLocation::Storage: // Other cases are done explicitly in LValue::storeValue, and only possible by assignment. solAssert( - (targetType.isPointer() || (typeOnStack.isByteArray() && targetType.isByteArray())) && + (targetType.isPointer() || (typeOnStack.isByteArrayOrString() && targetType.isByteArrayOrString())) && typeOnStack.location() == DataLocation::Storage, "Invalid conversion to storage type." ); @@ -1105,7 +1105,7 @@ void CompilerUtils::convertType( } case DataLocation::CallData: solAssert( - ((targetType.isByteArray() && typeOnStack.isByteArray()) || _typeOnStack == _targetType) && + ((targetType.isByteArrayOrString() && typeOnStack.isByteArrayOrString()) || _typeOnStack == _targetType) && typeOnStack.location() == DataLocation::CallData, "Invalid conversion to calldata type." ); @@ -1119,7 +1119,7 @@ void CompilerUtils::convertType( if (_targetType.category() == Type::Category::FixedBytes) { solAssert( - typeOnStack.arrayType().isByteArray() && !typeOnStack.arrayType().isString(), + typeOnStack.arrayType().isByteArrayOrString() && !typeOnStack.arrayType().isString(), "Array types other than bytes not convertible to bytesNN." ); solAssert(typeOnStack.isDynamicallySized()); @@ -1142,7 +1142,7 @@ void CompilerUtils::convertType( auto const& targetArrayType = dynamic_cast(_targetType); solAssert( typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType) || - (typeOnStack.arrayType().isByteArray() && targetArrayType.isByteArray()) + (typeOnStack.arrayType().isByteArrayOrString() && targetArrayType.isByteArrayOrString()) ); solAssert( typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) && diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index a76d1f3d9..da3022251 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -153,7 +153,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& if (paramTypes[i]->isDynamicallySized()) { solAssert( - dynamic_cast(*paramTypes[i]).isByteArray(), + dynamic_cast(*paramTypes[i]).isByteArrayOrString(), "Expected string or byte array for mapping key type" ); @@ -239,7 +239,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& if (returnTypes[i]->category() == Type::Category::Mapping) continue; if (auto arrayType = dynamic_cast(returnTypes[i])) - if (!arrayType->isByteArray()) + if (!arrayType->isByteArrayOrString()) continue; pair const& offsets = structType->storageOffsetsOfMember(names[i]); m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second); @@ -1047,7 +1047,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // stack: ArrayReference (newLength-1) ArrayUtils(m_context).accessIndex(*arrayType, false); - if (arrayType->isByteArray()) + if (arrayType->isByteArrayOrString()) setLValue(_functionCall); else setLValueToStorageItem(_functionCall); @@ -1084,7 +1084,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) utils().moveToStackTop(1 + type->sizeOnStack()); utils().moveToStackTop(1 + type->sizeOnStack()); // stack: argValue storageSlot slotOffset - if (!arrayType->isByteArray()) + if (!arrayType->isByteArrayOrString()) StorageItem(m_context, *paramType).storeValue(*type, _functionCall.location(), true); else StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true); @@ -1165,7 +1165,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // update free memory pointer m_context << Instruction::DUP1; // Stack: memptr requested_length requested_length - if (arrayType.isByteArray()) + if (arrayType.isByteArrayOrString()) // Round up to multiple of 32 m_context << u256(31) << Instruction::ADD << u256(31) << Instruction::NOT << Instruction::AND; else @@ -2086,7 +2086,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) { case DataLocation::Storage: ArrayUtils(m_context).accessIndex(arrayType); - if (arrayType.isByteArray()) + if (arrayType.isByteArrayOrString()) { solAssert(!arrayType.isString(), "Index access to string is not allowed."); setLValue(_indexAccess); @@ -2096,7 +2096,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) break; case DataLocation::Memory: ArrayUtils(m_context).accessIndex(arrayType); - setLValue(_indexAccess, *_indexAccess.annotation().type, !arrayType.isByteArray()); + setLValue(_indexAccess, *_indexAccess.annotation().type, !arrayType.isByteArrayOrString()); break; case DataLocation::CallData: ArrayUtils(m_context).accessCallDataArrayElement(arrayType); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 84f63a9e1..3c79b64b4 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1183,8 +1183,8 @@ string YulUtilFunctions::arrayLengthFunction(ArrayType const& _type) w("calldata", _type.location() == DataLocation::CallData); if (_type.location() == DataLocation::Storage) { - w("byteArray", _type.isByteArray()); - if (_type.isByteArray()) + w("byteArray", _type.isByteArrayOrString()); + if (_type.isByteArrayOrString()) w("extractByteArrayLength", extractByteArrayLengthFunction()); } @@ -1220,7 +1220,7 @@ std::string YulUtilFunctions::resizeArrayFunction(ArrayType const& _type) solAssert(_type.location() == DataLocation::Storage, ""); solUnimplementedAssert(_type.baseType()->storageBytes() <= 32); - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) return resizeDynamicByteArrayFunction(_type); string functionName = "resize_array_" + _type.identifier(); @@ -1259,7 +1259,7 @@ string YulUtilFunctions::cleanUpStorageArrayEndFunction(ArrayType const& _type) { solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.baseType()->category() != Type::Category::Mapping, ""); - solAssert(!_type.isByteArray(), ""); + solAssert(!_type.isByteArrayOrString(), ""); solUnimplementedAssert(_type.baseType()->storageBytes() <= 32); string functionName = "cleanup_storage_array_end_" + _type.identifier(); @@ -1319,7 +1319,7 @@ string YulUtilFunctions::resizeDynamicByteArrayFunction(ArrayType const& _type) string YulUtilFunctions::cleanUpDynamicByteArrayEndSlotsFunction(ArrayType const& _type) { - solAssert(_type.isByteArray(), ""); + solAssert(_type.isByteArrayOrString(), ""); solAssert(_type.isDynamicallySized(), ""); string functionName = "clean_up_bytearray_end_slots_" + _type.identifier(); @@ -1479,7 +1479,7 @@ string YulUtilFunctions::storageArrayPopFunction(ArrayType const& _type) solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.isDynamicallySized(), ""); solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "Base type is not yet implemented."); - if (_type.isByteArray()) + if (_type.isByteArrayOrString()) return storageByteArrayPopFunction(_type); string functionName = "array_pop_" + _type.identifier(); @@ -1509,7 +1509,7 @@ string YulUtilFunctions::storageByteArrayPopFunction(ArrayType const& _type) { solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.isDynamicallySized(), ""); - solAssert(_type.isByteArray(), ""); + solAssert(_type.isByteArrayOrString(), ""); string functionName = "byte_array_pop_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { @@ -1566,7 +1566,7 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type, Type c return m_functionCollector.createFunction(functionName, [&]() { return Whiskers(R"( function (array ) { - + let data := sload(array) let oldLen := (data) if iszero(lt(oldLen, )) { () } @@ -1598,20 +1598,20 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type, Type c let slot, offset := (array, oldLen) (slot, offset ) } - + let oldLen := sload(array) if iszero(lt(oldLen, )) { () } sstore(array, add(oldLen, 1)) let slot, offset := (array, oldLen) (slot, offset ) - + })") ("functionName", functionName) ("values", _fromType->sizeOnStack() == 0 ? "" : ", " + suffixedVariableNameList("value", 0, _fromType->sizeOnStack())) ("panic", panicFunction(PanicCode::ResourceError)) - ("extractByteArrayLength", _type.isByteArray() ? extractByteArrayLengthFunction() : "") + ("extractByteArrayLength", _type.isByteArrayOrString() ? extractByteArrayLengthFunction() : "") ("dataAreaFunction", arrayDataAreaFunction(_type)) - ("isByteArray", _type.isByteArray()) + ("isByteArrayOrString", _type.isByteArrayOrString()) ("indexAccess", storageArrayIndexAccessFunction(_type)) ("storeValue", updateStorageValueFunction(*_fromType, *_type.baseType())) ("maxArrayLength", (u256(1) << 64).str()) @@ -1642,9 +1642,9 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type) slot, offset := (array, oldLen) })") ("functionName", functionName) - ("isBytes", _type.isByteArray()) - ("increaseBytesSize", _type.isByteArray() ? increaseByteArraySizeFunction(_type) : "") - ("extractLength", _type.isByteArray() ? extractByteArrayLengthFunction() : "") + ("isBytes", _type.isByteArrayOrString()) + ("increaseBytesSize", _type.isByteArrayOrString() ? increaseByteArraySizeFunction(_type) : "") + ("extractLength", _type.isByteArrayOrString() ? extractByteArrayLengthFunction() : "") ("panic", panicFunction(PanicCode::ResourceError)) ("fetchLength", arrayLengthFunction(_type)) ("indexAccess", storageArrayIndexAccessFunction(_type)) @@ -1795,7 +1795,7 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType, if (!_toType.isDynamicallySized()) solAssert(!_fromType.isDynamicallySized() && _fromType.length() <= _toType.length(), ""); - if (_fromType.isByteArray()) + if (_fromType.isByteArrayOrString()) return copyByteArrayToStorageFunction(_fromType, _toType); if (_fromType.dataStoredIn(DataLocation::Storage) && _toType.baseType()->isValueType()) return copyValueArrayStorageToStorageFunction(_fromType, _toType); @@ -1902,8 +1902,8 @@ string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromTy *_fromType.copyForLocation(_toType.location(), _toType.isPointer()) == dynamic_cast(_toType), "" ); - solAssert(_fromType.isByteArray(), ""); - solAssert(_toType.isByteArray(), ""); + solAssert(_fromType.isByteArrayOrString(), ""); + solAssert(_toType.isByteArrayOrString(), ""); string functionName = "copy_byte_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); return m_functionCollector.createFunction(functionName, [&](){ @@ -1980,8 +1980,8 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const& solAssert(_toType.baseType()->isValueType(), ""); solAssert(_fromType.baseType()->isImplicitlyConvertibleTo(*_toType.baseType()), ""); - solAssert(!_fromType.isByteArray(), ""); - solAssert(!_toType.isByteArray(), ""); + solAssert(!_fromType.isByteArrayOrString(), ""); + solAssert(!_toType.isByteArrayOrString(), ""); solAssert(_fromType.dataStoredIn(DataLocation::Storage), ""); solAssert(_toType.dataStoredIn(DataLocation::Storage), ""); @@ -2155,7 +2155,7 @@ string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type) })") ("functionName", functionName) ("stride", to_string(_type.location() == DataLocation::Memory ? _type.memoryStride() : _type.calldataStride())) - ("byteArray", _type.isByteArray()) + ("byteArray", _type.isByteArrayOrString()) ("mul", overflowCheckedIntMulFunction(*TypeProvider::uint256())) .render(); default: @@ -2187,7 +2187,7 @@ string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type) )"); w("functionName", functionName); w("panic", panicFunction(PanicCode::ResourceError)); - w("byteArray", _type.isByteArray()); + w("byteArray", _type.isByteArrayOrString()); w("roundUp", roundUpFunction()); w("dynamic", _type.isDynamicallySized()); return w.render(); @@ -2262,7 +2262,7 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type) ("dataAreaFunc", arrayDataAreaFunction(_type)) ("indexAccessNoChecks", longByteArrayStorageIndexAccessNoCheckFunction()) ("multipleItemsPerSlot", _type.baseType()->storageBytes() <= 16) - ("isBytesArray", _type.isByteArray()) + ("isBytesArray", _type.isByteArrayOrString()) ("storageSize", _type.baseType()->storageSize().str()) ("storageBytes", toString(_type.baseType()->storageBytes())) ("itemsPerSlot", to_string(32 / _type.baseType()->storageBytes())) @@ -2376,7 +2376,7 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type) string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type) { - solAssert(!_type.isByteArray(), ""); + solAssert(!_type.isByteArrayOrString(), ""); if (_type.dataStoredIn(DataLocation::Storage)) solAssert(_type.baseType()->storageBytes() > 16, ""); string functionName = "array_nextElement_" + _type.identifier(); @@ -2447,7 +2447,7 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _ solAssert(_to.memoryStride() == 32, ""); solAssert(_to.baseType()->dataStoredIn(DataLocation::Memory), ""); solAssert(_from.baseType()->dataStoredIn(DataLocation::Storage), ""); - solAssert(!_from.isByteArray(), ""); + solAssert(!_from.isByteArrayOrString(), ""); solAssert(*_to.withLocation(DataLocation::Storage, _from.isPointer()) == _from, ""); return Whiskers(R"( function (slot) -> memPtr { @@ -2755,7 +2755,7 @@ string YulUtilFunctions::updateStorageValueFunction( solAssert(_fromType.category() == Type::Category::StringLiteral, ""); solAssert(toReferenceType->category() == Type::Category::Array, ""); auto const& toArrayType = dynamic_cast(*toReferenceType); - solAssert(toArrayType.isByteArray(), ""); + solAssert(toArrayType.isByteArrayOrString(), ""); return Whiskers(R"( function (slot, offset) { @@ -3216,7 +3216,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) auto const& fromType = dynamic_cast(_from); if (_to.category() == Type::Category::FixedBytes) { - solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN."); + solAssert(fromType.arrayType().isByteArrayOrString(), "Array types other than bytes not convertible to bytesNN."); return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast(_to)); } solAssert(_to.category() == Type::Category::Array); @@ -3224,7 +3224,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) solAssert( fromType.arrayType().isImplicitlyConvertibleTo(targetType) || - (fromType.arrayType().isByteArray() && targetType.isByteArray()) + (fromType.arrayType().isByteArrayOrString() && targetType.isByteArrayOrString()) ); solAssert( fromType.arrayType().dataStoredIn(DataLocation::CallData) && @@ -3256,7 +3256,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) auto const& fromArrayType = dynamic_cast(_from); if (_to.category() == Type::Category::FixedBytes) { - solAssert(fromArrayType.isByteArray(), "Array types other than bytes not convertible to bytesNN."); + solAssert(fromArrayType.isByteArrayOrString(), "Array types other than bytes not convertible to bytesNN."); return bytesToFixedBytesConversionFunction(fromArrayType, dynamic_cast(_to)); } solAssert(_to.category() == Type::Category::Array, ""); @@ -3460,7 +3460,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) string YulUtilFunctions::bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to) { - solAssert(_from.isByteArray() && !_from.isString(), ""); + solAssert(_from.isByteArrayOrString() && !_from.isString(), ""); solAssert(_from.isDynamicallySized(), ""); string functionName = "convert_bytes_to_fixedbytes_from_" + _from.identifier() + "_to_" + _to.identifier(); return m_functionCollector.createFunction(functionName, [&](auto& _args, auto& _returnParams) { @@ -3633,14 +3633,14 @@ string YulUtilFunctions::arrayConversionFunction(ArrayType const& _from, ArrayTy { if (_to.dataStoredIn(DataLocation::CallData)) solAssert( - _from.dataStoredIn(DataLocation::CallData) && _from.isByteArray() && _to.isByteArray(), + _from.dataStoredIn(DataLocation::CallData) && _from.isByteArrayOrString() && _to.isByteArrayOrString(), "" ); // Other cases are done explicitly in LValue::storeValue, and only possible by assignment. if (_to.location() == DataLocation::Storage) solAssert( - (_to.isPointer() || (_from.isByteArray() && _to.isByteArray())) && + (_to.isPointer() || (_from.isByteArrayOrString() && _to.isByteArrayOrString())) && _from.location() == DataLocation::Storage, "Invalid conversion to storage type." ); @@ -4238,7 +4238,7 @@ string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const } else if (_to.category() == Type::Category::Array) { - solAssert(dynamic_cast(_to).isByteArray(), ""); + solAssert(dynamic_cast(_to).isByteArrayOrString(), ""); Whiskers templ(R"( function () -> converted { converted := () diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index c2bb0c3cf..e361ada47 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -677,7 +677,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) continue; if ( auto const* arrayType = dynamic_cast(returnTypes[i]); - arrayType && !arrayType->isByteArray() + arrayType && !arrayType->isByteArrayOrString() ) continue; @@ -698,7 +698,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) solAssert(returnTypes.size() == 1, ""); auto const* arrayType = dynamic_cast(returnTypes.front()); if (arrayType) - solAssert(arrayType->isByteArray(), ""); + solAssert(arrayType->isByteArrayOrString(), ""); vector retVars = IRVariable("ret", *returnTypes.front()).stackSlots(); returnVariables += retVars; code += Whiskers(R"( diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 86d00dbc9..065b351f6 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -2088,7 +2088,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (dynamic_cast(&actualType)) solAssert(member == "wrap" || member == "unwrap"); else if (auto const* arrayType = dynamic_cast(&actualType)) - solAssert(arrayType->isByteArray() && member == "concat"); + solAssert(arrayType->isByteArrayOrString() && member == "concat"); else // The old code generator had a generic "else" case here // without any specific code being generated, @@ -2226,7 +2226,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) setLValue(_indexAccess, IRLValue{ *arrayType.baseType(), - IRLValue::Memory{memAddress, arrayType.isByteArray()} + IRLValue::Memory{memAddress, arrayType.isByteArrayOrString()} }); break; } @@ -2240,7 +2240,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) ", " + expressionAsType(*_indexAccess.indexExpression(), *TypeProvider::uint256()) + ")"; - if (arrayType.isByteArray()) + if (arrayType.isByteArrayOrString()) define(_indexAccess) << m_utils.cleanupFunction(*arrayType.baseType()) << "(calldataload(" << diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index b42e9b355..76342ba08 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -953,7 +953,7 @@ bool isReturnedFromStructGetter(Type const* _type) if (category == Type::Category::Mapping) return false; if (category == Type::Category::Array) - return dynamic_cast(*_type).isByteArray(); + return dynamic_cast(*_type).isByteArrayOrString(); // default return true; } @@ -990,7 +990,7 @@ void SMTEncoder::visitPublicGetter(FunctionCall const& _funCall) { if ( type->isValueType() || - (type->category() == Type::Category::Array && dynamic_cast(*type).isByteArray()) + (type->category() == Type::Category::Array && dynamic_cast(*type).isByteArrayOrString()) ) { solAssert(symbArguments.empty(), ""); @@ -1071,7 +1071,7 @@ void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall) if (auto sliceType = dynamic_cast(argType)) arrayType = &sliceType->arrayType(); - if (arrayType && arrayType->isByteArray() && smt::isFixedBytes(*funCallType)) + if (arrayType && arrayType->isByteArrayOrString() && smt::isFixedBytes(*funCallType)) { auto array = dynamic_pointer_cast(m_context.expression(*argument)); bytesToFixedBytesAssertions(*array, _funCall); @@ -2695,14 +2695,14 @@ Expression const* SMTEncoder::cleanExpression(Expression const& _expr) auto typeType = dynamic_cast(functionCall->expression().annotation().type); solAssert(typeType, ""); if (auto const* arrayType = dynamic_cast(typeType->actualType())) - if (arrayType->isByteArray()) + if (arrayType->isByteArrayOrString()) { // this is a cast to `bytes` solAssert(functionCall->arguments().size() == 1, ""); Expression const& arg = *functionCall->arguments()[0]; if ( auto const* argArrayType = dynamic_cast(arg.annotation().type); - argArrayType && argArrayType->isByteArray() + argArrayType && argArrayType->isByteArrayOrString() ) return cleanExpression(arg); } diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index 36d9a0f35..024e33be6 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -96,7 +96,7 @@ SortPointer smtSort(frontend::Type const& _type) auto sliceArrayType = dynamic_cast(&_type); ArrayType const* arrayType = sliceArrayType ? &sliceArrayType->arrayType() : dynamic_cast(&_type); if ( - (arrayType && (arrayType->isString() || arrayType->isByteArray())) || + (arrayType && (arrayType->isString() || arrayType->isByteArrayOrString())) || _type.category() == frontend::Type::Category::StringLiteral ) tupleName = "bytes"; diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp index cf395ffa0..9c7a645b6 100644 --- a/libsolidity/interface/ABI.cpp +++ b/libsolidity/interface/ABI.cpp @@ -176,7 +176,7 @@ Json::Value ABI::formatType( ret["type"] = _encodingType.canonicalName() + suffix; else if (ArrayType const* arrayType = dynamic_cast(&_encodingType)) { - if (arrayType->isByteArray()) + if (arrayType->isByteArrayOrString()) ret["type"] = _encodingType.canonicalName() + suffix; else { diff --git a/libsolidity/interface/StorageLayout.cpp b/libsolidity/interface/StorageLayout.cpp index a484503c1..74d7ccf4b 100644 --- a/libsolidity/interface/StorageLayout.cpp +++ b/libsolidity/interface/StorageLayout.cpp @@ -94,7 +94,7 @@ void StorageLayout::generate(Type const* _type) } else if (auto arrayType = dynamic_cast(_type)) { - if (arrayType->isByteArray()) + if (arrayType->isByteArrayOrString()) typeInfo["encoding"] = "bytes"; else { From cc6344c03c2b9c00a76bc2af1d9f1da7aa9c467b Mon Sep 17 00:00:00 2001 From: nishant-sachdeva Date: Wed, 2 Feb 2022 16:14:24 +0530 Subject: [PATCH 14/28] Changed instaces of isByteArrayOrString() to isByteArray() where it's only supposed to return a True for Bytes Type --- libsolidity/analysis/TypeChecker.cpp | 2 +- libsolidity/ast/Types.cpp | 6 +++--- libsolidity/ast/Types.h | 2 ++ libsolidity/codegen/CompilerUtils.cpp | 4 ++-- libsolidity/codegen/YulUtilFunctions.cpp | 6 +++--- libsolidity/formal/SymbolicTypes.cpp | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1a07d6ded..5b03717d9 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1791,7 +1791,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType( ); else solAssert( - argArrayType->isByteArrayOrString() && !argArrayType->isString() && resultType->category() == Type::Category::FixedBytes, + argArrayType->isByteArray() && resultType->category() == Type::Category::FixedBytes, "" ); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index f50210ff5..74cd76ee7 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1530,7 +1530,7 @@ BoolResult ArrayType::isImplicitlyConvertibleTo(Type const& _convertTo) const if (_convertTo.category() != category()) return false; auto& convertTo = dynamic_cast(_convertTo); - if (convertTo.isByteArrayOrString() != isByteArrayOrString() || convertTo.isString() != isString()) + if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString()) return false; // memory/calldata to storage can be converted, but only to a direct storage reference if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer()) @@ -1571,7 +1571,7 @@ BoolResult ArrayType::isExplicitlyConvertibleTo(Type const& _convertTo) const return true; // allow conversion bytes <-> string and bytes -> bytesNN if (_convertTo.category() != category()) - return isByteArrayOrString() && !isString() && _convertTo.category() == Type::Category::FixedBytes; + return isByteArray() && _convertTo.category() == Type::Category::FixedBytes; auto& convertTo = dynamic_cast(_convertTo); if (convertTo.location() != location()) return false; @@ -1608,7 +1608,7 @@ bool ArrayType::operator==(Type const& _other) const ArrayType const& other = dynamic_cast(_other); if ( !ReferenceType::operator==(other) || - other.isByteArrayOrString() != isByteArrayOrString() || + other.isByteArray() != isByteArray() || other.isString() != isString() || other.isDynamicallySized() != isDynamicallySized() ) diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index e34c11405..3f134df17 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -837,6 +837,8 @@ public: BoolResult validForLocation(DataLocation _loc) const override; + /// @returns true if this is a byte array. + bool isByteArray() const { return m_arrayKind == ArrayKind::Bytes; } /// @returns true if this is a byte array or a string bool isByteArrayOrString() const { return m_arrayKind != ArrayKind::Ordinary; } /// @returns true if this is a string diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index ba678878f..0ad37241b 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -992,7 +992,7 @@ void CompilerUtils::convertType( if (_targetType.category() == Type::Category::FixedBytes) { solAssert( - typeOnStack.isByteArrayOrString() && !typeOnStack.isString(), + typeOnStack.isByteArray(), "Array types other than bytes not convertible to bytesNN." ); solAssert(typeOnStack.isDynamicallySized()); @@ -1119,7 +1119,7 @@ void CompilerUtils::convertType( if (_targetType.category() == Type::Category::FixedBytes) { solAssert( - typeOnStack.arrayType().isByteArrayOrString() && !typeOnStack.arrayType().isString(), + typeOnStack.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN." ); solAssert(typeOnStack.isDynamicallySized()); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 3c79b64b4..9b50d68cd 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -3216,7 +3216,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) auto const& fromType = dynamic_cast(_from); if (_to.category() == Type::Category::FixedBytes) { - solAssert(fromType.arrayType().isByteArrayOrString(), "Array types other than bytes not convertible to bytesNN."); + solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN."); return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast(_to)); } solAssert(_to.category() == Type::Category::Array); @@ -3256,7 +3256,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) auto const& fromArrayType = dynamic_cast(_from); if (_to.category() == Type::Category::FixedBytes) { - solAssert(fromArrayType.isByteArrayOrString(), "Array types other than bytes not convertible to bytesNN."); + solAssert(fromArrayType.isByteArray(), "Array types other than bytes not convertible to bytesNN."); return bytesToFixedBytesConversionFunction(fromArrayType, dynamic_cast(_to)); } solAssert(_to.category() == Type::Category::Array, ""); @@ -3460,7 +3460,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) string YulUtilFunctions::bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to) { - solAssert(_from.isByteArrayOrString() && !_from.isString(), ""); + solAssert(_from.isByteArray(), ""); solAssert(_from.isDynamicallySized(), ""); string functionName = "convert_bytes_to_fixedbytes_from_" + _from.identifier() + "_to_" + _to.identifier(); return m_functionCollector.createFunction(functionName, [&](auto& _args, auto& _returnParams) { diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index 024e33be6..b9041c6bd 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -96,7 +96,7 @@ SortPointer smtSort(frontend::Type const& _type) auto sliceArrayType = dynamic_cast(&_type); ArrayType const* arrayType = sliceArrayType ? &sliceArrayType->arrayType() : dynamic_cast(&_type); if ( - (arrayType && (arrayType->isString() || arrayType->isByteArrayOrString())) || + (arrayType && arrayType->isByteArrayOrString()) || _type.category() == frontend::Type::Category::StringLiteral ) tupleName = "bytes"; From dcaa094f1f3850203f3908b9853efefeb3c54d58 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Wed, 2 Feb 2022 18:11:14 -0500 Subject: [PATCH 15/28] Add NatSpec note for libraries --- docs/natspec-format.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/natspec-format.rst b/docs/natspec-format.rst index 297bbc8c6..a66c10462 100644 --- a/docs/natspec-format.rst +++ b/docs/natspec-format.rst @@ -36,7 +36,7 @@ tools. Documentation Example ===================== -Documentation is inserted above each ``contract``, ``interface``, +Documentation is inserted above each ``contract``, ``interface``, ``library``, ``function``, and ``event`` using the Doxygen notation format. A ``public`` state variable is equivalent to a ``function`` for the purposes of NatSpec. From f5b345504beab1f1cd10c21f382f97b7c6aa5321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 3 Feb 2022 14:52:58 +0100 Subject: [PATCH 16/28] When installing solc-js use the dist/ subdir, which contains the built JS files --- scripts/bytecodecompare/storebytecode.sh | 2 +- scripts/solc-bin/bytecode_reports_for_modified_binaries.sh | 4 ++-- test/externalTests/colony.sh | 6 +++--- test/externalTests/gnosis-v2.sh | 6 +++--- test/externalTests/gnosis.sh | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/bytecodecompare/storebytecode.sh b/scripts/bytecodecompare/storebytecode.sh index 1c300662b..3574fe6bf 100755 --- a/scripts/bytecodecompare/storebytecode.sh +++ b/scripts/bytecodecompare/storebytecode.sh @@ -52,7 +52,7 @@ TMPDIR=$(mktemp -d) popd cp "$REPO_ROOT/scripts/bytecodecompare/prepare_report.js" . - npm install solc-js/ + npm install ./solc-js/dist echo "Running the compiler..." # shellcheck disable=SC2035 diff --git a/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh b/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh index be151bca8..68ab995af 100755 --- a/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh +++ b/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh @@ -149,11 +149,11 @@ for binary_name in $platform_binaries; do if [[ $platform == emscripten-wasm32 ]] || [[ $platform == emscripten-asmjs ]]; then ln -sf "${solc_bin_dir}/${platform}/${binary_name}" "${solcjs_dir}/soljson.js" ln -sf "${solc_bin_dir}/${platform}/${binary_name}" "${solcjs_dir}/dist/soljson.js" - ln -s "${solcjs_dir}" solc-js + npm install "${solcjs_dir}/dist" cp "${script_dir}/bytecodecompare/prepare_report.js" prepare_report.js validate_reported_version \ - "$(solc-js/dist/solc.js --version)" \ + "$(node_modules/solc/solc.js --version)" \ "$solidity_version_and_commit" # shellcheck disable=SC2035 diff --git a/test/externalTests/colony.sh b/test/externalTests/colony.sh index 8386b0b49..d65989953 100755 --- a/test/externalTests/colony.sh +++ b/test/externalTests/colony.sh @@ -59,7 +59,7 @@ function colony_test [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$SELECTED_PRESETS")" + force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")" yarn install git submodule update --init @@ -69,10 +69,10 @@ function colony_test cd .. replace_version_pragmas - [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc" + [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist" for preset in $SELECTED_PRESETS; do - truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$preset" "${compile_only_presets[*]}" compile_fn test_fn + truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } diff --git a/test/externalTests/gnosis-v2.sh b/test/externalTests/gnosis-v2.sh index 16f3d6f62..8ad070d11 100755 --- a/test/externalTests/gnosis-v2.sh +++ b/test/externalTests/gnosis-v2.sh @@ -63,14 +63,14 @@ function gnosis_safe_test neutralize_package_lock neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$SELECTED_PRESETS")" + force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")" npm install --package-lock replace_version_pragmas - [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc" + [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist" for preset in $SELECTED_PRESETS; do - truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$preset" "${compile_only_presets[*]}" compile_fn test_fn + truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } diff --git a/test/externalTests/gnosis.sh b/test/externalTests/gnosis.sh index 62dea10df..edada2fef 100755 --- a/test/externalTests/gnosis.sh +++ b/test/externalTests/gnosis.sh @@ -61,14 +61,14 @@ function gnosis_safe_test neutralize_package_lock neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$SELECTED_PRESETS")" + force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$(first_word "$SELECTED_PRESETS")" npm install --package-lock replace_version_pragmas - [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc" + [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc/dist" for preset in $SELECTED_PRESETS; do - truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$preset" "${compile_only_presets[*]}" compile_fn test_fn + truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc/dist" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } From e85bceb4178f82e05762dc3e7e7bcf3020ded091 Mon Sep 17 00:00:00 2001 From: nishant-sachdeva Date: Fri, 4 Feb 2022 02:08:36 +0530 Subject: [PATCH 17/28] Types.h:872 had a comment /// String is interpreted as a subtype of Bytes. - this was now incorrect after #12593 . That has been removed now. --- libsolidity/ast/Types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 3f134df17..c4aaf38ca 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -864,7 +864,6 @@ protected: std::vector decomposition() const override { return {m_baseType}; } private: - /// String is interpreted as a subtype of Bytes. enum class ArrayKind { Ordinary, Bytes, String }; bigint unlimitedStaticCalldataSize(bool _padded) const; From b52032a452004e53115a8c214341593ef29018db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 4 Feb 2022 15:18:37 +0100 Subject: [PATCH 18/28] Re-enable Bleeps and just disable the failing governor test --- .circleci/config.yml | 3 +-- test/externalTests/bleeps.sh | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 44b44bb01..143a692fd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1468,8 +1468,7 @@ workflows: - t_ems_ext: *job_native_test_ext_trident - t_ems_ext: *job_native_test_ext_euler - t_ems_ext: *job_native_test_ext_yield_liquidator - # Disabled until we have a fix for https://github.com/wighawag/bleeps/issues/2 - #-t_ems_ext: *job_native_test_ext_bleeps + - t_ems_ext: *job_native_test_ext_bleeps - t_ems_ext: *job_native_test_ext_pool_together - t_ems_ext: *job_native_test_ext_perpetual_pools - t_ems_ext: *job_native_test_ext_uniswap diff --git a/test/externalTests/bleeps.sh b/test/externalTests/bleeps.sh index d005cf8ef..561200e21 100755 --- a/test/externalTests/bleeps.sh +++ b/test/externalTests/bleeps.sh @@ -72,6 +72,10 @@ function bleeps_test sed -i 's/msg\.sender\.transfer(/payable(msg.sender).transfer(/g' src/externals/WETH9.sol sed -i 's/^\s*\(Deposit\|Withdrawal\|Approval\|Transfer\)(/emit \1(/g' src/externals/WETH9.sol + # This test does not currently pass due to an upstream problem. + # TODO: Remove this line when https://github.com/wighawag/bleeps/issues/2 is fixed + rm test/BleepsDAO.governor.test.ts + neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" From 4ebd839d3a303814865b83ff2c605f1a50d80b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 4 Feb 2022 15:51:34 +0100 Subject: [PATCH 19/28] Run full tests, not just test:contracts in PRBMath external test - `test:contracts` does not seem to be running any tests at all. --- test/externalTests/prb-math.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/externalTests/prb-math.sh b/test/externalTests/prb-math.sh index 339a5e75d..53fad2c25 100755 --- a/test/externalTests/prb-math.sh +++ b/test/externalTests/prb-math.sh @@ -30,7 +30,7 @@ BINARY_PATH="$2" SELECTED_PRESETS="$3" function compile_fn { yarn compile; } -function test_fn { yarn test:contracts; } +function test_fn { yarn test; } function prb_math_test { From 653c1e68429937abec17c9242a191227db0202b9 Mon Sep 17 00:00:00 2001 From: Ayush Shukla Date: Thu, 3 Feb 2022 20:26:46 +0530 Subject: [PATCH 20/28] Fix slot calculation for bytes/string mapping --- docs/internals/layout_in_storage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/internals/layout_in_storage.rst b/docs/internals/layout_in_storage.rst index b1b89a6a3..9afe97ddb 100644 --- a/docs/internals/layout_in_storage.rst +++ b/docs/internals/layout_in_storage.rst @@ -90,7 +90,7 @@ The value corresponding to a mapping key ``k`` is located at ``keccak256(h(k) . where ``.`` is concatenation and ``h`` is a function that is applied to the key depending on its type: - for value types, ``h`` pads the value to 32 bytes in the same way as when storing the value in memory. -- for strings and byte arrays, ``h`` computes the ``keccak256`` hash of the unpadded data. +- for strings and byte arrays, ``h(k)`` is just the unpadded data. If the mapping value is a non-value type, the computed slot marks the start of the data. If the value is of struct type, From 4d65bfa95e28f3dc3b8ad6cd6aaf8578c15851c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 5 Feb 2022 00:05:39 +0100 Subject: [PATCH 21/28] CI: Remove notes about Hardhat failing on nodejs 17; that version is officially not supported --- .circleci/config.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 143a692fd..3f2c661a0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -521,35 +521,30 @@ defaults: name: t_native_test_ext_ens project: ens binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_ext_trident: &job_native_test_ext_trident <<: *workflow_ubuntu2004_static name: t_native_test_ext_trident project: trident binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_ext_euler: &job_native_test_ext_euler <<: *workflow_ubuntu2004_static name: t_native_test_ext_euler project: euler binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_ext_yield_liquidator: &job_native_test_ext_yield_liquidator <<: *workflow_ubuntu2004_static name: t_native_test_ext_yield_liquidator project: yield-liquidator binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_ext_bleeps: &job_native_test_ext_bleeps <<: *workflow_ubuntu2004_static name: t_native_test_ext_bleeps project: bleeps binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' resource_class: medium - job_native_test_ext_pool_together: &job_native_test_ext_pool_together @@ -557,35 +552,30 @@ defaults: name: t_native_test_ext_pool_together project: pool-together binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_ext_perpetual_pools: &job_native_test_ext_perpetual_pools <<: *workflow_ubuntu2004_static name: t_native_test_ext_perpetual_pools project: perpetual-pools binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_ext_uniswap: &job_native_test_ext_uniswap <<: *workflow_ubuntu2004_static name: t_native_test_ext_uniswap project: uniswap binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_prb_math: &job_native_test_prb_math <<: *workflow_ubuntu2004_static name: t_native_test_ext_prb_math project: prb-math binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' - job_native_test_ext_elementfi: &job_native_test_ext_elementfi <<: *workflow_ubuntu2004_static name: t_native_test_ext_elementfi project: elementfi binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' resource_class: medium - job_ems_test_ext_colony: &job_ems_test_ext_colony From 247eab90567e36fb9d8e390ef530551316fc7a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 5 Feb 2022 00:03:53 +0100 Subject: [PATCH 22/28] CI: Rename node_latest_small to node_small --- .circleci/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f2c661a0..db9baaa64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -384,7 +384,7 @@ defaults: TERM: xterm MAKEFLAGS: -j 2 - - base_node_latest_small: &base_node_latest_small + - base_node_small: &base_node_small docker: - image: circleci/node resource_class: small @@ -605,7 +605,7 @@ jobs: - gitter_notify_failure_unless_pr chk_docs_examples: - <<: *base_node_latest_small + <<: *base_node_small steps: - checkout - attach_workspace: @@ -674,7 +674,7 @@ jobs: - gitter_notify_failure_unless_pr chk_buglist: - <<: *base_node_latest_small + <<: *base_node_small steps: - checkout - run: @@ -1136,7 +1136,7 @@ jobs: - gitter_notify_failure_unless_pr t_ems_ext_hardhat: - <<: *base_node_latest_small + <<: *base_node_small environment: TERM: xterm HARDHAT_TESTS_SOLC_PATH: /tmp/workspace/soljson.js @@ -1339,7 +1339,7 @@ jobs: - gitter_notify_failure_unless_pr b_bytecode_ems: - <<: *base_node_latest_small + <<: *base_node_small environment: SOLC_EMSCRIPTEN: "On" steps: From 2f0ccb21bef0ddee12b37b52289ca7081b6a5d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 5 Feb 2022 00:04:20 +0100 Subject: [PATCH 23/28] CI: Switch t_ems_ext_hardhat to nodejs 16 --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index db9baaa64..58a4c2742 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1137,6 +1137,8 @@ jobs: t_ems_ext_hardhat: <<: *base_node_small + docker: + - image: circleci/node:16 environment: TERM: xterm HARDHAT_TESTS_SOLC_PATH: /tmp/workspace/soljson.js From 6bd38aa4ef2ca036775896b77909b361ed3d8855 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Sat, 5 Feb 2022 23:59:09 -0500 Subject: [PATCH 24/28] Fix signature of pop member --- docs/types/reference-types.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index 126440321..88e23a47e 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -337,9 +337,9 @@ Array Members Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``push(x)`` that you can use to append a given element at the end of the array. The function returns nothing. -**pop**: +**pop()**: Dynamic storage arrays and ``bytes`` (not ``string``) have a member - function called ``pop`` that you can use to remove an element from the + function called ``pop()`` that you can use to remove an element from the end of the array. This also implicitly calls :ref:`delete` on the removed element. .. note:: From c3145979fc18c104479379916b17364e94fccb16 Mon Sep 17 00:00:00 2001 From: Hakeem Almidan Date: Sun, 6 Feb 2022 20:16:04 +0300 Subject: [PATCH 25/28] Update cheatsheet.rst Add more description to the bullet point of 'block.timestamp' (under 'Global Variables') --- docs/cheatsheet.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cheatsheet.rst b/docs/cheatsheet.rst index eab1e3d52..cd9ba5c14 100644 --- a/docs/cheatsheet.rst +++ b/docs/cheatsheet.rst @@ -92,7 +92,7 @@ Global Variables - ``block.difficulty`` (``uint``): current block difficulty - ``block.gaslimit`` (``uint``): current block gaslimit - ``block.number`` (``uint``): current block number -- ``block.timestamp`` (``uint``): current block timestamp +- ``block.timestamp`` (``uint``): current block timestamp in seconds since Unix epoch - ``gasleft() returns (uint256)``: remaining gas - ``msg.data`` (``bytes``): complete calldata - ``msg.sender`` (``address``): sender of the message (current call) From 4715fafb829a156e25a027027d8632689ee3d04b Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 7 Feb 2022 11:31:59 +0100 Subject: [PATCH 26/28] Re-enable preset for poolTogether. --- test/externalTests/pool-together.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/externalTests/pool-together.sh b/test/externalTests/pool-together.sh index 1cabd6a50..a7f5933c0 100755 --- a/test/externalTests/pool-together.sh +++ b/test/externalTests/pool-together.sh @@ -45,7 +45,7 @@ function pool_together_test "${compile_only_presets[@]}" #ir-no-optimize # Compilation fails with "YulException: Variable var_amount_205 is 9 slot(s) too deep inside the stack." #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_amount_205 is 9 slot(s) too deep inside the stack." - #ir-optimize-evm+yul # FIXME: ICE due to https://github.com/ethereum/solidity/issues/12558 + ir-optimize-evm+yul legacy-no-optimize legacy-optimize-evm-only legacy-optimize-evm+yul From b9fe628b70b0f118f02822ace678a69c39f5843c Mon Sep 17 00:00:00 2001 From: Marenz Date: Thu, 27 Jan 2022 14:07:50 +0100 Subject: [PATCH 27/28] Emit immutable references for pure yul code --- Changelog.md | 1 + libsolidity/interface/StandardCompiler.cpp | 22 ++++---- .../standard_yul_immutable_references/args | 1 + .../input.json | 22 ++++++++ .../output.json | 52 +++++++++++++++++++ .../standard_yul_object_name/output.json | 2 +- 6 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 test/cmdlineTests/standard_yul_immutable_references/args create mode 100644 test/cmdlineTests/standard_yul_immutable_references/input.json create mode 100644 test/cmdlineTests/standard_yul_immutable_references/output.json diff --git a/Changelog.md b/Changelog.md index e75e2c710..c938c44b0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Language Features: Compiler Features: * Yul Optimizer: Remove ``mstore`` and ``sstore`` operations if the slot already contains the same value. + * Yul: Emit immutable references for pure yul code when requested. diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 39ed7c10f..5ccf2d447 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -1461,36 +1461,36 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) stack.optimize(); MachineAssemblyObject object; - MachineAssemblyObject runtimeObject; - tie(object, runtimeObject) = stack.assembleWithDeployed(); + MachineAssemblyObject deployedObject; + tie(object, deployedObject) = stack.assembleWithDeployed(); if (object.bytecode) object.bytecode->link(_inputsAndSettings.libraries); - if (runtimeObject.bytecode) - runtimeObject.bytecode->link(_inputsAndSettings.libraries); + if (deployedObject.bytecode) + deployedObject.bytecode->link(_inputsAndSettings.libraries); - for (string const& objectKind: vector{"bytecode", "deployedBytecode"}) + for (auto&& [kind, isDeployed]: {make_pair("bytecode"s, false), make_pair("deployedBytecode"s, true)}) if (isArtifactRequested( _inputsAndSettings.outputSelection, sourceName, contractName, - evmObjectComponents(objectKind), + evmObjectComponents(kind), wildcardMatchesExperimental )) { - MachineAssemblyObject const& o = objectKind == "bytecode" ? object : runtimeObject; + MachineAssemblyObject const& o = isDeployed ? deployedObject : object; if (o.bytecode) - output["contracts"][sourceName][contractName]["evm"][objectKind] = + output["contracts"][sourceName][contractName]["evm"][kind] = collectEVMObject( *o.bytecode, o.sourceMappings.get(), Json::arrayValue, - false, - [&](string const& _element) { return isArtifactRequested( + isDeployed, + [&, kind = kind](string const& _element) { return isArtifactRequested( _inputsAndSettings.outputSelection, sourceName, contractName, - "evm." + objectKind + "." + _element, + "evm." + kind + "." + _element, wildcardMatchesExperimental ); } ); diff --git a/test/cmdlineTests/standard_yul_immutable_references/args b/test/cmdlineTests/standard_yul_immutable_references/args new file mode 100644 index 000000000..d13a8ac44 --- /dev/null +++ b/test/cmdlineTests/standard_yul_immutable_references/args @@ -0,0 +1 @@ +--pretty-json diff --git a/test/cmdlineTests/standard_yul_immutable_references/input.json b/test/cmdlineTests/standard_yul_immutable_references/input.json new file mode 100644 index 000000000..aedbae868 --- /dev/null +++ b/test/cmdlineTests/standard_yul_immutable_references/input.json @@ -0,0 +1,22 @@ +{ + "language": "Yul", + "sources": + { + "A": + { + "content": "object \"YulTest\" { code { let size := datasize(\"runtime\") datacopy(0, dataoffset(\"runtime\"), size) setimmutable(0, \"test\", 1) return(0, size) } object \"runtime\" { code { mstore(0, loadimmutable(\"test\")) return(0, 0x20) } }}" + } + }, + "settings": + { + "outputSelection": { + "A": { + "*": [ + "evm.deployedBytecode.immutableReferences", + "evm.bytecode", + "evm.deployedBytecode" + ] + } + } + } +} diff --git a/test/cmdlineTests/standard_yul_immutable_references/output.json b/test/cmdlineTests/standard_yul_immutable_references/output.json new file mode 100644 index 000000000..42361097d --- /dev/null +++ b/test/cmdlineTests/standard_yul_immutable_references/output.json @@ -0,0 +1,52 @@ +{ + "contracts": + { + "A": + { + "YulTest": + { + "evm": + { + "bytecode": + { + "functionDebugData": {}, + "generatedSources": [], + "linkReferences": {}, + "object": "60298060156000396001600060010152806000f3fe7f000000000000000000000000000000000000000000000000000000000000000060005260206000f3", + "opcodes": "PUSH1 0x29 DUP1 PUSH1 0x15 PUSH1 0x0 CODECOPY PUSH1 0x1 PUSH1 0x0 PUSH1 0x1 ADD MSTORE DUP1 PUSH1 0x0 RETURN INVALID PUSH32 0x0 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 RETURN ", + "sourceMap": "42:19:0:-:0;100:4;77:21;74:1;65:40;133:1;122;109:26;;;149:4;146:1;139:15" + }, + "deployedBytecode": + { + "functionDebugData": {}, + "generatedSources": [], + "immutableReferences": + { + "test": + [ + { + "length": 32, + "start": 1 + } + ] + }, + "linkReferences": {}, + "object": "7f000000000000000000000000000000000000000000000000000000000000000060005260206000f3", + "opcodes": "PUSH32 0x0 PUSH1 0x0 MSTORE PUSH1 0x20 PUSH1 0x0 RETURN ", + "sourceMap": "203:21:0:-:0;200:1;193:32;241:4;238:1;231:15" + } + } + } + } + }, + "errors": + [ + { + "component": "general", + "formattedMessage": "Yul is still experimental. Please use the output with care.", + "message": "Yul is still experimental. Please use the output with care.", + "severity": "warning", + "type": "Warning" + } + ] +} diff --git a/test/cmdlineTests/standard_yul_object_name/output.json b/test/cmdlineTests/standard_yul_object_name/output.json index f2e85ed7c..45280c8a1 100644 --- a/test/cmdlineTests/standard_yul_object_name/output.json +++ b/test/cmdlineTests/standard_yul_object_name/output.json @@ -23,7 +23,7 @@ sub_0: assembly { /* \"A\":137:149 */ revert } -","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"NamedObject\" { +","bytecode":{"functionDebugData":{},"generatedSources":[],"linkReferences":{},"object":"","opcodes":"","sourceMap":""},"deployedBytecode":{"functionDebugData":{},"generatedSources":[],"immutableReferences":{},"linkReferences":{},"object":"","opcodes":"","sourceMap":""}},"ir":"object \"NamedObject\" { code { let x := dataoffset(\"DataName\") sstore(add(x, 0), 0) From 2e2094ad820994161cf621c90a0e82f3d1c1d6f2 Mon Sep 17 00:00:00 2001 From: Naveen Sahu <42338831+theNvN@users.noreply.github.com> Date: Wed, 2 Feb 2022 02:02:31 +0530 Subject: [PATCH 28/28] plain `address` can be sent Ether too The docs state that a plain `address` cannot be sent Ether. But even though `send` and `transfer` members are not available for plain `address`, the `call` is. And `call` can be invoked upon a plain `address` type to send Ether to the address. For instance, the `someone` (`address` type) can be sent Ether by invoking `sendSomeone()` method in the following `Dummy` contract: ``` contract Dummy { address someone = 0xAb8...cb2; function balanceOf(address addr) public view returns (uint) { return addr.balance; } function sendToSomeone() public payable returns (bool) { (bool sent, ) = someone.call{value: msg.value}(""); return sent; } } ``` --- docs/types/value-types.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 30a857796..0d6a30cd6 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -188,7 +188,8 @@ The address type comes in two flavours, which are largely identical: - ``address payable``: Same as ``address``, but with the additional members ``transfer`` and ``send``. The idea behind this distinction is that ``address payable`` is an address you can send Ether to, -while a plain ``address`` cannot be sent Ether. +while you are not supposed to send Ether to a plain ``address``, for example because it might be a smart contract +that was not built to accept Ether. Type conversions: