aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2016-09-12 19:41:38 +0800
committerGitHub <noreply@github.com>2016-09-12 19:41:38 +0800
commit149dba9ba28fef5faaa1257de4c4542741a2d2b2 (patch)
tree4cb0333ed225792929875ab00c935cf71b202ee7
parent51a98ab84a59fd5fb34378763fd9ed635cf06d8d (diff)
parent4337e70cca58c02de15af258a0efc29062aa0a36 (diff)
downloaddexon-solidity-149dba9ba28fef5faaa1257de4c4542741a2d2b2.tar.gz
dexon-solidity-149dba9ba28fef5faaa1257de4c4542741a2d2b2.tar.zst
dexon-solidity-149dba9ba28fef5faaa1257de4c4542741a2d2b2.zip
Merge pull request #1045 from pirapira/formal_type_of_mapping
formal verification: Why3 translation of mapping types
-rw-r--r--libdevcore/Assertions.h14
-rw-r--r--libsolidity/formal/Why3Translator.cpp99
-rw-r--r--libsolidity/formal/Why3Translator.h5
3 files changed, 87 insertions, 31 deletions
diff --git a/libdevcore/Assertions.h b/libdevcore/Assertions.h
index 7b4a4a76..05e0b0e5 100644
--- a/libdevcore/Assertions.h
+++ b/libdevcore/Assertions.h
@@ -73,7 +73,7 @@ inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char con
/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong.");
/// Do NOT supply an exception object as the second parameter.
#define assertThrow(_condition, _ExceptionType, _description) \
- ::dev::assertThrowAux<_ExceptionType>(_condition, _description, __LINE__, __FILE__, ETH_FUNC)
+ ::dev::assertThrowAux<_ExceptionType>(!!(_condition), _description, __LINE__, __FILE__, ETH_FUNC)
using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
@@ -96,16 +96,4 @@ inline void assertThrowAux(
);
}
-template <class _ExceptionType>
-inline void assertThrowAux(
- void const* _pointer,
- ::std::string const& _errorDescription,
- unsigned _line,
- char const* _file,
- char const* _function
-)
-{
- assertThrowAux<_ExceptionType>(_pointer != nullptr, _errorDescription, _line, _file, _function);
-}
-
}
diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp
index b441b150..f3831b40 100644
--- a/libsolidity/formal/Why3Translator.cpp
+++ b/libsolidity/formal/Why3Translator.cpp
@@ -36,6 +36,10 @@ bool Why3Translator::process(SourceUnit const& _source)
appendPreface();
_source.accept(*this);
}
+ catch (NoFormalType&)
+ {
+ solAssert(false, "There is a call to toFormalType() that does not catch NoFormalType exceptions.");
+ }
catch (FatalError& /*_e*/)
{
solAssert(m_errorOccured, "");
@@ -77,14 +81,30 @@ string Why3Translator::toFormalType(Type const& _type) const
return "uint256";
}
else if (auto type = dynamic_cast<ArrayType const*>(&_type))
+ {
if (!type->isByteArray() && type->isDynamicallySized() && type->dataStoredIn(DataLocation::Memory))
{
+ // Not catching NoFormalType exception. Let the caller deal with it.
string base = toFormalType(*type->baseType());
- if (!base.empty())
- return "array " + base;
+ return "array " + base;
+ }
+ }
+ else if (auto mappingType = dynamic_cast<MappingType const*>(&_type))
+ {
+ solAssert(mappingType->keyType(), "A mappingType misses a keyType.");
+ if (dynamic_cast<IntegerType const*>(&*mappingType->keyType()))
+ {
+ //@TODO Use the information from the key type and specify the length of the array as an invariant.
+ // Also the constructor need to specify the length of the array.
+ solAssert(mappingType->valueType(), "A mappingType misses a valueType.");
+ // Not catching NoFormalType exception. Let the caller deal with it.
+ string valueTypeFormal = toFormalType(*mappingType->valueType());
+ return "array " + valueTypeFormal;
}
+ }
- return "";
+ BOOST_THROW_EXCEPTION(NoFormalType()
+ << errinfo_noFormalTypeFrom(_type.toString(true)));
}
void Why3Translator::addLine(string const& _line)
@@ -142,9 +162,17 @@ bool Why3Translator::visit(ContractDefinition const& _contract)
m_currentContract.stateVariables = _contract.stateVariables();
for (VariableDeclaration const* variable: m_currentContract.stateVariables)
{
- string varType = toFormalType(*variable->annotation().type);
- if (varType.empty())
- fatalError(*variable, "Type not supported for state variable.");
+ string varType;
+ try
+ {
+ varType = toFormalType(*variable->annotation().type);
+ }
+ catch (NoFormalType &err)
+ {
+ string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
+ string typeName = typeNamePtr ? " \"" + *typeNamePtr + "\"" : "";
+ fatalError(*variable, "Type" + typeName + " not supported for state variable.");
+ }
addLine("mutable _" + variable->name() + ": " + varType);
}
unindent();
@@ -218,9 +246,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
add(" (this: account)");
for (auto const& param: _function.parameters())
{
- string paramType = toFormalType(*param->annotation().type);
- if (paramType.empty())
- error(*param, "Parameter type not supported.");
+ string paramType;
+ try
+ {
+ paramType = toFormalType(*param->annotation().type);
+ }
+ catch (NoFormalType &err)
+ {
+ string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
+ error(*param, "Parameter type \"" + (typeName ? *typeName : "") + "\" not supported.");
+ }
if (param->name().empty())
error(*param, "Anonymous function parameters not supported.");
add(" (arg_" + param->name() + ": " + paramType + ")");
@@ -232,9 +267,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
string retString = "(";
for (auto const& retParam: _function.returnParameters())
{
- string paramType = toFormalType(*retParam->annotation().type);
- if (paramType.empty())
- error(*retParam, "Parameter type not supported.");
+ string paramType;
+ try
+ {
+ paramType = toFormalType(*retParam->annotation().type);
+ }
+ catch (NoFormalType &err)
+ {
+ string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
+ error(*retParam, "Parameter type " + (typeName ? *typeName : "") + " not supported.");
+ }
if (retString.size() != 1)
retString += ", ";
retString += paramType;
@@ -264,14 +306,32 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
{
if (variable->name().empty())
error(*variable, "Unnamed return variables not yet supported.");
- string varType = toFormalType(*variable->annotation().type);
+ string varType;
+ try
+ {
+ varType = toFormalType(*variable->annotation().type);
+ }
+ catch (NoFormalType &err)
+ {
+ string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
+ error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in return parameter not yet supported.");
+ }
addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in");
}
for (VariableDeclaration const* variable: _function.localVariables())
{
if (variable->name().empty())
error(*variable, "Unnamed variables not yet supported.");
- string varType = toFormalType(*variable->annotation().type);
+ string varType;
+ try
+ {
+ varType = toFormalType(*variable->annotation().type);
+ }
+ catch (NoFormalType &err)
+ {
+ string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
+ error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in variable declaration not yet supported.");
+ }
addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in");
}
addLine("try");
@@ -434,8 +494,15 @@ bool Why3Translator::visit(TupleExpression const& _node)
bool Why3Translator::visit(UnaryOperation const& _unaryOperation)
{
- if (toFormalType(*_unaryOperation.annotation().type).empty())
- error(_unaryOperation, "Type not supported in unary operation.");
+ try
+ {
+ toFormalType(*_unaryOperation.annotation().type);
+ }
+ catch (NoFormalType &err)
+ {
+ string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err);
+ error(_unaryOperation, "Type \"" + (typeNamePtr ? *typeNamePtr : "") + "\" supported in unary operation.");
+ }
switch (_unaryOperation.getOperator())
{
diff --git a/libsolidity/formal/Why3Translator.h b/libsolidity/formal/Why3Translator.h
index 1b80ed61..22bfff89 100644
--- a/libsolidity/formal/Why3Translator.h
+++ b/libsolidity/formal/Why3Translator.h
@@ -60,9 +60,10 @@ private:
/// Appends imports and constants use throughout the formal code.
void appendPreface();
- /// @returns a string representation of the corresponding formal type or the empty string
- /// if the type is not supported.
+ /// @returns a string representation of the corresponding formal type or throws NoFormalType exception.
std::string toFormalType(Type const& _type) const;
+ using errinfo_noFormalTypeFrom = boost::error_info<struct tag_noFormalTypeFrom, std::string /* name of the type that cannot be translated */ >;
+ struct NoFormalType: virtual Exception {};
void indent() { newLine(); m_lines.back().indentation++; }
void unindent();