Merge pull request #6168 from ethereum/better-errors-is-implictily-convertable

Prepare code to output errors returned by isImplicitlyConvertibleTo()
This commit is contained in:
chriseth 2019-03-05 15:28:29 +01:00 committed by GitHub
commit d7e36bb033
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 29 deletions

View File

@ -26,6 +26,9 @@
#include <liblangutil/Exceptions.h>
#include <liblangutil/SourceLocation.h>
#include <libdevcore/StringUtils.h>
#include <boost/range/adaptor/filtered.hpp>
namespace langutil
{
@ -87,6 +90,19 @@ public:
void typeError(SourceLocation const& _location, std::string const& _description);
template <typename... Strings>
void typeErrorConcatenateDescriptions(SourceLocation const& _location, Strings const&... _descriptions)
{
std::initializer_list<std::string> const descs = {_descriptions...};
solAssert(descs.size() > 0, "Need error descriptions!");
auto filterEmpty = boost::adaptors::filtered([](std::string const& _s) { return !_s.empty(); });
std::string errorStr = dev::joinHumanReadable(descs | filterEmpty);
error(Error::Type::TypeError, _location, errorStr);
}
void fatalTypeError(SourceLocation const& _location, std::string const& _description);
void docstringParsingError(std::string const& _description);

View File

@ -139,14 +139,21 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
toString(arguments.size()) +
" were provided."
);
if (arguments.size() >= 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory()))
m_errorReporter.typeError(
arguments.front()->location(),
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
type(*arguments.front())->toString() +
" to bytes memory requested."
);
if (arguments.size() >= 1)
{
BoolResult result = type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory());
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
arguments.front()->location(),
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
type(*arguments.front())->toString() +
" to bytes memory requested.",
result.message()
);
}
if (arguments.size() < 2)
return {};
@ -262,16 +269,20 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
);
}
for (size_t i = 0; i < std::min(arguments->size(), parameterTypes.size()); ++i)
if (!type(*(*arguments)[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
m_errorReporter.typeError(
{
BoolResult result = type(*(*arguments)[i])->isImplicitlyConvertibleTo(*parameterTypes[i]);
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
(*arguments)[i]->location(),
"Invalid type for argument in constructor call. "
"Invalid implicit conversion from " +
type(*(*arguments)[i])->toString() +
" to " +
parameterTypes[i]->toString() +
" requested."
" requested.",
result.message()
);
}
}
}
@ -566,16 +577,20 @@ void TypeChecker::visitManually(
return;
}
for (size_t i = 0; i < arguments.size(); ++i)
if (!type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i])))
m_errorReporter.typeError(
{
BoolResult result = type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i]));
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
arguments[i]->location(),
"Invalid type for argument in modifier invocation. "
"Invalid implicit conversion from " +
type(*arguments[i])->toString() +
" to " +
type(*(*parameters)[i])->toString() +
" requested."
" requested.",
result.message()
);
}
}
bool TypeChecker::visit(EventDefinition const& _eventDef)
@ -767,29 +782,34 @@ void TypeChecker::endVisit(Return const& _return)
{
if (tupleType->components().size() != params->parameters().size())
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
else if (!tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes)))
m_errorReporter.typeError(
_return.expression()->location(),
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type " +
TupleType(returnTypes).toString(false) +
"."
);
else
{
BoolResult result = tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes));
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
_return.expression()->location(),
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type " +
TupleType(returnTypes).toString(false) + ".",
result.message()
);
}
}
else if (params->parameters().size() != 1)
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
else
{
TypePointer const& expected = type(*params->parameters().front());
if (!type(*_return.expression())->isImplicitlyConvertibleTo(*expected))
m_errorReporter.typeError(
BoolResult result = type(*_return.expression())->isImplicitlyConvertibleTo(*expected);
if (!result)
m_errorReporter.typeErrorConcatenateDescriptions(
_return.expression()->location(),
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type (type of first return variable) " +
expected->toString() +
"."
expected->toString() + ".",
result.message()
);
}
}
@ -981,7 +1001,8 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
else
{
var.accept(*this);
if (!valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type))
BoolResult result = valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type);
if (!result)
{
auto errorMsg = "Type " +
valueComponentType->toString() +
@ -1008,7 +1029,11 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
);
}
else
m_errorReporter.typeError(_statement.location(), errorMsg + ".");
m_errorReporter.typeErrorConcatenateDescriptions(
_statement.location(),
errorMsg + ".",
result.message()
);
}
}
}