Skip to content

Commit 05c4571

Browse files
authored
Merge pull request #13227 from ethereum/functions_taking_calldata_args_should_be_assignable_to_function_pointer_of_same_type
functions taking calldata args should be assignable to function pointers of same type
2 parents 1d85eb5 + 8c07407 commit 05c4571

5 files changed

+54
-0
lines changed

docs/types/value-types.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,18 @@ This includes private, internal and public functions of both contracts and libra
789789
functions.
790790
External function types, on the other hand, are only compatible with public and external contract
791791
functions.
792+
793+
.. note::
794+
External functions with ``calldata`` parameters are incompatible with external function types with ``calldata`` parameters.
795+
They are compatible with the corresponding types with ``memory`` parameters instead.
796+
For example, there is no function that can be pointed at by a value of type ``function (string calldata) external`` while
797+
``function (string memory) external`` can point at both ``function f(string memory) external {}`` and
798+
``function g(string calldata) external {}``.
799+
This is because for both locations the arguments are passed to the function in the same way.
800+
The caller cannot pass its calldata directly to an external function and always ABI-encodes the arguments into memory.
801+
Marking the parameters as ``calldata`` only affects the implementation of the external function and is
802+
meaningless in a function pointer on the caller's side.
803+
792804
Libraries are excluded because they require a ``delegatecall`` and use :ref:`a different ABI
793805
convention for their selectors <library-selectors>`.
794806
Functions declared in interfaces do not have definitions so pointing at them does not make sense either.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
contract C {
2+
function g(string calldata) external returns (bool) { return true; }
3+
4+
function main() external returns (bool) {
5+
function (string memory) external returns (bool) ptr = this.g;
6+
return ptr("testString");
7+
}
8+
}
9+
// ----
10+
// main() -> true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
contract C {
2+
function f(function (string calldata) external) external {}
3+
function g(string calldata) external {}
4+
5+
function main() external {
6+
function (string calldata) external ptr = this.g;
7+
abi.encodeCall(this.f, (this.g));
8+
this.f(this.g);
9+
}
10+
}
11+
// ----
12+
// TypeError 9574: (161-209): Type function (string memory) external is not implicitly convertible to expected type function (string calldata) external.
13+
// TypeError 5407: (242-250): Cannot implicitly convert component at position 0 from "function (string memory) external" to "function (string calldata) external".
14+
// TypeError 9553: (268-274): Invalid type for argument in function call. Invalid implicit conversion from function (string memory) external to function (string calldata) external requested.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
contract C {
2+
function g(string calldata) external {}
3+
4+
function main() view external {
5+
function (string memory) external ptr = this.g;
6+
ptr;
7+
}
8+
}
9+
// ----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
contract C {
2+
function g(bytes calldata b) pure internal {}
3+
4+
function main() pure external {
5+
function (bytes calldata) internal ptr = g;
6+
ptr;
7+
}
8+
}
9+
// ----

0 commit comments

Comments
 (0)