Type representation of literals

In the solidity docs, it says literal are represented as their smallest mobile type but it seem different for shift left than arithmetic operators e.g. the following results in below error message but it works fine as 1 * a (it will treat 1 as uint8). Is there somewhere this is clarified or someone can elaborate on the semantics?

Error: Return argument type uint256 is not implicitly convertible to expected type (type of first return variable) uint8. --> test.sol:3:16: | 3 | return 1 << a; |

contract Test { function y(uint8 a) external pure returns(uint8){ return 1 << a; }

In past versions of the Solidity compiler, this has lead to a lot of confusion (and probably bugs), because results larger than uint8 would be truncated implicitly and “without a warning”.

I believe that in order to keep it safe, the compiler development team has changed it such that when the first operand of the shift-left operation is a constant literal, it is taken as a uint256.

Subsequently, the returned value of the operation is also of type uint256, so there are two different ways for you to fix the compilation error, depending on the desired behavior of your code:

function y(uint8 a) external pure returns (uint8) {
    return uint8(1) << a;
}

function y(uint8 a) external pure returns (uint256) {
    return 1 << a;
}
2 Likes