[TMP] suffixedLiteral annotation and overloading

This commit is contained in:
Kamil Śliwak 2022-07-22 19:42:33 +02:00
parent b815483fc3
commit 2d7a031d47
17 changed files with 131 additions and 86 deletions

View File

@ -3560,9 +3560,28 @@ bool TypeChecker::visit(Identifier const& _identifier)
for (Declaration const* declaration: annotation.overloadedDeclarations)
{
FunctionTypePointer functionType = declaration->functionType(true);
FunctionTypePointer functionType = declaration->functionType(true /* _internal */);
solAssert(!!functionType, "Requested type not present.");
bool argumentsMatch = false;
if (functionType->canTakeArguments(*annotation.arguments))
argumentsMatch = true;
else if (_identifier.annotation().suffixedLiteral && functionType->parameterTypes().size() == 2)
{
Type const* literalType = _identifier.annotation().suffixedLiteral->annotation().type;
auto const* literalRationalType = dynamic_cast<RationalNumberType const*>(literalType);
if (literalRationalType)
{
auto&& [mantissa, exponent] = literalRationalType->mantissaExponent();
// This was already validated in visit(Literal) but the error is not fatal.
if (!mantissa || !exponent)
solAssert(!m_errorReporter.errors().empty());
else
argumentsMatch = functionType->canTakeArguments({{mantissa, exponent}, {}});
}
}
if (argumentsMatch)
candidates.push_back(declaration);
}
if (candidates.size() == 1)
@ -3676,7 +3695,7 @@ void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
_expr.annotation().isConstant = false;
}
void TypeChecker::endVisit(Literal const& _literal)
bool TypeChecker::visit(Literal const& _literal)
{
Type const* type = nullptr;
if (_literal.looksLikeAddress())
@ -3733,8 +3752,45 @@ void TypeChecker::endVisit(Literal const& _literal)
// TODO at this point 'type' needs to be stored for code generation.
std::visit(GenericVisitor{
[&](ASTPointer<Identifier> const& _identifier) {
_identifier->annotation().suffixedLiteral = &_literal;
_identifier->annotation().arguments = {{type}, {}};
},
[&](ASTPointer<MemberAccess> const& _memberAccess) {
_memberAccess->annotation().suffixedLiteral = &_literal;
_memberAccess->annotation().arguments = {{type}, {}};
},
[&](Literal::SubDenomination) {},
}, _literal.suffix());
auto const* literalRationalType = dynamic_cast<RationalNumberType const*>(type);
if (!subDenomination && literalRationalType)
{
auto&& [mantissa, exponent] = literalRationalType->mantissaExponent();
solAssert((mantissa && exponent) || (!mantissa && !exponent));
if (!mantissa)
m_errorReporter.typeError(
5503_error,
_literal.location(),
"This fractional number cannot be decomposed into a mantissa and decimal exponent "
"that fit the range of parameters of any possible suffix function."
);
}
// NOTE: For suffixed literals this is not the final type yet. We will update it in endVisit()
// when we know what the suffix function returns.
_literal.annotation().type = type;
_literal.annotation().isLValue = false;
_literal.annotation().isConstant = false;
return true;
}
void TypeChecker::endVisit(Literal const& _literal)
{
bool isCompileTimeConstant = true;
if (!subDenomination)
if (!holds_alternative<Literal::SubDenomination>(_literal.suffix()))
{
FunctionType const* suffixFunctionType = dynamic_cast<FunctionType const*>(std::visit(GenericVisitor{
[&](ASTPointer<Identifier> const& _identifier) { return _identifier->annotation().type; },
@ -3760,7 +3816,8 @@ void TypeChecker::endVisit(Literal const& _literal)
solAssert(!suffixFunctionType->takesArbitraryParameters());
solAssert(suffixFunctionType->kind() == FunctionType::Kind::Internal);
auto const* literalRationalType = dynamic_cast<RationalNumberType const*>(type);
Type const* literalType = _literal.annotation().type;
auto const* literalRationalType = dynamic_cast<RationalNumberType const*>(literalType);
optional<string> parameterCountMessage;
if (suffixFunctionType->parameterTypes().size() == 0)
@ -3775,15 +3832,12 @@ void TypeChecker::endVisit(Literal const& _literal)
m_errorReporter.typeError(4778_error, _literal.location(), parameterCountMessage.value());
else if (suffixFunctionType->parameterTypes().size() == 2)
{
auto&& [mantissa, exponent] = dynamic_cast<RationalNumberType const*>(type)->mantissaExponent();
solAssert((mantissa && exponent) || (!mantissa && !exponent));
if (!mantissa)
m_errorReporter.typeError(
5503_error,
_literal.location(),
"This fractional number cannot be decomposed into a mantissa and decimal exponent "
"that fit the range of parameters of the suffix function."
);
solAssert(literalRationalType);
auto&& [mantissa, exponent] = literalRationalType->mantissaExponent();
// This was already validated in visit(Literal) but the error is not fatal.
if (!mantissa || !exponent)
solAssert(!m_errorReporter.errors().empty());
else if (
!mantissa->isImplicitlyConvertibleTo(*suffixFunctionType->parameterTypes().at(0)) ||
!exponent->isImplicitlyConvertibleTo(*suffixFunctionType->parameterTypes().at(1))
@ -3791,26 +3845,22 @@ void TypeChecker::endVisit(Literal const& _literal)
// TODO: Is this triggered when the argument is out of range? Test.
parameterTypeMessage = "The type of the literal cannot be converted to the parameters of the suffix function.";
}
else if (!type->isImplicitlyConvertibleTo(*suffixFunctionType->parameterTypes().front()))
else if (!literalType->isImplicitlyConvertibleTo(*suffixFunctionType->parameterTypes().front()))
parameterTypeMessage = "The type of the literal cannot be converted to the parameter of the suffix function.";
if (parameterTypeMessage.has_value())
m_errorReporter.typeError(8838_error, _literal.location(), parameterTypeMessage.value());
isCompileTimeConstant = suffixFunctionType->isPure();
if (suffixFunctionType->returnParameterTypes().size() == 1)
type = suffixFunctionType->returnParameterTypes().front();
_literal.annotation().type = suffixFunctionType->returnParameterTypes().front();
else
type = TypeProvider::tuple(suffixFunctionType->returnParameterTypes());
_literal.annotation().type = TypeProvider::tuple(suffixFunctionType->returnParameterTypes());
isCompileTimeConstant = suffixFunctionType->isPure();
}
}
else
solAssert(holds_alternative<Literal::SubDenomination>(_literal.suffix()));
_literal.annotation().type = type;
_literal.annotation().isPure = isCompileTimeConstant;
_literal.annotation().isLValue = false;
_literal.annotation().isConstant = false;
}
void TypeChecker::endVisit(UsingForDirective const& _usingFor)

View File

@ -164,6 +164,7 @@ private:
void endVisit(IdentifierPath const& _identifierPath) override;
void endVisit(UserDefinedTypeName const& _userDefinedTypeName) override;
void endVisit(ElementaryTypeNameExpression const& _expr) override;
bool visit(Literal const& _literal) override;
void endVisit(Literal const& _literal) override;
void endVisit(UsingForDirective const& _usingForDirective) override;

View File

@ -302,6 +302,8 @@ struct IdentifierAnnotation: ExpressionAnnotation
std::vector<Declaration const*> candidateDeclarations;
/// List of possible declarations it could refer to.
std::vector<Declaration const*> overloadedDeclarations;
/// If the identifier is used as a literal suffix, this points at the literal.
Literal const* suffixedLiteral = nullptr;
};
struct MemberAccessAnnotation: ExpressionAnnotation
@ -310,6 +312,8 @@ struct MemberAccessAnnotation: ExpressionAnnotation
Declaration const* referencedDeclaration = nullptr;
/// What kind of lookup needs to be done (static, virtual, super) find the declaration.
util::SetOnce<VirtualLookup> requiredLookup;
/// If the expression is used as a literal suffix, this points at the literal.
Literal const* suffixedLiteral = nullptr;
};
struct BinaryOperationAnnotation: ExpressionAnnotation

View File

@ -43,7 +43,7 @@ contract C {
// TypeError 8838: (827-837): The type of the literal cannot be converted to the parameters of the suffix function.
// TypeError 8838: (847-857): The type of the literal cannot be converted to the parameters of the suffix function.
// TypeError 8838: (867-950): The type of the literal cannot be converted to the parameters of the suffix function.
// TypeError 5503: (980-1064): This fractional number cannot be decomposed into a mantissa and decimal exponent that fit the range of parameters of the suffix function.
// TypeError 5503: (980-1064): This fractional number cannot be decomposed into a mantissa and decimal exponent that fit the range of parameters of any possible suffix function.
// TypeError 8838: (1095-1105): The type of the literal cannot be converted to the parameters of the suffix function.
// TypeError 8838: (1115-1125): The type of the literal cannot be converted to the parameters of the suffix function.
// TypeError 8838: (1135-1148): The type of the literal cannot be converted to the parameters of the suffix function.

View File

@ -1,13 +1,12 @@
function suffix(uint) pure returns (int) {}
function suffix(bool) pure returns (int) {}
function suffix(address) pure returns (int) {}
function suffix(string memory) pure returns (int) {}
function suffix(bool) pure returns (bool) {}
function suffix(address) pure returns (address) {}
function suffix(string memory) pure returns (string memory) {}
contract C {
int a = 1 suffix; // TODO: Should match only uint
int b = true suffix; // TODO: Should match only bool
int c = 0x1234567890123456789012345678901234567890 suffix; // TODO: Should match only address
int d = "a" suffix; // TODO: Should match only string
int a = 1 suffix;
bool b = true suffix;
address c = 0x1234567890123456789012345678901234567890 suffix;
string d = "a" suffix;
}
// ----
// TypeError 2144: (214-222): No matching declaration found after variable lookup.

View File

@ -1,21 +1,19 @@
function uSuffix(uint8, uint) pure returns (int) {}
function uSuffix(uint16, uint) pure returns (int) {}
function uSuffix(uint8, uint) pure returns (int8) {}
function uSuffix(uint16, uint) pure returns (int16) {}
function iSuffix(int8, uint) pure returns (int) {}
function iSuffix(int16, uint) pure returns (int) {}
function iSuffix(int8, uint) pure returns (int24) {}
function iSuffix(int16, uint) pure returns (int32) {}
function iuSuffix(uint8, uint) pure returns (int) {}
function iuSuffix(int8, uint) pure returns (int) {}
function iuSuffix(uint8, uint) pure returns (int40) {}
function iuSuffix(int8, uint) pure returns (int48) {}
contract C {
int a = 1.024 uSuffix; // TODO: Should match only (uint16, uint)
int b = 1.024 iSuffix; // TODO: Should match only (int16, uint)
int16 a = 1.024 uSuffix;
int32 b = 1.024 iSuffix;
int c = -1.024 uSuffix; // TODO: Should match only (uint16, uint)
int d = -1.024 iSuffix; // TODO: Should match only (int16, uint)
int16 c = -1.024 uSuffix;
int32 d = -1.024 iSuffix;
int e = 2.55 iuSuffix; // TODO: Should match only (uint8, uint)
int f = -2.55 iuSuffix; // TODO: Should match only (uint8, uint)
int40 e = 2.55 iuSuffix;
int40 f = -2.55 iuSuffix;
}
// ----
// TypeError 2144: (341-354): No matching declaration found after variable lookup.

View File

@ -2,7 +2,7 @@ function iuSuffix(uint8, uint) pure returns (uint) {}
function iuSuffix(int8, uint) pure returns (uint) {}
contract C {
uint a = 1.27 iuSuffix; // TODO: Error should say it's ambiguous
uint a = 1.27 iuSuffix;
}
// ----
// TypeError 2144: (134-147): No matching declaration found after variable lookup.
// TypeError 4487: (134-147): No unique declaration found after argument-dependent lookup.

View File

@ -2,7 +2,7 @@ function uSuffix(uint8, uint) pure returns (uint) {}
function uSuffix(uint16, uint) pure returns (uint) {}
contract C {
uint a = 1.27 uSuffix; // TODO: Error should say it's ambiguous
uint a = 1.27 uSuffix;
}
// ----
// TypeError 2144: (134-146): No matching declaration found after variable lookup.
// TypeError 4487: (134-146): No unique declaration found after argument-dependent lookup.

View File

@ -1,14 +1,11 @@
function suffix256(uint) pure returns (int) {}
function suffix256(uint) pure returns (uint) {}
function suffix256(uint, uint) pure returns (int) {}
function suffix8(uint) pure returns (int) {}
function suffix8(uint8, uint) pure returns (int) {}
function suffix8(uint) pure returns (uint8) {}
function suffix8(uint8, uint) pure returns (int8) {}
contract C {
function f() public pure {
int a = 1.1 suffix256; // TODO: Should match only (uint, uint)
int b = 1024 suffix8; // TODO: Should match only uint
}
int a = 1.1 suffix256;
uint8 b = 1024 suffix8;
}
// ----
// TypeError 2144: (259-272): No matching declaration found after variable lookup.

View File

@ -3,8 +3,8 @@ function suffix(uint, uint) pure returns (int) {}
contract C {
function f() public pure {
int a = 1 suffix; // TODO: Error should say it's ambiguous
int a = 1 suffix;
}
}
// ----
// TypeError 2144: (155-163): No matching declaration found after variable lookup.
// TypeError 4487: (155-163): No unique declaration found after argument-dependent lookup.

View File

@ -1,21 +1,19 @@
function uSuffix(uint8) pure returns (int) {}
function uSuffix(uint16) pure returns (int) {}
function uSuffix(uint8) pure returns (int8) {}
function uSuffix(uint16) pure returns (int16) {}
function iSuffix(int8) pure returns (int) {}
function iSuffix(int16) pure returns (int) {}
function iSuffix(int8) pure returns (int24) {}
function iSuffix(int16) pure returns (int32) {}
function iuSuffix(uint8) pure returns (int) {}
function iuSuffix(int8) pure returns (int) {}
function iuSuffix(uint8) pure returns (int40) {}
function iuSuffix(int8) pure returns (int48) {}
contract C {
int a = 1024 uSuffix; // TODO: Should match only uint16
int b = 1024 iSuffix; // TODO: Should match only int16
int16 a = 1024 uSuffix;
int32 b = 1024 iSuffix;
int c = -1024 uSuffix; // TODO: Should match only uint16
int d = -1024 iSuffix; // TODO: Should match only int16
int16 c = -1024 uSuffix;
int32 d = -1024 iSuffix;
int e = 255 iuSuffix; // TODO: Should match only uint8
int f = -255 iuSuffix; // TODO: Should match only uint8
int40 e = 255 iuSuffix;
int40 f = -255 iuSuffix;
}
// ----
// TypeError 2144: (305-317): No matching declaration found after variable lookup.

View File

@ -2,7 +2,7 @@ function iuSuffix(uint8) pure returns (int) {}
function iuSuffix(int8) pure returns (int) {}
contract C {
int a = 127 iuSuffix; // TODO: Error should say it's ambiguous
int a = 127 iuSuffix;
}
// ----
// TypeError 2144: (119-131): No matching declaration found after variable lookup.
// TypeError 4487: (119-131): No unique declaration found after argument-dependent lookup.

View File

@ -2,7 +2,7 @@ function uSuffix(uint8) pure returns (int) {}
function uSuffix(uint16) pure returns (int) {}
contract C {
int a = 127 uSuffix; // TODO: Error should say it's ambiguous
int a = 127 uSuffix;
}
// ----
// TypeError 2144: (119-130): No matching declaration found after variable lookup.
// TypeError 4487: (119-130): No unique declaration found after argument-dependent lookup.

View File

@ -1,8 +1,6 @@
function suffix(string memory) pure returns (int) {}
function suffix(bytes memory) pure returns (int) {}
function suffix(string memory) pure returns (string memory) {}
function suffix(bytes memory) pure returns (bytes memory) {}
contract C {
int a = hex"abcd" suffix; // TODO: Should match only bytes
bytes a = hex"abcd" suffix;
}
// ----
// TypeError 2144: (131-147): No matching declaration found after variable lookup.

View File

@ -2,7 +2,7 @@ function suffix(string memory) pure returns (uint) {}
function suffix(bytes memory) pure returns (uint) {}
contract C {
uint a = "abcd" suffix; // TODO: Error should say it's ambiguous
uint a = "abcd" suffix;
}
// ----
// TypeError 2144: (134-147): No matching declaration found after variable lookup.
// TypeError 4487: (134-147): No unique declaration found after argument-dependent lookup.

View File

@ -9,4 +9,4 @@ contract C {
Decimal x = 0.115792089237316195423570985008687907853269984665640564039457584007913129639936 suffix; // 2**256 * 10**-78
}
// ----
// TypeError 5503: (204-291): This fractional number cannot be decomposed into a mantissa and decimal exponent that fit the range of parameters of the suffix function.
// TypeError 5503: (204-291): This fractional number cannot be decomposed into a mantissa and decimal exponent that fit the range of parameters of any possible suffix function.

View File

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