Merge pull request #13739 from ethereum/code-reshuffling-before-operators

Code reshuffling before custom operators
This commit is contained in:
chriseth 2022-11-23 15:09:32 +01:00 committed by GitHub
commit 33f27098e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 34 deletions

View File

@ -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()
) )

View File

@ -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)

View File

@ -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);

View File

@ -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;
} }