Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.64.0 #110

Merged
merged 1 commit into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion API.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ contract development.
* [\<optional(Type)\>.set()](#optionaltypeset)
* [\<optional(Type)\>.reset()](#optionaltypereset)
* [Keyword `null`](#keyword-null)
* [variant](#variant)
* [variant.isUint()](#variantisuint)
* [variant.toUint()](#varianttouint)
* [vector(Type)](#vectortype)
* [\<vector(Type)\>.push(Type)](#vectortypepushtype)
* [\<vector(Type)\>.pop()](#vectortypepop)
Expand All @@ -68,6 +71,7 @@ contract development.
* [TON specific control structures](#ton-specific-control-structures)
* [Range-based for loop](#range-based-for-loop)
* [repeat](#repeat)
* [try-catch](#trycatch)
* [Changes and extensions in Solidity types](#changes-and-extensions-in-solidity-types)
* [Integers](#integers)
* [bitSize() and uBitSize()](#bitsize-and-ubitsize)
Expand Down Expand Up @@ -893,7 +897,7 @@ Replaces content of the `optional` with **value**.
<optional(Type)>.reset();
```

Deletes contents of the `optional`.
Deletes content of the `optional`.

##### Keyword `null`

Expand All @@ -905,6 +909,22 @@ optional(uint) x = 123;
x = null; // reset value
```

#### variant

The `variant` type acts like a union for the most common solidity data types. Supported only `uint` so far.

#### variant.isUint()

```TVMSolidity
<variant>.isUint() returns (bool)
```

Checks whether `<variant>` holds `uint` type.

#### variant.toUint()

Converts `<variant>` to `uint` type if it's possible. Otherwise, throws an exception with code `77`.

#### vector(Type)

`vector(Type)` is a template container type capable of storing an arbitrary set of values of a
Expand Down Expand Up @@ -1053,6 +1073,45 @@ repeat(a - 1) {
// a == 1
```

#### try-catch

It is an experimental feature available only in certain blockchain networks.

The `try` statement allows you to define a block of code to be tested for errors while it is executed. The
`catch` statement allows you to define a block of code to be executed, if an error occurs in the try block.
`catch` block gets two parameters of type variant and uint, whick contain exception argument and code respectively.
Example:

```TVMSolidity
TvmBuilder builder;
uint c = 0;
try {
c = a + b;
require(c != 42, 100, 22);
require(c != 43, 100, 33);
builder.store(c);
} catch (variant value, uint errorCode) {
uint errorValue;
if (value.isUint()) {
errorValue = value.toUint();
}

if (errorCode == 100) {
if (errorValue == 22) {
// it was line: `require(c != 42, 100, 22);`
} else if (errorValue == 33) {
// it was line: `require(c != 43, 100, 33);`
}
} else if (errorCode == 8) {
// Cell overflow
// It was line: `builder.store(c);`
} else if (errorCode == 4) {
// Integer overflow
// It was line: `c = a + b;`
}
}
```

### Changes and extensions in Solidity types

#### Integers
Expand Down Expand Up @@ -4386,6 +4445,7 @@ Solidity runtime error codes:
* **74** - Await answer message has wrong source address.
* **75** - Await answer message has wrong function id.
* **76** - Public function was called before constructor.
* **77** - It's impossible to convert `variant` type to target type. See [variant.toUint()](#varianttouint)

### Division and rounding

Expand Down
12 changes: 12 additions & 0 deletions Changelog_TON.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
### 0.64.0 (2022-08-18)

Fixed build [sold](https://github.com/tonlabs/TON-Solidity-Compiler/tree/master/sold) for Windows and macOS.

Compiler features:
* Supported [ABI v2.3](https://github.com/tonlabs/ton-labs-abi/blob/master/docs/ABI_2.3_spec.md).
* Supported try-catch (experimental feature).
* Supported type `variant`.

Typo:
* Rename function `storeZeros` -> `storeZeroes`.

### 0.63.0 (2022-07-27)

Compiler features:
Expand Down
2 changes: 1 addition & 1 deletion compiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ include(EthPolicy)
eth_policy()

# project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.63.0")
set(PROJECT_VERSION "0.64.0")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)

include(TestBigEndian)
Expand Down
1 change: 1 addition & 0 deletions compiler/liblangutil/Token.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ namespace solidity::langutil
K(TvmSlice, "TvmSlice", 0) \
K(TvmBuilder, "TvmBuilder", 0) \
K(ExtraCurrencyCollection, "ExtraCurrencyCollection", 0) \
K(Variant, "variant", 0) \
K(Fixed, "fixed", 0) \
K(UFixed, "ufixed", 0) \
T(IntM, "intM", 0) \
Expand Down
7 changes: 3 additions & 4 deletions compiler/libsolidity/analysis/ControlFlowBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,10 @@ bool ControlFlowBuilder::visit(Conditional const& _conditional)

bool ControlFlowBuilder::visit(TryStatement const& _tryStatement)
{
appendControlFlow(_tryStatement.externalCall());
appendControlFlow(_tryStatement.body());

auto nodes = splitFlow(_tryStatement.clauses().size());
for (size_t i = 0; i < _tryStatement.clauses().size(); ++i)
nodes[i] = createFlow(nodes[i], _tryStatement.clauses()[i]->block());
auto nodes = splitFlow(1);
nodes[0] = createFlow(nodes[0], _tryStatement.clause().block());
mergeFlow(nodes);

return false;
Expand Down
146 changes: 18 additions & 128 deletions compiler/libsolidity/analysis/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1026,134 +1026,24 @@ bool TypeChecker::visit(IfStatement const& _ifStatement)

void TypeChecker::endVisit(TryStatement const& _tryStatement)
{
m_errorReporter.fatalTypeError(
_tryStatement.location(),
"Try-catch statement is not supported yet."
);

FunctionCall const* externalCall = dynamic_cast<FunctionCall const*>(&_tryStatement.externalCall());
if (!externalCall || externalCall->annotation().kind != FunctionCallKind::FunctionCall)
{
m_errorReporter.typeError(
_tryStatement.externalCall().location(),
"Try can only be used with external function calls and contract creation calls."
);
return;
}

FunctionType const& functionType = dynamic_cast<FunctionType const&>(*externalCall->expression().annotation().type);
if (
functionType.kind() != FunctionType::Kind::External &&
functionType.kind() != FunctionType::Kind::Creation &&
functionType.kind() != FunctionType::Kind::DelegateCall
)
{
m_errorReporter.typeError(
_tryStatement.externalCall().location(),
"Try can only be used with external function calls and contract creation calls."
);
return;
}

externalCall->annotation().tryCall = true;

solAssert(_tryStatement.clauses().size() >= 2, "");
solAssert(_tryStatement.clauses().front(), "");

TryCatchClause const& successClause = *_tryStatement.clauses().front();
if (successClause.parameters())
{
TypePointers returnTypes =
m_evmVersion.supportsReturndata() ?
functionType.returnParameterTypes() :
functionType.returnParameterTypesWithoutDynamicTypes();
std::vector<ASTPointer<VariableDeclaration>> const& parameters =
successClause.parameters()->parameters();
if (returnTypes.size() != parameters.size())
m_errorReporter.typeError(
successClause.location(),
"Function returns " +
to_string(functionType.returnParameterTypes().size()) +
" values, but returns clause has " +
to_string(parameters.size()) +
" variables."
);
size_t len = min(returnTypes.size(), parameters.size());
for (size_t i = 0; i < len; ++i)
{
solAssert(returnTypes[i], "");
if (parameters[i] && *parameters[i]->annotation().type != *returnTypes[i])
m_errorReporter.typeError(
parameters[i]->location(),
"Invalid type, expected " +
returnTypes[i]->toString(false) +
" but got " +
parameters[i]->annotation().type->toString() +
"."
);
}
}

TryCatchClause const* errorClause = nullptr;
TryCatchClause const* lowLevelClause = nullptr;
for (size_t i = 1; i < _tryStatement.clauses().size(); ++i)
{
TryCatchClause const& clause = *_tryStatement.clauses()[i];
if (clause.errorName() == "")
{
if (lowLevelClause)
m_errorReporter.typeError(
clause.location(),
SecondarySourceLocation{}.append("The first clause is here:", lowLevelClause->location()),
"This try statement already has a low-level catch clause."
);
lowLevelClause = &clause;
if (clause.parameters() && !clause.parameters()->parameters().empty())
{
if (
clause.parameters()->parameters().size() != 1 ||
*clause.parameters()->parameters().front()->type() != *TypeProvider::bytesMemory()
)
m_errorReporter.typeError(clause.location(), "Expected `catch (bytes memory ...) { ... }` or `catch { ... }`.");
if (!m_evmVersion.supportsReturndata())
m_errorReporter.typeError(
clause.location(),
"This catch clause type cannot be used on the selected EVM version (" +
m_evmVersion.name() +
"). You need at least a Byzantium-compatible EVM or use `catch { ... }`."
);
}
}
else if (clause.errorName() == "Error")
{
if (!m_evmVersion.supportsReturndata())
m_errorReporter.typeError(
clause.location(),
"This catch clause type cannot be used on the selected EVM version (" +
m_evmVersion.name() +
"). You need at least a Byzantium-compatible EVM or use `catch { ... }`."
);

if (errorClause)
m_errorReporter.typeError(
clause.location(),
SecondarySourceLocation{}.append("The first clause is here:", errorClause->location()),
"This try statement already has an \"Error\" catch clause."
);
errorClause = &clause;
if (
!clause.parameters() ||
clause.parameters()->parameters().size() != 1 ||
*clause.parameters()->parameters().front()->type() != *TypeProvider::stringMemory()
)
m_errorReporter.typeError(clause.location(), "Expected `catch Error(string memory ...) { ... }`.");
}
else
m_errorReporter.typeError(
clause.location(),
"Invalid catch clause name. Expected either `catch (...)` or `catch Error(...)`."
);
}
TryCatchClause const& clause = _tryStatement.clause();
std::vector<ASTPointer<VariableDeclaration>> const& errArgs = clause.parameters()->parameters();

auto printError = [&](SourceLocation const& loc){
m_errorReporter.typeError(
loc,
"Expected `catch (variant value, uint number) { ... }`.");
};
if (errArgs.size() != 2) {
printError(clause.location());
return;
}
if (*errArgs.at(0)->type() != *TypeProvider::variant()) {
printError(errArgs.at(0)->location());
}
if (*errArgs.at(1)->type() != *TypeProvider::uint256()) {
printError(errArgs.at(1)->location());
}
}

bool TypeChecker::visit(WhileStatement const& _whileStatement)
Expand Down
16 changes: 8 additions & 8 deletions compiler/libsolidity/ast/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -1431,22 +1431,22 @@ class TryStatement: public Statement
int64_t _id,
SourceLocation const& _location,
ASTPointer<ASTString> const& _docString,
ASTPointer<Expression> const& _externalCall,
std::vector<ASTPointer<TryCatchClause>> const& _clauses
ASTPointer<Block> _body,
ASTPointer<TryCatchClause> _clause
):
Statement(_id, _location, _docString),
m_externalCall(_externalCall),
m_clauses(_clauses)
m_body(_body),
m_clause(_clause)
{}
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;

Expression const& externalCall() const { return *m_externalCall; }
std::vector<ASTPointer<TryCatchClause>> const& clauses() const { return m_clauses; }
Block const& body() const { return *m_body; }
TryCatchClause const& clause() const { return *m_clause; }

private:
ASTPointer<Expression> m_externalCall;
std::vector<ASTPointer<TryCatchClause>> m_clauses;
ASTPointer<Block> m_body;
ASTPointer<TryCatchClause> m_clause;
};

/**
Expand Down
4 changes: 2 additions & 2 deletions compiler/libsolidity/ast/ASTJsonConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,8 @@ bool ASTJsonConverter::visit(TryCatchClause const& _node)
bool ASTJsonConverter::visit(TryStatement const& _node)
{
setJsonNode(_node, "TryStatement", {
make_pair("externalCall", toJson(_node.externalCall())),
make_pair("clauses", toJson(_node.clauses()))
make_pair("body", toJson(_node.body())),
make_pair("clause", toJson(_node.clause()))
});
return false;
}
Expand Down
10 changes: 4 additions & 6 deletions compiler/libsolidity/ast/ASTJsonImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,16 +578,14 @@ ASTPointer<TryCatchClause> ASTJsonImporter::createTryCatchClause(Json::Value con

ASTPointer<TryStatement> ASTJsonImporter::createTryStatement(Json::Value const& _node)
{
vector<ASTPointer<TryCatchClause>> clauses;

for (auto& param: _node["clauses"])
clauses.emplace_back(createTryCatchClause(param));
ASTPointer<Block> body = createBlock(_node["block"]);
ASTPointer<TryCatchClause> clause = createTryCatchClause(_node["clause"]);

return createASTNode<TryStatement>(
_node,
nullOrASTString(_node, "documentation"),
convertJsonToASTNode<Expression>(member(_node, "externalCall")),
clauses
body,
clause
);
}

Expand Down
8 changes: 4 additions & 4 deletions compiler/libsolidity/ast/AST_accept.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,8 @@ void TryStatement::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
{
m_externalCall->accept(_visitor);
listAccept(m_clauses, _visitor);
m_body->accept(_visitor);
m_clause->accept(_visitor);
}
_visitor.endVisit(*this);
}
Expand All @@ -576,8 +576,8 @@ void TryStatement::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
{
m_externalCall->accept(_visitor);
listAccept(m_clauses, _visitor);
m_body->accept(_visitor);
m_clause->accept(_visitor);
}
_visitor.endVisit(*this);
}
Expand Down
Loading