diff options
11 files changed, 106 insertions, 27 deletions
diff --git a/Changelog.md b/Changelog.md index b899fa30..876182cc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ ### 0.5.1 (unreleased) Language Features: + * Allow mapping type for parameters and return variables of public and external library functions. * Allow public functions to override external functions. Compiler Features: diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1a3844ad..9d536a3a 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -697,20 +697,22 @@ bool TypeChecker::visit(FunctionDefinition const& _function) } for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters()) { + if (type(*var)->category() == Type::Category::Mapping) + { + if (!type(*var)->dataStoredIn(DataLocation::Storage)) + m_errorReporter.typeError(var->location(), "Mapping types can only have a data location of \"storage\"." ); + else if (!isLibraryFunction && _function.isPublic()) + m_errorReporter.typeError(var->location(), "Mapping types for parameters or return variables can only be used in internal or library functions."); + } + else + { + if (!type(*var)->canLiveOutsideStorage() && _function.isPublic()) + m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); + if (_function.isPublic() && !(type(*var)->interfaceType(isLibraryFunction))) + m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions."); + } if ( - type(*var)->category() == Type::Category::Mapping && - !type(*var)->dataStoredIn(DataLocation::Storage) - ) - m_errorReporter.typeError(var->location(), "Mapping types can only have a data location of \"storage\"."); - else if ( - !type(*var)->canLiveOutsideStorage() && - _function.visibility() > FunctionDefinition::Visibility::Internal - ) - m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); - if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction))) - m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions."); - if ( - _function.visibility() > FunctionDefinition::Visibility::Internal && + _function.isPublic() && !_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && !typeSupportedByOldABIEncoder(*type(*var)) ) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index b0d17286..c9a1e076 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1873,6 +1873,8 @@ void ExpressionCompiler::appendExternalFunctionCall( retSize = 0; break; } + else if (retType->decodingType()) + retSize += retType->decodingType()->calldataEncodedSize(); else retSize += retType->calldataEncodedSize(); } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index c34a1399..05bb7446 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -8710,6 +8710,90 @@ BOOST_AUTO_TEST_CASE(mapping_returns_in_library_named) ABI_CHECK(callContractFunction("g()"), encodeArgs(u256(0), u256(42), u256(0), u256(0), u256(21), u256(17))); } +BOOST_AUTO_TEST_CASE(using_library_mappings_public) +{ + char const* sourceCode = R"( + library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) public + { + m[key] = value; + } + } + contract Test { + mapping(uint => uint) m1; + mapping(uint => uint) m2; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.set(m1, 0, 1); + Lib.set(m1, 2, 42); + Lib.set(m2, 0, 23); + Lib.set(m2, 2, 99); + return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); + } + } + )"; + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); +} + +BOOST_AUTO_TEST_CASE(using_library_mappings_external) +{ + char const* libSourceCode = R"( + library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) external + { + m[key] = value * 2; + } + } + )"; + char const* sourceCode = R"( + library Lib { + function set(mapping(uint => uint) storage m, uint key, uint value) external; + } + contract Test { + mapping(uint => uint) m1; + mapping(uint => uint) m2; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.set(m1, 0, 1); + Lib.set(m1, 2, 42); + Lib.set(m2, 0, 23); + Lib.set(m2, 2, 99); + return (m1[0], m1[1], m1[2], m2[0], m2[1], m2[2]); + } + } + )"; + compileAndRun(libSourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(2), u256(0), u256(84), u256(46), u256(0), u256(198))); +} + +BOOST_AUTO_TEST_CASE(using_library_mappings_return) +{ + char const* sourceCode = R"( + library Lib { + function choose(mapping(uint => mapping(uint => uint)) storage m, uint key) external returns (mapping(uint => uint) storage) { + return m[key]; + } + } + contract Test { + mapping(uint => mapping(uint => uint)) m; + function f() public returns (uint, uint, uint, uint, uint, uint) + { + Lib.choose(m, 0)[0] = 1; + Lib.choose(m, 0)[2] = 42; + Lib.choose(m, 1)[0] = 23; + Lib.choose(m, 1)[2] = 99; + return (m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2]); + } + } + )"; + compileAndRun(sourceCode, 0, "Lib"); + compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}}); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1), u256(0), u256(42), u256(23), u256(0), u256(99))); +} + BOOST_AUTO_TEST_CASE(using_library_structs) { char const* sourceCode = R"( diff --git a/test/libsolidity/syntaxTests/types/mapping/library_argument_external.sol b/test/libsolidity/syntaxTests/types/mapping/library_argument_external.sol index 1098008d..ebd05d86 100644 --- a/test/libsolidity/syntaxTests/types/mapping/library_argument_external.sol +++ b/test/libsolidity/syntaxTests/types/mapping/library_argument_external.sol @@ -3,4 +3,3 @@ library L { } } // ---- -// TypeError: (27-56): Type is required to live outside storage. diff --git a/test/libsolidity/syntaxTests/types/mapping/library_argument_public.sol b/test/libsolidity/syntaxTests/types/mapping/library_argument_public.sol index dedd4f68..36e833b7 100644 --- a/test/libsolidity/syntaxTests/types/mapping/library_argument_public.sol +++ b/test/libsolidity/syntaxTests/types/mapping/library_argument_public.sol @@ -3,4 +3,3 @@ library L { } } // ---- -// TypeError: (27-56): Type is required to live outside storage. diff --git a/test/libsolidity/syntaxTests/types/mapping/library_return_external.sol b/test/libsolidity/syntaxTests/types/mapping/library_return_external.sol index 1e756819..6c145801 100644 --- a/test/libsolidity/syntaxTests/types/mapping/library_return_external.sol +++ b/test/libsolidity/syntaxTests/types/mapping/library_return_external.sol @@ -5,6 +5,3 @@ library L } } // ---- -// TypeError: (27-58): Type is required to live outside storage. -// TypeError: (60-91): Type is required to live outside storage. -// TypeError: (123-152): Type is required to live outside storage. diff --git a/test/libsolidity/syntaxTests/types/mapping/library_return_public.sol b/test/libsolidity/syntaxTests/types/mapping/library_return_public.sol index 357751a0..a98458cd 100644 --- a/test/libsolidity/syntaxTests/types/mapping/library_return_public.sol +++ b/test/libsolidity/syntaxTests/types/mapping/library_return_public.sol @@ -5,6 +5,3 @@ library L } } // ---- -// TypeError: (27-58): Type is required to live outside storage. -// TypeError: (60-91): Type is required to live outside storage. -// TypeError: (121-150): Type is required to live outside storage. diff --git a/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_external.sol b/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_external.sol index c050f8e9..fa3757fa 100644 --- a/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_external.sol +++ b/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_external.sol @@ -2,5 +2,5 @@ contract c { function f1(mapping(uint => uint) calldata) pure external returns (mapping(uint => uint) memory) {} } // ---- -// TypeError: (29-59): Type is required to live outside storage. -// TypeError: (29-59): Internal or recursive type is not allowed for public or external functions. +// TypeError: (29-59): Mapping types for parameters or return variables can only be used in internal or library functions. +// TypeError: (84-112): Mapping types for parameters or return variables can only be used in internal or library functions. diff --git a/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_public.sol b/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_public.sol index b63868b8..8c73b5ae 100644 --- a/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_public.sol +++ b/test/libsolidity/syntaxTests/types/mapping/mapping_data_location_function_param_public.sol @@ -2,5 +2,4 @@ contract c { function f3(mapping(uint => uint) memory) view public {} } // ---- -// TypeError: (29-57): Type is required to live outside storage. -// TypeError: (29-57): Internal or recursive type is not allowed for public or external functions. +// TypeError: (29-57): Mapping types for parameters or return variables can only be used in internal or library functions. diff --git a/test/libsolidity/syntaxTests/types/mapping/mapping_return_public_memory.sol b/test/libsolidity/syntaxTests/types/mapping/mapping_return_public_memory.sol index 35c3abc9..7378324a 100644 --- a/test/libsolidity/syntaxTests/types/mapping/mapping_return_public_memory.sol +++ b/test/libsolidity/syntaxTests/types/mapping/mapping_return_public_memory.sol @@ -3,5 +3,4 @@ contract C { } } // ---- -// TypeError: (51-79): Type is required to live outside storage. -// TypeError: (51-79): Internal or recursive type is not allowed for public or external functions. +// TypeError: (51-79): Mapping types for parameters or return variables can only be used in internal or library functions. |