mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #13739 from ethereum/code-reshuffling-before-operators
Code reshuffling before custom operators
This commit is contained in:
commit
33f27098e9
@ -1751,7 +1751,9 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
|
|||||||
else
|
else
|
||||||
_operation.annotation().type = result.get();
|
_operation.annotation().type = result.get();
|
||||||
_operation.annotation().isConstant = false;
|
_operation.annotation().isConstant = false;
|
||||||
_operation.annotation().isPure = !modifying && *_operation.subExpression().annotation().isPure;
|
_operation.annotation().isPure =
|
||||||
|
!modifying &&
|
||||||
|
*_operation.subExpression().annotation().isPure;
|
||||||
_operation.annotation().isLValue = false;
|
_operation.annotation().isLValue = false;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -3750,8 +3752,9 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
|||||||
solAssert(m_errorReporter.hasErrors());
|
solAssert(m_errorReporter.hasErrors());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
solAssert(_usingFor.typeName()->annotation().type);
|
Type const* usingForType = _usingFor.typeName()->annotation().type;
|
||||||
if (Declaration const* typeDefinition = _usingFor.typeName()->annotation().type->typeDefinition())
|
solAssert(usingForType);
|
||||||
|
if (Declaration const* typeDefinition = usingForType->typeDefinition())
|
||||||
{
|
{
|
||||||
if (typeDefinition->scope() != m_currentSourceUnit)
|
if (typeDefinition->scope() != m_currentSourceUnit)
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -3785,10 +3788,12 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
solAssert(_usingFor.typeName()->annotation().type);
|
Type const* usingForType = _usingFor.typeName()->annotation().type;
|
||||||
|
solAssert(usingForType);
|
||||||
|
|
||||||
Type const* normalizedType = TypeProvider::withLocationIfReference(
|
Type const* normalizedType = TypeProvider::withLocationIfReference(
|
||||||
DataLocation::Storage,
|
DataLocation::Storage,
|
||||||
_usingFor.typeName()->annotation().type
|
usingForType
|
||||||
);
|
);
|
||||||
solAssert(normalizedType);
|
solAssert(normalizedType);
|
||||||
|
|
||||||
@ -3824,7 +3829,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
|||||||
"The function \"{}\" cannot be bound to the type \"{}\" because the type cannot "
|
"The function \"{}\" cannot be bound to the type \"{}\" because the type cannot "
|
||||||
"be implicitly converted to the first argument of the function (\"{}\"){}",
|
"be implicitly converted to the first argument of the function (\"{}\"){}",
|
||||||
joinHumanReadable(path->path(), "."),
|
joinHumanReadable(path->path(), "."),
|
||||||
_usingFor.typeName()->annotation().type->toString(true /* withoutDataLocation */),
|
usingForType->toString(true /* withoutDataLocation */),
|
||||||
functionType->selfType()->humanReadableName(),
|
functionType->selfType()->humanReadableName(),
|
||||||
result.message().empty() ? "." : ": " + result.message()
|
result.message().empty() ? "." : ": " + result.message()
|
||||||
)
|
)
|
||||||
|
@ -323,16 +323,23 @@ ViewPureChecker::MutabilityAndLocation const& ViewPureChecker::modifierMutabilit
|
|||||||
return m_inferredMutability.at(&_modifier);
|
return m_inferredMutability.at(&_modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewPureChecker::reportFunctionCallMutability(StateMutability _mutability, langutil::SourceLocation const& _location)
|
||||||
|
{
|
||||||
|
// We only require "nonpayable" to call a payable function.
|
||||||
|
if (_mutability == StateMutability::Payable)
|
||||||
|
_mutability = StateMutability::NonPayable;
|
||||||
|
reportMutability(_mutability, _location);
|
||||||
|
}
|
||||||
|
|
||||||
void ViewPureChecker::endVisit(FunctionCall const& _functionCall)
|
void ViewPureChecker::endVisit(FunctionCall const& _functionCall)
|
||||||
{
|
{
|
||||||
if (*_functionCall.annotation().kind != FunctionCallKind::FunctionCall)
|
if (*_functionCall.annotation().kind != FunctionCallKind::FunctionCall)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StateMutability mutability = dynamic_cast<FunctionType const&>(*_functionCall.expression().annotation().type).stateMutability();
|
reportFunctionCallMutability(
|
||||||
// We only require "nonpayable" to call a payble function.
|
dynamic_cast<FunctionType const&>(*_functionCall.expression().annotation().type).stateMutability(),
|
||||||
if (mutability == StateMutability::Payable)
|
_functionCall.location()
|
||||||
mutability = StateMutability::NonPayable;
|
);
|
||||||
reportMutability(mutability, _functionCall.location());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViewPureChecker::visit(MemberAccess const& _memberAccess)
|
bool ViewPureChecker::visit(MemberAccess const& _memberAccess)
|
||||||
|
@ -73,6 +73,8 @@ private:
|
|||||||
std::optional<langutil::SourceLocation> const& _nestedLocation = {}
|
std::optional<langutil::SourceLocation> const& _nestedLocation = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void reportFunctionCallMutability(StateMutability _mutability, langutil::SourceLocation const& _location);
|
||||||
|
|
||||||
/// Determines the mutability of modifier if not already cached.
|
/// Determines the mutability of modifier if not already cached.
|
||||||
MutabilityAndLocation const& modifierMutability(ModifierDefinition const& _modifier);
|
MutabilityAndLocation const& modifierMutability(ModifierDefinition const& _modifier);
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include <range/v3/view/reverse.hpp>
|
#include <range/v3/view/reverse.hpp>
|
||||||
#include <range/v3/view/tail.hpp>
|
#include <range/v3/view/tail.hpp>
|
||||||
#include <range/v3/view/transform.hpp>
|
#include <range/v3/view/transform.hpp>
|
||||||
|
#include <range/v3/view/filter.hpp>
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
@ -337,7 +338,10 @@ Type const* Type::fullEncodingType(bool _inLibraryCall, bool _encoderV2, bool) c
|
|||||||
return encodingType;
|
return encodingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope)
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
vector<UsingForDirective const*> usingForDirectivesForType(Type const& _type, ASTNode const& _scope)
|
||||||
{
|
{
|
||||||
vector<UsingForDirective const*> usingForDirectives;
|
vector<UsingForDirective const*> usingForDirectives;
|
||||||
SourceUnit const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope);
|
SourceUnit const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope);
|
||||||
@ -362,6 +366,25 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc
|
|||||||
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
|
if (auto refType = dynamic_cast<ReferenceType const*>(&_type))
|
||||||
typeLocation = refType->location();
|
typeLocation = refType->location();
|
||||||
|
|
||||||
|
return usingForDirectives | ranges::views::filter([&](UsingForDirective const* _directive) -> bool {
|
||||||
|
// Convert both types to pointers for comparison to see if the `using for` directive applies.
|
||||||
|
// Note that at this point we don't yet know if the functions are actually usable with the type.
|
||||||
|
// `_type` may not be convertible to the function parameter type.
|
||||||
|
return
|
||||||
|
!_directive->typeName() ||
|
||||||
|
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) ==
|
||||||
|
*TypeProvider::withLocationIfReference(
|
||||||
|
typeLocation,
|
||||||
|
_directive->typeName()->annotation().type,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}) | ranges::to<vector<UsingForDirective const*>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _scope)
|
||||||
|
{
|
||||||
MemberList::MemberMap members;
|
MemberList::MemberMap members;
|
||||||
|
|
||||||
set<pair<string, Declaration const*>> seenFunctions;
|
set<pair<string, Declaration const*>> seenFunctions;
|
||||||
@ -381,27 +404,11 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc
|
|||||||
members.emplace_back(&_function, asBoundFunction, *_name);
|
members.emplace_back(&_function, asBoundFunction, *_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (UsingForDirective const* ufd: usingForDirectives)
|
for (UsingForDirective const* ufd: usingForDirectivesForType(_type, _scope))
|
||||||
{
|
for (auto const& identifierPath: ufd->functionsOrLibrary())
|
||||||
// Convert both types to pointers for comparison to see if the `using for`
|
|
||||||
// directive applies.
|
|
||||||
// Further down, we check more detailed for each function if `_type` is
|
|
||||||
// convertible to the function parameter type.
|
|
||||||
if (
|
|
||||||
ufd->typeName() &&
|
|
||||||
*TypeProvider::withLocationIfReference(typeLocation, &_type, true) !=
|
|
||||||
*TypeProvider::withLocationIfReference(
|
|
||||||
typeLocation,
|
|
||||||
ufd->typeName()->annotation().type,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (auto const& pathPointer: ufd->functionsOrLibrary())
|
|
||||||
{
|
{
|
||||||
solAssert(pathPointer);
|
solAssert(identifierPath);
|
||||||
Declaration const* declaration = pathPointer->annotation().referencedDeclaration;
|
Declaration const* declaration = identifierPath->annotation().referencedDeclaration;
|
||||||
solAssert(declaration);
|
solAssert(declaration);
|
||||||
|
|
||||||
if (ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(declaration))
|
if (ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
@ -417,10 +424,9 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc
|
|||||||
else
|
else
|
||||||
addFunction(
|
addFunction(
|
||||||
dynamic_cast<FunctionDefinition const&>(*declaration),
|
dynamic_cast<FunctionDefinition const&>(*declaration),
|
||||||
pathPointer->path().back()
|
identifierPath->path().back()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user