Description
Description
The compiler crashes when a conditional value is assigned to a tuple which contains both memory and calldata variables. (I may be wrong about the exact reasons – this is only from repetitive testing and derivation of a minimal reproducible scenario)
The error:
Error: Internal compiler error:
/solidity/libsolidity/codegen/YulUtilFunctions.cpp(3849): Throw in function std::string solidity::frontend::YulUtilFunctions::arrayConversionFunction(const solidity::frontend::ArrayType&, const solidity::frontend::ArrayType&)
Dynamic exception type: boost::wrapexcept<solidity::langutil::InternalCompilerError>
std::exception::what: Solidity assertion failed
[solidity::util::tag_comment*] = Solidity assertion failed
Note: I discovered this bug when trying to return some data from memory and some data from calldata, but it seems it's also triggered when assigning to a tuple. The latter is more minimal, so it's the one being shared. But the original use case of return data is not so easily worked around. In particular, changing the declared returned variable to be located to memory has very severe consequences for returning arrays of structs (my use case), since conversion to memory turns them into arrays of pointers, only to be brought back to the original form for abi encoding, which is very inefficient. So, there is currently no workaround for this issue without using Yul for abi encoding.
Environment
- Compiler version: 0.8.30
- Compilation pipeline (legacy, IR, EOF): default (IR)
- Target EVM version (as per compiler settings): cancun
- Framework/IDE (e.g. Foundry, Hardhat, Remix): Foundry
- EVM execution environment / backend / blockchain client: ---
- Operating system: Arch Linux
Steps to Reproduce
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.30;
contract Crash {
function crashCompiler(bool conditional, uint[] calldata arr) external pure {
uint[] memory ops1; // we take two arrays so the compiler won't short-circuit the conditional
uint[] memory ops2;
(uint[] memory a, uint[] calldata b) = conditional ? (ops1, arr) : (ops2, arr);
}
}