diff options
author | chriseth <chris@ethereum.org> | 2018-05-04 01:21:42 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2018-05-08 22:13:32 +0800 |
commit | fe12f05c080bd143cfb656f71e54d586d0810c4f (patch) | |
tree | 5ac4b16c6a40b4a9671af67946c36a7e3fcf38b8 | |
parent | 506d82796d53f5548fafbb10c59a3d409f425090 (diff) | |
download | dexon-solidity-fe12f05c080bd143cfb656f71e54d586d0810c4f.tar.gz dexon-solidity-fe12f05c080bd143cfb656f71e54d586d0810c4f.tar.zst dexon-solidity-fe12f05c080bd143cfb656f71e54d586d0810c4f.zip |
Deprecate wildcard assignments.
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 57 |
2 files changed, 50 insertions, 8 deletions
diff --git a/Changelog.md b/Changelog.md index 7c4ac925..37e0b0a1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Features: * Optimizer: Remove unnecessary masking of the result of known short instructions (``ADDRESS``, ``CALLER``, ``ORIGIN`` and ``COINBASE``). * Type Checker: Deprecate the ``years`` unit denomination and raise a warning for it (or an error as experimental 0.5.0 feature). * Type Checker: Make literals (without explicit type casting) an error for tight packing as experimental 0.5.0 feature. + * Type Checker: Warn about wildcard tuple assignments (this will turn into an error with version 0.5.0). Bugfixes: * Type Checker: Show proper error when trying to ``emit`` a non-event. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 32cf1b18..a222bdf0 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1076,6 +1076,7 @@ void TypeChecker::endVisit(EmitStatement const& _emit) bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { + bool const v050 = m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); if (!_statement.initialValue()) { // No initial value is only permitted for single variables with specified type. @@ -1092,7 +1093,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) if (varDecl.referenceLocation() == VariableDeclaration::Location::Default) errorText += " Did you mean '<type> memory " + varDecl.name() + "'?"; solAssert(m_scope, ""); - if (m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050)) + if (v050) m_errorReporter.declarationError(varDecl.location(), errorText); else m_errorReporter.warning(varDecl.location(), errorText); @@ -1132,12 +1133,33 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) ") in value for variable assignment (0) needed" ); } - else if (valueTypes.size() != variables.size() && !variables.front() && !variables.back()) - m_errorReporter.fatalTypeError( - _statement.location(), - "Wildcard both at beginning and end of variable declaration list is only allowed " - "if the number of components is equal." - ); + else if (valueTypes.size() != variables.size()) + { + if (v050) + m_errorReporter.fatalTypeError( + _statement.location(), + "Different number of components on the left hand side (" + + toString(variables.size()) + + ") than on the right hand side (" + + toString(valueTypes.size()) + + ")." + ); + else if (!variables.front() && !variables.back()) + m_errorReporter.fatalTypeError( + _statement.location(), + "Wildcard both at beginning and end of variable declaration list is only allowed " + "if the number of components is equal." + ); + else + m_errorReporter.warning( + _statement.location(), + "Different number of components on the left hand side (" + + toString(variables.size()) + + ") than on the right hand side (" + + toString(valueTypes.size()) + + ")." + ); + } size_t minNumValues = variables.size(); if (!variables.empty() && (!variables.back() || !variables.front())) --minNumValues; @@ -1335,6 +1357,7 @@ bool TypeChecker::visit(Conditional const& _conditional) bool TypeChecker::visit(Assignment const& _assignment) { + bool const v050 = m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); requireLValue(_assignment.leftHandSide()); TypePointer t = type(_assignment.leftHandSide()); _assignment.annotation().type = t; @@ -1347,11 +1370,29 @@ bool TypeChecker::visit(Assignment const& _assignment) ); // Sequenced assignments of tuples is not valid, make the result a "void" type. _assignment.annotation().type = make_shared<TupleType>(); + expectType(_assignment.rightHandSide(), *tupleType); // expectType does not cause fatal errors, so we have to check again here. - if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide()).get())) + if (TupleType const* rhsType = dynamic_cast<TupleType const*>(type(_assignment.rightHandSide()).get())) + { checkDoubleStorageAssignment(_assignment); + // @todo For 0.5.0, this code shoud move to TupleType::isImplicitlyConvertibleTo, + // but we cannot do it right now. + if (rhsType->components().size() != tupleType->components().size()) + { + string message = + "Different number of components on the left hand side (" + + toString(tupleType->components().size()) + + ") than on the right hand side (" + + toString(rhsType->components().size()) + + ")."; + if (v050) + m_errorReporter.typeError(_assignment.location(), message); + else + m_errorReporter.warning(_assignment.location(), message); + } + } } else if (t->category() == Type::Category::Mapping) { |