ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.14k stars 5.74k forks source link

Can't use function overloading in libraries #13981

Closed Sabnock01 closed 1 year ago

Sabnock01 commented 1 year ago

Description

I have a library with overloaded functions which builds without error, but when I go to use it in another file, the contract using the library only seems to recognize the first function declared. I have provided the following example to reproduce:

library Cast {
    function i128(uint256 x) internal {...}

    function i128(uint128 x) internal {...}
}

contract Caster {
    using Cast for uint256;
    using Cast for uint128;

    function castNums(uint256 a, uint128 b) public {
        int128 newA = a.i128();
        int128 newB = b.i128();
    }
}

In this example, only the first i128 may be used in the below contract. Use of the second one will give the following compiler error:

Compiler run failed
error[6675]: TypeError: Member "i128" not unique after argument-dependent lookup in type(library Cast).
  --> src/Counter.sol:24:23:
   |
24 |         int128 newB = Cast.i128(b);
   |                       ^^^^^^^^^

This is still the case if the using ... for ... syntax is removed and / or if the Cast.i128(...) syntax is used. It is also true if the function visibility is changed from internal to external.

Is this desired behavior? It seems to me this should be doable since the function signatures are the same.

Environment

Steps to Reproduce

Simply running forge build on the snippet above should be enough. Moreover I even get a syntax error in VS Code on the same line.

cameel commented 1 year ago

This is not limited to libraries. All functions in Solidity work this way. The first call works because there's only one overload that can take uint256. The second one is ambiguous because uint128 is also implicitly convertible to uint256 so both candidates are viable. We already have an issue about the compiler failing to explain that clearly: #9607.

The compiler could resolve the ambiguity by choosing the more fitting overload, it just does not do that yet. That's covered by #1256.

You should also be able to work around it by attaching only a specific overload for your type with the using {L.f} for T syntax but infortunately this is not yet implemented either: #3556.

Overall, this is a valid report and the behavior should be changed, but we already have issues covering all these problems so I'm closing this one as a duplicate.

Sabnock01 commented 1 year ago

Awesome, thanks!