Skip to content

Commit bbfef2d

Browse files
authored
Merge pull request #13005 from StrongerXi/fix-typechecker-for-custom-error
Display human readable type name in conversion error message
2 parents f2c9305 + 4b7ed2d commit bbfef2d

File tree

7 files changed

+113
-13
lines changed

7 files changed

+113
-13
lines changed

libsolidity/analysis/TypeChecker.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,7 +1842,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
18421842
_functionCall.location(),
18431843
ssl,
18441844
"Explicit type conversion not allowed from non-payable \"address\" to \"" +
1845-
resultType->toString() +
1845+
resultType->humanReadableName() +
18461846
"\", which has a payable fallback function."
18471847
);
18481848
}
@@ -1856,9 +1856,9 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
18561856
5030_error,
18571857
_functionCall.location(),
18581858
"Explicit type conversion not allowed from \"" +
1859-
argType->toString() +
1859+
argType->humanReadableName() +
18601860
"\" to \"" +
1861-
resultType->toString() +
1861+
resultType->humanReadableName() +
18621862
"\". To obtain the address of the contract of the function, " +
18631863
"you can use the .address member of the function."
18641864
);
@@ -1867,9 +1867,9 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
18671867
9640_error,
18681868
_functionCall.location(),
18691869
"Explicit type conversion not allowed from \"" +
1870-
argType->toString() +
1870+
argType->humanReadableName() +
18711871
"\" to \"" +
1872-
resultType->toString() +
1872+
resultType->humanReadableName() +
18731873
"\".",
18741874
result.message()
18751875
);

libsolidity/ast/Types.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ util::Result<TypePointers> transformParametersToExternal(TypePointers const& _pa
110110
return transformed;
111111
}
112112

113+
string toStringInParentheses(TypePointers const& _types, bool _short)
114+
{
115+
return '(' + util::joinHumanReadable(
116+
_types | ranges::views::transform([&](auto const* _type) { return _type->toString(_short); }),
117+
","
118+
) + ')';
119+
}
120+
113121
}
114122

115123
MemberList::Member::Member(Declaration const* _declaration, Type const* _type):
@@ -3090,6 +3098,19 @@ string FunctionType::canonicalName() const
30903098
return "function";
30913099
}
30923100

3101+
string FunctionType::humanReadableName() const
3102+
{
3103+
switch (m_kind)
3104+
{
3105+
case Kind::Error:
3106+
return "error " + m_declaration->name() + toStringInParentheses(m_parameterTypes, /* _short */ true);
3107+
case Kind::Event:
3108+
return "event " + m_declaration->name() + toStringInParentheses(m_parameterTypes, /* _short */ true);
3109+
default:
3110+
return toString(/* _short */ false);
3111+
}
3112+
}
3113+
30933114
string FunctionType::toString(bool _short) const
30943115
{
30953116
string name = "function ";
@@ -3101,20 +3122,15 @@ string FunctionType::toString(bool _short) const
31013122
name += *contract->annotation().canonicalName + ".";
31023123
name += functionDefinition->name();
31033124
}
3104-
name += '(';
3105-
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
3106-
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
3107-
name += ")";
3125+
name += toStringInParentheses(m_parameterTypes, _short);
31083126
if (m_stateMutability != StateMutability::NonPayable)
31093127
name += " " + stateMutabilityToString(m_stateMutability);
31103128
if (m_kind == Kind::External)
31113129
name += " external";
31123130
if (!m_returnParameterTypes.empty())
31133131
{
3114-
name += " returns (";
3115-
for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it)
3116-
name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
3117-
name += ")";
3132+
name += " returns ";
3133+
name += toStringInParentheses(m_returnParameterTypes, _short);
31183134
}
31193135
return name;
31203136
}

