diff options
author | Christian Parpart <christian@ethereum.org> | 2018-07-02 23:00:09 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2018-07-11 04:14:19 +0800 |
commit | 1505e28b56c3a90abdb606ed1389394d7918d7eb (patch) | |
tree | dc7e6da3a8ce720de73313065cceb6ec9f34cc9b /libsolidity | |
parent | d84976dc871a1fdfab233650b989af69e325bf2b (diff) | |
download | dexon-solidity-1505e28b56c3a90abdb606ed1389394d7918d7eb.tar.gz dexon-solidity-1505e28b56c3a90abdb606ed1389394d7918d7eb.tar.zst dexon-solidity-1505e28b56c3a90abdb606ed1389394d7918d7eb.zip |
semantics: Suggest auto-deduced type when user declares variable with `var` keyword.
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/SyntaxChecker.cpp | 9 | ||||
-rw-r--r-- | libsolidity/analysis/SyntaxChecker.h | 2 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 76 |
3 files changed, 68 insertions, 19 deletions
diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 63f8fac3..4311e77d 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -254,15 +254,6 @@ bool SyntaxChecker::visit(FunctionTypeName const& _node) return true; } -bool SyntaxChecker::visit(VariableDeclaration const& _declaration) -{ - if (!_declaration.typeName()) - { - m_errorReporter.syntaxError(_declaration.location(), "Use of the \"var\" keyword is disallowed."); - } - return true; -} - bool SyntaxChecker::visit(StructDefinition const& _struct) { if (_struct.members().empty()) diff --git a/libsolidity/analysis/SyntaxChecker.h b/libsolidity/analysis/SyntaxChecker.h index 1579df57..8ee3df37 100644 --- a/libsolidity/analysis/SyntaxChecker.h +++ b/libsolidity/analysis/SyntaxChecker.h @@ -69,8 +69,6 @@ private: virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(FunctionTypeName const& _node) override; - virtual bool visit(VariableDeclaration const& _declaration) override; - virtual bool visit(StructDefinition const& _struct) override; ErrorReporter& m_errorReporter; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 78536664..9de7829c 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -23,6 +23,7 @@ #include <libsolidity/analysis/TypeChecker.h> #include <memory> #include <boost/algorithm/string/predicate.hpp> +#include <boost/algorithm/string/join.hpp> #include <boost/range/adaptor/reversed.hpp> #include <libsolidity/ast/AST.h> #include <libsolidity/inlineasm/AsmAnalysis.h> @@ -1051,6 +1052,49 @@ void TypeChecker::endVisit(EmitStatement const& _emit) m_insideEmitStatement = false; } +/** + * Creates a tuple declaration syntax from a vector of variable declarations. + * + * @param decls a tuple of variables + * + * @returns a Solidity language confirming string of a tuple variable declaration. + */ +static string createTupleDecl(vector<VariableDeclaration const*> const & decls) +{ + vector<string> components; + for (VariableDeclaration const* decl : decls) + if (decl) + components.emplace_back(decl->annotation().type->toString(false) + " " + decl->name()); + else + components.emplace_back(); + + if (decls.size() == 1) + return components.front(); + else + return "(" + boost::algorithm::join(components, ", ") + ")"; +} + +static bool typeCanBeExpressed(vector<VariableDeclaration const*> const & decls) +{ + for (VariableDeclaration const* decl : decls) + { + // skip empty tuples (they can be expressed of course) + if (!decl) + continue; + + if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type.get())) + { + if ( + functionType->kind() != FunctionType::Kind::Internal && + functionType->kind() != FunctionType::Kind::External + ) + return false; + } + } + + return true; +} + bool TypeChecker::visit(VariableDeclarationStatement const& _statement) { bool const v050 = m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050); @@ -1161,6 +1205,8 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) else assignments[assignments.size() - i - 1] = variables[variables.size() - i - 1].get(); + bool autoTypeDeductionNeeded = false; + for (size_t i = 0; i < assignments.size(); ++i) { if (!assignments[i]) @@ -1171,6 +1217,8 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) solAssert(!!valueComponentType, ""); if (!var.annotation().type) { + autoTypeDeductionNeeded = true; + // Infer type from value. solAssert(!var.typeName(), ""); var.annotation().type = valueComponentType->mobileType(); @@ -1214,14 +1262,6 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) } else solAssert(dynamic_cast<FixedPointType const*>(var.annotation().type.get()), "Unknown type."); - - m_errorReporter.warning( - _statement.location(), - "The type of this variable was inferred as " + - typeName + - extension + - ". This is probably not desired. Use an explicit type to silence this warning." - ); } var.accept(*this); @@ -1258,6 +1298,26 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) } } } + + if (autoTypeDeductionNeeded) + { + if (!typeCanBeExpressed(assignments)) + { + m_errorReporter.syntaxError(_statement.location(), + "Use of the \"var\" keyword is disallowed. " + "Type cannot be expressed in syntax."); + } + else + { + // report with trivial snipped `uint i = ...` + string const typeName = createTupleDecl(assignments); + + m_errorReporter.syntaxError(_statement.location(), + "Use of the \"var\" keyword is disallowed. " + "Use explicit declaration `" + typeName + " = ...ยด instead."); + } + } + return false; } |