Skip to content

Commit 8c5fea7

Browse files
committed
fix: disambiguate library functions vs native properties in member access
When both a native property (e.g., address.isContract) and a library function with the same name are available via 'using for', disambiguate based on call syntax: - With parentheses: prefer library function (e.g., a.isContract()) - Without parentheses: prefer native property (e.g., a.isContract) This allows OpenZeppelin's Address.isContract() library function to work alongside Tron's native address.isContract property without conflict. The fix mirrors the identifier resolution pattern in visit(Identifier) where VariableDeclarations are preferred without parentheses (lines 3693-3745 in TypeChecker.cpp). Fixes the error: 'Member "isContract" not unique after argument-dependent lookup in address' when using OpenZeppelin contracts on Tron.
1 parent 3e2818d commit 8c5fea7

4 files changed

Lines changed: 75 additions & 0 deletions

File tree

libsolidity/analysis/TypeChecker.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3184,6 +3184,31 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
31843184
it = possibleMembers.erase(it);
31853185
else
31863186
++it;
3187+
3188+
// When both a native property and a library function share the same name,
3189+
// prefer functions when called with parentheses.
3190+
// This mirrors the identifier resolution pattern at lines 3693-3745 where
3191+
// VariableDeclarations are preferred without parentheses.
3192+
if (possibleMembers.size() > 1)
3193+
{
3194+
MemberList::MemberMap functions;
3195+
for (auto const& member: possibleMembers)
3196+
if (member.type->category() == Type::Category::Function)
3197+
functions.push_back(member);
3198+
if (!functions.empty() && functions.size() < possibleMembers.size())
3199+
possibleMembers = std::move(functions);
3200+
}
3201+
}
3202+
else if (initialMemberCount > 1)
3203+
{
3204+
// Without parentheses, prefer non-function members (native properties)
3205+
// over library functions attached via "using for".
3206+
MemberList::MemberMap nonFunctions;
3207+
for (auto const& member: possibleMembers)
3208+
if (member.type->category() != Type::Category::Function)
3209+
nonFunctions.push_back(member);
3210+
if (!nonFunctions.empty() && nonFunctions.size() < possibleMembers.size())
3211+
possibleMembers = std::move(nonFunctions);
31873212
}
31883213

31893214
annotation.isConstant = false;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity >=0.8.0;
3+
4+
// Test that library function is preferred over native property when called with parentheses.
5+
// This allows OpenZeppelin's Address.isContract() to work alongside Tron's native address.isContract property.
6+
library Address {
7+
function isContract(address account) internal view returns (bool) {
8+
return account.code.length > 0;
9+
}
10+
}
11+
12+
contract C {
13+
using Address for address;
14+
15+
function check(address a) public view returns (bool) {
16+
// With parentheses - should use library function
17+
return a.isContract();
18+
}
19+
}
20+
// ----
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity >=0.8.0;
3+
4+
// Test that native property is preferred over library function when accessed without parentheses.
5+
// This allows Tron's native address.isContract property to work alongside library functions.
6+
library Address {
7+
function isContract(address account) internal view returns (bool) {
8+
return account.code.length > 0;
9+
}
10+
}
11+
12+
contract C {
13+
using Address for address;
14+
15+
function check(address a) public view returns (bool) {
16+
// Without parentheses - should use native property
17+
return a.isContract;
18+
}
19+
}
20+
// ----
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity >=0.8.0;
3+
4+
// Test Tron's native address.isContract property works without library.
5+
contract C {
6+
function check(address a) public view returns (bool) {
7+
return a.isContract;
8+
}
9+
}
10+
// ----

0 commit comments

Comments
 (0)