Disallow using overloaded functions as literal suffixes

This commit is contained in:
Kamil Śliwak 2023-04-07 14:07:49 +02:00
parent 134c5a951f
commit de6c347577
24 changed files with 41 additions and 134 deletions

View File

@ -3021,10 +3021,6 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
bool TypeChecker::visit(FunctionCall const& _functionCall) bool TypeChecker::visit(FunctionCall const& _functionCall)
{ {
solAssert(!m_currentSuffixCall);
if (_functionCall.isSuffixCall())
m_currentSuffixCall = &_functionCall;
vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
bool argumentsArePure = true; bool argumentsArePure = true;
@ -3045,6 +3041,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
for (ASTPointer<Expression const> const& argument: arguments) for (ASTPointer<Expression const> const& argument: arguments)
funcCallArgs.types.push_back(type(*argument)); funcCallArgs.types.push_back(type(*argument));
if (!_functionCall.isSuffixCall())
_functionCall.expression().annotation().arguments = std::move(funcCallArgs); _functionCall.expression().annotation().arguments = std::move(funcCallArgs);
} }
@ -3220,7 +3217,6 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
break; break;
} }
m_currentSuffixCall = nullptr;
return false; return false;
} }
@ -3439,62 +3435,15 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
size_t const initialMemberCount = possibleMembers.size(); size_t const initialMemberCount = possibleMembers.size();
if (initialMemberCount > 1 && arguments) if (initialMemberCount > 1 && arguments)
{ {
RationalNumberType const* mantissa = nullptr;
RationalNumberType const* exponent = nullptr;
RationalNumberType const* literalRationalType = nullptr;
if (m_currentSuffixCall)
{
if (annotation.arguments->types.size() == 1)
{
solAssert(annotation.arguments->types[0]);
literalRationalType = dynamic_cast<RationalNumberType const*>(annotation.arguments->types[0]);
if (literalRationalType)
tie(mantissa, exponent) = literalRationalType->fractionalDecomposition();
}
}
// do overload resolution // do overload resolution
for (auto it = possibleMembers.begin(); it != possibleMembers.end();) for (auto it = possibleMembers.begin(); it != possibleMembers.end();)
{ if (
bool viableCandidate = false; it->type->category() == Type::Category::Function &&
if (it->type->category() == Type::Category::Function) !dynamic_cast<FunctionType const&>(*it->type).canTakeArguments(*arguments, exprType)
{ )
FunctionTypePointer functionType = dynamic_cast<FunctionType const*>(it->type);
solAssert(functionType);
if (!m_currentSuffixCall || m_currentSuffixCall->expression() != _memberAccess)
viableCandidate = functionType->canTakeArguments(*arguments, exprType);
else
{
// NOTE: We're before type-checking of suffix calls so we can't yet assume that
// the suffix is not something weird, including being a bound function.
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(it->declaration);
bool isSuffixFunction =
functionDefinition &&
functionDefinition->usableAsSuffix();
bool singleArgumentMatch =
functionType->parameterTypes().size() == 1 &&
functionType->canTakeArguments(*annotation.arguments);
bool mantissaExponentMatch =
functionType->parameterTypes().size() == 2 &&
literalRationalType &&
// NOTE: If the literal cannot be decomposed it's fine to act as if suffix could not take it.
// It will be reported as error when type-checking the suffix call anyway.
mantissa &&
exponent &&
functionType->canTakeArguments({{mantissa, exponent}, {}});
viableCandidate = isSuffixFunction && (singleArgumentMatch || mantissaExponentMatch);
}
}
if (viableCandidate)
++it;
else
it = possibleMembers.erase(it); it = possibleMembers.erase(it);
} else
++it;
} }
annotation.isConstant = false; annotation.isConstant = false;
@ -4004,8 +3953,6 @@ bool TypeChecker::visit(Identifier const& _identifier)
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin(); annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
else if (!annotation.arguments) else if (!annotation.arguments)
{ {
solAssert(!m_currentSuffixCall);
// The identifier should be a public state variable shadowing other functions // The identifier should be a public state variable shadowing other functions
vector<Declaration const*> candidates; vector<Declaration const*> candidates;
@ -4023,55 +3970,17 @@ bool TypeChecker::visit(Identifier const& _identifier)
} }
else else
{ {
vector<Declaration const*> candidates; // NOTE: Suffix calls intentionally have no 'arguments' annotation so that they never enter this branch.
RationalNumberType const* mantissa = nullptr; vector<Declaration const*> candidates;
RationalNumberType const* exponent = nullptr;
RationalNumberType const* literalRationalType = nullptr;
if (m_currentSuffixCall)
{
if (annotation.arguments->types.size() == 1)
{
solAssert(annotation.arguments->types[0]);
literalRationalType = dynamic_cast<RationalNumberType const*>(annotation.arguments->types[0]);
if (literalRationalType)
tie(mantissa, exponent) = literalRationalType->fractionalDecomposition();
}
}
for (Declaration const* declaration: annotation.overloadedDeclarations) for (Declaration const* declaration: annotation.overloadedDeclarations)
{ {
FunctionTypePointer functionType = declaration->functionType(true /* _internal */); FunctionTypePointer functionType = declaration->functionType(true /* _internal */);
solAssert(!!functionType, "Requested type not present."); solAssert(!!functionType, "Requested type not present.");
if (!m_currentSuffixCall)
{
if (functionType->canTakeArguments(*annotation.arguments)) if (functionType->canTakeArguments(*annotation.arguments))
candidates.push_back(declaration); candidates.push_back(declaration);
} }
else
{
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(declaration);
bool isSuffixFunction =
functionDefinition &&
functionDefinition->usableAsSuffix();
bool singleArgumentMatch =
functionType->parameterTypes().size() == 1 &&
functionType->canTakeArguments(*annotation.arguments);
bool mantissaExponentMatch =
functionType->parameterTypes().size() == 2 &&
literalRationalType &&
// NOTE: If the literal cannot be decomposed it's fine to act as if suffix could not take it.
// It will be reported as error when type-checking the suffix call anyway.
mantissa &&
exponent &&
functionType->canTakeArguments({{mantissa, exponent}, {}});
if (isSuffixFunction && (singleArgumentMatch || mantissaExponentMatch))
candidates.push_back(declaration);
}
}
if (candidates.size() == 1) if (candidates.size() == 1)
annotation.referencedDeclaration = candidates.front(); annotation.referencedDeclaration = candidates.front();
else else

View File

@ -206,7 +206,6 @@ private:
SourceUnit const* m_currentSourceUnit = nullptr; SourceUnit const* m_currentSourceUnit = nullptr;
ContractDefinition const* m_currentContract = nullptr; ContractDefinition const* m_currentContract = nullptr;
FunctionCall const* m_currentSuffixCall = nullptr;
langutil::EVMVersion m_evmVersion; langutil::EVMVersion m_evmVersion;

View File

@ -1,17 +0,0 @@
function suffix(uint x) pure suffix returns (uint) { return x; }
function suffix(bool x) pure suffix returns (bool) { return x; }
function suffix(address x) pure suffix returns (address) { return x; }
function suffix(string memory x) pure suffix returns (string memory) { return x; }
contract C {
function run() public returns (bytes memory) {
return abi.encode(
42 suffix,
true suffix,
0x1234567890123456789012345678901234567890 suffix,
"a" suffix
);
}
}
// ----
// run() -> 0x20, 0xc0, 0x2a, 1, 0x1234567890123456789012345678901234567890, 0x80, 1, "a"

View File

@ -9,3 +9,5 @@ contract C {
address c = 0x1234567890123456789012345678901234567890 suffix; address c = 0x1234567890123456789012345678901234567890 suffix;
string d = "a" suffix; string d = "a" suffix;
} }
// ----
// TypeError 2144: (259-265): No matching declaration found after variable lookup.

View File

@ -6,4 +6,4 @@ contract C {
} }
// ---- // ----
// TypeError 2998: (74-89): This literal suffix function is not usable as a suffix because no literal is implicitly convertible to its parameter type. // TypeError 2998: (74-89): This literal suffix function is not usable as a suffix because no literal is implicitly convertible to its parameter type.
// TypeError 7407: (170-219): Type address is not implicitly convertible to expected type address payable. // TypeError 2144: (213-219): No matching declaration found after variable lookup.