libsolidity/ast/Types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ class Type
339339
std::string toString() const { return toString(false); }
340340
/// @returns the canonical name of this type for use in library function signatures.
341341
virtual std::string canonicalName() const { return toString(true); }
342+
virtual std::string humanReadableName() const { return toString(); }
342343
/// @returns the signature of this type in external functions, i.e. `uint256` for integers
343344
/// or `(uint256,bytes8)[2]` for an array of structs. If @a _structsByName,
344345
/// structs are given by canonical name like `ContractName.StructName[2]`.
@@ -1378,6 +1379,7 @@ class FunctionType: public Type
13781379
TypeResult unaryOperatorResult(Token _operator) const override;
13791380
TypeResult binaryOperatorResult(Token, Type const*) const override;
13801381
std::string canonicalName() const override;
1382+
std::string humanReadableName() const override;
13811383
std::string toString(bool _short) const override;
13821384
unsigned calldataEncodedSize(bool _padded) const override;
13831385
bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
interface MyInterface {
2+
error MyCustomError(uint256, bool);
3+
}
4+
5+
contract Test {
6+
function test() public returns(bytes4) {
7+
return bytes4(MyInterface.MyCustomError);
8+
}
9+
}
10+
// ----
11+
// TypeError 9640: (143-176): Explicit type conversion not allowed from "error MyCustomError(uint256,bool)" to "bytes4".
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
contract Test {
2+
event MyCustomEvent(uint256);
3+
4+
function test() public returns(bytes4) {
5+
return bytes4(MyCustomEvent);
6+
}
7+
}
8+
// ----
9+
// TypeError 9640: (111-132): Explicit type conversion not allowed from "event MyCustomEvent(uint256)" to "bytes4".
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
interface MyInterface {
2+
enum MyEnum { E1, E2 }
3+
error CustomError1(
4+
uint256,
5+
bool,
6+
bool[],
7+
address payable,
8+
MyInterface,
9+
MyEnum,
10+
function (string memory) external returns (uint)
11+
);
12+
}
13+
14+
contract Test {
15+
function testFunction(string memory) external returns (uint) {}
16+
17+
function test() public {
18+
MyInterface instance = MyInterface(msg.sender);
19+
bool[] calldata arr;
20+
address payable addr;
21+
bytes4(MyInterface.CustomEror1);
22+
bytes4(MyInterface.CustomError1());
23+
bytes4(MyInterface.CustomError1(1, true, arr, addr, instance, MyInterface.MyEnum.E1, this.testFunction));
24+
address(MyInterface.CustomError1);
25+
}
26+
}
27+
// ----
28+
// TypeError 9582: (495-518): Member "CustomEror1" not found or not visible after argument-dependent lookup in type(contract MyInterface).
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
interface MyInterface {
2+
enum MyEnum { E1, E2 }
3+
}
4+
5+
contract Test {
6+
function testFunction(string memory) external returns (uint) {}
7+
8+
event CustomEvent1(
9+
uint256,
10+
bool,
11+
bool[],
12+
address payable,
13+
MyInterface,
14+
MyInterface.MyEnum,
15+
function (string memory) external returns (uint)
16+
);
17+
18+
19+
function test() public {
20+
MyInterface instance = MyInterface(msg.sender);
21+
bool[] calldata arr;
22+
address payable addr;
23+
bytes4(CustomEvent1);
24+
bytes4(CustomEvent1());
25+
bytes4(CustomEvent1(1, true, arr, addr, instance, MyInterface.MyEnum.E1, this.testFunction));
26+
address(CustomEvent1);
27+
}
28+
}
29+
// ----
30+
// TypeError 9640: (502-522): Explicit type conversion not allowed from "event CustomEvent1(uint256,bool,bool[],address payable,contract MyInterface,enum MyInterface.MyEnum,function (string) external returns (uint256))" to "bytes4".
31+
// TypeError 6160: (539-553): Wrong argument count for function call: 0 arguments given but expected 7.
32+
// TypeError 9640: (532-554): Explicit type conversion not allowed from "tuple()" to "bytes4".
33+
// TypeError 9640: (564-656): Explicit type conversion not allowed from "tuple()" to "bytes4".
34+
// TypeError 9640: (666-687): Explicit type conversion not allowed from "event CustomEvent1(uint256,bool,bool[],address payable,contract MyInterface,enum MyInterface.MyEnum,function (string) external returns (uint256))" to "address".

0 commit comments

Comments
 (0)