| 1418 | } |
| 1419 | |
| 1420 | void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& _expression) |
| 1421 | { |
| 1422 | if (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(&_expression)) |
| 1423 | { |
| 1424 | if (tupleExpression->components().empty()) |
| 1425 | m_errorReporter.typeError(5547_error, _expression.location(), "Empty tuple on the left hand side."); |
| 1426 | |
| 1427 | auto const* tupleType = dynamic_cast<TupleType const*>(&_type); |
| 1428 | auto const& types = tupleType && tupleExpression->components().size() != 1 ? tupleType->components() : std::vector<Type const*> { &_type }; |
| 1429 | |
| 1430 | solAssert( |
| 1431 | tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(), |
| 1432 | "Array sizes don't match and no errors generated." |
| 1433 | ); |
| 1434 | |
| 1435 | for (size_t i = 0; i < std::min(tupleExpression->components().size(), types.size()); i++) |
| 1436 | if (types[i]) |
| 1437 | { |
| 1438 | solAssert(!!tupleExpression->components()[i], ""); |
| 1439 | checkExpressionAssignment(*types[i], *tupleExpression->components()[i]); |
| 1440 | } |
| 1441 | } |
| 1442 | else if (_type.nameable() && _type.containsNestedMapping()) |
| 1443 | { |
| 1444 | bool isLocalOrReturn = false; |
| 1445 | if (auto const* identifier = dynamic_cast<Identifier const*>(&_expression)) |
| 1446 | if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration)) |
| 1447 | if (variableDeclaration->isLocalOrReturn()) |
| 1448 | isLocalOrReturn = true; |
| 1449 | if (!isLocalOrReturn) |
| 1450 | m_errorReporter.typeError(9214_error, _expression.location(), "Types in storage containing (nested) mappings cannot be assigned to."); |
| 1451 | } |
| 1452 | } |
| 1453 | |
| 1454 | bool TypeChecker::visit(Assignment const& _assignment) |
| 1455 | { |
nothing calls this directly
no test coverage detected