View File

@ -17,3 +17,5 @@ contract C {
f("a"); f("a");
} }
} }
// ----
// TypeError 2144: (268-269): No matching declaration found after variable lookup.

View File

@ -10,4 +10,4 @@ contract C {
} }
} }
// ---- // ----
// TypeError 9322: (208-209): No matching declaration found after argument-dependent lookup. // TypeError 2144: (162-163): No matching declaration found after variable lookup.

View File

@ -5,4 +5,4 @@ contract C {
int32 a = 115792089237316195423570985008687907853269984665640564039457584007913129639936 uSuffix; // 2**256 int32 a = 115792089237316195423570985008687907853269984665640564039457584007913129639936 uSuffix; // 2**256
} }
// ---- // ----
// TypeError 9322: (229-236): No matching declaration found after argument-dependent lookup. // TypeError 2144: (229-236): No matching declaration found after variable lookup.

View File

@ -17,3 +17,5 @@ contract C {
int e = 2.55 iuSuffix; int e = 2.55 iuSuffix;
int f = -2.55 iuSuffix; int f = -2.55 iuSuffix;
} }
// ----
// TypeError 2144: (392-399): No matching declaration found after variable lookup.

View File

@ -5,4 +5,4 @@ contract C {
uint a = 1.27 iuSuffix; uint a = 1.27 iuSuffix;
} }
// ---- // ----
// TypeError 4487: (151-159): No unique declaration found after argument-dependent lookup. // TypeError 2144: (151-159): No matching declaration found after variable lookup.

