diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 35 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h | 3 |
2 files changed, 33 insertions, 5 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index af4d44a6..7af0f5ed 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1330,11 +1330,41 @@ bool TypeChecker::visit(Conditional const& _conditional) return false; } +void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& _expression) +{ + if (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(&_expression)) + { + auto const* tupleType = dynamic_cast<TupleType const*>(&_type); + auto const& types = tupleType ? tupleType->components() : vector<TypePointer> { _type.shared_from_this() }; + + solAssert(tupleExpression->components().size() == types.size(), ""); + for (size_t i = 0; i < types.size(); i++) + if (types[i]) + { + solAssert(!!tupleExpression->components()[i], ""); + checkExpressionAssignment(*types[i], *tupleExpression->components()[i]); + } + } + else if (_type.category() == Type::Category::Mapping) + { + bool isLocalOrReturn = false; + if (auto const* identifier = dynamic_cast<Identifier const*>(&_expression)) + if (auto const *variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration)) + if (variableDeclaration->isLocalOrReturn()) + isLocalOrReturn = true; + if (!isLocalOrReturn) + m_errorReporter.typeError(_expression.location(), "Mappings cannot be assigned to."); + } +} + bool TypeChecker::visit(Assignment const& _assignment) { requireLValue(_assignment.leftHandSide()); TypePointer t = type(_assignment.leftHandSide()); _assignment.annotation().type = t; + + checkExpressionAssignment(*t, _assignment.leftHandSide()); + if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t.get())) { if (_assignment.assignmentOperator() != Token::Assign) @@ -1351,11 +1381,6 @@ bool TypeChecker::visit(Assignment const& _assignment) if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide()).get())) checkDoubleStorageAssignment(_assignment); } - else if (t->category() == Type::Category::Mapping) - { - m_errorReporter.typeError(_assignment.location(), "Mappings cannot be assigned to."); - _assignment.rightHandSide().accept(*this); - } else if (_assignment.assignmentOperator() == Token::Assign) expectType(_assignment.rightHandSide(), *t); else diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 8dc6b376..47892a3f 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -87,6 +87,9 @@ private: /// Checks (and warns) if a tuple assignment might cause unexpected overwrites in storage. /// Should only be called if the left hand side is tuple-typed. void checkDoubleStorageAssignment(Assignment const& _assignment); + // Checks whether the expression @arg _expression can be assigned from type @arg _type + // and reports an error, if not. + void checkExpressionAssignment(Type const& _type, Expression const& _expression); virtual void endVisit(InheritanceSpecifier const& _inheritance) override; virtual void endVisit(UsingForDirective const& _usingFor) override; |