Grammar and Documentation.

This commit is contained in:
chriseth 2019-09-02 17:25:59 +02:00
parent a66c354698
commit a54d9d622f
3 changed files with 105 additions and 2 deletions

View File

@ -50,6 +50,12 @@ This section gives detailed instructions on how to update prior code for every b
* Change ``uint length = array.push(value)`` to ``array.push(value);``. The new length can be
accessed via ``array.length``.
New Features
============
* The :ref:`try/catch statement <try-catch>` allows you to react on failed external calls.
Deprecated Elements
===================

View File

@ -15,6 +15,10 @@ Most of the control structures known from curly-braces languages are available i
There is: ``if``, ``else``, ``while``, ``do``, ``for``, ``break``, ``continue``, ``return``, with
the usual semantics known from C or JavaScript.
Solidity also supports exception handling in the form of ``try``/``catch``-statements,
but only for :ref:`external function calls <external-function-calls>` and
contract creation calls.
Parentheses can *not* be omitted for conditionals, but curly brances can be omitted
around single-statement bodies.
@ -383,7 +387,7 @@ of an exception instead of "bubbling up".
.. warning::
The low-level functions ``call``, ``delegatecall`` and ``staticcall`` return ``true`` as their first return value if the account called is non-existent, as part of the design of EVM. Existence must be checked prior to calling if needed.
It is not yet possible to catch exceptions with Solidity.
Exceptions can be caught with the ``try``/``catch`` statement.
``assert`` and ``require``
--------------------------
@ -488,3 +492,94 @@ In the above example, ``revert("Not enough Ether provided.");`` returns the foll
.. note::
There used to be a keyword called ``throw`` with the same semantics as ``revert()`` which
was deprecated in version 0.4.13 and removed in version 0.5.0.
.. _try-catch:
``try``/``catch``
-----------------
A failure in an external call can be caught using a try/catch statement, as follows:
::
pragma solidity >=0.5.0 <0.7.0;
interface DataFeed { function getData(address token) external returns (uint value); }
contract FeedConsumer {
DataFeed feed;
uint errorCount;
function rate(address token) public returns (uint value, bool success) {
// Permanently disable the mechanism if there are
// more than 10 errors.
require(errorCount < 10);
try feed.getData(token) returns (uint v) {
return (v, true);
} catch Error(string memory /*reason*/) {
// This is executed in case
// revert was called inside getData
// and a reason string was provided.
errorCount++;
return (0, false);
} catch (bytes memory /*lowLevelData*/) {
// This is executed in case revert() was used
// or there was a failing assertion, division
// by zero, etc. inside getData.
errorCount++;
return (0, false);
}
}
}
The ``try`` keyword has to be followed by an expression representing an external function call
or a contract creation (``new ContractName()``).
Errors inside the expression are not caught (for example if it is a complex expression
that also involves internal function calls), only a revert happening inside the external
call itself. The ``returns`` part (which is optional) that follows declares return variables
matching the types returned by the external call. In case there was no error,
these variables are assigned and the contract's execution continues inside the
first success block. If the end of the success block is reached, execution continues after the ``catch`` blocks.
Currently, Solidity supports different kinds of catch blocks depending on the
type of error. If the error was caused by ``revert("reasonString")`` or
``require(false, "reasonString")`` (or an internal error that causes such an
exception), then the catch clause
of the type ``catch Error(string memory reason)`` will be executed.
It is planned to support other types of error data in the future.
The string ``Error`` is currently parsed as is and is not treated as an identifier.
The clause ``catch (bytes memory lowLevelData)`` is executed if the error signature
does not match any other clause, there was an error during decoding of the error
message, if there was a failing assertion in the external
call (for example due to a division by zero or a failing ``assert()``) or
if no error data was provided with the exception.
The declared variable provides access to the low-level error data in that case.
If you are not interested in the error data, you can just use
``catch { ... }`` (even as the only catch clause).
In order to catch all error cases, you have to have at least the clause
``catch { ...}`` or the clause ``catch (bytes memory lowLevelData) { ... }``.
The variables declared in the ``returns`` and the ``catch`` clause are only
in scope in the block that follows.
.. note::
If an error happens during the decoding of the return data
inside a try/catch-statement, this causes an exception in the currently
executing contract and because of that, it is not caught in the catch clause.
If there is an error during decoding of ``catch Error(string memory reason)``
and there is a low-level catch clause, this error is caught there.
.. note::
If execution reaches a catch-block, then the state-changing effects of
the external call have been reverted. If execution reaches
the success block, the effects were not reverted.
If the effects have been reverted, then execution either continues
in a catch block or the execution of the try/catch statement itself
reverts (for example due to decoding failures as noted above or
due to not providing a low-level catch clause).

View File

@ -62,12 +62,14 @@ StorageLocation = 'memory' | 'storage' | 'calldata'
StateMutability = 'pure' | 'view' | 'payable'
Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | ForStatement | Block | InlineAssemblyStatement |
Statement = IfStatement | TryStatement | WhileStatement | ForStatement | Block | InlineAssemblyStatement |
( DoWhileStatement | PlaceholderStatement | Continue | Break | Return |
Throw | EmitStatement | SimpleStatement ) ';'
ExpressionStatement = Expression
IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )?
TryStatement = 'try' Expression ( 'returns' ParameterList )? Block CatchClause+
CatchClause = 'catch' Identifier? ParameterList Block
WhileStatement = 'while' '(' Expression ')' Statement
PlaceholderStatement = '_'
SimpleStatement = VariableDefinition | ExpressionStatement