diff options
Diffstat (limited to 'libsolidity/TypeChecker.cpp')
-rw-r--r-- | libsolidity/TypeChecker.cpp | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/libsolidity/TypeChecker.cpp b/libsolidity/TypeChecker.cpp index ca5b1eb7..c7b693bb 100644 --- a/libsolidity/TypeChecker.cpp +++ b/libsolidity/TypeChecker.cpp @@ -560,13 +560,31 @@ void TypeChecker::endVisit(Return const& _return) return; ParameterList const* params = _return.annotation().functionReturnParameters; if (!params) + { typeError(_return, "Return arguments not allowed."); + return; + } + TypePointers returnTypes; + for (auto const& var: params->parameters()) + returnTypes.push_back(type(*var)); + if (auto tupleType = dynamic_cast<TupleType const*>(type(*_return.expression()).get())) + { + if (tupleType->components().size() != params->parameters().size()) + typeError(_return, "Different number of arguments in return statement than in returns declaration."); + else if (!tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes))) + typeError( + *_return.expression(), + "Return argument type " + + type(*_return.expression())->toString() + + " is not implicitly convertible to expected type " + + TupleType(returnTypes).toString(false) + + "." + ); + } else if (params->parameters().size() != 1) typeError(_return, "Different number of arguments in return statement than in returns declaration."); else { - // this could later be changed such that the paramaters type is an anonymous struct type, - // but for now, we only allow one return parameter TypePointer const& expected = type(*params->parameters().front()); if (!type(*_return.expression())->isImplicitlyConvertibleTo(*expected)) typeError( @@ -590,7 +608,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) VariableDeclaration const& varDecl = *_statement.declarations().front(); if (!varDecl.annotation().type) fatalTypeError(_statement, "Assignment necessary for type detection."); - if (auto ref = dynamic_cast<ReferenceType const*>(varDecl.annotation().type.get())) + if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl).get())) { if (ref->dataStoredIn(DataLocation::Storage)) { @@ -610,10 +628,10 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) _statement.initialValue()->accept(*this); TypePointers valueTypes; - if (auto tupleType = dynamic_cast<TupleType const*>(_statement.initialValue()->annotation().type.get())) + if (auto tupleType = dynamic_cast<TupleType const*>(type(*_statement.initialValue()).get())) valueTypes = tupleType->components(); else - valueTypes = TypePointers{_statement.initialValue()->annotation().type}; + valueTypes = TypePointers{type(*_statement.initialValue())}; // Determine which component is assigned to which variable. // If numbers do not match, fill up if variables begin or end empty (not both). @@ -741,6 +759,51 @@ bool TypeChecker::visit(Assignment const& _assignment) return false; } +bool TypeChecker::visit(TupleExpression const& _tuple) +{ + vector<ASTPointer<Expression>> const& components = _tuple.components(); + TypePointers types; + if (_tuple.annotation().lValueRequested) + { + for (auto const& component: components) + if (component) + { + requireLValue(*component); + types.push_back(type(*component)); + } + else + types.push_back(TypePointer()); + _tuple.annotation().type = make_shared<TupleType>(types); + // If some of the components are not LValues, the error is reported above. + _tuple.annotation().isLValue = true; + } + else + { + for (size_t i = 0; i < components.size(); ++i) + { + // Outside of an lvalue-context, the only situation where a component can be empty is (x,). + if (!components[i] && !(i == 1 && components.size() == 2)) + fatalTypeError(_tuple, "Tuple component cannot be empty."); + else if (components[i]) + { + components[i]->accept(*this); + types.push_back(type(*components[i])); + } + else + types.push_back(TypePointer()); + } + if (components.size() == 1) + _tuple.annotation().type = type(*components[0]); + else + { + if (components.size() == 2 && !components[1]) + types.pop_back(); + _tuple.annotation().type = make_shared<TupleType>(types); + } + } + return false; +} + bool TypeChecker::visit(UnaryOperation const& _operation) { // Inc, Dec, Add, Sub, Not, BitNot, Delete @@ -1236,10 +1299,10 @@ void TypeChecker::expectType(Expression const& _expression, Type const& _expecte void TypeChecker::requireLValue(Expression const& _expression) { + _expression.annotation().lValueRequested = true; _expression.accept(*this); if (!_expression.annotation().isLValue) typeError(_expression, "Expression has to be an lvalue."); - _expression.annotation().lValueRequested = true; } void TypeChecker::typeError(ASTNode const& _node, string const& _description) |