Merge pull request #14087 from ethereum/better-error-for-invalid-call

Better error message when trying to call things that are not functions
This commit is contained in:
Kamil Śliwak 2023-04-05 17:38:10 +02:00 committed by GitHub
commit 9020efec58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 106 additions and 11 deletions

View File

@ -2847,7 +2847,11 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
}
default:
m_errorReporter.fatalTypeError(5704_error, _functionCall.location(), "Type is not callable");
m_errorReporter.fatalTypeError(
5704_error,
_functionCall.location(),
capitalized(Type::categoryName(expressionType->category())) + " is not callable."
);
// Unreachable, because fatalTypeError throws. We don't set kind, but that's okay because the switch below
// is never reached. And, even if it was, SetOnce would trigger an assertion violation and not UB.
funcCallAnno.isPure = argumentsArePure;

View File

@ -294,6 +294,35 @@ Type const* Type::commonType(Type const* _a, Type const* _b)
return nullptr;
}
char const* Type::categoryName(Type::Category _category)
{
switch (_category)
{
case Category::Address: return "address";
case Category::Integer: return "integer";
case Category::RationalNumber: return "rational number literal";
case Category::StringLiteral: return "string literal";
case Category::Bool: return "boolean";
case Category::FixedPoint: return "fixed-point number";
case Category::Array: return "array";
case Category::ArraySlice: return "array slice";
case Category::FixedBytes: return "fixed-size byte array";
case Category::Contract: return "contract";
case Category::Struct: return "struct";
case Category::Function: return "function";
case Category::Enum: return "enum";
case Category::UserDefinedValueType: return "user-defined value type";
case Category::Tuple: return "tuple";
case Category::Mapping: return "mapping";
case Category::TypeType: return "type of a type";
case Category::Modifier: return "modifier";
case Category::Magic: return "magic variable";
case Category::Module: return "module";
case Category::InaccessibleDynamic: return "inaccessible dynamic value";
}
util::unreachable();
}
MemberList const& Type::members(ASTNode const* _currentScope) const
{
if (!m_members[_currentScope])

View File

@ -174,9 +174,26 @@ public:
enum class Category
{
Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array, ArraySlice,
FixedBytes, Contract, Struct, Function, Enum, UserDefinedValueType, Tuple,
Mapping, TypeType, Modifier, Magic, Module,
Address,
Integer,
RationalNumber,
StringLiteral,
Bool,
FixedPoint,
Array,
ArraySlice,
FixedBytes,
Contract,
Struct,
Function,
Enum,
UserDefinedValueType,
Tuple,
Mapping,
TypeType,
Modifier,
Magic,
Module,
InaccessibleDynamic
};
@ -184,6 +201,8 @@ public:
static Type const* commonType(Type const* _a, Type const* _b);
virtual Category category() const = 0;
static char const* categoryName(Type::Category _category);
/// @returns a valid solidity identifier such that two types should compare equal if and
/// only if they have the same identifier.
/// The identifier should start with "t_".

View File

@ -160,6 +160,15 @@ inline std::string toLower(std::string _s)
return _s;
}
/// Returns a copy of the string with the first character converted to its uppercase equivalent.
/// Uses the classic "C" locale semantics.
inline std::string capitalized(std::string _s)
{
if (_s.size() > 0)
_s[0] = toUpper(_s[0]);
return _s;
}
/// Checks whether _c is a decimal digit character. It uses the classic "C" locale semantics.
/// @param _c character to be checked
/// @return true if _c is a decimal digit character, false otherwise

View File

@ -0,0 +1,7 @@
enum E { A, B, C }
contract C {
uint a = E.B(1000);
}
// ----
// TypeError 5704: (46-55): Enum is not callable.

View File

@ -5,4 +5,4 @@ contract C
}
}
// ----
// TypeError 5704: (53-60): Type is not callable
// TypeError 5704: (53-60): Rational number literal is not callable.

View File

@ -0,0 +1,5 @@
contract C {
uint a = msg(1000);
}
// ----
// TypeError 5704: (26-35): Magic variable is not callable.

View File

@ -0,0 +1,6 @@
contract C {
mapping (uint => uint) m;
uint a = m(1000);
}
// ----
// TypeError 5704: (56-63): Mapping is not callable.

View File

@ -0,0 +1,7 @@
contract C {
uint a = m(1000);
modifier m(uint) { _; }
}
// ----
// TypeError 5704: (26-33): Modifier is not callable.

View File

@ -0,0 +1,9 @@
==== Source: A.sol ====
==== Source: B.sol ====
import "A.sol" as A;
contract C {
uint a = A(1000);
}
// ----
// TypeError 5704: (B.sol:48-55): Module is not callable.

View File

@ -6,4 +6,4 @@ contract C {
}
}
// ----
// TypeError 5704: (72-78): Type is not callable
// TypeError 5704: (72-78): Contract is not callable.

View File

@ -6,4 +6,4 @@ contract C {
}
}
// ----
// TypeError 5704: (90-108): Type is not callable
// TypeError 5704: (90-108): Rational number literal is not callable.

View File

@ -6,4 +6,4 @@ contract C {
}
}
// ----
// TypeError 5704: (153-157): Type is not callable
// TypeError 5704: (153-157): Mapping is not callable.

View File

@ -11,4 +11,4 @@ contract SomeContract {
}
// ----
// DeclarationError 2333: (106-145): Identifier already declared.
// TypeError 5704: (185-195): Type is not callable
// TypeError 5704: (185-195): Integer is not callable.

View File

@ -7,4 +7,4 @@ contract CrashContract {
}
}
// ----
// TypeError 5704: (170-177): Type is not callable
// TypeError 5704: (170-177): Rational number literal is not callable.

View File

@ -4,4 +4,4 @@ contract C {
}
}
// ----
// TypeError 5704: (59-63): Type is not callable
// TypeError 5704: (59-63): Rational number literal is not callable.