[Bug]: Inconsistent behavior when setting the type of the return value of abi.decode()
- Dominant language
- Python
- Stars
- 6.4k
- Forks
- 1.1k
- PR merge metrics
- No merged PRs in 30d
Description
### Describe the issue:
First case: The type of return variable of `SOLIDITY_CALL abi.decode()` is None when the decoded data type is a single user-defined type, e.g., `(L.E x) = abi.decode(data, (L.E));`.
I am aware of #566, which leaves type None as a temporary solution.
However, I see (case 2) when the `lvalue` is `TupleVariable`, e.g., `(L.E y, uint z) = abi.decode(data, (L.E, uint));`, the reference variable refers to the user-defined type is used as the type of return values.
This is inconsistent with the first case where None is set as type.
Keeping the behavior of type inference consistent would benefit the downstream analyzers a lot.
I hope this can be improved, i.e., also set the type as the reference variable in the first case.
BTW, are you guys still planning to enhance `ReferenceVariable` as mentioned as one of the solutions in #566 in branch `dev-0.7`?
### Code example to reproduce the issue:
```solidity
library L {
enum E { A, B }
}
contract A {
function foo(bytes memory data) public {
(L.E x) = abi.decode(data, (L.E)); // case 1
(L.E y, uint z) = abi.decode(data, (L.E, unit)); // case 2
(uint m) = abi.decode(data, (uint));
}
}
```
### Version:
0.9.3
### Relevant log output:
```shell
Contract A
Function A.foo(bytes) (*)
Expression: x = abi.decode(data,(L.E)) # case 1
IRs:
REF_1(None) -> L.E
TMP_0(None) = SOLIDITY_CALL abi.decode()(data,REF_1)
x(L.E) := TMP_0(None)
Expression: (y,z) = abi.decode(data,(L.E,uint256)) # case 2
IRs:
REF_3(None) -> L.E
TUPLE_0(REF_3,uint256) = SOLIDITY_CALL abi.decode()(data(REF_3,uint256))
y(L.E)= UNPACK TUPLE_0 index: 0
z(uint256)= UNPACK TUPLE_0 index: 1
Expression: m = abi.decode(data,(uint256))
IRs:
TMP_1(uint256) = SOLIDITY_CALL abi.decode()(data,uint256)
m(uint256) := TMP_1(uint256)
```
Contributor guide
Research direction
Reproduce the two abi.decode() examples from the issue and compare their emitted IR, especially the SOLIDITY_CALL and ReferenceVariable handling. Trace the code path for single-value and tuple return types, then verify that both forms assign consistent user-defined types and that the existing uint case remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, solidity
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100