From 1505e28b56c3a90abdb606ed1389394d7918d7eb Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 2 Jul 2018 17:00:09 +0200 Subject: semantics: Suggest auto-deduced type when user declares variable with `var` keyword. --- libsolidity/analysis/SyntaxChecker.cpp | 9 --- libsolidity/analysis/SyntaxChecker.h | 2 - libsolidity/analysis/TypeChecker.cpp | 76 +++++++++++++++++++--- .../syntaxTests/types/var_type_suggest.sol | 23 +++++++ 4 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 test/libsolidity/syntaxTests/types/var_type_suggest.sol 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 #include #include +#include #include #include #include @@ -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 const & decls) +{ + vector 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 const & decls) +{ + for (VariableDeclaration const* decl : decls) + { + // skip empty tuples (they can be expressed of course) + if (!decl) + continue; + + if (auto functionType = dynamic_cast(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(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; } diff --git a/test/libsolidity/syntaxTests/types/var_type_suggest.sol b/test/libsolidity/syntaxTests/types/var_type_suggest.sol new file mode 100644 index 00000000..176fab96 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/var_type_suggest.sol @@ -0,0 +1,23 @@ +contract C { + function h() internal pure returns (uint, uint, uint) { + return (1, 2, 4); + } + function g(uint x) internal pure returns (uint) { + return x; + } + function f() internal pure { + var i = 31415; + var t = "string"; + var g2 = g; + var myblockhash = block.blockhash; + var (a, b) = (2, "troi"); + var (x,, z) = h(); + } +} +// ---- +// SyntaxError: (224-237): Use of the "var" keyword is disallowed. Use explicit declaration `uint16 i = ...´ instead. +// SyntaxError: (247-263): Use of the "var" keyword is disallowed. Use explicit declaration `string memory t = ...´ instead. +// SyntaxError: (273-283): Use of the "var" keyword is disallowed. Use explicit declaration `function (uint256) pure returns (uint256) g2 = ...´ instead. +// SyntaxError: (293-326): Use of the "var" keyword is disallowed. Type cannot be expressed in syntax. +// SyntaxError: (336-360): Use of the "var" keyword is disallowed. Use explicit declaration `(uint8 a, string memory b) = ...´ instead. +// SyntaxError: (370-387): Use of the "var" keyword is disallowed. Use explicit declaration `(uint256 x, , uint256 z) = ...´ instead. -- cgit