View File

@ -5,4 +5,4 @@ contract C {
uint a = 1.27 uSuffix; uint a = 1.27 uSuffix;
} }
// ---- // ----
// TypeError 4487: (151-158): No unique declaration found after argument-dependent lookup. // TypeError 2144: (151-158): No matching declaration found after variable lookup.

View File

@ -29,3 +29,5 @@ contract D {
"a" f; "a" f;
} }
} }
// ----
// TypeError 2144: (B.sol:201-202): No matching declaration found after variable lookup.

View File

@ -11,3 +11,5 @@ contract C {
// Not ambiguous: 1024 won't fit into uint8. // Not ambiguous: 1024 won't fit into uint8.
bool b = 1024 suffix8; bool b = 1024 suffix8;
} }
// ----
// TypeError 2144: (325-334): No matching declaration found after variable lookup.

View File

@ -7,4 +7,4 @@ contract C {
} }
} }
// ---- // ----
// TypeError 4487: (176-182): No unique declaration found after argument-dependent lookup. // TypeError 2144: (176-182): No matching declaration found after variable lookup.

View File

@ -17,3 +17,5 @@ contract C {
int e = 255 iuSuffix; int e = 255 iuSuffix;
int f = -255 iuSuffix; int f = -255 iuSuffix;
} }
// ----
// TypeError 2144: (355-362): No matching declaration found after variable lookup.

View File

@ -5,4 +5,4 @@ contract C {
int a = 127 iuSuffix; int a = 127 iuSuffix;
} }
// ---- // ----
// TypeError 4487: (137-145): No unique declaration found after argument-dependent lookup. // TypeError 2144: (137-145): No matching declaration found after variable lookup.

View File

@ -5,4 +5,4 @@ contract C {
int a = 127 uSuffix; int a = 127 uSuffix;
} }
// ---- // ----
// TypeError 4487: (137-144): No unique declaration found after argument-dependent lookup. // TypeError 2144: (137-144): No matching declaration found after variable lookup.

View File

@ -13,3 +13,5 @@ contract C {
address c = 0x1234567890123456789012345678901234567890 A.suffix; address c = 0x1234567890123456789012345678901234567890 A.suffix;
string d = "a" A.suffix; string d = "a" A.suffix;
} }
// ----
// TypeError 6675: (B.sol:49-57): Member "suffix" not unique after argument-dependent lookup in module "A.sol".

View File

@ -4,3 +4,5 @@ function suffix(bytes memory) pure suffix returns (bytes memory) {}
contract C { contract C {
bytes a = hex"abcd" suffix; bytes a = hex"abcd" suffix;
} }
// ----
// TypeError 2144: (176-182): No matching declaration found after variable lookup.

View File

@ -5,4 +5,4 @@ contract C {
uint a = "abcd" suffix; uint a = "abcd" suffix;
} }
// ---- // ----
// TypeError 4487: (155-161): No unique declaration found after argument-dependent lookup. // TypeError 2144: (155-161): No matching declaration found after variable lookup.

View File

@ -11,4 +11,4 @@ contract C {
} }
} }
// ---- // ----
// TypeError 9582: (218-226): Member "suffix" not found or not visible after argument-dependent lookup in uint8. // TypeError 6675: (218-226): Member "suffix" not unique after argument-dependent lookup in uint8.

View File

@ -7,4 +7,4 @@ abstract contract C {
} }
} }
// ---- // ----
// TypeError 9322: (194-200): No matching declaration found after argument-dependent lookup. // TypeError 2144: (194-200): No matching declaration found after variable lookup.

View File

@ -5,4 +5,4 @@ contract C {
function suffix(address) public pure returns (uint) {} function suffix(address) public pure returns (uint) {}
} }
// ---- // ----
// TypeError 9322: (31-37): No matching declaration found after argument-dependent lookup. // TypeError 2144: (31-37): No matching declaration found after variable lookup.

View File

@ -4,4 +4,4 @@ contract C {
} }
} }
// ---- // ----
// TypeError 9322: (54-60): No matching declaration found after argument-dependent lookup. // TypeError 2144: (54-60): No matching declaration found after variable lookup.