diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 0802f5c22e95..793854065ab9 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -3175,13 +3175,19 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) size_t const initialMemberCount = possibleMembers.size(); if (initialMemberCount > 1 && arguments) { - // do overload resolution + // Do overload resolution, and filter out non-functions when called with parentheses. + // This allows library functions like OpenZeppelin's Address.isContract() to work + // alongside Tron's native address.isContract property. + // Mirrors the identifier resolution pattern at lines 3693-3745 where + // VariableDeclarations are preferred without parentheses. for (auto it = possibleMembers.begin(); it != possibleMembers.end();) if ( it->type->category() == Type::Category::Function && !dynamic_cast(*it->type).canTakeArguments(*arguments, exprType) ) it = possibleMembers.erase(it); + else if (it->type->category() != Type::Category::Function) + it = possibleMembers.erase(it); else ++it; } diff --git a/test/libsolidity/syntaxTests/memberLookup/library_function_vs_native_property_with_parens.sol b/test/libsolidity/syntaxTests/memberLookup/library_function_vs_native_property_with_parens.sol new file mode 100644 index 000000000000..ecac94c4d24b --- /dev/null +++ b/test/libsolidity/syntaxTests/memberLookup/library_function_vs_native_property_with_parens.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0; + +// Test that library function is preferred over native property when called with parentheses. +// This allows OpenZeppelin's Address.isContract() to work alongside Tron's native address.isContract property. +library Address { + function isContract(address account) internal view returns (bool) { + return account.code.length > 0; + } +} + +contract C { + using Address for address; + + function check(address a) public view returns (bool) { + // With parentheses - should use library function + return a.isContract(); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/memberLookup/library_function_vs_native_property_without_parens.sol b/test/libsolidity/syntaxTests/memberLookup/library_function_vs_native_property_without_parens.sol new file mode 100644 index 000000000000..0447477402f4 --- /dev/null +++ b/test/libsolidity/syntaxTests/memberLookup/library_function_vs_native_property_without_parens.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0; + +// Test that accessing a member without parentheses when both a native property +// and a library function exist with the same name results in an ambiguity error. +// Users should use the native property syntax directly without "using for" to avoid this. +library Address { + function isContract(address account) internal view returns (bool) { + return account.code.length > 0; + } +} + +contract C { + using Address for address; + + function check(address a) public view returns (bool) { + // Without parentheses - ambiguous between native property and library function + return a.isContract; + } +} +// ---- +// TypeError 6675: (519-531): Member "isContract" not unique after argument-dependent lookup in address. diff --git a/test/libsolidity/syntaxTests/memberLookup/native_isContract_property.sol b/test/libsolidity/syntaxTests/memberLookup/native_isContract_property.sol new file mode 100644 index 000000000000..1f78572a80e5 --- /dev/null +++ b/test/libsolidity/syntaxTests/memberLookup/native_isContract_property.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.0; + +// Test Tron's native address.isContract property works without library. +contract C { + function check(address a) public view returns (bool) { + return a.isContract; + } +} +// ----