mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Unary operators with using for directive fix
This commit is contained in:
@@ -1733,7 +1733,8 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
|
||||
// Check if the operator is built-in or user-defined.
|
||||
FunctionDefinition const* userDefinedOperator = subExprType->userDefinedOperator(
|
||||
_operation.getOperator(),
|
||||
*currentDefinitionScope()
|
||||
*currentDefinitionScope(),
|
||||
true // _unaryOperation
|
||||
);
|
||||
_operation.annotation().userDefinedFunction = userDefinedOperator;
|
||||
FunctionType const* userDefinedFunctionType = nullptr;
|
||||
@@ -1791,7 +1792,8 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
||||
// Check if the operator is built-in or user-defined.
|
||||
FunctionDefinition const* userDefinedOperator = leftType->userDefinedOperator(
|
||||
_operation.getOperator(),
|
||||
*currentDefinitionScope()
|
||||
*currentDefinitionScope(),
|
||||
false // _unaryOperation
|
||||
);
|
||||
_operation.annotation().userDefinedFunction = userDefinedOperator;
|
||||
FunctionType const* userDefinedFunctionType = nullptr;
|
||||
@@ -3899,15 +3901,10 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// "-" can be used as unary and binary operator.
|
||||
bool isUnaryNegation = (
|
||||
operator_ == Token::Sub &&
|
||||
functionType->parameterTypesIncludingSelf().size() == 1
|
||||
);
|
||||
|
||||
if (
|
||||
(
|
||||
(TokenTraits::isBinaryOp(*operator_) && !isUnaryNegation) ||
|
||||
TokenTraits::isCompareOp(*operator_)
|
||||
(TokenTraits::isBinaryOp(*operator_) && !TokenTraits::isUnaryOp(*operator_)) || TokenTraits::isCompareOp(*operator_)
|
||||
) &&
|
||||
(
|
||||
functionType->parameterTypesIncludingSelf().size() != 2 ||
|
||||
|
||||
@@ -384,7 +384,7 @@ vector<UsingForDirective const*> usingForDirectivesForType(Type const& _type, AS
|
||||
|
||||
}
|
||||
|
||||
FunctionDefinition const* Type::userDefinedOperator(Token _token, ASTNode const& _scope) const
|
||||
FunctionDefinition const* Type::userDefinedOperator(Token _token, ASTNode const& _scope, bool _unaryOperation) const
|
||||
{
|
||||
// Check if it is a user-defined type.
|
||||
if (!typeDefinition())
|
||||
@@ -405,8 +405,11 @@ FunctionDefinition const* Type::userDefinedOperator(Token _token, ASTNode const&
|
||||
solAssert(functionType && !functionType->parameterTypes().empty());
|
||||
// TODO does this work (data location)?
|
||||
solAssert(isImplicitlyConvertibleTo(*functionType->parameterTypes().front()));
|
||||
seenFunctions.insert(&function);
|
||||
if ((_unaryOperation && function.parameterList().parameters().size() == 1) ||
|
||||
(!_unaryOperation && function.parameterList().parameters().size() == 2))
|
||||
seenFunctions.insert(&function);
|
||||
}
|
||||
|
||||
// TODO proper error handling.
|
||||
if (seenFunctions.size() == 1)
|
||||
return *seenFunctions.begin();
|
||||
|
||||
@@ -377,7 +377,7 @@ public:
|
||||
/// Clears all internally cached values (if any).
|
||||
virtual void clearCache() const;
|
||||
|
||||
FunctionDefinition const* userDefinedOperator(Token _token, ASTNode const& _scope) const;
|
||||
FunctionDefinition const* userDefinedOperator(Token _token, ASTNode const& _scope, bool _unaryOperation) const;
|
||||
|
||||
private:
|
||||
/// @returns a member list containing all members added to this type by `using for` directives.
|
||||
|
||||
@@ -410,6 +410,47 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
||||
bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _unaryOperation);
|
||||
|
||||
if (_unaryOperation.annotation().userDefinedFunction)
|
||||
{
|
||||
FunctionDefinition const& function = *_unaryOperation.annotation().userDefinedFunction;
|
||||
FunctionType const* functionType = dynamic_cast<FunctionType const*>(
|
||||
function.libraryFunction() ? function.typeViaContractName() : function.type());
|
||||
|
||||
solAssert(functionType);
|
||||
functionType = dynamic_cast<FunctionType const&>(*functionType).asBoundFunction();
|
||||
solAssert(functionType);
|
||||
evmasm::AssemblyItem returnLabel = m_context.pushNewTag();
|
||||
_unaryOperation.subExpression().accept(*this);
|
||||
utils().pushCombinedFunctionEntryLabel(
|
||||
function.resolveVirtual(m_context.mostDerivedContract()),
|
||||
false
|
||||
);
|
||||
|
||||
unsigned parameterSize =
|
||||
CompilerUtils::sizeOnStack(functionType->parameterTypes()) +
|
||||
functionType->selfType()->sizeOnStack();
|
||||
|
||||
if (m_context.runtimeContext())
|
||||
// We have a runtime context, so we need the creation part.
|
||||
utils().rightShiftNumberOnStack(32);
|
||||
else
|
||||
// Extract the runtime part.
|
||||
m_context << ((u256(1) << 32) - 1) << Instruction::AND;
|
||||
|
||||
m_context.appendJump(evmasm::AssemblyItem::JumpType::IntoFunction);
|
||||
m_context << returnLabel;
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -672,6 +672,34 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
|
||||
bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation)
|
||||
{
|
||||
setLocation(_unaryOperation);
|
||||
|
||||
if (_unaryOperation.annotation().userDefinedFunction)
|
||||
{
|
||||
_unaryOperation.subExpression().accept(*this);
|
||||
setLocation(_unaryOperation);
|
||||
|
||||
// TODO extract from function call
|
||||
FunctionDefinition const& function = *_unaryOperation.annotation().userDefinedFunction;
|
||||
FunctionType const* functionType = dynamic_cast<FunctionType const*>(
|
||||
function.libraryFunction() ? function.typeViaContractName() : function.type()
|
||||
);
|
||||
solAssert(functionType);
|
||||
functionType = dynamic_cast<FunctionType const&>(*functionType).asBoundFunction();
|
||||
solAssert(functionType);
|
||||
|
||||
// TODO virtual?
|
||||
|
||||
string parameter = expressionAsType(_unaryOperation.subExpression(), *functionType->selfType());
|
||||
solAssert(!parameter.empty());
|
||||
solAssert(function.isImplemented(), "");
|
||||
|
||||
define(_unaryOperation) <<
|
||||
m_context.enqueueFunctionForCodeGeneration(function) <<
|
||||
("(" + parameter + ")\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Type const& resultType = type(_unaryOperation);
|
||||
Token const op = _unaryOperation.getOperator();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user