diff options
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 12 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 23 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 3 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 17 |
4 files changed, 37 insertions, 18 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index bebdb9b6..c8e64c78 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1551,16 +1551,22 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) _functionCall.expression().annotation().isPure && functionType->isPure(); + bool allowDynamicTypes = false; // @TODO if (!functionType) { m_errorReporter.typeError(_functionCall.location(), "Type is not callable"); _functionCall.annotation().type = make_shared<TupleType>(); return false; } - else if (functionType->returnParameterTypes().size() == 1) - _functionCall.annotation().type = functionType->returnParameterTypes().front(); + + auto returnTypes = + allowDynamicTypes ? + functionType->returnParameterTypes() : + functionType->returnParameterTypesWithoutDynamicTypes(); + if (returnTypes.size() == 1) + _functionCall.annotation().type = returnTypes.front(); else - _functionCall.annotation().type = make_shared<TupleType>(functionType->returnParameterTypes()); + _functionCall.annotation().type = make_shared<TupleType>(returnTypes); if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression())) { diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index b2881bea..41700e28 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2311,6 +2311,18 @@ vector<string> FunctionType::parameterNames() const return vector<string>(m_parameterNames.cbegin() + 1, m_parameterNames.cend()); } +TypePointers FunctionType::returnParameterTypesWithoutDynamicTypes() const +{ + TypePointers returnParameterTypes = m_returnParameterTypes; + + if (m_kind == Kind::External || m_kind == Kind::CallCode || m_kind == Kind::DelegateCall) + for (auto& param: returnParameterTypes) + if (param->isDynamicallySized() && !param->dataStoredIn(DataLocation::Storage)) + param = make_shared<InaccessibleDynamicType>(); + + return returnParameterTypes; +} + TypePointers FunctionType::parameterTypes() const { if (!bound()) @@ -2772,18 +2784,9 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) kind = Kind::DelegateCall; } - TypePointers returnParameterTypes = m_returnParameterTypes; - if (kind != Kind::Internal) - { - // Alter dynamic types to be non-accessible. - for (auto& param: returnParameterTypes) - if (param->isDynamicallySized()) - param = make_shared<InaccessibleDynamicType>(); - } - return make_shared<FunctionType>( parameterTypes, - returnParameterTypes, + m_returnParameterTypes, m_parameterNames, m_returnParameterNames, kind, diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index c20a025f..c930dd24 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -973,6 +973,9 @@ public: TypePointers parameterTypes() const; std::vector<std::string> parameterNames() const; TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; } + /// @returns the list of return parameter types. All dynamically-sized types (this excludes + /// storage pointers) are replaced by InaccessibleDynamicType instances. + TypePointers returnParameterTypesWithoutDynamicTypes() const; std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; } /// @returns the "self" parameter type for a bound function TypePointer const& selfType() const; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index f50628ff..7d148c0c 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -139,8 +139,8 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& utils().popStackSlots(paramTypes.size() - 1); } unsigned retSizeOnStack = 0; - solAssert(accessorType.returnParameterTypes().size() >= 1, ""); - auto const& returnTypes = accessorType.returnParameterTypes(); + auto returnTypes = accessorType.returnParameterTypes(); + solAssert(returnTypes.size() >= 1, ""); if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get())) { // remove offset @@ -1618,15 +1618,22 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context.experimentalFeatureActive(ExperimentalFeature::V050) && m_context.evmVersion().hasStaticCall(); + bool allowDynamicTypes = false; // @TODO unsigned retSize = 0; + TypePointers returnTypes; if (returnSuccessCondition) retSize = 0; // return value actually is success condition + else if (allowDynamicTypes) + returnTypes = _functionType.returnParameterTypes(); else - for (auto const& retType: _functionType.returnParameterTypes()) + { + returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes(); + for (auto const& retType: returnTypes) { solAssert(!retType->isDynamicallySized(), "Unable to return dynamic type from external call."); retSize += retType->calldataEncodedSize(); } + } // Evaluate arguments. TypePointers argumentTypes; @@ -1824,11 +1831,11 @@ void ExpressionCompiler::appendExternalFunctionCall( utils().fetchFreeMemoryPointer(); m_context << Instruction::SUB << Instruction::MLOAD; } - else if (!_functionType.returnParameterTypes().empty()) + else if (!returnTypes.empty()) { utils().fetchFreeMemoryPointer(); bool memoryNeeded = false; - for (auto const& retType: _functionType.returnParameterTypes()) + for (auto const& retType: returnTypes) { utils().loadFromMemoryDynamic(*retType, false, true, true); if (dynamic_cast<ReferenceType const*>(retType.get())) |