mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #13790 from ethereum/user-defined-operators-for-udvt
User-defined operators for UDVTs
This commit is contained in:
commit
103bf7a71f
@ -1,6 +1,7 @@
|
||||
### 0.8.19 (unreleased)
|
||||
|
||||
Language Features:
|
||||
* Allow defining custom operators for user-defined value types via ``using {f as +} for T global`` syntax.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
@ -16,6 +17,10 @@ Bugfixes:
|
||||
* SMTChecker: Fix internal error caused by unhandled ``z3`` expressions that come from the solver when bitwise operators are used.
|
||||
|
||||
|
||||
AST Changes:
|
||||
* AST: Add ``function`` field to ``UnaryOperation`` and ``BinaryOperation`` AST nodes. ``functionList`` in ``UsingForDirective`` AST nodes will now contain ``operator`` and ``definition`` members instead of ``function`` when the list entry defines an operator.
|
||||
|
||||
|
||||
### 0.8.18 (2023-02-01)
|
||||
|
||||
Language Features:
|
||||
|
@ -1,4 +1,4 @@
|
||||
.. index:: ! using for, library
|
||||
.. index:: ! using for, library, ! operator; user-defined
|
||||
|
||||
.. _using-for:
|
||||
|
||||
@ -6,37 +6,87 @@
|
||||
Using For
|
||||
*********
|
||||
|
||||
The directive ``using A for B;`` can be used to attach
|
||||
functions (``A``) as member functions to any type (``B``).
|
||||
These functions will receive the object they are called on
|
||||
The directive ``using A for B`` can be used to attach
|
||||
functions (``A``) as operators to user-defined value types
|
||||
or as member functions to any type (``B``).
|
||||
The member functions receive the object they are called on
|
||||
as their first parameter (like the ``self`` variable in Python).
|
||||
The operator functions receive operands as parameters.
|
||||
|
||||
It is valid either at file level or inside a contract,
|
||||
at contract level.
|
||||
|
||||
The first part, ``A``, can be one of:
|
||||
|
||||
- A list of file-level or library functions (e.g. ``using {f, g, h, L.t} for uint;``) -
|
||||
only those functions will be attached to the type as member functions.
|
||||
Note that private library functions can only be specified when ``using for`` is inside the library.
|
||||
- The name of a library (e.g. ``using L for uint;``) -
|
||||
all non-private functions of the library are attached to the type.
|
||||
- A list of functions, optionally with an operator name assigned (e.g.
|
||||
``using {f, g as +, h, L.t} for uint``).
|
||||
If no operator is specified, the function can be either a library function or a free function and
|
||||
is attached to the type as a member function.
|
||||
Otherwise it must be a free function and it becomes the definition of that operator on the type.
|
||||
- The name of a library (e.g. ``using L for uint``) -
|
||||
all non-private functions of the library are attached to the type
|
||||
as member functions
|
||||
|
||||
At file level, the second part, ``B``, has to be an explicit type (without data location specifier).
|
||||
Inside contracts, you can also use ``*`` in place of the type (e.g. ``using L for *;``),
|
||||
which has the effect that all functions of the library ``L``
|
||||
are attached to *all* types.
|
||||
|
||||
If you specify a library, *all* functions in the library get attached,
|
||||
If you specify a library, *all* non-private functions in the library get attached,
|
||||
even those where the type of the first parameter does not
|
||||
match the type of the object. The type is checked at the
|
||||
point the function is called and function overload
|
||||
resolution is performed.
|
||||
|
||||
If you use a list of functions (e.g. ``using {f, g, h, L.t} for uint;``),
|
||||
If you use a list of functions (e.g. ``using {f, g, h, L.t} for uint``),
|
||||
then the type (``uint``) has to be implicitly convertible to the
|
||||
first parameter of each of these functions. This check is
|
||||
performed even if none of these functions are called.
|
||||
Note that private library functions can only be specified when ``using for`` is inside a library.
|
||||
|
||||
If you define an operator (e.g. ``using {f as +} for T``), then the type (``T``) must be a
|
||||
:ref:`user-defined value type <user-defined-value-types>` and the definition must be a ``pure`` function.
|
||||
Operator definitions must be global.
|
||||
The following operators can be defined this way:
|
||||
|
||||
+------------+----------+---------------------------------------------+
|
||||
| Category | Operator | Possible signatures |
|
||||
+============+==========+=============================================+
|
||||
| Bitwise | ``&`` | ``function (T, T) pure returns (T)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``|`` | ``function (T, T) pure returns (T)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``^`` | ``function (T, T) pure returns (T)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``~`` | ``function (T) pure returns (T)`` |
|
||||
+------------+----------+---------------------------------------------+
|
||||
| Arithmetic | ``+`` | ``function (T, T) pure returns (T)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``-`` | ``function (T, T) pure returns (T)`` |
|
||||
| + +---------------------------------------------+
|
||||
| | | ``function (T) pure returns (T)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``*`` | ``function (T, T) pure returns (T)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``/`` | ``function (T, T) pure returns (T)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``%`` | ``function (T, T) pure returns (T)`` |
|
||||
+------------+----------+---------------------------------------------+
|
||||
| Comparison | ``==`` | ``function (T, T) pure returns (bool)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``!=`` | ``function (T, T) pure returns (bool)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``<`` | ``function (T, T) pure returns (bool)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``<=`` | ``function (T, T) pure returns (bool)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``>`` | ``function (T, T) pure returns (bool)`` |
|
||||
| +----------+---------------------------------------------+
|
||||
| | ``>=`` | ``function (T, T) pure returns (bool)`` |
|
||||
+------------+----------+---------------------------------------------+
|
||||
|
||||
Note that unary and binary ``-`` need separate definitions.
|
||||
The compiler will choose the right definition based on how the operator is invoked.
|
||||
|
||||
The ``using A for B;`` directive is active only within the current
|
||||
scope (either the contract or the current module/source unit),
|
||||
@ -46,7 +96,7 @@ outside of the contract or module in which it is used.
|
||||
When the directive is used at file level and applied to a
|
||||
user-defined type which was defined at file level in the same file,
|
||||
the word ``global`` can be added at the end. This will have the
|
||||
effect that the functions are attached to the type everywhere
|
||||
effect that the functions and operators are attached to the type everywhere
|
||||
the type is available (including other files), not only in the
|
||||
scope of the using statement.
|
||||
|
||||
@ -150,3 +200,37 @@ if you pass memory or value types, a copy will be performed, even in case of the
|
||||
``self`` variable. The only situation where no copy will be performed
|
||||
is when storage reference variables are used or when internal library
|
||||
functions are called.
|
||||
|
||||
Another example shows how to define a custom operator for a user-defined type:
|
||||
|
||||
.. code-block:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
type UFixed16x2 is uint16;
|
||||
|
||||
using {
|
||||
add as +,
|
||||
div as /
|
||||
} for UFixed16x2 global;
|
||||
|
||||
uint32 constant SCALE = 100;
|
||||
|
||||
function add(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) {
|
||||
return UFixed16x2.wrap(UFixed16x2.unwrap(a) + UFixed16x2.unwrap(b));
|
||||
}
|
||||
|
||||
function div(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) {
|
||||
uint32 a32 = UFixed16x2.unwrap(a);
|
||||
uint32 b32 = UFixed16x2.unwrap(b);
|
||||
uint32 result32 = a32 * SCALE / b32;
|
||||
require(result32 <= type(uint16).max, "Divide overflow");
|
||||
return UFixed16x2.wrap(uint16(a32 * SCALE / b32));
|
||||
}
|
||||
|
||||
contract Math {
|
||||
function avg(UFixed16x2 a, UFixed16x2 b) public pure returns (UFixed16x2) {
|
||||
return (a + b) / UFixed16x2.wrap(200);
|
||||
}
|
||||
}
|
||||
|
@ -311,11 +311,31 @@ errorDefinition:
|
||||
LParen (parameters+=errorParameter (Comma parameters+=errorParameter)*)? RParen
|
||||
Semicolon;
|
||||
|
||||
/**
|
||||
* Operators that users are allowed to implement for some types with `using for`.
|
||||
*/
|
||||
userDefinableOperator:
|
||||
BitAnd
|
||||
| BitNot
|
||||
| BitOr
|
||||
| BitXor
|
||||
| Add
|
||||
| Div
|
||||
| Mod
|
||||
| Mul
|
||||
| Sub
|
||||
| Equal
|
||||
| GreaterThan
|
||||
| GreaterThanOrEqual
|
||||
| LessThan
|
||||
| LessThanOrEqual
|
||||
| NotEqual;
|
||||
|
||||
/**
|
||||
* Using directive to attach library functions and free functions to types.
|
||||
* Can occur within contracts and libraries and at the file level.
|
||||
*/
|
||||
usingDirective: Using (identifierPath | (LBrace identifierPath (Comma identifierPath)* RBrace)) For (Mul | typeName) Global? Semicolon;
|
||||
usingDirective: Using (identifierPath | (LBrace identifierPath (As userDefinableOperator)? (Comma identifierPath (As userDefinableOperator)?)* RBrace)) For (Mul | typeName) Global? Semicolon;
|
||||
/**
|
||||
* A type name can be an elementary type, a function type, a mapping type, a user-defined type
|
||||
* (e.g. a contract or struct) or an array type.
|
||||
|
@ -63,6 +63,7 @@ set(sources
|
||||
ast/CallGraph.cpp
|
||||
ast/CallGraph.h
|
||||
ast/ExperimentalFeatures.h
|
||||
ast/UserDefinableOperators.h
|
||||
ast/Types.cpp
|
||||
ast/Types.h
|
||||
ast/TypeProvider.cpp
|
||||
|
@ -64,17 +64,53 @@ bool ControlFlowBuilder::visit(BinaryOperation const& _operation)
|
||||
case Token::And:
|
||||
{
|
||||
visitNode(_operation);
|
||||
solAssert(*_operation.annotation().userDefinedFunction == nullptr);
|
||||
appendControlFlow(_operation.leftExpression());
|
||||
|
||||
auto nodes = splitFlow<2>();
|
||||
nodes[0] = createFlow(nodes[0], _operation.rightExpression());
|
||||
mergeFlow(nodes, nodes[1]);
|
||||
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return ASTConstVisitor::visit(_operation);
|
||||
{
|
||||
if (*_operation.annotation().userDefinedFunction != nullptr)
|
||||
{
|
||||
visitNode(_operation);
|
||||
_operation.leftExpression().accept(*this);
|
||||
_operation.rightExpression().accept(*this);
|
||||
|
||||
m_currentNode->functionDefinition = *_operation.annotation().userDefinedFunction;
|
||||
|
||||
auto nextNode = newLabel();
|
||||
|
||||
connect(m_currentNode, nextNode);
|
||||
m_currentNode = nextNode;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ASTConstVisitor::visit(_operation);
|
||||
}
|
||||
|
||||
bool ControlFlowBuilder::visit(UnaryOperation const& _operation)
|
||||
{
|
||||
solAssert(!!m_currentNode);
|
||||
|
||||
if (*_operation.annotation().userDefinedFunction != nullptr)
|
||||
{
|
||||
visitNode(_operation);
|
||||
_operation.subExpression().accept(*this);
|
||||
m_currentNode->functionDefinition = *_operation.annotation().userDefinedFunction;
|
||||
|
||||
auto nextNode = newLabel();
|
||||
|
||||
connect(m_currentNode, nextNode);
|
||||
m_currentNode = nextNode;
|
||||
return false;
|
||||
}
|
||||
|
||||
return ASTConstVisitor::visit(_operation);
|
||||
}
|
||||
|
||||
bool ControlFlowBuilder::visit(Conditional const& _conditional)
|
||||
|
@ -50,6 +50,7 @@ private:
|
||||
|
||||
// Visits for constructing the control flow.
|
||||
bool visit(BinaryOperation const& _operation) override;
|
||||
bool visit(UnaryOperation const& _operation) override;
|
||||
bool visit(Conditional const& _conditional) override;
|
||||
bool visit(TryStatement const& _tryStatement) override;
|
||||
bool visit(IfStatement const& _ifStatement) override;
|
||||
|
@ -204,6 +204,20 @@ bool FunctionCallGraphBuilder::visit(MemberAccess const& _memberAccess)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionCallGraphBuilder::visit(BinaryOperation const& _binaryOperation)
|
||||
{
|
||||
if (*_binaryOperation.annotation().userDefinedFunction != nullptr)
|
||||
functionReferenced(**_binaryOperation.annotation().userDefinedFunction, true /* called directly */);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionCallGraphBuilder::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
if (*_unaryOperation.annotation().userDefinedFunction != nullptr)
|
||||
functionReferenced(**_unaryOperation.annotation().userDefinedFunction, true /* called directly */);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionCallGraphBuilder::visit(ModifierInvocation const& _modifierInvocation)
|
||||
{
|
||||
if (auto const* modifier = dynamic_cast<ModifierDefinition const*>(_modifierInvocation.name().annotation().referencedDeclaration))
|
||||
|
@ -72,6 +72,8 @@ private:
|
||||
bool visit(EmitStatement const& _emitStatement) override;
|
||||
bool visit(Identifier const& _identifier) override;
|
||||
bool visit(MemberAccess const& _memberAccess) override;
|
||||
bool visit(BinaryOperation const& _binaryOperation) override;
|
||||
bool visit(UnaryOperation const& _unaryOperation) override;
|
||||
bool visit(ModifierInvocation const& _modifierInvocation) override;
|
||||
bool visit(NewExpression const& _newExpression) override;
|
||||
|
||||
|
@ -411,6 +411,12 @@ void SyntaxChecker::endVisit(ContractDefinition const&)
|
||||
|
||||
bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
|
||||
{
|
||||
if (!_usingFor.usesBraces())
|
||||
solAssert(
|
||||
_usingFor.functionsAndOperators().size() == 1 &&
|
||||
!get<1>(_usingFor.functionsAndOperators().front())
|
||||
);
|
||||
|
||||
if (!m_currentContractKind && !_usingFor.typeName())
|
||||
m_errorReporter.syntaxError(
|
||||
8118_error,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <libsolidity/analysis/TypeChecker.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/ASTUtils.h>
|
||||
#include <libsolidity/ast/UserDefinableOperators.h>
|
||||
#include <libsolidity/ast/TypeProvider.h>
|
||||
|
||||
#include <libyul/AsmAnalysis.h>
|
||||
@ -1606,7 +1607,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
||||
7366_error,
|
||||
_assignment.location(),
|
||||
"Operator " +
|
||||
string(TokenTraits::toString(_assignment.assignmentOperator())) +
|
||||
string(TokenTraits::friendlyName(_assignment.assignmentOperator())) +
|
||||
" not compatible with types " +
|
||||
t->humanReadableName() +
|
||||
" and " +
|
||||
@ -1729,16 +1730,45 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
|
||||
requireLValue(_operation.subExpression(), false);
|
||||
else
|
||||
_operation.subExpression().accept(*this);
|
||||
Type const* subExprType = type(_operation.subExpression());
|
||||
TypeResult result = type(_operation.subExpression())->unaryOperatorResult(op);
|
||||
if (!result)
|
||||
Type const* operandType = type(_operation.subExpression());
|
||||
|
||||
// Check if the operator is built-in or user-defined.
|
||||
TypeResult builtinResult = operandType->unaryOperatorResult(op);
|
||||
set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = operandType->operatorDefinitions(
|
||||
op,
|
||||
*currentDefinitionScope(),
|
||||
true // _unary
|
||||
);
|
||||
|
||||
// Operator can't be both user-defined and built-in at the same time.
|
||||
solAssert(!builtinResult || matchingDefinitions.empty());
|
||||
|
||||
// By default use the type we'd expect from correct code. This way we can continue analysis
|
||||
// of other expressions in a sensible way in case of a non-fatal error.
|
||||
Type const* resultType = operandType;
|
||||
|
||||
FunctionDefinition const* operatorDefinition = nullptr;
|
||||
if (builtinResult)
|
||||
resultType = builtinResult;
|
||||
else if (!matchingDefinitions.empty())
|
||||
{
|
||||
// This is checked along with `using for` directive but the error is not fatal.
|
||||
if (matchingDefinitions.size() != 1)
|
||||
solAssert(m_errorReporter.hasErrors());
|
||||
|
||||
operatorDefinition = *matchingDefinitions.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
string description = fmt::format(
|
||||
"Built-in unary operator {} cannot be applied to type {}.{}",
|
||||
TokenTraits::toString(op),
|
||||
subExprType->humanReadableName(),
|
||||
!result.message().empty() ? " " + result.message() : ""
|
||||
"Built-in unary operator {} cannot be applied to type {}.",
|
||||
TokenTraits::friendlyName(op),
|
||||
operandType->humanReadableName()
|
||||
);
|
||||
if (!builtinResult.message().empty())
|
||||
description += " " + builtinResult.message();
|
||||
if (operandType->typeDefinition() && util::contains(userDefinableOperators, op))
|
||||
description += " No matching user-defined operator found.";
|
||||
|
||||
if (modifying)
|
||||
// Cannot just report the error, ignore the unary operator, and continue,
|
||||
@ -1746,14 +1776,21 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
|
||||
m_errorReporter.fatalTypeError(9767_error, _operation.location(), description);
|
||||
else
|
||||
m_errorReporter.typeError(4907_error, _operation.location(), description);
|
||||
_operation.annotation().type = subExprType;
|
||||
}
|
||||
else
|
||||
_operation.annotation().type = result.get();
|
||||
|
||||
_operation.annotation().userDefinedFunction = operatorDefinition;
|
||||
|
||||
TypePointers const& returnParameterTypes = _operation.userDefinedFunctionType()->returnParameterTypes();
|
||||
if (operatorDefinition && !returnParameterTypes.empty())
|
||||
// Use the actual result type from operator definition. Ignore all values but the
|
||||
// first one - in valid code there will be only one anyway.
|
||||
resultType = returnParameterTypes[0];
|
||||
_operation.annotation().type = resultType;
|
||||
_operation.annotation().isConstant = false;
|
||||
_operation.annotation().isPure =
|
||||
!modifying &&
|
||||
*_operation.subExpression().annotation().isPure;
|
||||
*_operation.subExpression().annotation().isPure &&
|
||||
(!_operation.userDefinedFunctionType() || _operation.userDefinedFunctionType()->isPure());
|
||||
_operation.annotation().isLValue = false;
|
||||
|
||||
return false;
|
||||
@ -1763,31 +1800,95 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
||||
{
|
||||
Type const* leftType = type(_operation.leftExpression());
|
||||
Type const* rightType = type(_operation.rightExpression());
|
||||
TypeResult result = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
|
||||
Type const* commonType = result.get();
|
||||
if (!commonType)
|
||||
|
||||
// Check if the operator is built-in or user-defined.
|
||||
TypeResult builtinResult = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
|
||||
set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = leftType->operatorDefinitions(
|
||||
_operation.getOperator(),
|
||||
*currentDefinitionScope(),
|
||||
false // _unary
|
||||
);
|
||||
|
||||
// Operator can't be both user-defined and built-in at the same time.
|
||||
solAssert(!builtinResult || matchingDefinitions.empty());
|
||||
|
||||
Type const* commonType = nullptr;
|
||||
FunctionDefinition const* operatorDefinition = nullptr;
|
||||
if (builtinResult)
|
||||
commonType = builtinResult.get();
|
||||
else if (!matchingDefinitions.empty())
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
2271_error,
|
||||
_operation.location(),
|
||||
"Built-in binary operator " +
|
||||
string(TokenTraits::toString(_operation.getOperator())) +
|
||||
" cannot be applied to types " +
|
||||
leftType->humanReadableName() +
|
||||
" and " +
|
||||
rightType->humanReadableName() + "." +
|
||||
(!result.message().empty() ? " " + result.message() : "")
|
||||
);
|
||||
// This is checked along with `using for` directive but the error is not fatal.
|
||||
if (matchingDefinitions.size() != 1)
|
||||
solAssert(m_errorReporter.hasErrors());
|
||||
|
||||
operatorDefinition = *matchingDefinitions.begin();
|
||||
|
||||
// Set common type to the type used in the `using for` directive.
|
||||
commonType = leftType;
|
||||
}
|
||||
else
|
||||
{
|
||||
string description = fmt::format(
|
||||
"Built-in binary operator {} cannot be applied to types {} and {}.",
|
||||
TokenTraits::friendlyName(_operation.getOperator()),
|
||||
leftType->humanReadableName(),
|
||||
rightType->humanReadableName()
|
||||
);
|
||||
if (!builtinResult.message().empty())
|
||||
description += " " + builtinResult.message();
|
||||
if (leftType->typeDefinition() && util::contains(userDefinableOperators, _operation.getOperator()))
|
||||
description += " No matching user-defined operator found.";
|
||||
|
||||
m_errorReporter.typeError(2271_error, _operation.location(), description);
|
||||
|
||||
// Set common type to something we'd expect from correct code just so that we can continue analysis.
|
||||
commonType = leftType;
|
||||
}
|
||||
|
||||
_operation.annotation().commonType = commonType;
|
||||
_operation.annotation().type =
|
||||
_operation.annotation().userDefinedFunction = operatorDefinition;
|
||||
FunctionType const* userDefinedFunctionType = _operation.userDefinedFunctionType();
|
||||
|
||||
// By default use the type we'd expect from correct code. This way we can continue analysis
|
||||
// of other expressions in a sensible way in case of a non-fatal error.
|
||||
Type const* resultType =
|
||||
TokenTraits::isCompareOp(_operation.getOperator()) ?
|
||||
TypeProvider::boolean() :
|
||||
commonType;
|
||||
|
||||
if (operatorDefinition)
|
||||
{
|
||||
TypePointers const& parameterTypes = userDefinedFunctionType->parameterTypes();
|
||||
TypePointers const& returnParameterTypes = userDefinedFunctionType->returnParameterTypes();
|
||||
|
||||
// operatorDefinitions() filters out definitions with non-matching first argument.
|
||||
solAssert(parameterTypes.size() == 2);
|
||||
solAssert(parameterTypes[0] && *leftType == *parameterTypes[0]);
|
||||
|
||||
if (*rightType != *parameterTypes[0])
|
||||
m_errorReporter.typeError(
|
||||
5653_error,
|
||||
_operation.location(),
|
||||
fmt::format(
|
||||
"The type of the second operand of this user-defined binary operator {} "
|
||||
"does not match the type of the first operand, which is {}.",
|
||||
TokenTraits::friendlyName(_operation.getOperator()),
|
||||
parameterTypes[0]->humanReadableName()
|
||||
)
|
||||
);
|
||||
|
||||
if (!returnParameterTypes.empty())
|
||||
// Use the actual result type from operator definition. Ignore all values but the
|
||||
// first one - in valid code there will be only one anyway.
|
||||
resultType = returnParameterTypes[0];
|
||||
}
|
||||
|
||||
_operation.annotation().type = resultType;
|
||||
_operation.annotation().isPure =
|
||||
*_operation.leftExpression().annotation().isPure &&
|
||||
*_operation.rightExpression().annotation().isPure;
|
||||
*_operation.rightExpression().annotation().isPure &&
|
||||
(!userDefinedFunctionType || userDefinedFunctionType->isPure());
|
||||
_operation.annotation().isLValue = false;
|
||||
_operation.annotation().isConstant = false;
|
||||
|
||||
@ -1814,14 +1915,14 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
||||
m_errorReporter.warning(
|
||||
3149_error,
|
||||
_operation.location(),
|
||||
"The result type of the " +
|
||||
operation +
|
||||
" operation is equal to the type of the first operand (" +
|
||||
commonType->humanReadableName() +
|
||||
") ignoring the (larger) type of the second operand (" +
|
||||
rightType->humanReadableName() +
|
||||
") which might be unexpected. Silence this warning by either converting "
|
||||
"the first or the second operand to the type of the other."
|
||||
fmt::format(
|
||||
"The result type of the {} operation is equal to the type of the first operand ({}) "
|
||||
"ignoring the (larger) type of the second operand ({}) which might be unexpected. "
|
||||
"Silence this warning by either converting the first or the second operand to the type of the other.",
|
||||
operation,
|
||||
commonType->humanReadableName(),
|
||||
rightType->humanReadableName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -3820,7 +3921,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
);
|
||||
solAssert(normalizedType);
|
||||
|
||||
for (ASTPointer<IdentifierPath> const& path: _usingFor.functionsOrLibrary())
|
||||
for (auto const& [path, operator_]: _usingFor.functionsAndOperators())
|
||||
{
|
||||
solAssert(path->annotation().referencedDeclaration);
|
||||
FunctionDefinition const& functionDefinition =
|
||||
@ -3839,8 +3940,8 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
4731_error,
|
||||
path->location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Function defined here:",
|
||||
functionDefinition.location()
|
||||
"Function defined here:",
|
||||
functionDefinition.location()
|
||||
),
|
||||
fmt::format(
|
||||
"The function \"{}\" does not have any parameters, and therefore cannot be attached to the type \"{}\".",
|
||||
@ -3859,8 +3960,8 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
6772_error,
|
||||
path->location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Function defined here:",
|
||||
functionDefinition.location()
|
||||
"Function defined here:",
|
||||
functionDefinition.location()
|
||||
),
|
||||
fmt::format(
|
||||
"Function \"{}\" is private and therefore cannot be attached"
|
||||
@ -3875,13 +3976,13 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
BoolResult result = normalizedType->isImplicitlyConvertibleTo(
|
||||
*TypeProvider::withLocationIfReference(DataLocation::Storage, functionTypeWithBoundFirstArgument->selfType())
|
||||
);
|
||||
if (!result)
|
||||
if (!result && !operator_)
|
||||
m_errorReporter.typeError(
|
||||
3100_error,
|
||||
path->location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Function defined here:",
|
||||
functionDefinition.location()
|
||||
"Function defined here:",
|
||||
functionDefinition.location()
|
||||
),
|
||||
fmt::format(
|
||||
"The function \"{}\" cannot be attached to the type \"{}\" because the type cannot "
|
||||
@ -3892,6 +3993,144 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
result.message().empty() ? "." : ": " + result.message()
|
||||
)
|
||||
);
|
||||
else if (operator_.has_value())
|
||||
{
|
||||
if (!_usingFor.global())
|
||||
m_errorReporter.typeError(
|
||||
3320_error,
|
||||
path->location(),
|
||||
"Operators can only be defined in a global 'using for' directive."
|
||||
);
|
||||
|
||||
if (
|
||||
functionType->stateMutability() != StateMutability::Pure ||
|
||||
!functionDefinition.isFree()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
7775_error,
|
||||
path->location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Function defined as non-pure here:",
|
||||
functionDefinition.location()
|
||||
),
|
||||
"Only pure free functions can be used to define operators."
|
||||
);
|
||||
|
||||
solAssert(!functionType->hasBoundFirstArgument());
|
||||
TypePointers const& parameterTypes = functionType->parameterTypes();
|
||||
size_t const parameterCount = parameterTypes.size();
|
||||
if (usingForType->category() != Type::Category::UserDefinedValueType)
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
5332_error,
|
||||
path->location(),
|
||||
"Operators can only be implemented for user-defined value types."
|
||||
);
|
||||
continue;
|
||||
}
|
||||
solAssert(usingForType->typeDefinition());
|
||||
|
||||
bool identicalFirstTwoParameters = (parameterCount < 2 || *parameterTypes.at(0) == *parameterTypes.at(1));
|
||||
bool isUnaryOnlyOperator = (!TokenTraits::isBinaryOp(operator_.value()) && TokenTraits::isUnaryOp(operator_.value()));
|
||||
bool isBinaryOnlyOperator =
|
||||
(TokenTraits::isBinaryOp(operator_.value()) && !TokenTraits::isUnaryOp(operator_.value())) ||
|
||||
operator_.value() == Token::Add;
|
||||
bool firstParameterMatchesUsingFor = parameterCount == 0 || *usingForType == *parameterTypes.front();
|
||||
|
||||
optional<string> wrongParametersMessage;
|
||||
if (isBinaryOnlyOperator && (parameterCount != 2 || !identicalFirstTwoParameters))
|
||||
wrongParametersMessage = fmt::format("two parameters of type {} and the same data location", usingForType->canonicalName());
|
||||
else if (isUnaryOnlyOperator && (parameterCount != 1 || !firstParameterMatchesUsingFor))
|
||||
wrongParametersMessage = fmt::format("exactly one parameter of type {}", usingForType->canonicalName());
|
||||
else if (parameterCount >= 3 || !firstParameterMatchesUsingFor || !identicalFirstTwoParameters)
|
||||
wrongParametersMessage = fmt::format("one or two parameters of type {} and the same data location", usingForType->canonicalName());
|
||||
|
||||
if (wrongParametersMessage.has_value())
|
||||
m_errorReporter.typeError(
|
||||
1884_error,
|
||||
functionDefinition.parameterList().location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Function was used to implement an operator here:",
|
||||
path->location()
|
||||
),
|
||||
fmt::format(
|
||||
"Wrong parameters in operator definition. "
|
||||
"The function \"{}\" needs to have {} to be used for the operator {}.",
|
||||
joinHumanReadable(path->path(), "."),
|
||||
wrongParametersMessage.value(),
|
||||
TokenTraits::friendlyName(operator_.value())
|
||||
)
|
||||
);
|
||||
|
||||
// This case is separately validated for all attached functions and is a fatal error
|
||||
solAssert(parameterCount != 0);
|
||||
|
||||
TypePointers const& returnParameterTypes = functionType->returnParameterTypes();
|
||||
size_t const returnParameterCount = returnParameterTypes.size();
|
||||
|
||||
optional<string> wrongReturnParametersMessage;
|
||||
if (!TokenTraits::isCompareOp(operator_.value()) && operator_.value() != Token::Not)
|
||||
{
|
||||
if (returnParameterCount != 1 || *usingForType != *returnParameterTypes.front())
|
||||
wrongReturnParametersMessage = "exactly one value of type " + usingForType->canonicalName();
|
||||
else if (*returnParameterTypes.front() != *parameterTypes.front())
|
||||
wrongReturnParametersMessage = "a value of the same type and data location as its parameters";
|
||||
}
|
||||
else if (returnParameterCount != 1 || *returnParameterTypes.front() != *TypeProvider::boolean())
|
||||
wrongReturnParametersMessage = "exactly one value of type bool";
|
||||
|
||||
solAssert(functionDefinition.returnParameterList());
|
||||
if (wrongReturnParametersMessage.has_value())
|
||||
m_errorReporter.typeError(
|
||||
7743_error,
|
||||
functionDefinition.returnParameterList()->location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Function was used to implement an operator here:",
|
||||
path->location()
|
||||
),
|
||||
fmt::format(
|
||||
"Wrong return parameters in operator definition. "
|
||||
"The function \"{}\" needs to return {} to be used for the operator {}.",
|
||||
joinHumanReadable(path->path(), "."),
|
||||
wrongReturnParametersMessage.value(),
|
||||
TokenTraits::friendlyName(operator_.value())
|
||||
)
|
||||
);
|
||||
|
||||
if (parameterCount != 1 && parameterCount != 2)
|
||||
solAssert(m_errorReporter.hasErrors());
|
||||
else
|
||||
{
|
||||
// TODO: This is pretty inefficient. For every operator binding we find, we're
|
||||
// traversing all bindings in all `using for` directives in the current scope.
|
||||
set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = usingForType->operatorDefinitions(
|
||||
operator_.value(),
|
||||
*currentDefinitionScope(),
|
||||
parameterCount == 1 // _unary
|
||||
);
|
||||
|
||||
if (matchingDefinitions.size() >= 2)
|
||||
{
|
||||
// TODO: We should point at other places that bind the operator rather than at
|
||||
// the definitions they bind.
|
||||
SecondarySourceLocation secondaryLocation;
|
||||
for (FunctionDefinition const* definition: matchingDefinitions)
|
||||
if (functionDefinition != *definition)
|
||||
secondaryLocation.append("Conflicting definition:", definition->location());
|
||||
|
||||
m_errorReporter.typeError(
|
||||
4705_error,
|
||||
path->location(),
|
||||
secondaryLocation,
|
||||
fmt::format(
|
||||
"User-defined {} operator {} has more than one definition matching the operand type visible in the current scope.",
|
||||
parameterCount == 1 ? "unary" : "binary",
|
||||
TokenTraits::friendlyName(operator_.value())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,6 +331,18 @@ void ViewPureChecker::reportFunctionCallMutability(StateMutability _mutability,
|
||||
reportMutability(_mutability, _location);
|
||||
}
|
||||
|
||||
void ViewPureChecker::endVisit(BinaryOperation const& _binaryOperation)
|
||||
{
|
||||
if (*_binaryOperation.annotation().userDefinedFunction != nullptr)
|
||||
reportFunctionCallMutability((*_binaryOperation.annotation().userDefinedFunction)->stateMutability(), _binaryOperation.location());
|
||||
}
|
||||
|
||||
void ViewPureChecker::endVisit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
if (*_unaryOperation.annotation().userDefinedFunction != nullptr)
|
||||
reportFunctionCallMutability((*_unaryOperation.annotation().userDefinedFunction)->stateMutability(), _unaryOperation.location());
|
||||
}
|
||||
|
||||
void ViewPureChecker::endVisit(FunctionCall const& _functionCall)
|
||||
{
|
||||
if (*_functionCall.annotation().kind != FunctionCallKind::FunctionCall)
|
||||
|
@ -54,6 +54,8 @@ private:
|
||||
|
||||
bool visit(FunctionDefinition const& _funDef) override;
|
||||
void endVisit(FunctionDefinition const& _funDef) override;
|
||||
void endVisit(BinaryOperation const& _binaryOperation) override;
|
||||
void endVisit(UnaryOperation const& _unaryOperation) override;
|
||||
bool visit(ModifierDefinition const& _modifierDef) override;
|
||||
void endVisit(ModifierDefinition const& _modifierDef) override;
|
||||
void endVisit(Identifier const& _identifier) override;
|
||||
|
@ -30,7 +30,9 @@
|
||||
#include <libsolutil/FunctionSelector.h>
|
||||
#include <libsolutil/Keccak256.h>
|
||||
|
||||
#include <range/v3/range/conversion.hpp>
|
||||
#include <range/v3/view/tail.hpp>
|
||||
#include <range/v3/view/zip.hpp>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
@ -367,6 +369,11 @@ TypeDeclarationAnnotation& UserDefinedValueTypeDefinition::annotation() const
|
||||
return initAnnotation<TypeDeclarationAnnotation>();
|
||||
}
|
||||
|
||||
std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> UsingForDirective::functionsAndOperators() const
|
||||
{
|
||||
return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<vector>;
|
||||
}
|
||||
|
||||
Type const* StructDefinition::type() const
|
||||
{
|
||||
solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker.");
|
||||
@ -895,6 +902,37 @@ MemberAccessAnnotation& MemberAccess::annotation() const
|
||||
return initAnnotation<MemberAccessAnnotation>();
|
||||
}
|
||||
|
||||
OperationAnnotation& UnaryOperation::annotation() const
|
||||
{
|
||||
return initAnnotation<OperationAnnotation>();
|
||||
}
|
||||
|
||||
FunctionType const* UnaryOperation::userDefinedFunctionType() const
|
||||
{
|
||||
if (*annotation().userDefinedFunction == nullptr)
|
||||
return nullptr;
|
||||
|
||||
FunctionDefinition const* userDefinedFunction = *annotation().userDefinedFunction;
|
||||
return dynamic_cast<FunctionType const*>(
|
||||
userDefinedFunction->libraryFunction() ?
|
||||
userDefinedFunction->typeViaContractName() :
|
||||
userDefinedFunction->type()
|
||||
);
|
||||
}
|
||||
|
||||
FunctionType const* BinaryOperation::userDefinedFunctionType() const
|
||||
{
|
||||
if (*annotation().userDefinedFunction == nullptr)
|
||||
return nullptr;
|
||||
|
||||
FunctionDefinition const* userDefinedFunction = *annotation().userDefinedFunction;
|
||||
return dynamic_cast<FunctionType const*>(
|
||||
userDefinedFunction->libraryFunction() ?
|
||||
userDefinedFunction->typeViaContractName() :
|
||||
userDefinedFunction->type()
|
||||
);
|
||||
}
|
||||
|
||||
BinaryOperationAnnotation& BinaryOperation::annotation() const
|
||||
{
|
||||
return initAnnotation<BinaryOperationAnnotation>();
|
||||
|
@ -647,11 +647,17 @@ private:
|
||||
* 1. `using LibraryName for T` attaches all functions from the library `LibraryName` to the type `T`.
|
||||
* 2. `using LibraryName for *` attaches to all types.
|
||||
* 3. `using {f1, f2, ..., fn} for T` attaches the functions `f1`, `f2`, ..., `fn`, respectively to `T`.
|
||||
* 4. `using {f1 as op1, f2 as op2, ..., fn as opn} for T` implements operator `opn` for type `T` with function `fn`.
|
||||
*
|
||||
* For version 3, T has to be implicitly convertible to the first parameter type of
|
||||
* all functions, and this is checked at the point of the using statement. For versions 1 and
|
||||
* 2, this check is only done when a function is called.
|
||||
*
|
||||
* For version 4, T has to be user-defined value type and the function must be pure.
|
||||
* All parameters and return value of all the functions have to be of type T.
|
||||
* This version can be combined with version 3 - a single directive may attach functions to the
|
||||
* type and define operators on it at the same time.
|
||||
*
|
||||
* Finally, `using {f1, f2, ..., fn} for T global` is also valid at file level, as long as T is
|
||||
* a user-defined type defined in the same file at file level. In this case, the methods are
|
||||
* attached to all objects of that type regardless of scope.
|
||||
@ -663,16 +669,19 @@ public:
|
||||
int64_t _id,
|
||||
SourceLocation const& _location,
|
||||
std::vector<ASTPointer<IdentifierPath>> _functionsOrLibrary,
|
||||
std::vector<std::optional<Token>> _operators,
|
||||
bool _usesBraces,
|
||||
ASTPointer<TypeName> _typeName,
|
||||
bool _global
|
||||
):
|
||||
ASTNode(_id, _location),
|
||||
m_functionsOrLibrary(std::move(_functionsOrLibrary)),
|
||||
m_operators(std::move(_operators)),
|
||||
m_usesBraces(_usesBraces),
|
||||
m_typeName(std::move(_typeName)),
|
||||
m_global{_global}
|
||||
{
|
||||
solAssert(m_functionsOrLibrary.size() == m_operators.size());
|
||||
}
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
@ -683,12 +692,18 @@ public:
|
||||
|
||||
/// @returns a list of functions or the single library.
|
||||
std::vector<ASTPointer<IdentifierPath>> const& functionsOrLibrary() const { return m_functionsOrLibrary; }
|
||||
std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> functionsAndOperators() const;
|
||||
bool usesBraces() const { return m_usesBraces; }
|
||||
bool global() const { return m_global; }
|
||||
|
||||
private:
|
||||
/// Either the single library or a list of functions.
|
||||
std::vector<ASTPointer<IdentifierPath>> m_functionsOrLibrary;
|
||||
/// Operators, the functions from @a m_functionsOrLibrary implement.
|
||||
/// A token if the corresponding element in m_functionsOrLibrary
|
||||
/// defines an operator, nullptr otherwise.
|
||||
/// Note that this vector size must be equal to m_functionsOrLibrary size.
|
||||
std::vector<std::optional<Token>> m_operators;
|
||||
bool m_usesBraces;
|
||||
ASTPointer<TypeName> m_typeName;
|
||||
bool m_global = false;
|
||||
@ -2073,6 +2088,10 @@ public:
|
||||
bool isPrefixOperation() const { return m_isPrefix; }
|
||||
Expression const& subExpression() const { return *m_subExpression; }
|
||||
|
||||
FunctionType const* userDefinedFunctionType() const;
|
||||
|
||||
OperationAnnotation& annotation() const override;
|
||||
|
||||
private:
|
||||
Token m_operator;
|
||||
ASTPointer<Expression> m_subExpression;
|
||||
@ -2104,6 +2123,8 @@ public:
|
||||
Expression const& rightExpression() const { return *m_right; }
|
||||
Token getOperator() const { return m_operator; }
|
||||
|
||||
FunctionType const* userDefinedFunctionType() const;
|
||||
|
||||
BinaryOperationAnnotation& annotation() const override;
|
||||
|
||||
private:
|
||||
|
@ -312,7 +312,12 @@ struct MemberAccessAnnotation: ExpressionAnnotation
|
||||
util::SetOnce<VirtualLookup> requiredLookup;
|
||||
};
|
||||
|
||||
struct BinaryOperationAnnotation: ExpressionAnnotation
|
||||
struct OperationAnnotation: ExpressionAnnotation
|
||||
{
|
||||
util::SetOnce<FunctionDefinition const*> userDefinedFunction;
|
||||
};
|
||||
|
||||
struct BinaryOperationAnnotation: OperationAnnotation
|
||||
{
|
||||
/// The common type that is used for the operation, not necessarily the result type (which
|
||||
/// e.g. for comparisons is bool).
|
||||
|
@ -330,19 +330,31 @@ bool ASTJsonExporter::visit(UsingForDirective const& _node)
|
||||
vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue)
|
||||
};
|
||||
|
||||
if (_node.usesBraces())
|
||||
{
|
||||
Json::Value functionList;
|
||||
for (auto const& function: _node.functionsOrLibrary())
|
||||
for (auto&& [function, op]: _node.functionsAndOperators())
|
||||
{
|
||||
Json::Value functionNode;
|
||||
functionNode["function"] = toJson(*function);
|
||||
if (!op.has_value())
|
||||
functionNode["function"] = toJson(*function);
|
||||
else
|
||||
{
|
||||
functionNode["definition"] = toJson(*function);
|
||||
functionNode["operator"] = string(TokenTraits::toString(*op));
|
||||
}
|
||||
functionList.append(std::move(functionNode));
|
||||
}
|
||||
attributes.emplace_back("functionList", std::move(functionList));
|
||||
}
|
||||
else
|
||||
attributes.emplace_back("libraryName", toJson(*_node.functionsOrLibrary().front()));
|
||||
{
|
||||
auto const& functionAndOperators = _node.functionsAndOperators();
|
||||
solAssert(_node.functionsAndOperators().size() == 1);
|
||||
solAssert(!functionAndOperators.front().second.has_value());
|
||||
attributes.emplace_back("libraryName", toJson(*(functionAndOperators.front().first)));
|
||||
}
|
||||
attributes.emplace_back("global", _node.global());
|
||||
|
||||
setJsonNode(_node, "UsingForDirective", std::move(attributes));
|
||||
@ -830,6 +842,9 @@ bool ASTJsonExporter::visit(UnaryOperation const& _node)
|
||||
make_pair("operator", TokenTraits::toString(_node.getOperator())),
|
||||
make_pair("subExpression", toJson(_node.subExpression()))
|
||||
};
|
||||
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
|
||||
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
|
||||
attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction));
|
||||
appendExpressionAttributes(attributes, _node.annotation());
|
||||
setJsonNode(_node, "UnaryOperation", std::move(attributes));
|
||||
return false;
|
||||
@ -843,6 +858,9 @@ bool ASTJsonExporter::visit(BinaryOperation const& _node)
|
||||
make_pair("rightExpression", toJson(_node.rightExpression())),
|
||||
make_pair("commonType", typePointerToJson(_node.annotation().commonType)),
|
||||
};
|
||||
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
|
||||
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
|
||||
attributes.emplace_back("function", nodeId(**_node.annotation().userDefinedFunction));
|
||||
appendExpressionAttributes(attributes, _node.annotation());
|
||||
setJsonNode(_node, "BinaryOperation", std::move(attributes));
|
||||
return false;
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include <libsolidity/ast/ASTJsonImporter.h>
|
||||
#include <libsolidity/ast/UserDefinableOperators.h>
|
||||
|
||||
#include <libyul/AsmJsonImporter.h>
|
||||
#include <libyul/AST.h>
|
||||
@ -397,15 +398,42 @@ ASTPointer<InheritanceSpecifier> ASTJsonImporter::createInheritanceSpecifier(Jso
|
||||
ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
|
||||
{
|
||||
vector<ASTPointer<IdentifierPath>> functions;
|
||||
vector<optional<Token>> operators;
|
||||
if (_node.isMember("libraryName"))
|
||||
{
|
||||
astAssert(!_node["libraryName"].isArray());
|
||||
astAssert(!_node["libraryName"]["operator"]);
|
||||
functions.emplace_back(createIdentifierPath(_node["libraryName"]));
|
||||
operators.emplace_back(nullopt);
|
||||
}
|
||||
else if (_node.isMember("functionList"))
|
||||
for (Json::Value const& function: _node["functionList"])
|
||||
functions.emplace_back(createIdentifierPath(function["function"]));
|
||||
{
|
||||
if (function.isMember("function"))
|
||||
{
|
||||
astAssert(!function.isMember("operator"));
|
||||
astAssert(!function.isMember("definition"));
|
||||
|
||||
functions.emplace_back(createIdentifierPath(function["function"]));
|
||||
operators.emplace_back(nullopt);
|
||||
}
|
||||
else
|
||||
{
|
||||
astAssert(function.isMember("operator"));
|
||||
astAssert(function.isMember("definition"));
|
||||
|
||||
Token const operatorName = scanSingleToken(function["operator"]);
|
||||
astAssert(util::contains(frontend::userDefinableOperators, operatorName));
|
||||
|
||||
functions.emplace_back(createIdentifierPath(function["definition"]));
|
||||
operators.emplace_back(operatorName);
|
||||
}
|
||||
}
|
||||
|
||||
return createASTNode<UsingForDirective>(
|
||||
_node,
|
||||
std::move(functions),
|
||||
std::move(operators),
|
||||
!_node.isMember("libraryName"),
|
||||
_node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"]),
|
||||
memberAsBool(_node, "global")
|
||||
|
@ -383,6 +383,38 @@ vector<UsingForDirective const*> usingForDirectivesForType(Type const& _type, AS
|
||||
|
||||
}
|
||||
|
||||
set<FunctionDefinition const*, ASTNode::CompareByID> Type::operatorDefinitions(
|
||||
Token _token,
|
||||
ASTNode const& _scope,
|
||||
bool _unary
|
||||
) const
|
||||
{
|
||||
if (!typeDefinition())
|
||||
return {};
|
||||
|
||||
set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions;
|
||||
for (UsingForDirective const* directive: usingForDirectivesForType(*this, _scope))
|
||||
for (auto const& [identifierPath, operator_]: directive->functionsAndOperators())
|
||||
{
|
||||
if (operator_ != _token)
|
||||
continue;
|
||||
|
||||
auto const& functionDefinition = dynamic_cast<FunctionDefinition const&>(
|
||||
*identifierPath->annotation().referencedDeclaration
|
||||
);
|
||||
auto const* functionType = dynamic_cast<FunctionType const*>(
|
||||
functionDefinition.libraryFunction() ? functionDefinition.typeViaContractName() : functionDefinition.type()
|
||||
);
|
||||
solAssert(functionType && !functionType->parameterTypes().empty());
|
||||
|
||||
size_t parameterCount = functionDefinition.parameterList().parameters().size();
|
||||
if (*this == *functionType->parameterTypes().front() && (_unary ? parameterCount == 1 : parameterCount == 2))
|
||||
matchingDefinitions.insert(&functionDefinition);
|
||||
}
|
||||
|
||||
return matchingDefinitions;
|
||||
}
|
||||
|
||||
MemberList::MemberMap Type::attachedFunctions(Type const& _type, ASTNode const& _scope)
|
||||
{
|
||||
MemberList::MemberMap members;
|
||||
@ -405,8 +437,13 @@ MemberList::MemberMap Type::attachedFunctions(Type const& _type, ASTNode const&
|
||||
};
|
||||
|
||||
for (UsingForDirective const* ufd: usingForDirectivesForType(_type, _scope))
|
||||
for (auto const& identifierPath: ufd->functionsOrLibrary())
|
||||
for (auto const& [identifierPath, operator_]: ufd->functionsAndOperators())
|
||||
{
|
||||
if (operator_.has_value())
|
||||
// Functions used to define operators are not automatically attached to the type.
|
||||
// I.e. `using {f, f as +} for T` allows `T x; x.f()` but `using {f as +} for T` does not.
|
||||
continue;
|
||||
|
||||
solAssert(identifierPath);
|
||||
Declaration const* declaration = identifierPath->annotation().referencedDeclaration;
|
||||
solAssert(declaration);
|
||||
|
@ -377,6 +377,21 @@ public:
|
||||
/// Clears all internally cached values (if any).
|
||||
virtual void clearCache() const;
|
||||
|
||||
/// Scans all "using for" directives in the @a _scope for functions implementing
|
||||
/// the operator represented by @a _token. Returns the set of all definitions where the type
|
||||
/// of the first argument matches this type object.
|
||||
///
|
||||
/// @note: If the AST has passed analysis without errors,
|
||||
/// the function will find at most one definition for an operator.
|
||||
///
|
||||
/// @param _unary If true, only definitions that accept exactly one argument are included.
|
||||
/// Otherwise only definitions that accept exactly two arguments.
|
||||
std::set<FunctionDefinition const*, ASTCompareByID<ASTNode>> operatorDefinitions(
|
||||
Token _token,
|
||||
ASTNode const& _scope,
|
||||
bool _unary
|
||||
) const;
|
||||
|
||||
private:
|
||||
/// @returns a member list containing all members added to this type by `using for` directives.
|
||||
static MemberList::MemberMap attachedFunctions(Type const& _type, ASTNode const& _scope);
|
||||
|
31
libsolidity/ast/UserDefinableOperators.h
Normal file
31
libsolidity/ast/UserDefinableOperators.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <liblangutil/Token.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
std::vector<langutil::Token> const userDefinableOperators = {
|
||||
// Bitwise
|
||||
langutil::Token::BitOr,
|
||||
langutil::Token::BitAnd,
|
||||
langutil::Token::BitXor,
|
||||
langutil::Token::BitNot,
|
||||
// Arithmetic
|
||||
langutil::Token::Add,
|
||||
langutil::Token::Sub,
|
||||
langutil::Token::Mul,
|
||||
langutil::Token::Div,
|
||||
langutil::Token::Mod,
|
||||
// Comparison
|
||||
langutil::Token::Equal,
|
||||
langutil::Token::NotEqual,
|
||||
langutil::Token::LessThan,
|
||||
langutil::Token::GreaterThan,
|
||||
langutil::Token::LessThanOrEqual,
|
||||
langutil::Token::GreaterThanOrEqual,
|
||||
};
|
||||
|
||||
}
|
@ -410,6 +410,38 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
||||
bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _unaryOperation);
|
||||
|
||||
FunctionDefinition const* function = *_unaryOperation.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
solAssert(function->isFree());
|
||||
|
||||
FunctionType const* functionType = _unaryOperation.userDefinedFunctionType();
|
||||
solAssert(functionType);
|
||||
solAssert(functionType->parameterTypes().size() == 1);
|
||||
solAssert(functionType->returnParameterTypes().size() == 1);
|
||||
solAssert(functionType->kind() == FunctionType::Kind::Internal);
|
||||
|
||||
evmasm::AssemblyItem returnLabel = m_context.pushNewTag();
|
||||
acceptAndConvert(
|
||||
_unaryOperation.subExpression(),
|
||||
*functionType->parameterTypes()[0],
|
||||
false // _cleanupNeeded
|
||||
);
|
||||
|
||||
m_context << m_context.functionEntryLabel(*function).pushTag();
|
||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
m_context << returnLabel;
|
||||
|
||||
unsigned parameterSize = CompilerUtils::sizeOnStack(functionType->parameterTypes());
|
||||
unsigned returnParametersSize = CompilerUtils::sizeOnStack(functionType->returnParameterTypes());
|
||||
|
||||
// callee adds return parameters, but removes arguments and return label
|
||||
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type const& type = *_unaryOperation.annotation().type;
|
||||
if (type.category() == Type::Category::RationalNumber)
|
||||
{
|
||||
@ -502,7 +534,42 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation)
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _binaryOperation);
|
||||
Expression const& leftExpression = _binaryOperation.leftExpression();
|
||||
Expression const& rightExpression = _binaryOperation.rightExpression();
|
||||
solAssert(!!_binaryOperation.annotation().commonType, "");
|
||||
FunctionDefinition const* function = *_binaryOperation.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
solAssert(function->isFree());
|
||||
|
||||
FunctionType const* functionType = _binaryOperation.userDefinedFunctionType();
|
||||
solAssert(functionType);
|
||||
solAssert(functionType->parameterTypes().size() == 2);
|
||||
solAssert(functionType->returnParameterTypes().size() == 1);
|
||||
solAssert(functionType->kind() == FunctionType::Kind::Internal);
|
||||
|
||||
evmasm::AssemblyItem returnLabel = m_context.pushNewTag();
|
||||
acceptAndConvert(
|
||||
leftExpression,
|
||||
*functionType->parameterTypes()[0],
|
||||
false // _cleanupNeeded
|
||||
);
|
||||
acceptAndConvert(
|
||||
rightExpression,
|
||||
*functionType->parameterTypes()[1],
|
||||
false // _cleanupNeeded
|
||||
);
|
||||
|
||||
m_context << m_context.functionEntryLabel(*function).pushTag();
|
||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
m_context << returnLabel;
|
||||
|
||||
unsigned parameterSize = CompilerUtils::sizeOnStack(functionType->parameterTypes());
|
||||
unsigned returnParametersSize = CompilerUtils::sizeOnStack(functionType->returnParameterTypes());
|
||||
|
||||
// callee adds return parameters, but removes arguments and return label
|
||||
m_context.adjustStackOffset(static_cast<int>(returnParametersSize - parameterSize) - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
solAssert(!!_binaryOperation.annotation().commonType);
|
||||
Type const* commonType = _binaryOperation.annotation().commonType;
|
||||
Token const c_op = _binaryOperation.getOperator();
|
||||
|
||||
|
@ -672,6 +672,30 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
||||
bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
setLocation(_unaryOperation);
|
||||
|
||||
FunctionDefinition const* function = *_unaryOperation.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
_unaryOperation.subExpression().accept(*this);
|
||||
setLocation(_unaryOperation);
|
||||
|
||||
solAssert(function->isImplemented());
|
||||
solAssert(function->isFree());
|
||||
solAssert(function->parameters().size() == 1);
|
||||
solAssert(function->returnParameters().size() == 1);
|
||||
solAssert(*function->returnParameters()[0]->type() == *_unaryOperation.annotation().type);
|
||||
|
||||
string argument = expressionAsType(_unaryOperation.subExpression(), *function->parameters()[0]->type());
|
||||
solAssert(!argument.empty());
|
||||
|
||||
solAssert(_unaryOperation.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal);
|
||||
define(_unaryOperation) <<
|
||||
m_context.enqueueFunctionForCodeGeneration(*function) <<
|
||||
("(" + argument + ")\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type const& resultType = type(_unaryOperation);
|
||||
Token const op = _unaryOperation.getOperator();
|
||||
|
||||
@ -775,6 +799,31 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
|
||||
{
|
||||
setLocation(_binOp);
|
||||
|
||||
FunctionDefinition const* function = *_binOp.annotation().userDefinedFunction;
|
||||
if (function)
|
||||
{
|
||||
_binOp.leftExpression().accept(*this);
|
||||
_binOp.rightExpression().accept(*this);
|
||||
setLocation(_binOp);
|
||||
|
||||
solAssert(function->isImplemented());
|
||||
solAssert(function->isFree());
|
||||
solAssert(function->parameters().size() == 2);
|
||||
solAssert(function->returnParameters().size() == 1);
|
||||
solAssert(*function->returnParameters()[0]->type() == *_binOp.annotation().type);
|
||||
|
||||
string left = expressionAsType(_binOp.leftExpression(), *function->parameters()[0]->type());
|
||||
string right = expressionAsType(_binOp.rightExpression(), *function->parameters()[1]->type());
|
||||
solAssert(!left.empty() && !right.empty());
|
||||
|
||||
solAssert(_binOp.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal);
|
||||
define(_binOp) <<
|
||||
m_context.enqueueFunctionForCodeGeneration(*function) <<
|
||||
("(" + left + ", " + right + ")\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
solAssert(!!_binOp.annotation().commonType);
|
||||
Type const* commonType = _binOp.annotation().commonType;
|
||||
langutil::Token op = _binOp.getOperator();
|
||||
|
@ -449,11 +449,25 @@ void SMTEncoder::endVisit(UnaryOperation const& _op)
|
||||
if (_op.annotation().type->category() == Type::Category::RationalNumber)
|
||||
return;
|
||||
|
||||
if (TokenTraits::isBitOp(_op.getOperator()))
|
||||
if (TokenTraits::isBitOp(_op.getOperator()) && !*_op.annotation().userDefinedFunction)
|
||||
return bitwiseNotOperation(_op);
|
||||
|
||||
createExpr(_op);
|
||||
|
||||
// User-defined operators are essentially function calls.
|
||||
if (*_op.annotation().userDefinedFunction)
|
||||
{
|
||||
// TODO: Implement user-defined operators properly.
|
||||
m_errorReporter.warning(
|
||||
6156_error,
|
||||
_op.location(),
|
||||
"User-defined operators are not yet supported by SMTChecker. "s +
|
||||
"This invocation of operator " + TokenTraits::friendlyName(_op.getOperator()) +
|
||||
" has been ignored, which may lead to incorrect results."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto const* subExpr = innermostTuple(_op.subExpression());
|
||||
auto type = _op.annotation().type;
|
||||
switch (_op.getOperator())
|
||||
@ -524,7 +538,7 @@ bool SMTEncoder::visit(BinaryOperation const& _op)
|
||||
{
|
||||
if (shortcutRationalNumber(_op))
|
||||
return false;
|
||||
if (TokenTraits::isBooleanOp(_op.getOperator()))
|
||||
if (TokenTraits::isBooleanOp(_op.getOperator()) && !*_op.annotation().userDefinedFunction)
|
||||
{
|
||||
booleanOperation(_op);
|
||||
return false;
|
||||
@ -537,11 +551,25 @@ void SMTEncoder::endVisit(BinaryOperation const& _op)
|
||||
/// If _op is const evaluated the RationalNumber shortcut was taken.
|
||||
if (isConstant(_op))
|
||||
return;
|
||||
if (TokenTraits::isBooleanOp(_op.getOperator()))
|
||||
if (TokenTraits::isBooleanOp(_op.getOperator()) && !*_op.annotation().userDefinedFunction)
|
||||
return;
|
||||
|
||||
createExpr(_op);
|
||||
|
||||
// User-defined operators are essentially function calls.
|
||||
if (*_op.annotation().userDefinedFunction)
|
||||
{
|
||||
// TODO: Implement user-defined operators properly.
|
||||
m_errorReporter.warning(
|
||||
6756_error,
|
||||
_op.location(),
|
||||
"User-defined operators are not yet supported by SMTChecker. "s +
|
||||
"This invocation of operator " + TokenTraits::friendlyName(_op.getOperator()) +
|
||||
" has been ignored, which may lead to incorrect results."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TokenTraits::isArithmeticOp(_op.getOperator()))
|
||||
arithmeticOperation(_op);
|
||||
else if (TokenTraits::isCompareOp(_op.getOperator()))
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <libsolidity/parsing/Parser.h>
|
||||
|
||||
#include <libsolidity/ast/UserDefinableOperators.h>
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libyul/AST.h>
|
||||
#include <libyul/AsmParser.h>
|
||||
@ -976,6 +977,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||
expectToken(Token::Using);
|
||||
|
||||
vector<ASTPointer<IdentifierPath>> functions;
|
||||
vector<optional<Token>> operators;
|
||||
bool const usesBraces = m_scanner->currentToken() == Token::LBrace;
|
||||
if (usesBraces)
|
||||
{
|
||||
@ -983,12 +985,35 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||
{
|
||||
advance();
|
||||
functions.emplace_back(parseIdentifierPath());
|
||||
if (m_scanner->currentToken() == Token::As)
|
||||
{
|
||||
advance();
|
||||
Token operator_ = m_scanner->currentToken();
|
||||
if (!util::contains(userDefinableOperators, operator_))
|
||||
{
|
||||
parserError(
|
||||
4403_error,
|
||||
fmt::format(
|
||||
"Not a user-definable operator: {}. Only the following operators can be user-defined: {}",
|
||||
(!m_scanner->currentLiteral().empty() ? m_scanner->currentLiteral() : string(TokenTraits::toString(operator_))),
|
||||
util::joinHumanReadable(userDefinableOperators | ranges::views::transform([](Token _t) { return string{TokenTraits::toString(_t)}; }))
|
||||
)
|
||||
);
|
||||
}
|
||||
operators.emplace_back(operator_);
|
||||
advance();
|
||||
}
|
||||
else
|
||||
operators.emplace_back(nullopt);
|
||||
}
|
||||
while (m_scanner->currentToken() == Token::Comma);
|
||||
expectToken(Token::RBrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
functions.emplace_back(parseIdentifierPath());
|
||||
operators.emplace_back(nullopt);
|
||||
}
|
||||
|
||||
ASTPointer<TypeName> typeName;
|
||||
expectToken(Token::For);
|
||||
@ -1004,7 +1029,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||
}
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::Semicolon);
|
||||
return nodeFactory.createNode<UsingForDirective>(std::move(functions), usesBraces, typeName, global);
|
||||
return nodeFactory.createNode<UsingForDirective>(std::move(functions), std::move(operators), usesBraces, typeName, global);
|
||||
}
|
||||
|
||||
ASTPointer<ModifierInvocation> Parser::parseModifierInvocation()
|
||||
|
663
test/libsolidity/ASTJSON/user_defined_operator.json
Normal file
663
test/libsolidity/ASTJSON/user_defined_operator.json
Normal file
@ -0,0 +1,663 @@
|
||||
{
|
||||
"absolutePath": "a",
|
||||
"exportedSymbols":
|
||||
{
|
||||
"C":
|
||||
[
|
||||
49
|
||||
],
|
||||
"I8":
|
||||
[
|
||||
2
|
||||
],
|
||||
"sub":
|
||||
[
|
||||
20
|
||||
],
|
||||
"unsub":
|
||||
[
|
||||
30
|
||||
]
|
||||
},
|
||||
"id": 50,
|
||||
"nodeType": "SourceUnit",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"canonicalName": "I8",
|
||||
"id": 2,
|
||||
"name": "I8",
|
||||
"nameLocation": "5:2:1",
|
||||
"nodeType": "UserDefinedValueTypeDefinition",
|
||||
"src": "0:16:1",
|
||||
"underlyingType":
|
||||
{
|
||||
"id": 1,
|
||||
"name": "int8",
|
||||
"nodeType": "ElementaryTypeName",
|
||||
"src": "11:4:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_int8",
|
||||
"typeString": "int8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionList":
|
||||
[
|
||||
{
|
||||
"definition":
|
||||
{
|
||||
"id": 3,
|
||||
"name": "sub",
|
||||
"nameLocations":
|
||||
[
|
||||
"24:3:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 20,
|
||||
"src": "24:3:1"
|
||||
},
|
||||
"operator": "-"
|
||||
},
|
||||
{
|
||||
"definition":
|
||||
{
|
||||
"id": 4,
|
||||
"name": "unsub",
|
||||
"nameLocations":
|
||||
[
|
||||
"34:5:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 30,
|
||||
"src": "34:5:1"
|
||||
},
|
||||
"operator": "-"
|
||||
}
|
||||
],
|
||||
"global": true,
|
||||
"id": 7,
|
||||
"nodeType": "UsingForDirective",
|
||||
"src": "17:43:1",
|
||||
"typeName":
|
||||
{
|
||||
"id": 6,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 5,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"50:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "50:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "50:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"body":
|
||||
{
|
||||
"id": 19,
|
||||
"nodeType": "Block",
|
||||
"src": "100:2:1",
|
||||
"statements": []
|
||||
},
|
||||
"id": 20,
|
||||
"implemented": true,
|
||||
"kind": "freeFunction",
|
||||
"modifiers": [],
|
||||
"name": "sub",
|
||||
"nameLocation": "70:3:1",
|
||||
"nodeType": "FunctionDefinition",
|
||||
"parameters":
|
||||
{
|
||||
"id": 14,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 10,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 20,
|
||||
"src": "74:2:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 9,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 8,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"74:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "74:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "74:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 13,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 20,
|
||||
"src": "78:2:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 12,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 11,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"78:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "78:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "78:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "73:8:1"
|
||||
},
|
||||
"returnParameters":
|
||||
{
|
||||
"id": 18,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 17,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 20,
|
||||
"src": "96:2:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 16,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 15,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"96:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "96:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "96:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "95:4:1"
|
||||
},
|
||||
"scope": 50,
|
||||
"src": "61:41:1",
|
||||
"stateMutability": "pure",
|
||||
"virtual": false,
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"body":
|
||||
{
|
||||
"id": 29,
|
||||
"nodeType": "Block",
|
||||
"src": "140:2:1",
|
||||
"statements": []
|
||||
},
|
||||
"id": 30,
|
||||
"implemented": true,
|
||||
"kind": "freeFunction",
|
||||
"modifiers": [],
|
||||
"name": "unsub",
|
||||
"nameLocation": "112:5:1",
|
||||
"nodeType": "FunctionDefinition",
|
||||
"parameters":
|
||||
{
|
||||
"id": 24,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 23,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 30,
|
||||
"src": "118:2:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 22,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 21,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"118:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "118:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "118:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "117:4:1"
|
||||
},
|
||||
"returnParameters":
|
||||
{
|
||||
"id": 28,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 27,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 30,
|
||||
"src": "136:2:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 26,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 25,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"136:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "136:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "136:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "135:4:1"
|
||||
},
|
||||
"scope": 50,
|
||||
"src": "103:39:1",
|
||||
"stateMutability": "pure",
|
||||
"virtual": false,
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"abstract": false,
|
||||
"baseContracts": [],
|
||||
"canonicalName": "C",
|
||||
"contractDependencies": [],
|
||||
"contractKind": "contract",
|
||||
"fullyImplemented": true,
|
||||
"id": 49,
|
||||
"linearizedBaseContracts":
|
||||
[
|
||||
49
|
||||
],
|
||||
"name": "C",
|
||||
"nameLocation": "152:1:1",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"body":
|
||||
{
|
||||
"id": 47,
|
||||
"nodeType": "Block",
|
||||
"src": "208:30:1",
|
||||
"statements":
|
||||
[
|
||||
{
|
||||
"expression":
|
||||
{
|
||||
"commonType":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"function": 20,
|
||||
"id": 45,
|
||||
"isConstant": false,
|
||||
"isLValue": false,
|
||||
"isPure": false,
|
||||
"lValueRequested": false,
|
||||
"leftExpression":
|
||||
{
|
||||
"function": 30,
|
||||
"id": 43,
|
||||
"isConstant": false,
|
||||
"isLValue": false,
|
||||
"isPure": false,
|
||||
"lValueRequested": false,
|
||||
"nodeType": "UnaryOperation",
|
||||
"operator": "-",
|
||||
"prefix": true,
|
||||
"src": "225:2:1",
|
||||
"subExpression":
|
||||
{
|
||||
"id": 42,
|
||||
"name": "a",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [],
|
||||
"referencedDeclaration": 33,
|
||||
"src": "226:1:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"nodeType": "BinaryOperation",
|
||||
"operator": "-",
|
||||
"rightExpression":
|
||||
{
|
||||
"id": 44,
|
||||
"name": "b",
|
||||
"nodeType": "Identifier",
|
||||
"overloadedDeclarations": [],
|
||||
"referencedDeclaration": 36,
|
||||
"src": "230:1:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"src": "225:6:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"functionReturnParameters": 41,
|
||||
"id": 46,
|
||||
"nodeType": "Return",
|
||||
"src": "218:13:1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"functionSelector": "ac9fe858",
|
||||
"id": 48,
|
||||
"implemented": true,
|
||||
"kind": "function",
|
||||
"modifiers": [],
|
||||
"name": "f",
|
||||
"nameLocation": "169:1:1",
|
||||
"nodeType": "FunctionDefinition",
|
||||
"parameters":
|
||||
{
|
||||
"id": 37,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 33,
|
||||
"mutability": "mutable",
|
||||
"name": "a",
|
||||
"nameLocation": "174:1:1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 48,
|
||||
"src": "171:4:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 32,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 31,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"171:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "171:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "171:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"id": 36,
|
||||
"mutability": "mutable",
|
||||
"name": "b",
|
||||
"nameLocation": "180:1:1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 48,
|
||||
"src": "177:4:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 35,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 34,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"177:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "177:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "177:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "170:12:1"
|
||||
},
|
||||
"returnParameters":
|
||||
{
|
||||
"id": 41,
|
||||
"nodeType": "ParameterList",
|
||||
"parameters":
|
||||
[
|
||||
{
|
||||
"constant": false,
|
||||
"id": 40,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "VariableDeclaration",
|
||||
"scope": 48,
|
||||
"src": "204:2:1",
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
},
|
||||
"typeName":
|
||||
{
|
||||
"id": 39,
|
||||
"nodeType": "UserDefinedTypeName",
|
||||
"pathNode":
|
||||
{
|
||||
"id": 38,
|
||||
"name": "I8",
|
||||
"nameLocations":
|
||||
[
|
||||
"204:2:1"
|
||||
],
|
||||
"nodeType": "IdentifierPath",
|
||||
"referencedDeclaration": 2,
|
||||
"src": "204:2:1"
|
||||
},
|
||||
"referencedDeclaration": 2,
|
||||
"src": "204:2:1",
|
||||
"typeDescriptions":
|
||||
{
|
||||
"typeIdentifier": "t_userDefinedValueType$_I8_$2",
|
||||
"typeString": "I8"
|
||||
}
|
||||
},
|
||||
"visibility": "internal"
|
||||
}
|
||||
],
|
||||
"src": "203:4:1"
|
||||
},
|
||||
"scope": 49,
|
||||
"src": "160:78:1",
|
||||
"stateMutability": "pure",
|
||||
"virtual": false,
|
||||
"visibility": "public"
|
||||
}
|
||||
],
|
||||
"scope": 50,
|
||||
"src": "143:97:1",
|
||||
"usedErrors": []
|
||||
}
|
||||
],
|
||||
"src": "0:241:1"
|
||||
}
|
11
test/libsolidity/ASTJSON/user_defined_operator.sol
Normal file
11
test/libsolidity/ASTJSON/user_defined_operator.sol
Normal file
@ -0,0 +1,11 @@
|
||||
type I8 is int8;
|
||||
using {sub as -, unsub as -} for I8 global;
|
||||
function sub(I8, I8) pure returns (I8) {}
|
||||
function unsub(I8) pure returns (I8) {}
|
||||
contract C {
|
||||
function f(I8 a, I8 b) public pure returns (I8) {
|
||||
return -a - b;
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
@ -1702,6 +1702,72 @@ BOOST_AUTO_TEST_CASE(using_for)
|
||||
checkCallGraphExpectations(get<1>(graphs), expectedDeployedEdges);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_defined_binary_operator)
|
||||
{
|
||||
unique_ptr<CompilerStack> compilerStack = parseAndAnalyzeContracts(R"(
|
||||
type Int is int128;
|
||||
using {add as +} for Int global;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {
|
||||
return Int.wrap(0);
|
||||
}
|
||||
|
||||
contract C {
|
||||
function pub() public {
|
||||
Int.wrap(0) + Int.wrap(1);
|
||||
}
|
||||
}
|
||||
)"s);
|
||||
tuple<CallGraphMap, CallGraphMap> graphs = collectGraphs(*compilerStack);
|
||||
|
||||
map<string, EdgeNames> expectedCreationEdges = {
|
||||
{"C", {}},
|
||||
};
|
||||
|
||||
map<string, EdgeNames> expectedDeployedEdges = {
|
||||
{"C", {
|
||||
{"Entry", "function C.pub()"},
|
||||
{"function C.pub()", "function add(Int,Int)"},
|
||||
}},
|
||||
};
|
||||
|
||||
checkCallGraphExpectations(get<0>(graphs), expectedCreationEdges);
|
||||
checkCallGraphExpectations(get<1>(graphs), expectedDeployedEdges);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(user_defined_unary_operator)
|
||||
{
|
||||
unique_ptr<CompilerStack> compilerStack = parseAndAnalyzeContracts(R"(
|
||||
type Int is int128;
|
||||
using {sub as -} for Int global;
|
||||
|
||||
function sub(Int) pure returns (Int) {
|
||||
return Int.wrap(0);
|
||||
}
|
||||
|
||||
contract C {
|
||||
function pub() public {
|
||||
-Int.wrap(1);
|
||||
}
|
||||
}
|
||||
)"s);
|
||||
tuple<CallGraphMap, CallGraphMap> graphs = collectGraphs(*compilerStack);
|
||||
|
||||
map<string, EdgeNames> expectedCreationEdges = {
|
||||
{"C", {}},
|
||||
};
|
||||
|
||||
map<string, EdgeNames> expectedDeployedEdges = {
|
||||
{"C", {
|
||||
{"Entry", "function C.pub()"},
|
||||
{"function C.pub()", "function sub(Int)"},
|
||||
}},
|
||||
};
|
||||
|
||||
checkCallGraphExpectations(get<0>(graphs), expectedCreationEdges);
|
||||
checkCallGraphExpectations(get<1>(graphs), expectedDeployedEdges);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(getters)
|
||||
{
|
||||
unique_ptr<CompilerStack> compilerStack = parseAndAnalyzeContracts(R"(
|
||||
|
@ -0,0 +1,92 @@
|
||||
type Int is int8;
|
||||
using {
|
||||
bitor as |, bitand as &, bitxor as ^, bitnot as ~,
|
||||
add as +, sub as -, unsub as -, mul as *, div as /, mod as %,
|
||||
eq as ==, noteq as !=, lt as <, gt as >, leq as <=, geq as >=
|
||||
} for Int global;
|
||||
|
||||
function bitor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) | Int.unwrap(y)); }
|
||||
function bitand(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) & Int.unwrap(y)); }
|
||||
function bitxor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) ^ Int.unwrap(y)); }
|
||||
function bitnot(Int x) pure returns (Int) { return Int.wrap(~Int.unwrap(x)); }
|
||||
|
||||
function add(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) + Int.unwrap(y)); }
|
||||
function sub(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) - Int.unwrap(y)); }
|
||||
function unsub(Int x) pure returns (Int) { return Int.wrap(-Int.unwrap(x)); }
|
||||
function mul(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) * Int.unwrap(y)); }
|
||||
function div(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) / Int.unwrap(y)); }
|
||||
function mod(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) % Int.unwrap(y)); }
|
||||
|
||||
function eq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) == Int.unwrap(y); }
|
||||
function noteq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) != Int.unwrap(y); }
|
||||
function lt(Int x, Int y) pure returns (bool) { return Int.unwrap(x) < Int.unwrap(y); }
|
||||
function gt(Int x, Int y) pure returns (bool) { return Int.unwrap(x) > Int.unwrap(y); }
|
||||
function leq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) <= Int.unwrap(y); }
|
||||
function geq(Int x, Int y) pure returns (bool) { return Int.unwrap(x) >= Int.unwrap(y); }
|
||||
|
||||
contract C {
|
||||
Int constant ZERO = Int.wrap(0);
|
||||
Int constant ONE = Int.wrap(1);
|
||||
Int constant TWO = Int.wrap(2);
|
||||
Int constant THREE = Int.wrap(3);
|
||||
Int constant SIX = Int.wrap(6);
|
||||
|
||||
function testBitwise() public pure {
|
||||
assert(Int.unwrap(ONE | TWO) == 3);
|
||||
assert(Int.unwrap(ONE | ZERO) == 1);
|
||||
|
||||
assert(Int.unwrap(ONE & THREE) == 1);
|
||||
assert(Int.unwrap(ONE & ONE) == 1);
|
||||
|
||||
assert(Int.unwrap(TWO ^ TWO) == 0);
|
||||
assert(Int.unwrap(TWO ^ ONE) == 3);
|
||||
|
||||
assert(Int.unwrap(~ZERO) == -1);
|
||||
assert(Int.unwrap(~ONE) == -2);
|
||||
assert(Int.unwrap(~TWO) == -3);
|
||||
}
|
||||
|
||||
function testArithmetic() public pure {
|
||||
assert(Int.unwrap(ONE + TWO) == 3);
|
||||
assert(Int.unwrap(ONE + ZERO) == 1);
|
||||
|
||||
assert(Int.unwrap(TWO - ONE) == 1);
|
||||
assert(Int.unwrap(THREE - THREE) == 0);
|
||||
|
||||
assert(Int.unwrap(-TWO) == -2);
|
||||
assert(Int.unwrap(-ZERO) == 0);
|
||||
|
||||
assert(Int.unwrap(ONE * ONE) == 1);
|
||||
assert(Int.unwrap(THREE * TWO) == 6);
|
||||
|
||||
assert(Int.unwrap(SIX / TWO) == 3);
|
||||
assert(Int.unwrap(THREE / TWO) == 1);
|
||||
|
||||
assert(Int.unwrap(SIX % TWO) == 0);
|
||||
assert(Int.unwrap(THREE % TWO) == 1);
|
||||
}
|
||||
|
||||
function testComparison() public pure {
|
||||
assert((ONE == ONE) == true);
|
||||
assert((ONE == TWO) == false);
|
||||
|
||||
assert((ONE != ONE) == false);
|
||||
assert((ONE != TWO) == true);
|
||||
|
||||
assert((ONE < TWO) == true);
|
||||
assert((TWO < ONE) == false);
|
||||
|
||||
assert((ONE <= TWO) == true);
|
||||
assert((TWO <= ONE) == false);
|
||||
|
||||
assert((ONE > TWO) == false);
|
||||
assert((TWO > ONE) == true);
|
||||
|
||||
assert((ONE >= TWO) == false);
|
||||
assert((TWO >= ONE) == true);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testBitwise() ->
|
||||
// testArithmetic() ->
|
||||
// testComparison() ->
|
@ -0,0 +1,670 @@
|
||||
type Int8 is int8;
|
||||
type Int16 is int16;
|
||||
type Int24 is int24;
|
||||
type Int32 is int32;
|
||||
type Int40 is int40;
|
||||
type Int48 is int48;
|
||||
type Int56 is int56;
|
||||
type Int64 is int64;
|
||||
type Int72 is int72;
|
||||
type Int80 is int80;
|
||||
type Int88 is int88;
|
||||
type Int96 is int96;
|
||||
type Int104 is int104;
|
||||
type Int112 is int112;
|
||||
type Int120 is int120;
|
||||
type Int128 is int128;
|
||||
type Int136 is int136;
|
||||
type Int144 is int144;
|
||||
type Int152 is int152;
|
||||
type Int160 is int160;
|
||||
type Int168 is int168;
|
||||
type Int176 is int176;
|
||||
type Int184 is int184;
|
||||
type Int192 is int192;
|
||||
type Int200 is int200;
|
||||
type Int208 is int208;
|
||||
type Int216 is int216;
|
||||
type Int224 is int224;
|
||||
type Int232 is int232;
|
||||
type Int240 is int240;
|
||||
type Int248 is int248;
|
||||
type Int256 is int256;
|
||||
type Int is int;
|
||||
|
||||
type Uint8 is uint8;
|
||||
type Uint16 is uint16;
|
||||
type Uint24 is uint24;
|
||||
type Uint32 is uint32;
|
||||
type Uint40 is uint40;
|
||||
type Uint48 is uint48;
|
||||
type Uint56 is uint56;
|
||||
type Uint64 is uint64;
|
||||
type Uint72 is uint72;
|
||||
type Uint80 is uint80;
|
||||
type Uint88 is uint88;
|
||||
type Uint96 is uint96;
|
||||
type Uint104 is uint104;
|
||||
type Uint112 is uint112;
|
||||
type Uint120 is uint120;
|
||||
type Uint128 is uint128;
|
||||
type Uint136 is uint136;
|
||||
type Uint144 is uint144;
|
||||
type Uint152 is uint152;
|
||||
type Uint160 is uint160;
|
||||
type Uint168 is uint168;
|
||||
type Uint176 is uint176;
|
||||
type Uint184 is uint184;
|
||||
type Uint192 is uint192;
|
||||
type Uint200 is uint200;
|
||||
type Uint208 is uint208;
|
||||
type Uint216 is uint216;
|
||||
type Uint224 is uint224;
|
||||
type Uint232 is uint232;
|
||||
type Uint240 is uint240;
|
||||
type Uint248 is uint248;
|
||||
type Uint256 is uint256;
|
||||
type Uint is uint;
|
||||
|
||||
type Bytes1 is bytes1;
|
||||
type Bytes2 is bytes2;
|
||||
type Bytes3 is bytes3;
|
||||
type Bytes4 is bytes4;
|
||||
type Bytes5 is bytes5;
|
||||
type Bytes6 is bytes6;
|
||||
type Bytes7 is bytes7;
|
||||
type Bytes8 is bytes8;
|
||||
type Bytes9 is bytes9;
|
||||
type Bytes10 is bytes10;
|
||||
type Bytes11 is bytes11;
|
||||
type Bytes12 is bytes12;
|
||||
type Bytes13 is bytes13;
|
||||
type Bytes14 is bytes14;
|
||||
type Bytes15 is bytes15;
|
||||
type Bytes16 is bytes16;
|
||||
type Bytes17 is bytes17;
|
||||
type Bytes18 is bytes18;
|
||||
type Bytes19 is bytes19;
|
||||
type Bytes20 is bytes20;
|
||||
type Bytes21 is bytes21;
|
||||
type Bytes22 is bytes22;
|
||||
type Bytes23 is bytes23;
|
||||
type Bytes24 is bytes24;
|
||||
type Bytes25 is bytes25;
|
||||
type Bytes26 is bytes26;
|
||||
type Bytes27 is bytes27;
|
||||
type Bytes28 is bytes28;
|
||||
type Bytes29 is bytes29;
|
||||
type Bytes30 is bytes30;
|
||||
type Bytes31 is bytes31;
|
||||
type Bytes32 is bytes32;
|
||||
|
||||
type Address is address;
|
||||
type AddressPayable is address payable;
|
||||
|
||||
type Bool is bool;
|
||||
|
||||
using {bitorInt8 as |, unsubInt8 as -} for Int8 global;
|
||||
using {bitorInt16 as |, unsubInt16 as -} for Int16 global;
|
||||
using {bitorInt24 as |, unsubInt24 as -} for Int24 global;
|
||||
using {bitorInt32 as |, unsubInt32 as -} for Int32 global;
|
||||
using {bitorInt40 as |, unsubInt40 as -} for Int40 global;
|
||||
using {bitorInt48 as |, unsubInt48 as -} for Int48 global;
|
||||
using {bitorInt56 as |, unsubInt56 as -} for Int56 global;
|
||||
using {bitorInt64 as |, unsubInt64 as -} for Int64 global;
|
||||
using {bitorInt72 as |, unsubInt72 as -} for Int72 global;
|
||||
using {bitorInt80 as |, unsubInt80 as -} for Int80 global;
|
||||
using {bitorInt88 as |, unsubInt88 as -} for Int88 global;
|
||||
using {bitorInt96 as |, unsubInt96 as -} for Int96 global;
|
||||
using {bitorInt104 as |, unsubInt104 as -} for Int104 global;
|
||||
using {bitorInt112 as |, unsubInt112 as -} for Int112 global;
|
||||
using {bitorInt120 as |, unsubInt120 as -} for Int120 global;
|
||||
using {bitorInt128 as |, unsubInt128 as -} for Int128 global;
|
||||
using {bitorInt136 as |, unsubInt136 as -} for Int136 global;
|
||||
using {bitorInt144 as |, unsubInt144 as -} for Int144 global;
|
||||
using {bitorInt152 as |, unsubInt152 as -} for Int152 global;
|
||||
using {bitorInt160 as |, unsubInt160 as -} for Int160 global;
|
||||
using {bitorInt168 as |, unsubInt168 as -} for Int168 global;
|
||||
using {bitorInt176 as |, unsubInt176 as -} for Int176 global;
|
||||
using {bitorInt184 as |, unsubInt184 as -} for Int184 global;
|
||||
using {bitorInt192 as |, unsubInt192 as -} for Int192 global;
|
||||
using {bitorInt200 as |, unsubInt200 as -} for Int200 global;
|
||||
using {bitorInt208 as |, unsubInt208 as -} for Int208 global;
|
||||
using {bitorInt216 as |, unsubInt216 as -} for Int216 global;
|
||||
using {bitorInt224 as |, unsubInt224 as -} for Int224 global;
|
||||
using {bitorInt232 as |, unsubInt232 as -} for Int232 global;
|
||||
using {bitorInt240 as |, unsubInt240 as -} for Int240 global;
|
||||
using {bitorInt248 as |, unsubInt248 as -} for Int248 global;
|
||||
using {bitorInt256 as |, unsubInt256 as -} for Int256 global;
|
||||
using {bitorInt as |, unsubInt as -} for Int global;
|
||||
|
||||
using {bitorUint8 as |, bitnotUint8 as ~} for Uint8 global;
|
||||
using {bitorUint16 as |, bitnotUint16 as ~} for Uint16 global;
|
||||
using {bitorUint24 as |, bitnotUint24 as ~} for Uint24 global;
|
||||
using {bitorUint32 as |, bitnotUint32 as ~} for Uint32 global;
|
||||
using {bitorUint40 as |, bitnotUint40 as ~} for Uint40 global;
|
||||
using {bitorUint48 as |, bitnotUint48 as ~} for Uint48 global;
|
||||
using {bitorUint56 as |, bitnotUint56 as ~} for Uint56 global;
|
||||
using {bitorUint64 as |, bitnotUint64 as ~} for Uint64 global;
|
||||
using {bitorUint72 as |, bitnotUint72 as ~} for Uint72 global;
|
||||
using {bitorUint80 as |, bitnotUint80 as ~} for Uint80 global;
|
||||
using {bitorUint88 as |, bitnotUint88 as ~} for Uint88 global;
|
||||
using {bitorUint96 as |, bitnotUint96 as ~} for Uint96 global;
|
||||
using {bitorUint104 as |, bitnotUint104 as ~} for Uint104 global;
|
||||
using {bitorUint112 as |, bitnotUint112 as ~} for Uint112 global;
|
||||
using {bitorUint120 as |, bitnotUint120 as ~} for Uint120 global;
|
||||
using {bitorUint128 as |, bitnotUint128 as ~} for Uint128 global;
|
||||
using {bitorUint136 as |, bitnotUint136 as ~} for Uint136 global;
|
||||
using {bitorUint144 as |, bitnotUint144 as ~} for Uint144 global;
|
||||
using {bitorUint152 as |, bitnotUint152 as ~} for Uint152 global;
|
||||
using {bitorUint160 as |, bitnotUint160 as ~} for Uint160 global;
|
||||
using {bitorUint168 as |, bitnotUint168 as ~} for Uint168 global;
|
||||
using {bitorUint176 as |, bitnotUint176 as ~} for Uint176 global;
|
||||
using {bitorUint184 as |, bitnotUint184 as ~} for Uint184 global;
|
||||
using {bitorUint192 as |, bitnotUint192 as ~} for Uint192 global;
|
||||
using {bitorUint200 as |, bitnotUint200 as ~} for Uint200 global;
|
||||
using {bitorUint208 as |, bitnotUint208 as ~} for Uint208 global;
|
||||
using {bitorUint216 as |, bitnotUint216 as ~} for Uint216 global;
|
||||
using {bitorUint224 as |, bitnotUint224 as ~} for Uint224 global;
|
||||
using {bitorUint232 as |, bitnotUint232 as ~} for Uint232 global;
|
||||
using {bitorUint240 as |, bitnotUint240 as ~} for Uint240 global;
|
||||
using {bitorUint248 as |, bitnotUint248 as ~} for Uint248 global;
|
||||
using {bitorUint256 as |, bitnotUint256 as ~} for Uint256 global;
|
||||
using {bitorUint as |, bitnotUint as ~} for Uint global;
|
||||
|
||||
using {bitorBytes1 as |, bitnotBytes1 as ~} for Bytes1 global;
|
||||
using {bitorBytes2 as |, bitnotBytes2 as ~} for Bytes2 global;
|
||||
using {bitorBytes3 as |, bitnotBytes3 as ~} for Bytes3 global;
|
||||
using {bitorBytes4 as |, bitnotBytes4 as ~} for Bytes4 global;
|
||||
using {bitorBytes5 as |, bitnotBytes5 as ~} for Bytes5 global;
|
||||
using {bitorBytes6 as |, bitnotBytes6 as ~} for Bytes6 global;
|
||||
using {bitorBytes7 as |, bitnotBytes7 as ~} for Bytes7 global;
|
||||
using {bitorBytes8 as |, bitnotBytes8 as ~} for Bytes8 global;
|
||||
using {bitorBytes9 as |, bitnotBytes9 as ~} for Bytes9 global;
|
||||
using {bitorBytes10 as |, bitnotBytes10 as ~} for Bytes10 global;
|
||||
using {bitorBytes11 as |, bitnotBytes11 as ~} for Bytes11 global;
|
||||
using {bitorBytes12 as |, bitnotBytes12 as ~} for Bytes12 global;
|
||||
using {bitorBytes13 as |, bitnotBytes13 as ~} for Bytes13 global;
|
||||
using {bitorBytes14 as |, bitnotBytes14 as ~} for Bytes14 global;
|
||||
using {bitorBytes15 as |, bitnotBytes15 as ~} for Bytes15 global;
|
||||
using {bitorBytes16 as |, bitnotBytes16 as ~} for Bytes16 global;
|
||||
using {bitorBytes17 as |, bitnotBytes17 as ~} for Bytes17 global;
|
||||
using {bitorBytes18 as |, bitnotBytes18 as ~} for Bytes18 global;
|
||||
using {bitorBytes19 as |, bitnotBytes19 as ~} for Bytes19 global;
|
||||
using {bitorBytes20 as |, bitnotBytes20 as ~} for Bytes20 global;
|
||||
using {bitorBytes21 as |, bitnotBytes21 as ~} for Bytes21 global;
|
||||
using {bitorBytes22 as |, bitnotBytes22 as ~} for Bytes22 global;
|
||||
using {bitorBytes23 as |, bitnotBytes23 as ~} for Bytes23 global;
|
||||
using {bitorBytes24 as |, bitnotBytes24 as ~} for Bytes24 global;
|
||||
using {bitorBytes25 as |, bitnotBytes25 as ~} for Bytes25 global;
|
||||
using {bitorBytes26 as |, bitnotBytes26 as ~} for Bytes26 global;
|
||||
using {bitorBytes27 as |, bitnotBytes27 as ~} for Bytes27 global;
|
||||
using {bitorBytes28 as |, bitnotBytes28 as ~} for Bytes28 global;
|
||||
using {bitorBytes29 as |, bitnotBytes29 as ~} for Bytes29 global;
|
||||
using {bitorBytes30 as |, bitnotBytes30 as ~} for Bytes30 global;
|
||||
using {bitorBytes31 as |, bitnotBytes31 as ~} for Bytes31 global;
|
||||
using {bitorBytes32 as |, bitnotBytes32 as ~} for Bytes32 global;
|
||||
|
||||
function bitorInt8(Int8 x, Int8 y) pure returns (Int8) { return Int8.wrap(Int8.unwrap(x) | Int8.unwrap(y)); }
|
||||
function bitorInt16(Int16 x, Int16 y) pure returns (Int16) { return Int16.wrap(Int16.unwrap(x) | Int16.unwrap(y)); }
|
||||
function bitorInt24(Int24 x, Int24 y) pure returns (Int24) { return Int24.wrap(Int24.unwrap(x) | Int24.unwrap(y)); }
|
||||
function bitorInt32(Int32 x, Int32 y) pure returns (Int32) { return Int32.wrap(Int32.unwrap(x) | Int32.unwrap(y)); }
|
||||
function bitorInt40(Int40 x, Int40 y) pure returns (Int40) { return Int40.wrap(Int40.unwrap(x) | Int40.unwrap(y)); }
|
||||
function bitorInt48(Int48 x, Int48 y) pure returns (Int48) { return Int48.wrap(Int48.unwrap(x) | Int48.unwrap(y)); }
|
||||
function bitorInt56(Int56 x, Int56 y) pure returns (Int56) { return Int56.wrap(Int56.unwrap(x) | Int56.unwrap(y)); }
|
||||
function bitorInt64(Int64 x, Int64 y) pure returns (Int64) { return Int64.wrap(Int64.unwrap(x) | Int64.unwrap(y)); }
|
||||
function bitorInt72(Int72 x, Int72 y) pure returns (Int72) { return Int72.wrap(Int72.unwrap(x) | Int72.unwrap(y)); }
|
||||
function bitorInt80(Int80 x, Int80 y) pure returns (Int80) { return Int80.wrap(Int80.unwrap(x) | Int80.unwrap(y)); }
|
||||
function bitorInt88(Int88 x, Int88 y) pure returns (Int88) { return Int88.wrap(Int88.unwrap(x) | Int88.unwrap(y)); }
|
||||
function bitorInt96(Int96 x, Int96 y) pure returns (Int96) { return Int96.wrap(Int96.unwrap(x) | Int96.unwrap(y)); }
|
||||
function bitorInt104(Int104 x, Int104 y) pure returns (Int104) { return Int104.wrap(Int104.unwrap(x) | Int104.unwrap(y)); }
|
||||
function bitorInt112(Int112 x, Int112 y) pure returns (Int112) { return Int112.wrap(Int112.unwrap(x) | Int112.unwrap(y)); }
|
||||
function bitorInt120(Int120 x, Int120 y) pure returns (Int120) { return Int120.wrap(Int120.unwrap(x) | Int120.unwrap(y)); }
|
||||
function bitorInt128(Int128 x, Int128 y) pure returns (Int128) { return Int128.wrap(Int128.unwrap(x) | Int128.unwrap(y)); }
|
||||
function bitorInt136(Int136 x, Int136 y) pure returns (Int136) { return Int136.wrap(Int136.unwrap(x) | Int136.unwrap(y)); }
|
||||
function bitorInt144(Int144 x, Int144 y) pure returns (Int144) { return Int144.wrap(Int144.unwrap(x) | Int144.unwrap(y)); }
|
||||
function bitorInt152(Int152 x, Int152 y) pure returns (Int152) { return Int152.wrap(Int152.unwrap(x) | Int152.unwrap(y)); }
|
||||
function bitorInt160(Int160 x, Int160 y) pure returns (Int160) { return Int160.wrap(Int160.unwrap(x) | Int160.unwrap(y)); }
|
||||
function bitorInt168(Int168 x, Int168 y) pure returns (Int168) { return Int168.wrap(Int168.unwrap(x) | Int168.unwrap(y)); }
|
||||
function bitorInt176(Int176 x, Int176 y) pure returns (Int176) { return Int176.wrap(Int176.unwrap(x) | Int176.unwrap(y)); }
|
||||
function bitorInt184(Int184 x, Int184 y) pure returns (Int184) { return Int184.wrap(Int184.unwrap(x) | Int184.unwrap(y)); }
|
||||
function bitorInt192(Int192 x, Int192 y) pure returns (Int192) { return Int192.wrap(Int192.unwrap(x) | Int192.unwrap(y)); }
|
||||
function bitorInt200(Int200 x, Int200 y) pure returns (Int200) { return Int200.wrap(Int200.unwrap(x) | Int200.unwrap(y)); }
|
||||
function bitorInt208(Int208 x, Int208 y) pure returns (Int208) { return Int208.wrap(Int208.unwrap(x) | Int208.unwrap(y)); }
|
||||
function bitorInt216(Int216 x, Int216 y) pure returns (Int216) { return Int216.wrap(Int216.unwrap(x) | Int216.unwrap(y)); }
|
||||
function bitorInt224(Int224 x, Int224 y) pure returns (Int224) { return Int224.wrap(Int224.unwrap(x) | Int224.unwrap(y)); }
|
||||
function bitorInt232(Int232 x, Int232 y) pure returns (Int232) { return Int232.wrap(Int232.unwrap(x) | Int232.unwrap(y)); }
|
||||
function bitorInt240(Int240 x, Int240 y) pure returns (Int240) { return Int240.wrap(Int240.unwrap(x) | Int240.unwrap(y)); }
|
||||
function bitorInt248(Int248 x, Int248 y) pure returns (Int248) { return Int248.wrap(Int248.unwrap(x) | Int248.unwrap(y)); }
|
||||
function bitorInt256(Int256 x, Int256 y) pure returns (Int256) { return Int256.wrap(Int256.unwrap(x) | Int256.unwrap(y)); }
|
||||
function bitorInt(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) | Int.unwrap(y)); }
|
||||
|
||||
function unsubInt8(Int8 x) pure returns (Int8) { return Int8.wrap(-Int8.unwrap(x)); }
|
||||
function unsubInt16(Int16 x) pure returns (Int16) { return Int16.wrap(-Int16.unwrap(x)); }
|
||||
function unsubInt24(Int24 x) pure returns (Int24) { return Int24.wrap(-Int24.unwrap(x)); }
|
||||
function unsubInt32(Int32 x) pure returns (Int32) { return Int32.wrap(-Int32.unwrap(x)); }
|
||||
function unsubInt40(Int40 x) pure returns (Int40) { return Int40.wrap(-Int40.unwrap(x)); }
|
||||
function unsubInt48(Int48 x) pure returns (Int48) { return Int48.wrap(-Int48.unwrap(x)); }
|
||||
function unsubInt56(Int56 x) pure returns (Int56) { return Int56.wrap(-Int56.unwrap(x)); }
|
||||
function unsubInt64(Int64 x) pure returns (Int64) { return Int64.wrap(-Int64.unwrap(x)); }
|
||||
function unsubInt72(Int72 x) pure returns (Int72) { return Int72.wrap(-Int72.unwrap(x)); }
|
||||
function unsubInt80(Int80 x) pure returns (Int80) { return Int80.wrap(-Int80.unwrap(x)); }
|
||||
function unsubInt88(Int88 x) pure returns (Int88) { return Int88.wrap(-Int88.unwrap(x)); }
|
||||
function unsubInt96(Int96 x) pure returns (Int96) { return Int96.wrap(-Int96.unwrap(x)); }
|
||||
function unsubInt104(Int104 x) pure returns (Int104) { return Int104.wrap(-Int104.unwrap(x)); }
|
||||
function unsubInt112(Int112 x) pure returns (Int112) { return Int112.wrap(-Int112.unwrap(x)); }
|
||||
function unsubInt120(Int120 x) pure returns (Int120) { return Int120.wrap(-Int120.unwrap(x)); }
|
||||
function unsubInt128(Int128 x) pure returns (Int128) { return Int128.wrap(-Int128.unwrap(x)); }
|
||||
function unsubInt136(Int136 x) pure returns (Int136) { return Int136.wrap(-Int136.unwrap(x)); }
|
||||
function unsubInt144(Int144 x) pure returns (Int144) { return Int144.wrap(-Int144.unwrap(x)); }
|
||||
function unsubInt152(Int152 x) pure returns (Int152) { return Int152.wrap(-Int152.unwrap(x)); }
|
||||
function unsubInt160(Int160 x) pure returns (Int160) { return Int160.wrap(-Int160.unwrap(x)); }
|
||||
function unsubInt168(Int168 x) pure returns (Int168) { return Int168.wrap(-Int168.unwrap(x)); }
|
||||
function unsubInt176(Int176 x) pure returns (Int176) { return Int176.wrap(-Int176.unwrap(x)); }
|
||||
function unsubInt184(Int184 x) pure returns (Int184) { return Int184.wrap(-Int184.unwrap(x)); }
|
||||
function unsubInt192(Int192 x) pure returns (Int192) { return Int192.wrap(-Int192.unwrap(x)); }
|
||||
function unsubInt200(Int200 x) pure returns (Int200) { return Int200.wrap(-Int200.unwrap(x)); }
|
||||
function unsubInt208(Int208 x) pure returns (Int208) { return Int208.wrap(-Int208.unwrap(x)); }
|
||||
function unsubInt216(Int216 x) pure returns (Int216) { return Int216.wrap(-Int216.unwrap(x)); }
|
||||
function unsubInt224(Int224 x) pure returns (Int224) { return Int224.wrap(-Int224.unwrap(x)); }
|
||||
function unsubInt232(Int232 x) pure returns (Int232) { return Int232.wrap(-Int232.unwrap(x)); }
|
||||
function unsubInt240(Int240 x) pure returns (Int240) { return Int240.wrap(-Int240.unwrap(x)); }
|
||||
function unsubInt248(Int248 x) pure returns (Int248) { return Int248.wrap(-Int248.unwrap(x)); }
|
||||
function unsubInt256(Int256 x) pure returns (Int256) { return Int256.wrap(-Int256.unwrap(x)); }
|
||||
function unsubInt(Int x) pure returns (Int) { return Int.wrap(-Int.unwrap(x)); }
|
||||
|
||||
function bitorUint8(Uint8 x, Uint8 y) pure returns (Uint8) { return Uint8.wrap(Uint8.unwrap(x) | Uint8.unwrap(y)); }
|
||||
function bitorUint16(Uint16 x, Uint16 y) pure returns (Uint16) { return Uint16.wrap(Uint16.unwrap(x) | Uint16.unwrap(y)); }
|
||||
function bitorUint24(Uint24 x, Uint24 y) pure returns (Uint24) { return Uint24.wrap(Uint24.unwrap(x) | Uint24.unwrap(y)); }
|
||||
function bitorUint32(Uint32 x, Uint32 y) pure returns (Uint32) { return Uint32.wrap(Uint32.unwrap(x) | Uint32.unwrap(y)); }
|
||||
function bitorUint40(Uint40 x, Uint40 y) pure returns (Uint40) { return Uint40.wrap(Uint40.unwrap(x) | Uint40.unwrap(y)); }
|
||||
function bitorUint48(Uint48 x, Uint48 y) pure returns (Uint48) { return Uint48.wrap(Uint48.unwrap(x) | Uint48.unwrap(y)); }
|
||||
function bitorUint56(Uint56 x, Uint56 y) pure returns (Uint56) { return Uint56.wrap(Uint56.unwrap(x) | Uint56.unwrap(y)); }
|
||||
function bitorUint64(Uint64 x, Uint64 y) pure returns (Uint64) { return Uint64.wrap(Uint64.unwrap(x) | Uint64.unwrap(y)); }
|
||||
function bitorUint72(Uint72 x, Uint72 y) pure returns (Uint72) { return Uint72.wrap(Uint72.unwrap(x) | Uint72.unwrap(y)); }
|
||||
function bitorUint80(Uint80 x, Uint80 y) pure returns (Uint80) { return Uint80.wrap(Uint80.unwrap(x) | Uint80.unwrap(y)); }
|
||||
function bitorUint88(Uint88 x, Uint88 y) pure returns (Uint88) { return Uint88.wrap(Uint88.unwrap(x) | Uint88.unwrap(y)); }
|
||||
function bitorUint96(Uint96 x, Uint96 y) pure returns (Uint96) { return Uint96.wrap(Uint96.unwrap(x) | Uint96.unwrap(y)); }
|
||||
function bitorUint104(Uint104 x, Uint104 y) pure returns (Uint104) { return Uint104.wrap(Uint104.unwrap(x) | Uint104.unwrap(y)); }
|
||||
function bitorUint112(Uint112 x, Uint112 y) pure returns (Uint112) { return Uint112.wrap(Uint112.unwrap(x) | Uint112.unwrap(y)); }
|
||||
function bitorUint120(Uint120 x, Uint120 y) pure returns (Uint120) { return Uint120.wrap(Uint120.unwrap(x) | Uint120.unwrap(y)); }
|
||||
function bitorUint128(Uint128 x, Uint128 y) pure returns (Uint128) { return Uint128.wrap(Uint128.unwrap(x) | Uint128.unwrap(y)); }
|
||||
function bitorUint136(Uint136 x, Uint136 y) pure returns (Uint136) { return Uint136.wrap(Uint136.unwrap(x) | Uint136.unwrap(y)); }
|
||||
function bitorUint144(Uint144 x, Uint144 y) pure returns (Uint144) { return Uint144.wrap(Uint144.unwrap(x) | Uint144.unwrap(y)); }
|
||||
function bitorUint152(Uint152 x, Uint152 y) pure returns (Uint152) { return Uint152.wrap(Uint152.unwrap(x) | Uint152.unwrap(y)); }
|
||||
function bitorUint160(Uint160 x, Uint160 y) pure returns (Uint160) { return Uint160.wrap(Uint160.unwrap(x) | Uint160.unwrap(y)); }
|
||||
function bitorUint168(Uint168 x, Uint168 y) pure returns (Uint168) { return Uint168.wrap(Uint168.unwrap(x) | Uint168.unwrap(y)); }
|
||||
function bitorUint176(Uint176 x, Uint176 y) pure returns (Uint176) { return Uint176.wrap(Uint176.unwrap(x) | Uint176.unwrap(y)); }
|
||||
function bitorUint184(Uint184 x, Uint184 y) pure returns (Uint184) { return Uint184.wrap(Uint184.unwrap(x) | Uint184.unwrap(y)); }
|
||||
function bitorUint192(Uint192 x, Uint192 y) pure returns (Uint192) { return Uint192.wrap(Uint192.unwrap(x) | Uint192.unwrap(y)); }
|
||||
function bitorUint200(Uint200 x, Uint200 y) pure returns (Uint200) { return Uint200.wrap(Uint200.unwrap(x) | Uint200.unwrap(y)); }
|
||||
function bitorUint208(Uint208 x, Uint208 y) pure returns (Uint208) { return Uint208.wrap(Uint208.unwrap(x) | Uint208.unwrap(y)); }
|
||||
function bitorUint216(Uint216 x, Uint216 y) pure returns (Uint216) { return Uint216.wrap(Uint216.unwrap(x) | Uint216.unwrap(y)); }
|
||||
function bitorUint224(Uint224 x, Uint224 y) pure returns (Uint224) { return Uint224.wrap(Uint224.unwrap(x) | Uint224.unwrap(y)); }
|
||||
function bitorUint232(Uint232 x, Uint232 y) pure returns (Uint232) { return Uint232.wrap(Uint232.unwrap(x) | Uint232.unwrap(y)); }
|
||||
function bitorUint240(Uint240 x, Uint240 y) pure returns (Uint240) { return Uint240.wrap(Uint240.unwrap(x) | Uint240.unwrap(y)); }
|
||||
function bitorUint248(Uint248 x, Uint248 y) pure returns (Uint248) { return Uint248.wrap(Uint248.unwrap(x) | Uint248.unwrap(y)); }
|
||||
function bitorUint256(Uint256 x, Uint256 y) pure returns (Uint256) { return Uint256.wrap(Uint256.unwrap(x) | Uint256.unwrap(y)); }
|
||||
function bitorUint(Uint x, Uint y) pure returns (Uint) { return Uint.wrap(Uint.unwrap(x) | Uint.unwrap(y)); }
|
||||
|
||||
function bitnotUint8(Uint8 x) pure returns (Uint8) { return Uint8.wrap(~Uint8.unwrap(x)); }
|
||||
function bitnotUint16(Uint16 x) pure returns (Uint16) { return Uint16.wrap(~Uint16.unwrap(x)); }
|
||||
function bitnotUint24(Uint24 x) pure returns (Uint24) { return Uint24.wrap(~Uint24.unwrap(x)); }
|
||||
function bitnotUint32(Uint32 x) pure returns (Uint32) { return Uint32.wrap(~Uint32.unwrap(x)); }
|
||||
function bitnotUint40(Uint40 x) pure returns (Uint40) { return Uint40.wrap(~Uint40.unwrap(x)); }
|
||||
function bitnotUint48(Uint48 x) pure returns (Uint48) { return Uint48.wrap(~Uint48.unwrap(x)); }
|
||||
function bitnotUint56(Uint56 x) pure returns (Uint56) { return Uint56.wrap(~Uint56.unwrap(x)); }
|
||||
function bitnotUint64(Uint64 x) pure returns (Uint64) { return Uint64.wrap(~Uint64.unwrap(x)); }
|
||||
function bitnotUint72(Uint72 x) pure returns (Uint72) { return Uint72.wrap(~Uint72.unwrap(x)); }
|
||||
function bitnotUint80(Uint80 x) pure returns (Uint80) { return Uint80.wrap(~Uint80.unwrap(x)); }
|
||||
function bitnotUint88(Uint88 x) pure returns (Uint88) { return Uint88.wrap(~Uint88.unwrap(x)); }
|
||||
function bitnotUint96(Uint96 x) pure returns (Uint96) { return Uint96.wrap(~Uint96.unwrap(x)); }
|
||||
function bitnotUint104(Uint104 x) pure returns (Uint104) { return Uint104.wrap(~Uint104.unwrap(x)); }
|
||||
function bitnotUint112(Uint112 x) pure returns (Uint112) { return Uint112.wrap(~Uint112.unwrap(x)); }
|
||||
function bitnotUint120(Uint120 x) pure returns (Uint120) { return Uint120.wrap(~Uint120.unwrap(x)); }
|
||||
function bitnotUint128(Uint128 x) pure returns (Uint128) { return Uint128.wrap(~Uint128.unwrap(x)); }
|
||||
function bitnotUint136(Uint136 x) pure returns (Uint136) { return Uint136.wrap(~Uint136.unwrap(x)); }
|
||||
function bitnotUint144(Uint144 x) pure returns (Uint144) { return Uint144.wrap(~Uint144.unwrap(x)); }
|
||||
function bitnotUint152(Uint152 x) pure returns (Uint152) { return Uint152.wrap(~Uint152.unwrap(x)); }
|
||||
function bitnotUint160(Uint160 x) pure returns (Uint160) { return Uint160.wrap(~Uint160.unwrap(x)); }
|
||||
function bitnotUint168(Uint168 x) pure returns (Uint168) { return Uint168.wrap(~Uint168.unwrap(x)); }
|
||||
function bitnotUint176(Uint176 x) pure returns (Uint176) { return Uint176.wrap(~Uint176.unwrap(x)); }
|
||||
function bitnotUint184(Uint184 x) pure returns (Uint184) { return Uint184.wrap(~Uint184.unwrap(x)); }
|
||||
function bitnotUint192(Uint192 x) pure returns (Uint192) { return Uint192.wrap(~Uint192.unwrap(x)); }
|
||||
function bitnotUint200(Uint200 x) pure returns (Uint200) { return Uint200.wrap(~Uint200.unwrap(x)); }
|
||||
function bitnotUint208(Uint208 x) pure returns (Uint208) { return Uint208.wrap(~Uint208.unwrap(x)); }
|
||||
function bitnotUint216(Uint216 x) pure returns (Uint216) { return Uint216.wrap(~Uint216.unwrap(x)); }
|
||||
function bitnotUint224(Uint224 x) pure returns (Uint224) { return Uint224.wrap(~Uint224.unwrap(x)); }
|
||||
function bitnotUint232(Uint232 x) pure returns (Uint232) { return Uint232.wrap(~Uint232.unwrap(x)); }
|
||||
function bitnotUint240(Uint240 x) pure returns (Uint240) { return Uint240.wrap(~Uint240.unwrap(x)); }
|
||||
function bitnotUint248(Uint248 x) pure returns (Uint248) { return Uint248.wrap(~Uint248.unwrap(x)); }
|
||||
function bitnotUint256(Uint256 x) pure returns (Uint256) { return Uint256.wrap(~Uint256.unwrap(x)); }
|
||||
function bitnotUint(Uint x) pure returns (Uint) { return Uint.wrap(~Uint.unwrap(x)); }
|
||||
|
||||
function bitorBytes1(Bytes1 x, Bytes1 y) pure returns (Bytes1) { return Bytes1.wrap(Bytes1.unwrap(x) | Bytes1.unwrap(y)); }
|
||||
function bitorBytes2(Bytes2 x, Bytes2 y) pure returns (Bytes2) { return Bytes2.wrap(Bytes2.unwrap(x) | Bytes2.unwrap(y)); }
|
||||
function bitorBytes3(Bytes3 x, Bytes3 y) pure returns (Bytes3) { return Bytes3.wrap(Bytes3.unwrap(x) | Bytes3.unwrap(y)); }
|
||||
function bitorBytes4(Bytes4 x, Bytes4 y) pure returns (Bytes4) { return Bytes4.wrap(Bytes4.unwrap(x) | Bytes4.unwrap(y)); }
|
||||
function bitorBytes5(Bytes5 x, Bytes5 y) pure returns (Bytes5) { return Bytes5.wrap(Bytes5.unwrap(x) | Bytes5.unwrap(y)); }
|
||||
function bitorBytes6(Bytes6 x, Bytes6 y) pure returns (Bytes6) { return Bytes6.wrap(Bytes6.unwrap(x) | Bytes6.unwrap(y)); }
|
||||
function bitorBytes7(Bytes7 x, Bytes7 y) pure returns (Bytes7) { return Bytes7.wrap(Bytes7.unwrap(x) | Bytes7.unwrap(y)); }
|
||||
function bitorBytes8(Bytes8 x, Bytes8 y) pure returns (Bytes8) { return Bytes8.wrap(Bytes8.unwrap(x) | Bytes8.unwrap(y)); }
|
||||
function bitorBytes9(Bytes9 x, Bytes9 y) pure returns (Bytes9) { return Bytes9.wrap(Bytes9.unwrap(x) | Bytes9.unwrap(y)); }
|
||||
function bitorBytes10(Bytes10 x, Bytes10 y) pure returns (Bytes10) { return Bytes10.wrap(Bytes10.unwrap(x) | Bytes10.unwrap(y)); }
|
||||
function bitorBytes11(Bytes11 x, Bytes11 y) pure returns (Bytes11) { return Bytes11.wrap(Bytes11.unwrap(x) | Bytes11.unwrap(y)); }
|
||||
function bitorBytes12(Bytes12 x, Bytes12 y) pure returns (Bytes12) { return Bytes12.wrap(Bytes12.unwrap(x) | Bytes12.unwrap(y)); }
|
||||
function bitorBytes13(Bytes13 x, Bytes13 y) pure returns (Bytes13) { return Bytes13.wrap(Bytes13.unwrap(x) | Bytes13.unwrap(y)); }
|
||||
function bitorBytes14(Bytes14 x, Bytes14 y) pure returns (Bytes14) { return Bytes14.wrap(Bytes14.unwrap(x) | Bytes14.unwrap(y)); }
|
||||
function bitorBytes15(Bytes15 x, Bytes15 y) pure returns (Bytes15) { return Bytes15.wrap(Bytes15.unwrap(x) | Bytes15.unwrap(y)); }
|
||||
function bitorBytes16(Bytes16 x, Bytes16 y) pure returns (Bytes16) { return Bytes16.wrap(Bytes16.unwrap(x) | Bytes16.unwrap(y)); }
|
||||
function bitorBytes17(Bytes17 x, Bytes17 y) pure returns (Bytes17) { return Bytes17.wrap(Bytes17.unwrap(x) | Bytes17.unwrap(y)); }
|
||||
function bitorBytes18(Bytes18 x, Bytes18 y) pure returns (Bytes18) { return Bytes18.wrap(Bytes18.unwrap(x) | Bytes18.unwrap(y)); }
|
||||
function bitorBytes19(Bytes19 x, Bytes19 y) pure returns (Bytes19) { return Bytes19.wrap(Bytes19.unwrap(x) | Bytes19.unwrap(y)); }
|
||||
function bitorBytes20(Bytes20 x, Bytes20 y) pure returns (Bytes20) { return Bytes20.wrap(Bytes20.unwrap(x) | Bytes20.unwrap(y)); }
|
||||
function bitorBytes21(Bytes21 x, Bytes21 y) pure returns (Bytes21) { return Bytes21.wrap(Bytes21.unwrap(x) | Bytes21.unwrap(y)); }
|
||||
function bitorBytes22(Bytes22 x, Bytes22 y) pure returns (Bytes22) { return Bytes22.wrap(Bytes22.unwrap(x) | Bytes22.unwrap(y)); }
|
||||
function bitorBytes23(Bytes23 x, Bytes23 y) pure returns (Bytes23) { return Bytes23.wrap(Bytes23.unwrap(x) | Bytes23.unwrap(y)); }
|
||||
function bitorBytes24(Bytes24 x, Bytes24 y) pure returns (Bytes24) { return Bytes24.wrap(Bytes24.unwrap(x) | Bytes24.unwrap(y)); }
|
||||
function bitorBytes25(Bytes25 x, Bytes25 y) pure returns (Bytes25) { return Bytes25.wrap(Bytes25.unwrap(x) | Bytes25.unwrap(y)); }
|
||||
function bitorBytes26(Bytes26 x, Bytes26 y) pure returns (Bytes26) { return Bytes26.wrap(Bytes26.unwrap(x) | Bytes26.unwrap(y)); }
|
||||
function bitorBytes27(Bytes27 x, Bytes27 y) pure returns (Bytes27) { return Bytes27.wrap(Bytes27.unwrap(x) | Bytes27.unwrap(y)); }
|
||||
function bitorBytes28(Bytes28 x, Bytes28 y) pure returns (Bytes28) { return Bytes28.wrap(Bytes28.unwrap(x) | Bytes28.unwrap(y)); }
|
||||
function bitorBytes29(Bytes29 x, Bytes29 y) pure returns (Bytes29) { return Bytes29.wrap(Bytes29.unwrap(x) | Bytes29.unwrap(y)); }
|
||||
function bitorBytes30(Bytes30 x, Bytes30 y) pure returns (Bytes30) { return Bytes30.wrap(Bytes30.unwrap(x) | Bytes30.unwrap(y)); }
|
||||
function bitorBytes31(Bytes31 x, Bytes31 y) pure returns (Bytes31) { return Bytes31.wrap(Bytes31.unwrap(x) | Bytes31.unwrap(y)); }
|
||||
function bitorBytes32(Bytes32 x, Bytes32 y) pure returns (Bytes32) { return Bytes32.wrap(Bytes32.unwrap(x) | Bytes32.unwrap(y)); }
|
||||
|
||||
function bitnotBytes1(Bytes1 x) pure returns (Bytes1) { return Bytes1.wrap(~Bytes1.unwrap(x)); }
|
||||
function bitnotBytes2(Bytes2 x) pure returns (Bytes2) { return Bytes2.wrap(~Bytes2.unwrap(x)); }
|
||||
function bitnotBytes3(Bytes3 x) pure returns (Bytes3) { return Bytes3.wrap(~Bytes3.unwrap(x)); }
|
||||
function bitnotBytes4(Bytes4 x) pure returns (Bytes4) { return Bytes4.wrap(~Bytes4.unwrap(x)); }
|
||||
function bitnotBytes5(Bytes5 x) pure returns (Bytes5) { return Bytes5.wrap(~Bytes5.unwrap(x)); }
|
||||
function bitnotBytes6(Bytes6 x) pure returns (Bytes6) { return Bytes6.wrap(~Bytes6.unwrap(x)); }
|
||||
function bitnotBytes7(Bytes7 x) pure returns (Bytes7) { return Bytes7.wrap(~Bytes7.unwrap(x)); }
|
||||
function bitnotBytes8(Bytes8 x) pure returns (Bytes8) { return Bytes8.wrap(~Bytes8.unwrap(x)); }
|
||||
function bitnotBytes9(Bytes9 x) pure returns (Bytes9) { return Bytes9.wrap(~Bytes9.unwrap(x)); }
|
||||
function bitnotBytes10(Bytes10 x) pure returns (Bytes10) { return Bytes10.wrap(~Bytes10.unwrap(x)); }
|
||||
function bitnotBytes11(Bytes11 x) pure returns (Bytes11) { return Bytes11.wrap(~Bytes11.unwrap(x)); }
|
||||
function bitnotBytes12(Bytes12 x) pure returns (Bytes12) { return Bytes12.wrap(~Bytes12.unwrap(x)); }
|
||||
function bitnotBytes13(Bytes13 x) pure returns (Bytes13) { return Bytes13.wrap(~Bytes13.unwrap(x)); }
|
||||
function bitnotBytes14(Bytes14 x) pure returns (Bytes14) { return Bytes14.wrap(~Bytes14.unwrap(x)); }
|
||||
function bitnotBytes15(Bytes15 x) pure returns (Bytes15) { return Bytes15.wrap(~Bytes15.unwrap(x)); }
|
||||
function bitnotBytes16(Bytes16 x) pure returns (Bytes16) { return Bytes16.wrap(~Bytes16.unwrap(x)); }
|
||||
function bitnotBytes17(Bytes17 x) pure returns (Bytes17) { return Bytes17.wrap(~Bytes17.unwrap(x)); }
|
||||
function bitnotBytes18(Bytes18 x) pure returns (Bytes18) { return Bytes18.wrap(~Bytes18.unwrap(x)); }
|
||||
function bitnotBytes19(Bytes19 x) pure returns (Bytes19) { return Bytes19.wrap(~Bytes19.unwrap(x)); }
|
||||
function bitnotBytes20(Bytes20 x) pure returns (Bytes20) { return Bytes20.wrap(~Bytes20.unwrap(x)); }
|
||||
function bitnotBytes21(Bytes21 x) pure returns (Bytes21) { return Bytes21.wrap(~Bytes21.unwrap(x)); }
|
||||
function bitnotBytes22(Bytes22 x) pure returns (Bytes22) { return Bytes22.wrap(~Bytes22.unwrap(x)); }
|
||||
function bitnotBytes23(Bytes23 x) pure returns (Bytes23) { return Bytes23.wrap(~Bytes23.unwrap(x)); }
|
||||
function bitnotBytes24(Bytes24 x) pure returns (Bytes24) { return Bytes24.wrap(~Bytes24.unwrap(x)); }
|
||||
function bitnotBytes25(Bytes25 x) pure returns (Bytes25) { return Bytes25.wrap(~Bytes25.unwrap(x)); }
|
||||
function bitnotBytes26(Bytes26 x) pure returns (Bytes26) { return Bytes26.wrap(~Bytes26.unwrap(x)); }
|
||||
function bitnotBytes27(Bytes27 x) pure returns (Bytes27) { return Bytes27.wrap(~Bytes27.unwrap(x)); }
|
||||
function bitnotBytes28(Bytes28 x) pure returns (Bytes28) { return Bytes28.wrap(~Bytes28.unwrap(x)); }
|
||||
function bitnotBytes29(Bytes29 x) pure returns (Bytes29) { return Bytes29.wrap(~Bytes29.unwrap(x)); }
|
||||
function bitnotBytes30(Bytes30 x) pure returns (Bytes30) { return Bytes30.wrap(~Bytes30.unwrap(x)); }
|
||||
function bitnotBytes31(Bytes31 x) pure returns (Bytes31) { return Bytes31.wrap(~Bytes31.unwrap(x)); }
|
||||
function bitnotBytes32(Bytes32 x) pure returns (Bytes32) { return Bytes32.wrap(~Bytes32.unwrap(x)); }
|
||||
|
||||
using {bitorAddress as |, bitnotAddress as ~} for Address global;
|
||||
using {bitorAddressPayable as |, bitnotAddressPayable as ~} for AddressPayable global;
|
||||
using {bitorBool as |, bitnotBool as ~} for Bool global;
|
||||
|
||||
function bitorAddress(Address x, Address y) pure returns (Address) {
|
||||
return Address.wrap(address(bytes20(Address.unwrap(x)) | bytes20(Address.unwrap(y))));
|
||||
}
|
||||
function bitnotAddress(Address x) pure returns (Address) {
|
||||
return Address.wrap(address(~bytes20(Address.unwrap(x))));
|
||||
}
|
||||
|
||||
function bitorAddressPayable(AddressPayable x, AddressPayable y) pure returns (AddressPayable) {
|
||||
return AddressPayable.wrap(payable(address(bytes20(address(AddressPayable.unwrap(x))) | bytes20(address(AddressPayable.unwrap(y))))));
|
||||
}
|
||||
function bitnotAddressPayable(AddressPayable x) pure returns (AddressPayable) {
|
||||
return AddressPayable.wrap(payable(address(~bytes20(address(AddressPayable.unwrap(x))))));
|
||||
}
|
||||
|
||||
function bitorBool(Bool x, Bool y) pure returns (Bool) {
|
||||
return Bool.wrap(Bool.unwrap(x) || Bool.unwrap(y));
|
||||
}
|
||||
function bitnotBool(Bool x) pure returns (Bool) {
|
||||
return Bool.wrap(!Bool.unwrap(x));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function testIntBinary() public pure {
|
||||
assert(Int8.unwrap(Int8.wrap(1) | Int8.wrap(2)) == 3);
|
||||
assert(Int16.unwrap(Int16.wrap(1) | Int16.wrap(2)) == 3);
|
||||
assert(Int24.unwrap(Int24.wrap(1) | Int24.wrap(2)) == 3);
|
||||
assert(Int32.unwrap(Int32.wrap(1) | Int32.wrap(2)) == 3);
|
||||
assert(Int40.unwrap(Int40.wrap(1) | Int40.wrap(2)) == 3);
|
||||
assert(Int48.unwrap(Int48.wrap(1) | Int48.wrap(2)) == 3);
|
||||
assert(Int56.unwrap(Int56.wrap(1) | Int56.wrap(2)) == 3);
|
||||
assert(Int64.unwrap(Int64.wrap(1) | Int64.wrap(2)) == 3);
|
||||
assert(Int72.unwrap(Int72.wrap(1) | Int72.wrap(2)) == 3);
|
||||
assert(Int80.unwrap(Int80.wrap(1) | Int80.wrap(2)) == 3);
|
||||
assert(Int88.unwrap(Int88.wrap(1) | Int88.wrap(2)) == 3);
|
||||
assert(Int96.unwrap(Int96.wrap(1) | Int96.wrap(2)) == 3);
|
||||
assert(Int104.unwrap(Int104.wrap(1) | Int104.wrap(2)) == 3);
|
||||
assert(Int112.unwrap(Int112.wrap(1) | Int112.wrap(2)) == 3);
|
||||
assert(Int120.unwrap(Int120.wrap(1) | Int120.wrap(2)) == 3);
|
||||
assert(Int128.unwrap(Int128.wrap(1) | Int128.wrap(2)) == 3);
|
||||
assert(Int136.unwrap(Int136.wrap(1) | Int136.wrap(2)) == 3);
|
||||
assert(Int144.unwrap(Int144.wrap(1) | Int144.wrap(2)) == 3);
|
||||
assert(Int152.unwrap(Int152.wrap(1) | Int152.wrap(2)) == 3);
|
||||
assert(Int160.unwrap(Int160.wrap(1) | Int160.wrap(2)) == 3);
|
||||
assert(Int168.unwrap(Int168.wrap(1) | Int168.wrap(2)) == 3);
|
||||
assert(Int176.unwrap(Int176.wrap(1) | Int176.wrap(2)) == 3);
|
||||
assert(Int184.unwrap(Int184.wrap(1) | Int184.wrap(2)) == 3);
|
||||
assert(Int192.unwrap(Int192.wrap(1) | Int192.wrap(2)) == 3);
|
||||
assert(Int200.unwrap(Int200.wrap(1) | Int200.wrap(2)) == 3);
|
||||
assert(Int208.unwrap(Int208.wrap(1) | Int208.wrap(2)) == 3);
|
||||
assert(Int216.unwrap(Int216.wrap(1) | Int216.wrap(2)) == 3);
|
||||
assert(Int224.unwrap(Int224.wrap(1) | Int224.wrap(2)) == 3);
|
||||
assert(Int232.unwrap(Int232.wrap(1) | Int232.wrap(2)) == 3);
|
||||
assert(Int240.unwrap(Int240.wrap(1) | Int240.wrap(2)) == 3);
|
||||
assert(Int248.unwrap(Int248.wrap(1) | Int248.wrap(2)) == 3);
|
||||
assert(Int256.unwrap(Int256.wrap(1) | Int256.wrap(2)) == 3);
|
||||
assert(Int.unwrap(Int.wrap(1) | Int.wrap(2)) == 3);
|
||||
}
|
||||
|
||||
function testIntUnary() public pure {
|
||||
assert(Int8.unwrap(-Int8.wrap(1)) == -1);
|
||||
assert(Int16.unwrap(-Int16.wrap(1)) == -1);
|
||||
assert(Int24.unwrap(-Int24.wrap(1)) == -1);
|
||||
assert(Int32.unwrap(-Int32.wrap(1)) == -1);
|
||||
assert(Int40.unwrap(-Int40.wrap(1)) == -1);
|
||||
assert(Int48.unwrap(-Int48.wrap(1)) == -1);
|
||||
assert(Int56.unwrap(-Int56.wrap(1)) == -1);
|
||||
assert(Int64.unwrap(-Int64.wrap(1)) == -1);
|
||||
assert(Int72.unwrap(-Int72.wrap(1)) == -1);
|
||||
assert(Int80.unwrap(-Int80.wrap(1)) == -1);
|
||||
assert(Int88.unwrap(-Int88.wrap(1)) == -1);
|
||||
assert(Int96.unwrap(-Int96.wrap(1)) == -1);
|
||||
assert(Int104.unwrap(-Int104.wrap(1)) == -1);
|
||||
assert(Int112.unwrap(-Int112.wrap(1)) == -1);
|
||||
assert(Int120.unwrap(-Int120.wrap(1)) == -1);
|
||||
assert(Int128.unwrap(-Int128.wrap(1)) == -1);
|
||||
assert(Int136.unwrap(-Int136.wrap(1)) == -1);
|
||||
assert(Int144.unwrap(-Int144.wrap(1)) == -1);
|
||||
assert(Int152.unwrap(-Int152.wrap(1)) == -1);
|
||||
assert(Int160.unwrap(-Int160.wrap(1)) == -1);
|
||||
assert(Int168.unwrap(-Int168.wrap(1)) == -1);
|
||||
assert(Int176.unwrap(-Int176.wrap(1)) == -1);
|
||||
assert(Int184.unwrap(-Int184.wrap(1)) == -1);
|
||||
assert(Int192.unwrap(-Int192.wrap(1)) == -1);
|
||||
assert(Int200.unwrap(-Int200.wrap(1)) == -1);
|
||||
assert(Int208.unwrap(-Int208.wrap(1)) == -1);
|
||||
assert(Int216.unwrap(-Int216.wrap(1)) == -1);
|
||||
assert(Int224.unwrap(-Int224.wrap(1)) == -1);
|
||||
assert(Int232.unwrap(-Int232.wrap(1)) == -1);
|
||||
assert(Int240.unwrap(-Int240.wrap(1)) == -1);
|
||||
assert(Int248.unwrap(-Int248.wrap(1)) == -1);
|
||||
assert(Int256.unwrap(-Int256.wrap(1)) == -1);
|
||||
assert(Int.unwrap(-Int.wrap(1)) == -1);
|
||||
}
|
||||
|
||||
function testUintBinary() public pure {
|
||||
assert(Uint8.unwrap(Uint8.wrap(1) | Uint8.wrap(2)) == 3);
|
||||
assert(Uint16.unwrap(Uint16.wrap(1) | Uint16.wrap(2)) == 3);
|
||||
assert(Uint24.unwrap(Uint24.wrap(1) | Uint24.wrap(2)) == 3);
|
||||
assert(Uint32.unwrap(Uint32.wrap(1) | Uint32.wrap(2)) == 3);
|
||||
assert(Uint40.unwrap(Uint40.wrap(1) | Uint40.wrap(2)) == 3);
|
||||
assert(Uint48.unwrap(Uint48.wrap(1) | Uint48.wrap(2)) == 3);
|
||||
assert(Uint56.unwrap(Uint56.wrap(1) | Uint56.wrap(2)) == 3);
|
||||
assert(Uint64.unwrap(Uint64.wrap(1) | Uint64.wrap(2)) == 3);
|
||||
assert(Uint72.unwrap(Uint72.wrap(1) | Uint72.wrap(2)) == 3);
|
||||
assert(Uint80.unwrap(Uint80.wrap(1) | Uint80.wrap(2)) == 3);
|
||||
assert(Uint88.unwrap(Uint88.wrap(1) | Uint88.wrap(2)) == 3);
|
||||
assert(Uint96.unwrap(Uint96.wrap(1) | Uint96.wrap(2)) == 3);
|
||||
assert(Uint104.unwrap(Uint104.wrap(1) | Uint104.wrap(2)) == 3);
|
||||
assert(Uint112.unwrap(Uint112.wrap(1) | Uint112.wrap(2)) == 3);
|
||||
assert(Uint120.unwrap(Uint120.wrap(1) | Uint120.wrap(2)) == 3);
|
||||
assert(Uint128.unwrap(Uint128.wrap(1) | Uint128.wrap(2)) == 3);
|
||||
assert(Uint136.unwrap(Uint136.wrap(1) | Uint136.wrap(2)) == 3);
|
||||
assert(Uint144.unwrap(Uint144.wrap(1) | Uint144.wrap(2)) == 3);
|
||||
assert(Uint152.unwrap(Uint152.wrap(1) | Uint152.wrap(2)) == 3);
|
||||
assert(Uint160.unwrap(Uint160.wrap(1) | Uint160.wrap(2)) == 3);
|
||||
assert(Uint168.unwrap(Uint168.wrap(1) | Uint168.wrap(2)) == 3);
|
||||
assert(Uint176.unwrap(Uint176.wrap(1) | Uint176.wrap(2)) == 3);
|
||||
assert(Uint184.unwrap(Uint184.wrap(1) | Uint184.wrap(2)) == 3);
|
||||
assert(Uint192.unwrap(Uint192.wrap(1) | Uint192.wrap(2)) == 3);
|
||||
assert(Uint200.unwrap(Uint200.wrap(1) | Uint200.wrap(2)) == 3);
|
||||
assert(Uint208.unwrap(Uint208.wrap(1) | Uint208.wrap(2)) == 3);
|
||||
assert(Uint216.unwrap(Uint216.wrap(1) | Uint216.wrap(2)) == 3);
|
||||
assert(Uint224.unwrap(Uint224.wrap(1) | Uint224.wrap(2)) == 3);
|
||||
assert(Uint232.unwrap(Uint232.wrap(1) | Uint232.wrap(2)) == 3);
|
||||
assert(Uint240.unwrap(Uint240.wrap(1) | Uint240.wrap(2)) == 3);
|
||||
assert(Uint248.unwrap(Uint248.wrap(1) | Uint248.wrap(2)) == 3);
|
||||
assert(Uint256.unwrap(Uint256.wrap(1) | Uint256.wrap(2)) == 3);
|
||||
assert(Uint.unwrap(Uint.wrap(1) | Uint.wrap(2)) == 3);
|
||||
}
|
||||
|
||||
function testUintUnary() public pure {
|
||||
assert(Uint8.unwrap(~Uint8.wrap(1)) == ~uint8(1));
|
||||
assert(Uint16.unwrap(~Uint16.wrap(1)) == ~uint16(1));
|
||||
assert(Uint24.unwrap(~Uint24.wrap(1)) == ~uint24(1));
|
||||
assert(Uint32.unwrap(~Uint32.wrap(1)) == ~uint32(1));
|
||||
assert(Uint40.unwrap(~Uint40.wrap(1)) == ~uint40(1));
|
||||
assert(Uint48.unwrap(~Uint48.wrap(1)) == ~uint48(1));
|
||||
assert(Uint56.unwrap(~Uint56.wrap(1)) == ~uint56(1));
|
||||
assert(Uint64.unwrap(~Uint64.wrap(1)) == ~uint64(1));
|
||||
assert(Uint72.unwrap(~Uint72.wrap(1)) == ~uint72(1));
|
||||
assert(Uint80.unwrap(~Uint80.wrap(1)) == ~uint80(1));
|
||||
assert(Uint88.unwrap(~Uint88.wrap(1)) == ~uint88(1));
|
||||
assert(Uint96.unwrap(~Uint96.wrap(1)) == ~uint96(1));
|
||||
assert(Uint104.unwrap(~Uint104.wrap(1)) == ~uint104(1));
|
||||
assert(Uint112.unwrap(~Uint112.wrap(1)) == ~uint112(1));
|
||||
assert(Uint120.unwrap(~Uint120.wrap(1)) == ~uint120(1));
|
||||
assert(Uint128.unwrap(~Uint128.wrap(1)) == ~uint128(1));
|
||||
assert(Uint136.unwrap(~Uint136.wrap(1)) == ~uint136(1));
|
||||
assert(Uint144.unwrap(~Uint144.wrap(1)) == ~uint144(1));
|
||||
assert(Uint152.unwrap(~Uint152.wrap(1)) == ~uint152(1));
|
||||
assert(Uint160.unwrap(~Uint160.wrap(1)) == ~uint160(1));
|
||||
assert(Uint168.unwrap(~Uint168.wrap(1)) == ~uint168(1));
|
||||
assert(Uint176.unwrap(~Uint176.wrap(1)) == ~uint176(1));
|
||||
assert(Uint184.unwrap(~Uint184.wrap(1)) == ~uint184(1));
|
||||
assert(Uint192.unwrap(~Uint192.wrap(1)) == ~uint192(1));
|
||||
assert(Uint200.unwrap(~Uint200.wrap(1)) == ~uint200(1));
|
||||
assert(Uint208.unwrap(~Uint208.wrap(1)) == ~uint208(1));
|
||||
assert(Uint216.unwrap(~Uint216.wrap(1)) == ~uint216(1));
|
||||
assert(Uint224.unwrap(~Uint224.wrap(1)) == ~uint224(1));
|
||||
assert(Uint232.unwrap(~Uint232.wrap(1)) == ~uint232(1));
|
||||
assert(Uint240.unwrap(~Uint240.wrap(1)) == ~uint240(1));
|
||||
assert(Uint248.unwrap(~Uint248.wrap(1)) == ~uint248(1));
|
||||
assert(Uint256.unwrap(~Uint256.wrap(1)) == ~uint256(1));
|
||||
assert(Uint.unwrap(~Uint.wrap(1)) == ~uint(1));
|
||||
}
|
||||
|
||||
function testBytesBinary() public pure {
|
||||
assert(Bytes1.unwrap(Bytes1.wrap(0x01) | Bytes1.wrap(0x02)) == bytes1(0x03));
|
||||
assert(Bytes2.unwrap(Bytes2.wrap(bytes2(bytes1(0x01))) | Bytes2.wrap(bytes2(bytes1(0x02)))) == bytes2(bytes1(0x03)));
|
||||
assert(Bytes3.unwrap(Bytes3.wrap(bytes3(bytes1(0x01))) | Bytes3.wrap(bytes3(bytes1(0x02)))) == bytes3(bytes1(0x03)));
|
||||
assert(Bytes4.unwrap(Bytes4.wrap(bytes4(bytes1(0x01))) | Bytes4.wrap(bytes4(bytes1(0x02)))) == bytes4(bytes1(0x03)));
|
||||
assert(Bytes5.unwrap(Bytes5.wrap(bytes5(bytes1(0x01))) | Bytes5.wrap(bytes5(bytes1(0x02)))) == bytes5(bytes1(0x03)));
|
||||
assert(Bytes6.unwrap(Bytes6.wrap(bytes6(bytes1(0x01))) | Bytes6.wrap(bytes6(bytes1(0x02)))) == bytes6(bytes1(0x03)));
|
||||
assert(Bytes7.unwrap(Bytes7.wrap(bytes7(bytes1(0x01))) | Bytes7.wrap(bytes7(bytes1(0x02)))) == bytes7(bytes1(0x03)));
|
||||
assert(Bytes8.unwrap(Bytes8.wrap(bytes8(bytes1(0x01))) | Bytes8.wrap(bytes8(bytes1(0x02)))) == bytes8(bytes1(0x03)));
|
||||
assert(Bytes9.unwrap(Bytes9.wrap(bytes9(bytes1(0x01))) | Bytes9.wrap(bytes9(bytes1(0x02)))) == bytes9(bytes1(0x03)));
|
||||
assert(Bytes10.unwrap(Bytes10.wrap(bytes10(bytes1(0x01))) | Bytes10.wrap(bytes10(bytes1(0x02)))) == bytes10(bytes1(0x03)));
|
||||
assert(Bytes11.unwrap(Bytes11.wrap(bytes11(bytes1(0x01))) | Bytes11.wrap(bytes11(bytes1(0x02)))) == bytes11(bytes1(0x03)));
|
||||
assert(Bytes12.unwrap(Bytes12.wrap(bytes12(bytes1(0x01))) | Bytes12.wrap(bytes12(bytes1(0x02)))) == bytes12(bytes1(0x03)));
|
||||
assert(Bytes13.unwrap(Bytes13.wrap(bytes13(bytes1(0x01))) | Bytes13.wrap(bytes13(bytes1(0x02)))) == bytes13(bytes1(0x03)));
|
||||
assert(Bytes14.unwrap(Bytes14.wrap(bytes14(bytes1(0x01))) | Bytes14.wrap(bytes14(bytes1(0x02)))) == bytes14(bytes1(0x03)));
|
||||
assert(Bytes15.unwrap(Bytes15.wrap(bytes15(bytes1(0x01))) | Bytes15.wrap(bytes15(bytes1(0x02)))) == bytes15(bytes1(0x03)));
|
||||
assert(Bytes16.unwrap(Bytes16.wrap(bytes16(bytes1(0x01))) | Bytes16.wrap(bytes16(bytes1(0x02)))) == bytes16(bytes1(0x03)));
|
||||
assert(Bytes17.unwrap(Bytes17.wrap(bytes17(bytes1(0x01))) | Bytes17.wrap(bytes17(bytes1(0x02)))) == bytes17(bytes1(0x03)));
|
||||
assert(Bytes18.unwrap(Bytes18.wrap(bytes18(bytes1(0x01))) | Bytes18.wrap(bytes18(bytes1(0x02)))) == bytes18(bytes1(0x03)));
|
||||
assert(Bytes19.unwrap(Bytes19.wrap(bytes19(bytes1(0x01))) | Bytes19.wrap(bytes19(bytes1(0x02)))) == bytes19(bytes1(0x03)));
|
||||
assert(Bytes20.unwrap(Bytes20.wrap(bytes20(bytes1(0x01))) | Bytes20.wrap(bytes20(bytes1(0x02)))) == bytes20(bytes1(0x03)));
|
||||
assert(Bytes21.unwrap(Bytes21.wrap(bytes21(bytes1(0x01))) | Bytes21.wrap(bytes21(bytes1(0x02)))) == bytes21(bytes1(0x03)));
|
||||
assert(Bytes22.unwrap(Bytes22.wrap(bytes22(bytes1(0x01))) | Bytes22.wrap(bytes22(bytes1(0x02)))) == bytes22(bytes1(0x03)));
|
||||
assert(Bytes23.unwrap(Bytes23.wrap(bytes23(bytes1(0x01))) | Bytes23.wrap(bytes23(bytes1(0x02)))) == bytes23(bytes1(0x03)));
|
||||
assert(Bytes24.unwrap(Bytes24.wrap(bytes24(bytes1(0x01))) | Bytes24.wrap(bytes24(bytes1(0x02)))) == bytes24(bytes1(0x03)));
|
||||
assert(Bytes25.unwrap(Bytes25.wrap(bytes25(bytes1(0x01))) | Bytes25.wrap(bytes25(bytes1(0x02)))) == bytes25(bytes1(0x03)));
|
||||
assert(Bytes26.unwrap(Bytes26.wrap(bytes26(bytes1(0x01))) | Bytes26.wrap(bytes26(bytes1(0x02)))) == bytes26(bytes1(0x03)));
|
||||
assert(Bytes27.unwrap(Bytes27.wrap(bytes27(bytes1(0x01))) | Bytes27.wrap(bytes27(bytes1(0x02)))) == bytes27(bytes1(0x03)));
|
||||
assert(Bytes28.unwrap(Bytes28.wrap(bytes28(bytes1(0x01))) | Bytes28.wrap(bytes28(bytes1(0x02)))) == bytes28(bytes1(0x03)));
|
||||
assert(Bytes29.unwrap(Bytes29.wrap(bytes29(bytes1(0x01))) | Bytes29.wrap(bytes29(bytes1(0x02)))) == bytes29(bytes1(0x03)));
|
||||
assert(Bytes30.unwrap(Bytes30.wrap(bytes30(bytes1(0x01))) | Bytes30.wrap(bytes30(bytes1(0x02)))) == bytes30(bytes1(0x03)));
|
||||
assert(Bytes31.unwrap(Bytes31.wrap(bytes31(bytes1(0x01))) | Bytes31.wrap(bytes31(bytes1(0x02)))) == bytes31(bytes1(0x03)));
|
||||
assert(Bytes32.unwrap(Bytes32.wrap(bytes32(bytes1(0x01))) | Bytes32.wrap(bytes32(bytes1(0x02)))) == bytes32(bytes1(0x03)));
|
||||
}
|
||||
|
||||
function testBytesUnary() public pure {
|
||||
assert(Bytes1.unwrap(~Bytes1.wrap(bytes1(0x01))) == ~bytes1(0x01));
|
||||
assert(Bytes2.unwrap(~Bytes2.wrap(bytes2(bytes1(0x01)))) == ~bytes2(bytes1(0x01)));
|
||||
assert(Bytes3.unwrap(~Bytes3.wrap(bytes3(bytes1(0x01)))) == ~bytes3(bytes1(0x01)));
|
||||
assert(Bytes4.unwrap(~Bytes4.wrap(bytes4(bytes1(0x01)))) == ~bytes4(bytes1(0x01)));
|
||||
assert(Bytes5.unwrap(~Bytes5.wrap(bytes5(bytes1(0x01)))) == ~bytes5(bytes1(0x01)));
|
||||
assert(Bytes6.unwrap(~Bytes6.wrap(bytes6(bytes1(0x01)))) == ~bytes6(bytes1(0x01)));
|
||||
assert(Bytes7.unwrap(~Bytes7.wrap(bytes7(bytes1(0x01)))) == ~bytes7(bytes1(0x01)));
|
||||
assert(Bytes8.unwrap(~Bytes8.wrap(bytes8(bytes1(0x01)))) == ~bytes8(bytes1(0x01)));
|
||||
assert(Bytes9.unwrap(~Bytes9.wrap(bytes9(bytes1(0x01)))) == ~bytes9(bytes1(0x01)));
|
||||
assert(Bytes10.unwrap(~Bytes10.wrap(bytes10(bytes1(0x01)))) == ~bytes10(bytes1(0x01)));
|
||||
assert(Bytes11.unwrap(~Bytes11.wrap(bytes11(bytes1(0x01)))) == ~bytes11(bytes1(0x01)));
|
||||
assert(Bytes12.unwrap(~Bytes12.wrap(bytes12(bytes1(0x01)))) == ~bytes12(bytes1(0x01)));
|
||||
assert(Bytes13.unwrap(~Bytes13.wrap(bytes13(bytes1(0x01)))) == ~bytes13(bytes1(0x01)));
|
||||
assert(Bytes14.unwrap(~Bytes14.wrap(bytes14(bytes1(0x01)))) == ~bytes14(bytes1(0x01)));
|
||||
assert(Bytes15.unwrap(~Bytes15.wrap(bytes15(bytes1(0x01)))) == ~bytes15(bytes1(0x01)));
|
||||
assert(Bytes16.unwrap(~Bytes16.wrap(bytes16(bytes1(0x01)))) == ~bytes16(bytes1(0x01)));
|
||||
assert(Bytes17.unwrap(~Bytes17.wrap(bytes17(bytes1(0x01)))) == ~bytes17(bytes1(0x01)));
|
||||
assert(Bytes18.unwrap(~Bytes18.wrap(bytes18(bytes1(0x01)))) == ~bytes18(bytes1(0x01)));
|
||||
assert(Bytes19.unwrap(~Bytes19.wrap(bytes19(bytes1(0x01)))) == ~bytes19(bytes1(0x01)));
|
||||
assert(Bytes20.unwrap(~Bytes20.wrap(bytes20(bytes1(0x01)))) == ~bytes20(bytes1(0x01)));
|
||||
assert(Bytes21.unwrap(~Bytes21.wrap(bytes21(bytes1(0x01)))) == ~bytes21(bytes1(0x01)));
|
||||
assert(Bytes22.unwrap(~Bytes22.wrap(bytes22(bytes1(0x01)))) == ~bytes22(bytes1(0x01)));
|
||||
assert(Bytes23.unwrap(~Bytes23.wrap(bytes23(bytes1(0x01)))) == ~bytes23(bytes1(0x01)));
|
||||
assert(Bytes24.unwrap(~Bytes24.wrap(bytes24(bytes1(0x01)))) == ~bytes24(bytes1(0x01)));
|
||||
assert(Bytes25.unwrap(~Bytes25.wrap(bytes25(bytes1(0x01)))) == ~bytes25(bytes1(0x01)));
|
||||
assert(Bytes26.unwrap(~Bytes26.wrap(bytes26(bytes1(0x01)))) == ~bytes26(bytes1(0x01)));
|
||||
assert(Bytes27.unwrap(~Bytes27.wrap(bytes27(bytes1(0x01)))) == ~bytes27(bytes1(0x01)));
|
||||
assert(Bytes28.unwrap(~Bytes28.wrap(bytes28(bytes1(0x01)))) == ~bytes28(bytes1(0x01)));
|
||||
assert(Bytes29.unwrap(~Bytes29.wrap(bytes29(bytes1(0x01)))) == ~bytes29(bytes1(0x01)));
|
||||
assert(Bytes30.unwrap(~Bytes30.wrap(bytes30(bytes1(0x01)))) == ~bytes30(bytes1(0x01)));
|
||||
assert(Bytes31.unwrap(~Bytes31.wrap(bytes31(bytes1(0x01)))) == ~bytes31(bytes1(0x01)));
|
||||
assert(Bytes32.unwrap(~Bytes32.wrap(bytes32(bytes1(0x01)))) == ~bytes32(bytes1(0x01)));
|
||||
}
|
||||
|
||||
function testOtherBinary() public pure {
|
||||
assert(Address.unwrap(Address.wrap(address(0x01)) | Address.wrap(address(0x02))) == address(0x03));
|
||||
assert(AddressPayable.unwrap(AddressPayable.wrap(payable(address(0x01))) | AddressPayable.wrap(payable(address(0x02)))) == payable(address(0x03)));
|
||||
assert(Bool.unwrap(~Bool.wrap(true)) == false);
|
||||
}
|
||||
|
||||
function testOtherUnary() public pure {
|
||||
assert(Address.unwrap(~Address.wrap(address(0))) == address(~bytes20(0)));
|
||||
assert(AddressPayable.unwrap(~AddressPayable.wrap(payable(address(0)))) == payable(address(~bytes20(0))));
|
||||
assert(Bool.unwrap(~Bool.wrap(true)) == false);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testIntBinary() ->
|
||||
// testIntUnary() ->
|
||||
// testUintBinary() ->
|
||||
// testUintUnary() ->
|
||||
// testBytesBinary() ->
|
||||
// testBytesUnary() ->
|
||||
// testOtherBinary() ->
|
||||
// testOtherUnary() ->
|
@ -0,0 +1,20 @@
|
||||
type Int is int16;
|
||||
|
||||
using {add as +, add} for Int global;
|
||||
|
||||
function add(Int _a, Int _b) pure returns (Int) {
|
||||
return Int.wrap(Int.unwrap(_a) + Int.unwrap(_b));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() pure public returns (Int) {
|
||||
return Int.wrap(5) + Int.wrap(5);
|
||||
}
|
||||
|
||||
function g() pure public returns (Int) {
|
||||
return Int.wrap(7).add(Int.wrap(6));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f() -> 10
|
||||
// g() -> 13
|
@ -0,0 +1,22 @@
|
||||
type U8 is uint8;
|
||||
|
||||
function checkedAdd(U8 x, U8 y) pure returns (U8) {
|
||||
return U8.wrap(U8.unwrap(x) + U8.unwrap(y));
|
||||
}
|
||||
|
||||
using {checkedAdd as +} for U8 global;
|
||||
|
||||
contract C {
|
||||
function testCheckedOperator() public pure returns (U8) {
|
||||
return U8.wrap(250) + U8.wrap(10);
|
||||
}
|
||||
|
||||
function testCheckedOperatorInUncheckedBlock() public pure returns (U8) {
|
||||
unchecked {
|
||||
return U8.wrap(250) + U8.wrap(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testCheckedOperator() -> FAILURE, hex"4e487b71", 0x11
|
||||
// testCheckedOperatorInUncheckedBlock() -> FAILURE, hex"4e487b71", 0x11
|
@ -0,0 +1,18 @@
|
||||
type A is address;
|
||||
|
||||
using {add as +} for A global;
|
||||
|
||||
function add(A a, A b) pure returns (A) {
|
||||
return A.wrap(address(uint160(A.unwrap(a)) + uint160(A.unwrap(b))));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function g() public pure returns (A) {
|
||||
A a = A.wrap(0x3333333333333333333333333333333333333333);
|
||||
A b = A.wrap(0x1111111111111111111111111111111111111111);
|
||||
A c = A.wrap(0x5555555555555555555555555555555555555555);
|
||||
return a + b + c;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// g() -> 0x9999999999999999999999999999999999999999
|
@ -0,0 +1,22 @@
|
||||
type Fixed is int128;
|
||||
using {add as +, mul as *} for Fixed global;
|
||||
|
||||
int constant MULTIPLIER = 10**18;
|
||||
|
||||
function add(Fixed a, Fixed b) pure returns (Fixed) {
|
||||
return Fixed.wrap(Fixed.unwrap(a) + Fixed.unwrap(b));
|
||||
}
|
||||
|
||||
function mul(Fixed a, Fixed b) pure returns (Fixed) {
|
||||
int intermediate = (int(Fixed.unwrap(a)) * int(Fixed.unwrap(b))) / MULTIPLIER;
|
||||
if (int128(intermediate) != intermediate) { revert("Overflow"); }
|
||||
return Fixed.wrap(int128(intermediate));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function applyInterest(Fixed value, Fixed percentage) public pure returns (Fixed result) {
|
||||
return value + value * percentage;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// applyInterest(int128,int128): 500000000000000000000, 100000000000000000 -> 550000000000000000000
|
@ -0,0 +1,26 @@
|
||||
type SmallInt is int;
|
||||
type BigInt is int;
|
||||
|
||||
using {addSmall as +} for SmallInt global;
|
||||
using {addBig as +} for BigInt global;
|
||||
|
||||
function addSmall(SmallInt a, SmallInt b) pure returns (SmallInt) {
|
||||
return SmallInt.wrap(SmallInt.unwrap(a) + SmallInt.unwrap(b));
|
||||
}
|
||||
|
||||
function addBig(BigInt a, BigInt b) pure returns (BigInt) {
|
||||
return BigInt.wrap(10 * (BigInt.unwrap(a) + BigInt.unwrap(b)));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function small() public pure returns (SmallInt) {
|
||||
return SmallInt.wrap(1) + SmallInt.wrap(2);
|
||||
}
|
||||
|
||||
function big() public pure returns (BigInt) {
|
||||
return BigInt.wrap(3) + BigInt.wrap(4);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// small() -> 3
|
||||
// big() -> 70
|
@ -0,0 +1,20 @@
|
||||
type Int is int32;
|
||||
|
||||
using {foo as +, foo as -} for Int global;
|
||||
|
||||
function foo(Int a, Int b) pure returns(Int) {
|
||||
return Int.wrap(Int.unwrap(a) + Int.unwrap(b));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() pure public returns (Int) {
|
||||
return Int.wrap(2) + Int.wrap(3);
|
||||
}
|
||||
|
||||
function g() pure public returns (Int) {
|
||||
return Int.wrap(6) - Int.wrap(1);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// f() -> 5
|
||||
// g() -> 7
|
@ -0,0 +1,15 @@
|
||||
type Int is int16;
|
||||
|
||||
using {keccak256 as +} for Int global;
|
||||
|
||||
function keccak256(Int a, Int b) pure returns (Int) {
|
||||
return Int.wrap(Int.unwrap(a) + Int.unwrap(b));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function test() public returns (Int) {
|
||||
return Int.wrap(3) + Int.wrap(4);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// test() -> 7
|
@ -0,0 +1,83 @@
|
||||
type Bool is bool;
|
||||
using {add as +, mul as *, unsub as -} for Bool global;
|
||||
|
||||
function add(Bool x, Bool y) pure returns (Bool) {
|
||||
return Bool.wrap(Bool.unwrap(x) || Bool.unwrap(y));
|
||||
}
|
||||
|
||||
function mul(Bool x, Bool y) pure returns (Bool) {
|
||||
return Bool.wrap(Bool.unwrap(x) && Bool.unwrap(y));
|
||||
}
|
||||
|
||||
function unsub(Bool x) pure returns (Bool) {
|
||||
return Bool.wrap(!Bool.unwrap(x));
|
||||
}
|
||||
|
||||
contract C {
|
||||
event Wrapped(uint);
|
||||
event Probe(Bool);
|
||||
|
||||
function toBool(uint x) public returns (Bool) {
|
||||
emit Wrapped(x);
|
||||
return Bool.wrap(x > 0);
|
||||
}
|
||||
|
||||
function probe(Bool x) public returns (Bool) {
|
||||
emit Probe(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
function testSingleOperator() public {
|
||||
toBool(0) +
|
||||
(toBool(1) + toBool(2)) +
|
||||
toBool(3);
|
||||
}
|
||||
|
||||
function testTwoBinaryOperators() public {
|
||||
toBool(0) * toBool(1) +
|
||||
(toBool(2) * toBool(3)) +
|
||||
toBool(4) * toBool(5);
|
||||
}
|
||||
|
||||
function testBinaryAndUnaryOperators() public {
|
||||
-toBool(0) * -toBool(1) +
|
||||
(-toBool(2) * -toBool(3)) +
|
||||
-toBool(4) * -toBool(5);
|
||||
}
|
||||
|
||||
function testOperatorsNestedInCalls() public {
|
||||
-probe(toBool(0) * -toBool(1)) +
|
||||
(-probe(toBool(2) * -toBool(3))) +
|
||||
-probe(toBool(4) * -toBool(5));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testSingleOperator() ->
|
||||
// ~ emit Wrapped(uint256): 0x00
|
||||
// ~ emit Wrapped(uint256): 0x01
|
||||
// ~ emit Wrapped(uint256): 0x02
|
||||
// ~ emit Wrapped(uint256): 0x03
|
||||
// testTwoBinaryOperators() ->
|
||||
// ~ emit Wrapped(uint256): 0x00
|
||||
// ~ emit Wrapped(uint256): 0x01
|
||||
// ~ emit Wrapped(uint256): 0x02
|
||||
// ~ emit Wrapped(uint256): 0x03
|
||||
// ~ emit Wrapped(uint256): 0x04
|
||||
// ~ emit Wrapped(uint256): 0x05
|
||||
// testBinaryAndUnaryOperators() ->
|
||||
// ~ emit Wrapped(uint256): 0x00
|
||||
// ~ emit Wrapped(uint256): 0x01
|
||||
// ~ emit Wrapped(uint256): 0x02
|
||||
// ~ emit Wrapped(uint256): 0x03
|
||||
// ~ emit Wrapped(uint256): 0x04
|
||||
// ~ emit Wrapped(uint256): 0x05
|
||||
// testOperatorsNestedInCalls() ->
|
||||
// ~ emit Wrapped(uint256): 0x00
|
||||
// ~ emit Wrapped(uint256): 0x01
|
||||
// ~ emit Probe(bool): 0x00
|
||||
// ~ emit Wrapped(uint256): 0x02
|
||||
// ~ emit Wrapped(uint256): 0x03
|
||||
// ~ emit Probe(bool): 0x00
|
||||
// ~ emit Wrapped(uint256): 0x04
|
||||
// ~ emit Wrapped(uint256): 0x05
|
||||
// ~ emit Probe(bool): 0x00
|
@ -0,0 +1,61 @@
|
||||
type Int32 is int32;
|
||||
using {add as +, unsub as -} for Int32 global;
|
||||
|
||||
function add(Int32 x, Int32 y) pure returns (Int32) {
|
||||
return loadAdder().mul(x, y);
|
||||
}
|
||||
|
||||
function unsub(Int32 x) pure returns (Int32) {
|
||||
return loadAdder().inc(x);
|
||||
}
|
||||
|
||||
interface IAdder {
|
||||
function mul(Int32, Int32) external pure returns (Int32);
|
||||
function inc(Int32) external pure returns (Int32);
|
||||
}
|
||||
|
||||
contract Adder is IAdder {
|
||||
function mul(Int32 x, Int32 y) external pure override returns (Int32) {
|
||||
return Int32.wrap(Int32.unwrap(x) * Int32.unwrap(y));
|
||||
}
|
||||
|
||||
function inc(Int32 x) external pure override returns (Int32) {
|
||||
return Int32.wrap(Int32.unwrap(x) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function storeAdder(IAdder adder) pure {
|
||||
assembly {
|
||||
// This test would also work without assembly if we could hard-code an address here.
|
||||
mstore(0, adder)
|
||||
}
|
||||
}
|
||||
|
||||
function loadAdder() pure returns (IAdder adder) {
|
||||
assembly {
|
||||
adder := mload(0)
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function testMul(Int32 x, Int32 y) public returns (Int32) {
|
||||
storeAdder(new Adder());
|
||||
|
||||
return x + y;
|
||||
}
|
||||
|
||||
function testInc(Int32 x) public returns (Int32) {
|
||||
storeAdder(new Adder());
|
||||
|
||||
return -x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testMul(int32,int32): 42, 10 -> 420
|
||||
// gas irOptimized: 103347
|
||||
// gas legacy: 188203
|
||||
// gas legacyOptimized: 126164
|
||||
// testInc(int32): 42 -> 43
|
||||
// gas irOptimized: 103173
|
||||
// gas legacy: 187452
|
||||
// gas legacyOptimized: 125851
|
@ -0,0 +1,67 @@
|
||||
type Int32 is int32;
|
||||
using {add as +, unsub as -} for Int32 global;
|
||||
|
||||
function add(Int32 x, Int32 y) pure returns (Int32) {
|
||||
return loadAdder().mul(x, y);
|
||||
}
|
||||
|
||||
function unsub(Int32 x) pure returns (Int32) {
|
||||
return loadAdder().inc(x);
|
||||
}
|
||||
|
||||
interface IAdderPure {
|
||||
function mul(Int32, Int32) external pure returns (Int32);
|
||||
function inc(Int32) external pure returns (Int32);
|
||||
}
|
||||
|
||||
interface IAdderView {
|
||||
function mul(Int32, Int32) external view returns (Int32);
|
||||
function inc(Int32) external view returns (Int32);
|
||||
}
|
||||
|
||||
contract Adder is IAdderView {
|
||||
function mul(Int32 x, Int32 y) external view override returns (Int32) {
|
||||
return Int32.wrap(Int32.unwrap(x) * Int32.unwrap(y));
|
||||
}
|
||||
|
||||
function inc(Int32 x) external view override returns (Int32) {
|
||||
return Int32.wrap(Int32.unwrap(x) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function storeAdder(IAdderView adder) pure {
|
||||
assembly {
|
||||
// This test would also work without assembly if we could hard-code an address here.
|
||||
mstore(0, adder)
|
||||
}
|
||||
}
|
||||
|
||||
function loadAdder() pure returns (IAdderPure adder) {
|
||||
assembly {
|
||||
// The adder we stored is view but we cheat by using a modified version with pure functions
|
||||
adder := mload(0)
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function testMul(Int32 x, Int32 y) public returns (Int32) {
|
||||
storeAdder(new Adder());
|
||||
|
||||
return x + y;
|
||||
}
|
||||
|
||||
function testInc(Int32 x) public returns (Int32) {
|
||||
storeAdder(new Adder());
|
||||
|
||||
return -x;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testMul(int32,int32): 42, 10 -> 420
|
||||
// gas irOptimized: 103347
|
||||
// gas legacy: 188203
|
||||
// gas legacyOptimized: 126164
|
||||
// testInc(int32): 42 -> 43
|
||||
// gas irOptimized: 103173
|
||||
// gas legacy: 187452
|
||||
// gas legacyOptimized: 125851
|
@ -0,0 +1,40 @@
|
||||
type U8 is uint8;
|
||||
using {f as ~, add as +} for U8 global;
|
||||
|
||||
function f(U8 x) pure returns (U8 z) {
|
||||
assembly {
|
||||
// NOTE: Not using shr so that the test works pre-constantinople too
|
||||
z := div(x, 256)
|
||||
}
|
||||
}
|
||||
|
||||
function add(U8 x, U8 y) pure returns (U8 z) {
|
||||
assembly {
|
||||
z := add(div(x, 256), div(x, 256))
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function testUnary() external pure returns (U8, U8) {
|
||||
U8 a;
|
||||
assembly {
|
||||
a := 0x4200
|
||||
}
|
||||
// If the result is not 0, no cleanup was performed.
|
||||
return (~a, f(a));
|
||||
}
|
||||
|
||||
function testBinary() external pure returns (U8, U8) {
|
||||
U8 a;
|
||||
U8 b;
|
||||
assembly {
|
||||
a := 0x4200
|
||||
b := 0x4200
|
||||
}
|
||||
// If the result is not 0, no cleanup was performed.
|
||||
return (a + b, add(a, b));
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testUnary() -> 0x42, 0x42
|
||||
// testBinary() -> 0x84, 0x84
|
@ -0,0 +1,71 @@
|
||||
type Int is int64;
|
||||
using {
|
||||
bitor as |, bitand as &, bitxor as ^, bitnot as ~,
|
||||
add as +, sub as -, unsub as -, mul as *, div as /, mod as %
|
||||
} for Int global;
|
||||
|
||||
function bitor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) | Int.unwrap(y)); }
|
||||
function bitand(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) & Int.unwrap(y)); }
|
||||
function bitxor(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) ^ Int.unwrap(y)); }
|
||||
function bitnot(Int x) pure returns (Int) { return Int.wrap(~Int.unwrap(x)); }
|
||||
|
||||
function add(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) + Int.unwrap(y)); }
|
||||
function sub(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) - Int.unwrap(y)); }
|
||||
function unsub(Int x) pure returns (Int) { return Int.wrap(-Int.unwrap(x)); }
|
||||
function mul(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) * Int.unwrap(y)); }
|
||||
function div(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) / Int.unwrap(y)); }
|
||||
function mod(Int x, Int y) pure returns (Int) { return Int.wrap(Int.unwrap(x) % Int.unwrap(y)); }
|
||||
|
||||
contract C {
|
||||
Int constant I0 = Int.wrap(0);
|
||||
Int constant I1 = Int.wrap(1);
|
||||
Int constant I2 = Int.wrap(2);
|
||||
Int constant I3 = Int.wrap(3);
|
||||
Int constant I4 = Int.wrap(4);
|
||||
Int constant I5 = Int.wrap(5);
|
||||
Int constant I6 = Int.wrap(6);
|
||||
Int constant I7 = Int.wrap(7);
|
||||
Int constant I8 = Int.wrap(8);
|
||||
Int constant I10 = Int.wrap(10);
|
||||
Int constant I13 = Int.wrap(13);
|
||||
Int constant I15 = Int.wrap(15);
|
||||
Int constant I20 = Int.wrap(20);
|
||||
Int constant I128 = Int.wrap(128);
|
||||
|
||||
function testBitwise() public pure {
|
||||
assert(Int.unwrap(I0 & I0 | I1) == (0 & 0 | 1));
|
||||
assert(Int.unwrap(I0 & I0 | I1) == ((0 & 0) | 1));
|
||||
}
|
||||
|
||||
function testBitwise_arithmetic() public pure {
|
||||
assert(Int.unwrap(I2 + I2 & ~I1 | I6 * I6 - I4 & ~I3) == (2 + 2 & ~1 | 6 * 6 - 4 & ~3));
|
||||
assert(Int.unwrap(I2 + I2 & ~I1 | I6 * I6 - I4 & ~I3) == (((2 + 2) & (~1)) | (((6 * 6) - 4) & (~3))));
|
||||
}
|
||||
|
||||
function testArithmetic() public pure {
|
||||
assert(Int.unwrap(I1 + I8 / I4 - I5 % I6 * I7) == (1 + 8 / 4 - 5 % 6 * 7));
|
||||
assert(Int.unwrap(I1 + I8 / I4 - I5 % I6 * I7) == ((1 + (8 / 4)) - ((5 % 6) * 7)));
|
||||
}
|
||||
|
||||
function testAll() public pure {
|
||||
assert(
|
||||
Int.unwrap(I128 + I1 - I10 + I4 & ~I1 ^ ~I1 * I2 | -I15 % -I10 * I20 / I2 + I13 & ~I3) ==
|
||||
(128 + 1 - 10 + 4 & ~1 ^ ~1 * 2 | -15 % -10 * 20 / 2 + 13 & ~3)
|
||||
);
|
||||
assert(
|
||||
Int.unwrap(I128 + I1 - I10 + I4 & ~I1 ^ ~I1 * I2 | -I15 % -I10 * I20 / I2 + I13 & ~I3) ==
|
||||
(
|
||||
(
|
||||
((((128 + 1) - 10) + 4) & (~1)) ^
|
||||
((~1) * 2)
|
||||
) |
|
||||
((((((-15) % (-10)) * 20) / 2) + 13) & (~3))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testBitwise() ->
|
||||
// testBitwise_arithmetic() ->
|
||||
// testArithmetic() ->
|
||||
// testAll() ->
|
@ -0,0 +1,58 @@
|
||||
type U8 is uint8;
|
||||
using {f as ~, g as +} for U8 global;
|
||||
|
||||
function f(U8) pure returns (U8 z) {
|
||||
assembly {
|
||||
// Return a value with dirty bytes outside of uint8
|
||||
z := 0xffff
|
||||
}
|
||||
}
|
||||
|
||||
function g(U8, U8) pure returns (U8 z) {
|
||||
assembly {
|
||||
// Return a value with dirty bytes outside of uint8
|
||||
z := 0xffff
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function testUnary() external pure returns (uint, uint) {
|
||||
U8 a; // Value does not matter
|
||||
|
||||
U8 opResult = ~a;
|
||||
U8 fResult = f(a);
|
||||
|
||||
// Get the slot, including bytes outside of uint8
|
||||
uint opResultFull;
|
||||
uint fResultFull;
|
||||
assembly {
|
||||
opResultFull := opResult
|
||||
fResultFull := fResult
|
||||
}
|
||||
|
||||
// If the result is not 0xff, no cleanup was performed.
|
||||
return (opResultFull, fResultFull);
|
||||
}
|
||||
|
||||
function testBinary() external pure returns (uint, uint) {
|
||||
U8 a; // Value does not matter
|
||||
U8 b; // Value does not matter
|
||||
|
||||
U8 opResult = a + b;
|
||||
U8 fResult = g(a, b);
|
||||
|
||||
// Get the slot, including bytes outside of uint8
|
||||
uint opResultFull;
|
||||
uint fResultFull;
|
||||
assembly {
|
||||
opResultFull := opResult
|
||||
fResultFull := fResult
|
||||
}
|
||||
|
||||
// If the result is not 0xff, no cleanup was performed.
|
||||
return (opResultFull, fResultFull);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testUnary() -> 0xffff, 0xffff
|
||||
// testBinary() -> 0xffff, 0xffff
|
@ -0,0 +1,41 @@
|
||||
type Uint is uint;
|
||||
using {unaryCountdown as ~, binaryCountdown as ^, eq as ==} for Uint global;
|
||||
|
||||
function unaryCountdown(Uint x) pure returns (Uint) {
|
||||
if (x == Uint.wrap(0))
|
||||
return Uint.wrap(0);
|
||||
|
||||
return ~Uint.wrap(Uint.unwrap(x) - 1);
|
||||
}
|
||||
|
||||
function binaryCountdown(Uint x, Uint y) pure returns (Uint) {
|
||||
if (x == Uint.wrap(0) && y == Uint.wrap(0))
|
||||
return Uint.wrap(0);
|
||||
if (x == Uint.wrap(0))
|
||||
return y ^ x;
|
||||
|
||||
return Uint.wrap(Uint.unwrap(x) - 1) ^ y;
|
||||
}
|
||||
|
||||
function eq(Uint x, Uint y) pure returns (bool) {
|
||||
return Uint.unwrap(x) == Uint.unwrap(y);
|
||||
}
|
||||
|
||||
contract C {
|
||||
function testUnary(Uint x) public pure returns (Uint) {
|
||||
return ~x;
|
||||
}
|
||||
|
||||
function testBinary(Uint x, Uint y) public pure returns (Uint) {
|
||||
return x ^ y;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// testUnary(uint256): 0 -> 0
|
||||
// testUnary(uint256): 1 -> 0
|
||||
// testUnary(uint256): 99999999999 -> FAILURE
|
||||
// testBinary(uint256,uint256): 0, 0 -> 0
|
||||
// testBinary(uint256,uint256): 1, 0 -> 0
|
||||
// testBinary(uint256,uint256): 0, 1 -> 0
|
||||
// testBinary(uint256,uint256): 1, 1 -> 0
|
||||
// testBinary(uint256,uint256): 99999999999, 99999999999 -> FAILURE
|
@ -0,0 +1,25 @@
|
||||
type U8 is uint8;
|
||||
|
||||
function uncheckedAdd(U8 x, U8 y) pure returns (U8) {
|
||||
unchecked {
|
||||
return U8.wrap(U8.unwrap(x) + U8.unwrap(y));
|
||||
}
|
||||
}
|
||||
|
||||
using {uncheckedAdd as +} for U8 global;
|
||||
|
||||
contract D {
|
||||
function testUncheckedOperator() public pure returns (U8) {
|
||||
return U8.wrap(250) + U8.wrap(10);
|
||||
}
|
||||
|
||||
function testUncheckedOperatorInUncheckedBlock() public pure returns (U8) {
|
||||
unchecked {
|
||||
return U8.wrap(250) + U8.wrap(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// testUncheckedOperator() -> 4
|
||||
// testUncheckedOperatorInUncheckedBlock() -> 4
|
@ -0,0 +1,16 @@
|
||||
type U is uint;
|
||||
using {div as /} for U global;
|
||||
|
||||
function div(U x, U y) pure returns (U) {
|
||||
return U.wrap(U.unwrap(x) / U.unwrap(y));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f(U x, U y) public pure returns (U) {
|
||||
return x / y; // FIXME: should detect div by zero
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTEngine: all
|
||||
// ----
|
||||
// Warning 6756: (218-223): User-defined operators are not yet supported by SMTChecker. This invocation of operator / has been ignored, which may lead to incorrect results.
|
@ -0,0 +1,19 @@
|
||||
type U is uint;
|
||||
using {div as /} for U global;
|
||||
|
||||
function div(U x, U y) pure returns (U) {
|
||||
if (U.unwrap(y) == 0)
|
||||
return U.wrap(0);
|
||||
|
||||
return U.wrap(U.unwrap(x) / U.unwrap(y));
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f(U x, U y) public pure returns (U) {
|
||||
return x / y; // no div by zero possible here
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTEngine: all
|
||||
// ----
|
||||
// Warning 6756: (271-276): User-defined operators are not yet supported by SMTChecker. This invocation of operator / has been ignored, which may lead to incorrect results.
|
@ -0,0 +1,104 @@
|
||||
type I16 is int16;
|
||||
using {
|
||||
bitor as |, bitand as &, bitxor as ^, bitnot as ~,
|
||||
add as +, sub as -, unsub as -, mul as *, div as /, mod as %,
|
||||
eq as ==, noteq as !=, lt as <, gt as >, leq as <=, geq as >=
|
||||
} for I16 global;
|
||||
|
||||
function bitor(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) | I16.unwrap(y)); }
|
||||
function bitand(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) & I16.unwrap(y)); }
|
||||
function bitxor(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) ^ I16.unwrap(y)); }
|
||||
function bitnot(I16 x) pure returns (I16) { return I16.wrap(~I16.unwrap(x)); }
|
||||
|
||||
function add(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) + I16.unwrap(y)); }
|
||||
function sub(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) - I16.unwrap(y)); }
|
||||
function unsub(I16 x) pure returns (I16) { return I16.wrap(-I16.unwrap(x)); }
|
||||
function mul(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) * I16.unwrap(y)); }
|
||||
function div(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) / I16.unwrap(y)); }
|
||||
function mod(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) % I16.unwrap(y)); }
|
||||
|
||||
function eq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) == I16.unwrap(y); }
|
||||
function noteq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) != I16.unwrap(y); }
|
||||
function lt(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) < I16.unwrap(y); }
|
||||
function gt(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) > I16.unwrap(y); }
|
||||
function leq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) <= I16.unwrap(y); }
|
||||
function geq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) >= I16.unwrap(y); }
|
||||
|
||||
contract C {
|
||||
I16 constant MINUS_TWO = I16.wrap(-2);
|
||||
I16 constant ZERO = I16.wrap(0);
|
||||
I16 constant ONE = I16.wrap(1);
|
||||
I16 constant TWO = I16.wrap(2);
|
||||
I16 constant THREE = I16.wrap(3);
|
||||
I16 constant FOUR = I16.wrap(4);
|
||||
|
||||
function testBitwise() public pure {
|
||||
assert(ONE | TWO == THREE); // FIXME: should hold
|
||||
assert(ONE & THREE == ZERO); // FIXME: should hold
|
||||
assert(TWO ^ TWO == ZERO); // FIXME: should hold
|
||||
assert(~ONE == MINUS_TWO); // FIXME: should hold
|
||||
}
|
||||
|
||||
function testArithmetic() public pure {
|
||||
assert(TWO + TWO == FOUR); // FIXME: should hold
|
||||
assert(TWO - TWO == ZERO); // FIXME: should hold
|
||||
assert(-TWO == MINUS_TWO); // FIXME: should hold
|
||||
assert(TWO * TWO == FOUR); // FIXME: should hold
|
||||
assert(TWO / TWO == ONE); // FIXME: should hold
|
||||
assert(TWO % TWO == ZERO); // FIXME: should hold
|
||||
}
|
||||
|
||||
function testComparison() public pure {
|
||||
assert(TWO == TWO); // FIXME: should hold
|
||||
assert(!(TWO != TWO)); // FIXME: should hold
|
||||
assert(!(TWO < TWO)); // FIXME: should hold
|
||||
assert(!(TWO > TWO)); // FIXME: should hold
|
||||
assert(TWO <= TWO); // FIXME: should hold
|
||||
assert(TWO >= TWO); // FIXME: should hold
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTEngine: all
|
||||
// ----
|
||||
// Warning 6756: (2019-2028): User-defined operators are not yet supported by SMTChecker. This invocation of operator | has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2019-2037): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2077-2088): User-defined operators are not yet supported by SMTChecker. This invocation of operator & has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2077-2096): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2136-2145): User-defined operators are not yet supported by SMTChecker. This invocation of operator ^ has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2136-2153): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6156: (2193-2197): User-defined operators are not yet supported by SMTChecker. This invocation of operator ~ has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2193-2210): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2301-2310): User-defined operators are not yet supported by SMTChecker. This invocation of operator + has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2301-2318): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2358-2367): User-defined operators are not yet supported by SMTChecker. This invocation of operator - has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2358-2375): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6156: (2415-2419): User-defined operators are not yet supported by SMTChecker. This invocation of operator - has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2415-2432): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2472-2481): User-defined operators are not yet supported by SMTChecker. This invocation of operator * has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2472-2489): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2529-2538): User-defined operators are not yet supported by SMTChecker. This invocation of operator / has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2529-2545): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2585-2594): User-defined operators are not yet supported by SMTChecker. This invocation of operator % has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2585-2602): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2693-2703): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2745-2755): User-defined operators are not yet supported by SMTChecker. This invocation of operator != has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2798-2807): User-defined operators are not yet supported by SMTChecker. This invocation of operator < has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2850-2859): User-defined operators are not yet supported by SMTChecker. This invocation of operator > has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2900-2910): User-defined operators are not yet supported by SMTChecker. This invocation of operator <= has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2950-2960): User-defined operators are not yet supported by SMTChecker. This invocation of operator >= has been ignored, which may lead to incorrect results.
|
||||
// Warning 6328: (2012-2038): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2070-2097): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2129-2154): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2186-2211): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2294-2319): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2351-2376): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2408-2433): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2465-2490): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2522-2546): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2578-2603): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2686-2704): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2736-2757): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2789-2809): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2841-2861): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2893-2911): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2943-2961): CHC: Assertion violation happens here.
|
@ -0,0 +1,104 @@
|
||||
type I16 is int16;
|
||||
using {
|
||||
bitor as |, bitand as &, bitxor as ^, bitnot as ~,
|
||||
add as +, sub as -, unsub as -, mul as *, div as /, mod as %,
|
||||
eq as ==, noteq as !=, lt as <, gt as >, leq as <=, geq as >=
|
||||
} for I16 global;
|
||||
|
||||
function bitor(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) | I16.unwrap(y)); }
|
||||
function bitand(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) & I16.unwrap(y)); }
|
||||
function bitxor(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) ^ I16.unwrap(y)); }
|
||||
function bitnot(I16 x) pure returns (I16) { return I16.wrap(~I16.unwrap(x)); }
|
||||
|
||||
function add(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) + I16.unwrap(y)); }
|
||||
function sub(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) - I16.unwrap(y)); }
|
||||
function unsub(I16 x) pure returns (I16) { return I16.wrap(-I16.unwrap(x)); }
|
||||
function mul(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) * I16.unwrap(y)); }
|
||||
function div(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) / I16.unwrap(y)); }
|
||||
function mod(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) % I16.unwrap(y)); }
|
||||
|
||||
function eq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) == I16.unwrap(y); }
|
||||
function noteq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) != I16.unwrap(y); }
|
||||
function lt(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) < I16.unwrap(y); }
|
||||
function gt(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) > I16.unwrap(y); }
|
||||
function leq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) <= I16.unwrap(y); }
|
||||
function geq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) >= I16.unwrap(y); }
|
||||
|
||||
contract C {
|
||||
I16 constant MINUS_TWO = I16.wrap(-2);
|
||||
I16 constant ZERO = I16.wrap(0);
|
||||
I16 constant ONE = I16.wrap(1);
|
||||
I16 constant TWO = I16.wrap(2);
|
||||
I16 constant THREE = I16.wrap(3);
|
||||
I16 constant FOUR = I16.wrap(4);
|
||||
|
||||
function testBitwise() public pure {
|
||||
assert(ONE | TWO == FOUR); // should fail
|
||||
assert(ONE & THREE == FOUR); // should fail
|
||||
assert(TWO ^ TWO == FOUR); // should fail
|
||||
assert(~ONE == FOUR); // should fail
|
||||
}
|
||||
|
||||
function testArithmetic() public pure {
|
||||
assert(TWO + THREE == FOUR); // should fail
|
||||
assert(TWO - TWO == FOUR); // should fail
|
||||
assert(-TWO == FOUR); // should fail
|
||||
assert(TWO * THREE == FOUR); // should fail
|
||||
assert(TWO / TWO == FOUR); // should fail
|
||||
assert(TWO % TWO == FOUR); // should fail
|
||||
}
|
||||
|
||||
function testComparison() public pure {
|
||||
assert(!(TWO == TWO)); // should fail
|
||||
assert(TWO != TWO); // should fail
|
||||
assert(TWO < TWO); // should fail
|
||||
assert(TWO > TWO); // should fail
|
||||
assert(!(TWO <= TWO)); // should fail
|
||||
assert(!(TWO >= TWO)); // should fail
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTEngine: all
|
||||
// ----
|
||||
// Warning 6756: (2019-2028): User-defined operators are not yet supported by SMTChecker. This invocation of operator | has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2019-2036): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2069-2080): User-defined operators are not yet supported by SMTChecker. This invocation of operator & has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2069-2088): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2121-2130): User-defined operators are not yet supported by SMTChecker. This invocation of operator ^ has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2121-2138): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6156: (2171-2175): User-defined operators are not yet supported by SMTChecker. This invocation of operator ~ has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2171-2183): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2267-2278): User-defined operators are not yet supported by SMTChecker. This invocation of operator + has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2267-2286): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2319-2328): User-defined operators are not yet supported by SMTChecker. This invocation of operator - has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2319-2336): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6156: (2369-2373): User-defined operators are not yet supported by SMTChecker. This invocation of operator - has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2369-2381): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2414-2425): User-defined operators are not yet supported by SMTChecker. This invocation of operator * has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2414-2433): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2466-2475): User-defined operators are not yet supported by SMTChecker. This invocation of operator / has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2466-2483): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2516-2525): User-defined operators are not yet supported by SMTChecker. This invocation of operator % has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2516-2533): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2619-2629): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2663-2673): User-defined operators are not yet supported by SMTChecker. This invocation of operator != has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2706-2715): User-defined operators are not yet supported by SMTChecker. This invocation of operator < has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2748-2757): User-defined operators are not yet supported by SMTChecker. This invocation of operator > has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2792-2802): User-defined operators are not yet supported by SMTChecker. This invocation of operator <= has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2838-2848): User-defined operators are not yet supported by SMTChecker. This invocation of operator >= has been ignored, which may lead to incorrect results.
|
||||
// Warning 6328: (2012-2037): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2062-2089): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2114-2139): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2164-2184): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2260-2287): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2312-2337): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2362-2382): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2407-2434): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2459-2484): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2509-2534): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2610-2631): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2656-2674): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2699-2716): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2741-2758): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2783-2804): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2829-2850): CHC: Assertion violation happens here.
|
@ -0,0 +1,105 @@
|
||||
type I16 is int16;
|
||||
using {
|
||||
bitor as |, bitand as &, bitxor as ^, bitnot as ~,
|
||||
add as +, sub as -, unsub as -, mul as *, div as /, mod as %,
|
||||
eq as ==, noteq as !=, lt as <, gt as >, leq as <=, geq as >=
|
||||
} for I16 global;
|
||||
|
||||
function bitor(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) | I16.unwrap(y)); }
|
||||
function bitand(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) & I16.unwrap(y)); }
|
||||
function bitxor(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) ^ I16.unwrap(y)); }
|
||||
function bitnot(I16 x) pure returns (I16) { return I16.wrap(~I16.unwrap(x)); }
|
||||
|
||||
function add(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) + I16.unwrap(y)); }
|
||||
function sub(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) - I16.unwrap(y)); }
|
||||
function unsub(I16 x) pure returns (I16) { return I16.wrap(-I16.unwrap(x)); }
|
||||
function mul(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) * I16.unwrap(y)); }
|
||||
function div(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) / I16.unwrap(y)); }
|
||||
function mod(I16 x, I16 y) pure returns (I16) { return I16.wrap(I16.unwrap(x) % I16.unwrap(y)); }
|
||||
|
||||
function eq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) == I16.unwrap(y); }
|
||||
function noteq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) != I16.unwrap(y); }
|
||||
function lt(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) < I16.unwrap(y); }
|
||||
function gt(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) > I16.unwrap(y); }
|
||||
function leq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) <= I16.unwrap(y); }
|
||||
function geq(I16 x, I16 y) pure returns (bool) { return I16.unwrap(x) >= I16.unwrap(y); }
|
||||
|
||||
contract C {
|
||||
function testBitwise(I16 x, I16 y) public pure {
|
||||
assert(x | y == bitor(x, y)); // FIXME: should hold
|
||||
assert(x & y == bitand(x, y)); // FIXME: should hold
|
||||
assert(x ^ y == bitxor(x, y)); // FIXME: should hold
|
||||
assert(~x == bitnot(x)); // FIXME: should hold
|
||||
}
|
||||
|
||||
function testArithmetic(I16 x, I16 y) public pure {
|
||||
assert(x + y == add(x, y)); // FIXME: should hold
|
||||
assert(x - y == sub(x, y)); // FIXME: should hold
|
||||
assert(-x == unsub(x)); // FIXME: should hold
|
||||
assert(x * y == mul(x, y)); // FIXME: should hold
|
||||
assert(x / y == div(x, y)); // FIXME: should hold
|
||||
assert(x % y == mod(x, y)); // FIXME: should hold
|
||||
}
|
||||
|
||||
function testComparison(I16 x, I16 y) public pure {
|
||||
assert((x == y) == eq(x, y)); // FIXME: should hold
|
||||
assert((x != y) == noteq(x, y)); // FIXME: should hold
|
||||
assert((x < y) == lt(x, y)); // FIXME: should hold
|
||||
assert((x > y) == gt(x, y)); // FIXME: should hold
|
||||
assert((x <= y) == leq(x, y)); // FIXME: should hold
|
||||
assert((x >= y) == geq(x, y)); // FIXME: should hold
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTEngine: all
|
||||
// ----
|
||||
// Warning 6756: (1803-1808): User-defined operators are not yet supported by SMTChecker. This invocation of operator | has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (1803-1823): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (1863-1868): User-defined operators are not yet supported by SMTChecker. This invocation of operator & has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (1863-1884): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (1924-1929): User-defined operators are not yet supported by SMTChecker. This invocation of operator ^ has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (1924-1945): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6156: (1985-1987): User-defined operators are not yet supported by SMTChecker. This invocation of operator ~ has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (1985-2000): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2103-2108): User-defined operators are not yet supported by SMTChecker. This invocation of operator + has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2103-2121): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2161-2166): User-defined operators are not yet supported by SMTChecker. This invocation of operator - has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2161-2179): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6156: (2219-2221): User-defined operators are not yet supported by SMTChecker. This invocation of operator - has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2219-2233): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2273-2278): User-defined operators are not yet supported by SMTChecker. This invocation of operator * has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2273-2291): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2331-2336): User-defined operators are not yet supported by SMTChecker. This invocation of operator / has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2331-2349): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2389-2394): User-defined operators are not yet supported by SMTChecker. This invocation of operator % has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2389-2407): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2511-2517): User-defined operators are not yet supported by SMTChecker. This invocation of operator == has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2571-2577): User-defined operators are not yet supported by SMTChecker. This invocation of operator != has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2634-2639): User-defined operators are not yet supported by SMTChecker. This invocation of operator < has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2693-2698): User-defined operators are not yet supported by SMTChecker. This invocation of operator > has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2752-2758): User-defined operators are not yet supported by SMTChecker. This invocation of operator <= has been ignored, which may lead to incorrect results.
|
||||
// Warning 6756: (2813-2819): User-defined operators are not yet supported by SMTChecker. This invocation of operator >= has been ignored, which may lead to incorrect results.
|
||||
// Warning 3944: (679-708): CHC: Underflow (resulting value less than -32768) happens here.
|
||||
// Warning 4984: (679-708): CHC: Overflow (resulting value larger than 32767) happens here.
|
||||
// Warning 3944: (777-806): CHC: Underflow (resulting value less than -32768) happens here.
|
||||
// Warning 4984: (777-806): CHC: Overflow (resulting value larger than 32767) happens here.
|
||||
// Warning 3944: (953-982): CHC: Underflow (resulting value less than -32768) happens here.
|
||||
// Warning 4984: (953-982): CHC: Overflow (resulting value larger than 32767) happens here.
|
||||
// Warning 4281: (1051-1080): CHC: Division by zero happens here.
|
||||
// Warning 4281: (1149-1178): CHC: Division by zero happens here.
|
||||
// Warning 6328: (1796-1824): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1856-1885): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1917-1946): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (1978-2001): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2096-2122): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2154-2180): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2212-2234): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2266-2292): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2324-2350): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2382-2408): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2503-2531): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2563-2594): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2626-2653): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2685-2712): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2744-2773): CHC: Assertion violation happens here.
|
||||
// Warning 6328: (2805-2834): CHC: Assertion violation happens here.
|
@ -0,0 +1,23 @@
|
||||
type U8 is uint8;
|
||||
using {add as +} for U8 global;
|
||||
|
||||
function add(U8 x, U8 y) pure returns (U8) {
|
||||
return U8.wrap(U8.unwrap(x) + U8.unwrap(y)); // FIXME: should detect possible overflow here
|
||||
}
|
||||
|
||||
contract C {
|
||||
U8 x = U8.wrap(254);
|
||||
|
||||
function inc() public {
|
||||
x = x + U8.wrap(1); // FIXME: should detect possible overflow here
|
||||
}
|
||||
|
||||
function check() view public {
|
||||
U8 y = x;
|
||||
assert(U8.unwrap(y) < 256);
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// SMTEngine: all
|
||||
// ----
|
||||
// Warning 6756: (274-288): User-defined operators are not yet supported by SMTChecker. This invocation of operator + has been ignored, which may lead to incorrect results.
|
@ -0,0 +1,10 @@
|
||||
type Type is uint;
|
||||
using {f as +} for Type global;
|
||||
function f(Type, Type) pure returns (Type) {}
|
||||
|
||||
Type constant t = Type.wrap(1);
|
||||
Type constant u = v + t;
|
||||
Type constant v = u + t;
|
||||
// ----
|
||||
// TypeError 8349: (148-153): Initial value for constant variable has to be compile-time constant.
|
||||
// TypeError 8349: (173-178): Initial value for constant variable has to be compile-time constant.
|
@ -0,0 +1,17 @@
|
||||
type X is uint24;
|
||||
type Y is uint16;
|
||||
|
||||
using {addX as +} for X global;
|
||||
using {addY as +} for Y global;
|
||||
|
||||
function addX(X, X) pure returns (X) {}
|
||||
function addY(Y, Y) pure returns (Y) { revert(); }
|
||||
|
||||
contract C {
|
||||
function f() public pure {
|
||||
X.wrap(1) + X.wrap(Y.unwrap(Y.wrap(2) + Y.wrap(3)));
|
||||
X.wrap(4) + X.wrap(5); // Unreachable
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 5740: (307-328): Unreachable code.
|
@ -0,0 +1,17 @@
|
||||
type X is uint24;
|
||||
type Y is uint16;
|
||||
|
||||
using {unsubX as -} for X global;
|
||||
using {unsubY as -} for Y global;
|
||||
|
||||
function unsubX(X) pure returns (X) {}
|
||||
function unsubY(Y) pure returns (Y) { revert(); }
|
||||
|
||||
contract C {
|
||||
function f() public pure {
|
||||
-X.wrap(Y.unwrap(-Y.wrap(1)));
|
||||
-X.wrap(Y.unwrap(Y.wrap(2))); // Unreachable
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 5740: (287-315): Unreachable code.
|
@ -7,4 +7,4 @@ contract test {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 2271: (79-85): Built-in binary operator == cannot be applied to types struct test.s storage ref and struct test.s storage ref.
|
||||
// TypeError 2271: (79-85): Built-in binary operator == cannot be applied to types struct test.s storage ref and struct test.s storage ref. No matching user-defined operator found.
|
||||
|
@ -0,0 +1,11 @@
|
||||
type Int is int256;
|
||||
|
||||
function f() pure {
|
||||
Int a = Int.wrap(0);
|
||||
a + a;
|
||||
a >>> a;
|
||||
}
|
||||
|
||||
// ----
|
||||
// TypeError 2271: (70-75): Built-in binary operator + cannot be applied to types Int and Int. No matching user-defined operator found.
|
||||
// TypeError 2271: (81-88): Built-in binary operator >>> cannot be applied to types Int and Int.
|
@ -0,0 +1,11 @@
|
||||
type Int is int256;
|
||||
|
||||
function f() pure {
|
||||
Int a = Int.wrap(0);
|
||||
-a;
|
||||
a++;
|
||||
}
|
||||
|
||||
// ----
|
||||
// TypeError 4907: (70-72): Built-in unary operator - cannot be applied to type Int. No matching user-defined operator found.
|
||||
// TypeError 9767: (78-81): Built-in unary operator ++ cannot be applied to type Int.
|
@ -0,0 +1,11 @@
|
||||
type Int is int;
|
||||
using {add as +} for Int global;
|
||||
using {unsub as -} for Int global;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
function unsub(Int) pure returns (Int) {}
|
||||
|
||||
function f() pure {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
type Int is int16;
|
||||
|
||||
using {add as +} for Int global;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
|
||||
function f() {
|
||||
Int a;
|
||||
a.add(a);
|
||||
}
|
||||
// ----
|
||||
// TypeError 9582: (130-135): Member "add" not found or not visible after argument-dependent lookup in Int.
|
@ -0,0 +1,12 @@
|
||||
type Int is int16;
|
||||
|
||||
using {add as +} for Int global;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
|
||||
function f() {
|
||||
Int a;
|
||||
a.+(a);
|
||||
}
|
||||
// ----
|
||||
// ParserError 2314: (132-133): Expected identifier but got '+'
|
@ -0,0 +1,23 @@
|
||||
==== Source: definition.sol ====
|
||||
import "type-and-binding.sol";
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
function unsub(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: type-and-binding.sol ====
|
||||
import "definition.sol";
|
||||
|
||||
type Int is int;
|
||||
|
||||
using {add as +} for Int global;
|
||||
using {unsub as -} for Int global;
|
||||
|
||||
==== Source: use.sol ====
|
||||
import "type-and-binding.sol";
|
||||
|
||||
contract C {
|
||||
function f() pure public {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
==== Source: binding.sol ====
|
||||
import "definition.sol";
|
||||
import "type.sol";
|
||||
|
||||
using {add as +} for Int global;
|
||||
using {unsub as -} for Int global;
|
||||
|
||||
==== Source: definition.sol ====
|
||||
import "type.sol";
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
function unsub(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: type.sol ====
|
||||
type Int is int;
|
||||
|
||||
==== Source: use.sol ====
|
||||
import "type.sol";
|
||||
|
||||
contract C {
|
||||
function f() pure public {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 4117: (binding.sol:45-77): Can only use "global" with types defined in the same source unit at file level.
|
||||
// TypeError 4117: (binding.sol:78-112): Can only use "global" with types defined in the same source unit at file level.
|
||||
// TypeError 2271: (use.sol:72-97): Built-in binary operator + cannot be applied to types Int and Int. No matching user-defined operator found.
|
||||
// TypeError 4907: (use.sol:107-119): Built-in unary operator - cannot be applied to type Int. No matching user-defined operator found.
|
@ -0,0 +1,17 @@
|
||||
==== Source: s1.sol ====
|
||||
type Int is int;
|
||||
using {add as +} for Int global;
|
||||
using {unsub as -} for Int global;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
function unsub(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
|
||||
contract C {
|
||||
function f() pure public {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
==== Source: s1.sol ====
|
||||
type Int is int;
|
||||
using {add as +} for Int;
|
||||
using {unsub as -} for Int;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
function unsub(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
|
||||
contract C {
|
||||
function f() pure public {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3320: (s1.sol:24-27): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 3320: (s1.sol:50-55): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 2271: (s2.sol:70-95): Built-in binary operator + cannot be applied to types Int and Int. No matching user-defined operator found.
|
||||
// TypeError 4907: (s2.sol:105-117): Built-in unary operator - cannot be applied to type Int. No matching user-defined operator found.
|
@ -0,0 +1,35 @@
|
||||
==== Source: s0.sol ====
|
||||
type Int is int;
|
||||
|
||||
==== Source: s1.sol ====
|
||||
import "s0.sol";
|
||||
using {add1 as +} for Int global;
|
||||
using {unsub1 as -} for Int global;
|
||||
|
||||
function add1(Int, Int) pure returns (Int) {}
|
||||
function unsub1(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: s2.sol ====
|
||||
import "s0.sol";
|
||||
using {add2 as +} for Int global;
|
||||
using {unsub2 as -} for Int global;
|
||||
|
||||
function add2(Int, Int) pure returns (Int) {}
|
||||
function unsub2(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: s3.sol ====
|
||||
import "s1.sol";
|
||||
import "s2.sol";
|
||||
contract C {
|
||||
function f() public {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 4117: (s1.sol:17-50): Can only use "global" with types defined in the same source unit at file level.
|
||||
// TypeError 4117: (s1.sol:51-86): Can only use "global" with types defined in the same source unit at file level.
|
||||
// TypeError 4117: (s2.sol:17-50): Can only use "global" with types defined in the same source unit at file level.
|
||||
// TypeError 4117: (s2.sol:51-86): Can only use "global" with types defined in the same source unit at file level.
|
||||
// TypeError 2271: (s3.sol:81-106): Built-in binary operator + cannot be applied to types Int and Int. No matching user-defined operator found.
|
||||
// TypeError 4907: (s3.sol:116-128): Built-in unary operator - cannot be applied to type Int. No matching user-defined operator found.
|
@ -0,0 +1,35 @@
|
||||
==== Source: s0.sol ====
|
||||
type Int is int;
|
||||
|
||||
==== Source: s1.sol ====
|
||||
import "s0.sol";
|
||||
using {add1 as +} for Int;
|
||||
using {unsub1 as -} for Int;
|
||||
|
||||
function add1(Int, Int) pure returns (Int) {}
|
||||
function unsub1(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: s2.sol ====
|
||||
import "s0.sol";
|
||||
using {add2 as +} for Int;
|
||||
using {unsub2 as -} for Int;
|
||||
|
||||
function add2(Int, Int) pure returns (Int) {}
|
||||
function unsub2(Int) pure returns (Int) {}
|
||||
|
||||
==== Source: s3.sol ====
|
||||
import "s1.sol";
|
||||
import "s2.sol";
|
||||
contract C {
|
||||
function f() public {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3320: (s1.sol:24-28): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 3320: (s1.sol:51-57): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 3320: (s2.sol:24-28): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 3320: (s2.sol:51-57): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 2271: (s3.sol:81-106): Built-in binary operator + cannot be applied to types Int and Int. No matching user-defined operator found.
|
||||
// TypeError 4907: (s3.sol:116-128): Built-in unary operator - cannot be applied to type Int. No matching user-defined operator found.
|
@ -0,0 +1,24 @@
|
||||
type B4 is bytes4;
|
||||
using {bitor as |, bitnot as ~} for B4 global;
|
||||
|
||||
function bitor(B4, B4) pure returns (B4) {}
|
||||
function bitnot(B4) pure returns (B4) {}
|
||||
|
||||
B4 constant X = B4.wrap(0x12345678) | B4.wrap(0xaabbccdd);
|
||||
|
||||
contract C {
|
||||
B4 constant Y = B4.wrap(0x12345678) | B4.wrap(0xaabbccdd);
|
||||
}
|
||||
|
||||
library L {
|
||||
B4 constant Z = ~B4.wrap(0x12345678);
|
||||
}
|
||||
|
||||
interface I {
|
||||
B4 constant W = ~B4.wrap(0x12345678);
|
||||
}
|
||||
// ----
|
||||
// TypeError 8349: (169-210): Initial value for constant variable has to be compile-time constant.
|
||||
// TypeError 8349: (246-287): Initial value for constant variable has to be compile-time constant.
|
||||
// TypeError 8349: (324-344): Initial value for constant variable has to be compile-time constant.
|
||||
// TypeError 8349: (383-403): Initial value for constant variable has to be compile-time constant.
|
@ -0,0 +1,14 @@
|
||||
type Int is int;
|
||||
using {add as +} for Int;
|
||||
using {unsub as -} for Int;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
function unsub(Int) pure returns (Int) {}
|
||||
|
||||
function f() pure {
|
||||
Int.wrap(0) + Int.wrap(0);
|
||||
-Int.wrap(0);
|
||||
}
|
||||
// ----
|
||||
// TypeError 3320: (24-27): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 3320: (50-55): Operators can only be defined in a global 'using for' directive.
|
@ -0,0 +1,24 @@
|
||||
type Int is int16;
|
||||
|
||||
using {add as +} for Int global;
|
||||
|
||||
function add(Int, Int) returns (Int) {
|
||||
B b = new B();
|
||||
return b.f();
|
||||
}
|
||||
|
||||
contract B {
|
||||
Int s;
|
||||
function f() external returns (Int) {
|
||||
s = Int.wrap(3);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
function test() public returns (Int) {
|
||||
return Int.wrap(0) + Int.wrap(0);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 7775: (27-30): Only pure free functions can be used to define operators.
|
@ -0,0 +1,20 @@
|
||||
type Int is int16;
|
||||
using {add as +, unsub as -} for Int global;
|
||||
|
||||
IAdder constant ADDER = IAdder(address(0));
|
||||
|
||||
function add(Int x, Int y) pure returns (Int) {
|
||||
return ADDER.mul(x, y);
|
||||
}
|
||||
|
||||
function unsub(Int x) pure returns (Int) {
|
||||
return ADDER.inc(x);
|
||||
}
|
||||
|
||||
interface IAdder {
|
||||
function mul(Int, Int) external returns (Int);
|
||||
function inc(Int) external returns (Int);
|
||||
}
|
||||
// ----
|
||||
// TypeError 8961: (169-184): Function cannot be declared as pure because this expression (potentially) modifies the state.
|
||||
// TypeError 8961: (243-255): Function cannot be declared as pure because this expression (potentially) modifies the state.
|
@ -0,0 +1,17 @@
|
||||
type Int is int16;
|
||||
using {add as +, unsub as -} for Int global;
|
||||
|
||||
IAdder constant ADDER = IAdder(address(0));
|
||||
|
||||
function add(Int x, Int y) pure returns (Int) {
|
||||
return ADDER.mul(x, y);
|
||||
}
|
||||
|
||||
function unsub(Int x) pure returns (Int) {
|
||||
return ADDER.inc(x);
|
||||
}
|
||||
|
||||
interface IAdder {
|
||||
function mul(Int, Int) external pure returns (Int);
|
||||
function inc(Int) external pure returns (Int);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
type Int is int16;
|
||||
using {add as +, unsub as -} for Int global;
|
||||
|
||||
IAdder constant ADDER = IAdder(address(0));
|
||||
|
||||
function add(Int x, Int y) pure returns (Int) {
|
||||
return ADDER.mul(x, y);
|
||||
}
|
||||
|
||||
function unsub(Int x) pure returns (Int) {
|
||||
return ADDER.inc(x);
|
||||
}
|
||||
|
||||
interface IAdder {
|
||||
function mul(Int, Int) external view returns (Int);
|
||||
function inc(Int) external view returns (Int);
|
||||
}
|
||||
// ----
|
||||
// TypeError 2527: (169-184): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
|
||||
// TypeError 2527: (243-255): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
|
@ -0,0 +1,32 @@
|
||||
using {add as +, unsub as -} for U global;
|
||||
|
||||
type U is uint;
|
||||
|
||||
function add(U, U) pure returns (U) {}
|
||||
function unsub(U) pure returns (U) {}
|
||||
|
||||
contract C {
|
||||
function fromBool() public {
|
||||
U u;
|
||||
|
||||
u + true;
|
||||
true + u;
|
||||
-true;
|
||||
}
|
||||
|
||||
function fromUint() public {
|
||||
U u;
|
||||
uint32 u32;
|
||||
|
||||
u + u32;
|
||||
u32 + u;
|
||||
-u32;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 5653: (207-215): The type of the second operand of this user-defined binary operator + does not match the type of the first operand, which is U.
|
||||
// TypeError 2271: (225-233): Built-in binary operator + cannot be applied to types bool and U.
|
||||
// TypeError 4907: (243-248): Built-in unary operator - cannot be applied to type bool.
|
||||
// TypeError 5653: (332-339): The type of the second operand of this user-defined binary operator + does not match the type of the first operand, which is U.
|
||||
// TypeError 2271: (349-356): Built-in binary operator + cannot be applied to types uint32 and U.
|
||||
// TypeError 4907: (366-370): Built-in unary operator - cannot be applied to type uint32. Unary negation is only allowed for signed integers.
|
@ -0,0 +1,18 @@
|
||||
using {f as +} for uint global;
|
||||
using {f as +} for uint[2] global;
|
||||
using {f as +} for mapping(uint => uint) global;
|
||||
using {f as +} for function (uint) pure returns (uint) global;
|
||||
using {f as +} for string global;
|
||||
|
||||
function f(uint, uint) pure returns (uint) {}
|
||||
// ----
|
||||
// TypeError 8841: (0-31): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (7-8): Operators can only be implemented for user-defined value types.
|
||||
// TypeError 8841: (32-66): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (39-40): Operators can only be implemented for user-defined value types.
|
||||
// TypeError 8841: (67-115): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (74-75): Operators can only be implemented for user-defined value types.
|
||||
// TypeError 8841: (116-178): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (123-124): Operators can only be implemented for user-defined value types.
|
||||
// TypeError 8841: (179-212): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (186-187): Operators can only be implemented for user-defined value types.
|
@ -0,0 +1,13 @@
|
||||
using {fc as +} for C global;
|
||||
using {fa as +} for A global;
|
||||
|
||||
function fc(C, C) pure returns (C) {}
|
||||
function fa(A, A) pure returns (A) {}
|
||||
|
||||
contract C {}
|
||||
abstract contract A {}
|
||||
// ----
|
||||
// TypeError 8841: (0-29): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (7-9): Operators can only be implemented for user-defined value types.
|
||||
// TypeError 8841: (30-59): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (37-39): Operators can only be implemented for user-defined value types.
|
@ -0,0 +1,10 @@
|
||||
using {add as +} for E global;
|
||||
|
||||
enum E {
|
||||
E1,
|
||||
E2
|
||||
}
|
||||
|
||||
function add(E, E) pure returns (E) {}
|
||||
// ----
|
||||
// TypeError 5332: (7-10): Operators can only be implemented for user-defined value types.
|
@ -0,0 +1,10 @@
|
||||
using {add as +} for E global;
|
||||
|
||||
error E();
|
||||
|
||||
function add(E, E) pure returns (E) {
|
||||
return E.E1;
|
||||
}
|
||||
|
||||
// ----
|
||||
// TypeError 5172: (21-22): Name has to refer to a user-defined type.
|
@ -0,0 +1,10 @@
|
||||
using {add as +} for C.Event global;
|
||||
|
||||
contract C {
|
||||
event Event();
|
||||
}
|
||||
|
||||
function add(C.Event, C.Event) pure returns (C.Event) {}
|
||||
|
||||
// ----
|
||||
// TypeError 5172: (21-28): Name has to refer to a user-defined type.
|
@ -0,0 +1,8 @@
|
||||
using {f as +} for I global;
|
||||
|
||||
function f(I, I) pure returns (I) {}
|
||||
|
||||
interface I {}
|
||||
// ----
|
||||
// TypeError 8841: (0-28): Can only use "global" with user-defined types.
|
||||
// TypeError 5332: (7-8): Operators can only be implemented for user-defined value types.
|
@ -0,0 +1,6 @@
|
||||
using {f as +} for L global;
|
||||
|
||||
function f() pure {}
|
||||
library L {}
|
||||
// ----
|
||||
// TypeError 1130: (19-20): Invalid use of a library name.
|
@ -0,0 +1,9 @@
|
||||
using {add as +} for S global;
|
||||
|
||||
struct S {
|
||||
uint x;
|
||||
}
|
||||
|
||||
function add(S memory, S memory) pure returns (S memory) {}
|
||||
// ----
|
||||
// TypeError 5332: (7-10): Operators can only be implemented for user-defined value types.
|
@ -0,0 +1,16 @@
|
||||
type Int is int;
|
||||
|
||||
function add(Int, Int) pure returns (Int) {}
|
||||
|
||||
contract C {
|
||||
using {add as +} for *;
|
||||
}
|
||||
|
||||
contract D {
|
||||
using {add as +} for * global;
|
||||
}
|
||||
// ----
|
||||
// SyntaxError 3349: (81-104): The type has to be specified explicitly when attaching specific functions.
|
||||
// SyntaxError 3349: (125-155): The type has to be specified explicitly when attaching specific functions.
|
||||
// SyntaxError 2854: (125-155): Can only globally attach functions to specific types.
|
||||
// SyntaxError 3367: (125-155): "global" can only be used at file level.
|
@ -0,0 +1,6 @@
|
||||
using {add as +} for * global;
|
||||
|
||||
function add(int, int) returns (int) {}
|
||||
// ----
|
||||
// SyntaxError 8118: (0-30): The type has to be specified explicitly at file level (cannot use '*').
|
||||
// SyntaxError 2854: (0-30): Can only globally attach functions to specific types.
|
@ -0,0 +1,9 @@
|
||||
type Int is uint;
|
||||
using {f} for Int;
|
||||
|
||||
Int constant v;
|
||||
using {v.f as +} for Int global;
|
||||
|
||||
function f(Int) pure returns (Int) {}
|
||||
// ----
|
||||
// DeclarationError 9589: (61-64): Identifier is not a function name or not unique.
|
@ -0,0 +1,8 @@
|
||||
type Int is int16;
|
||||
|
||||
using {abi.encode as +} for Int global;
|
||||
|
||||
function f(Int, Int) pure returns (Int) {}
|
||||
|
||||
// ----
|
||||
// DeclarationError 9589: (27-37): Identifier is not a function name or not unique.
|
@ -0,0 +1,5 @@
|
||||
type Int is int16;
|
||||
|
||||
using {keccak256 as +} for Int global;
|
||||
// ----
|
||||
// TypeError 8187: (27-36): Expected function name.
|
@ -0,0 +1,5 @@
|
||||
type Int is int16;
|
||||
|
||||
using {revert as +} for Int global;
|
||||
// ----
|
||||
// DeclarationError 9589: (27-33): Identifier is not a function name or not unique.
|
@ -0,0 +1,9 @@
|
||||
type Int is int;
|
||||
|
||||
contract C {
|
||||
using {add as +} for Int;
|
||||
|
||||
function add(Int, Int) public pure returns (Int) {}
|
||||
}
|
||||
// ----
|
||||
// TypeError 4167: (42-45): Only file-level functions and library functions can be attached to a type in a "using" statement
|
@ -0,0 +1,11 @@
|
||||
type Int is int;
|
||||
|
||||
using {C.add as +} for Int global;
|
||||
|
||||
contract C {
|
||||
function add(Int, Int) public pure returns (Int) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 4167: (25-30): Only file-level functions and library functions can be attached to a type in a "using" statement
|
@ -0,0 +1,7 @@
|
||||
type Int is int16;
|
||||
|
||||
using {IntError as +} for Int global;
|
||||
|
||||
error IntError(Int a, Int b);
|
||||
// ----
|
||||
// TypeError 8187: (27-35): Expected function name.
|
@ -0,0 +1,9 @@
|
||||
type Int is int16;
|
||||
|
||||
using {C.IntEvent as +} for Int global;
|
||||
|
||||
contract C {
|
||||
event IntEvent(Int a, Int b);
|
||||
}
|
||||
// ----
|
||||
// TypeError 8187: (27-37): Expected function name.
|
@ -0,0 +1,8 @@
|
||||
type Int is int8;
|
||||
|
||||
contract C {
|
||||
function(Int, Int) external pure returns (Int) ptr;
|
||||
using {ptr as +} for Int;
|
||||
}
|
||||
// ----
|
||||
// TypeError 8187: (99-102): Expected function name.
|
@ -0,0 +1,9 @@
|
||||
type Int is int16;
|
||||
|
||||
using {keccak256 as +} for Int global;
|
||||
|
||||
function keccak256(Int, Int) pure returns (Int) {
|
||||
return Int.wrap(0);
|
||||
}
|
||||
// ----
|
||||
// Warning 2319: (60-135): This declaration shadows a builtin symbol.
|
@ -0,0 +1,7 @@
|
||||
type Int is int16;
|
||||
|
||||
using {L as +} for Int global;
|
||||
|
||||
library L {}
|
||||
// ----
|
||||
// TypeError 8187: (27-28): Expected function name.
|
@ -0,0 +1,113 @@
|
||||
==== Source: external.sol ====
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) external pure returns (Int) {}
|
||||
function unaryOperator(Int) external pure returns (Int) {}
|
||||
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
contract C {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
library X {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
==== Source: internal.sol ====
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) internal pure returns (Int) {}
|
||||
function unaryOperator(Int) internal pure returns (Int) {}
|
||||
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
contract C {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
library X {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
==== Source: private.sol ====
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) private pure returns (Int) {}
|
||||
function unaryOperator(Int) private pure returns (Int) {}
|
||||
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
==== Source: public.sol ====
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) public pure returns (Int) {}
|
||||
function unaryOperator(Int) public pure returns (Int) {}
|
||||
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
contract C {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
library X {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
// ----
|
||||
// TypeError 3320: (external.sol:177-193): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (external.sol:177-193): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (external.sol:220-235): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (external.sol:220-235): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (external.sol:278-294): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (external.sol:278-294): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (external.sol:321-336): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (external.sol:321-336): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (external.sol:378-394): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (external.sol:378-394): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (external.sol:421-436): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (external.sol:421-436): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (internal.sol:177-193): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (internal.sol:177-193): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (internal.sol:220-235): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (internal.sol:220-235): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (internal.sol:278-294): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (internal.sol:278-294): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (internal.sol:321-336): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (internal.sol:321-336): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (internal.sol:378-394): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (internal.sol:378-394): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (internal.sol:421-436): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (internal.sol:421-436): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (private.sol:175-191): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (private.sol:175-191): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (private.sol:218-233): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (private.sol:218-233): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (public.sol:173-189): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (public.sol:173-189): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (public.sol:216-231): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (public.sol:216-231): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (public.sol:274-290): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (public.sol:274-290): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (public.sol:317-332): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (public.sol:317-332): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (public.sol:374-390): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (public.sol:374-390): Only pure free functions can be used to define operators.
|
||||
// TypeError 3320: (public.sol:417-432): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (public.sol:417-432): Only pure free functions can be used to define operators.
|
@ -0,0 +1,39 @@
|
||||
==== Source: external.sol ====
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) external pure returns (Int) {}
|
||||
function unaryOperator(Int) external pure returns (Int) {}
|
||||
}
|
||||
|
||||
using {L.binaryOperator as +} for Int global;
|
||||
using {L.unaryOperator as -} for Int global;
|
||||
|
||||
==== Source: internal.sol ====
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) internal pure returns (Int) {}
|
||||
function unaryOperator(Int) internal pure returns (Int) {}
|
||||
}
|
||||
|
||||
using {L.binaryOperator as +} for Int global;
|
||||
using {L.unaryOperator as -} for Int global;
|
||||
|
||||
==== Source: public.sol ====
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) public pure returns (Int) {}
|
||||
function unaryOperator(Int) public pure returns (Int) {}
|
||||
}
|
||||
|
||||
using {L.binaryOperator as +} for Int global;
|
||||
using {L.unaryOperator as -} for Int global;
|
||||
// ----
|
||||
// TypeError 7775: (external.sol:175-191): Only pure free functions can be used to define operators.
|
||||
// TypeError 7775: (external.sol:221-236): Only pure free functions can be used to define operators.
|
||||
// TypeError 7775: (internal.sol:175-191): Only pure free functions can be used to define operators.
|
||||
// TypeError 7775: (internal.sol:221-236): Only pure free functions can be used to define operators.
|
||||
// TypeError 7775: (public.sol:171-187): Only pure free functions can be used to define operators.
|
||||
// TypeError 7775: (public.sol:217-232): Only pure free functions can be used to define operators.
|
@ -0,0 +1,36 @@
|
||||
type Int is int128;
|
||||
|
||||
library L {
|
||||
function binaryOperator(Int, Int) private pure returns (Int) {}
|
||||
function unaryOperator(Int) private pure returns (Int) {}
|
||||
}
|
||||
|
||||
using {L.binaryOperator as +} for Int global;
|
||||
using {L.unaryOperator as -} for Int global;
|
||||
|
||||
contract C {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
|
||||
library X {
|
||||
using {L.binaryOperator as *} for Int;
|
||||
using {L.unaryOperator as ~} for Int;
|
||||
}
|
||||
// ----
|
||||
// TypeError 6772: (173-189): Function "L.binaryOperator" is private and therefore cannot be attached to a type outside of the library where it is defined.
|
||||
// TypeError 7775: (173-189): Only pure free functions can be used to define operators.
|
||||
// TypeError 6772: (219-234): Function "L.unaryOperator" is private and therefore cannot be attached to a type outside of the library where it is defined.
|
||||
// TypeError 7775: (219-234): Only pure free functions can be used to define operators.
|
||||
// TypeError 6772: (282-298): Function "L.binaryOperator" is private and therefore cannot be attached to a type outside of the library where it is defined.
|
||||
// TypeError 3320: (282-298): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (282-298): Only pure free functions can be used to define operators.
|
||||
// TypeError 6772: (325-340): Function "L.unaryOperator" is private and therefore cannot be attached to a type outside of the library where it is defined.
|
||||
// TypeError 3320: (325-340): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (325-340): Only pure free functions can be used to define operators.
|
||||
// TypeError 6772: (382-398): Function "L.binaryOperator" is private and therefore cannot be attached to a type outside of the library where it is defined.
|
||||
// TypeError 3320: (382-398): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (382-398): Only pure free functions can be used to define operators.
|
||||
// TypeError 6772: (425-440): Function "L.unaryOperator" is private and therefore cannot be attached to a type outside of the library where it is defined.
|
||||
// TypeError 3320: (425-440): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (425-440): Only pure free functions can be used to define operators.
|
@ -0,0 +1,12 @@
|
||||
using {add as +, sub as -, mul as *} for A global;
|
||||
|
||||
function add(A, A) view returns (A) {}
|
||||
function sub(A, A) returns (A) {}
|
||||
function mul(A, A) payable returns (A) {}
|
||||
|
||||
type A is address payable;
|
||||
// ----
|
||||
// TypeError 7775: (7-10): Only pure free functions can be used to define operators.
|
||||
// TypeError 7775: (17-20): Only pure free functions can be used to define operators.
|
||||
// TypeError 7775: (27-30): Only pure free functions can be used to define operators.
|
||||
// TypeError 9559: (125-166): Free functions cannot be payable.
|
@ -0,0 +1,8 @@
|
||||
// This should point out all 3 errors, rather than give up after the first one.
|
||||
using {add as +} for address;
|
||||
|
||||
function add(address, address) view returns (address) {}
|
||||
// ----
|
||||
// TypeError 3320: (87-90): Operators can only be defined in a global 'using for' directive.
|
||||
// TypeError 7775: (87-90): Only pure free functions can be used to define operators.
|
||||
// TypeError 5332: (87-90): Operators can only be implemented for user-defined value types.
|
@ -0,0 +1,10 @@
|
||||
using {add as +} for A global;
|
||||
using {add as +} for AP global;
|
||||
|
||||
function add(A, A) pure returns (A) {}
|
||||
function add(AP, AP) pure returns (AP) {}
|
||||
|
||||
type A is address;
|
||||
type AP is address payable;
|
||||
// ----
|
||||
// DeclarationError 9589: (7-10): Identifier is not a function name or not unique.
|
@ -0,0 +1,12 @@
|
||||
using {L.add as +} for A global;
|
||||
using {L.add as +} for AP global;
|
||||
|
||||
library L {
|
||||
function add(A, A) private pure returns (A) {}
|
||||
function add(AP, AP) internal pure returns (AP) {}
|
||||
}
|
||||
|
||||
type A is address;
|
||||
type AP is address payable;
|
||||
// ----
|
||||
// DeclarationError 9589: (7-12): Identifier is not a function name or not unique.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user