Question about IR semantic changes

Hi all, apologies in advance if this is not the right place to ask this. If so, please let me know the more appropriate channel to ask these questions.


I was reading through Solidity IR-based Codegen Changes — Solidity 0.8.23 documentation but don’t really understand the explanations for:

  1. Evaluation order of expression

    • For the old code generator, the evaluation order of expressions is unspecified but how does the compiler decide whether to go from left to right or right to left?
    • For the new code generator, we try to evaluate in source order (left to right), but do not guarantee it. What is an example of when this is not guaranteed and why is this not guaranteed? As a protocol developer, how can I ensure that my functions are always executed in the right order? Is it possible for different compiler versions to execute functions in the opposite order?
  2. Internal function pointers

    • In the new code generator, function pointers use internal IDs that are allocated in sequence. What exactly is a function pointer and how can I see these internal IDs and the internal dispatch function in action? Is this the same dispatch function as the traditional dispatch function where the current selector is matched against all selectors in the contract?

Any help is appreciated.

1 Like

Answer by example:

uint32 private stateVar;

function func1(uint16 arg) private pure returns (uint32) {
    return uint32(arg) + 1;
}

function func2(uint16 arg) private pure returns (uint32) {
    return uint32(arg) + 2;
}

function doStuff(function (uint16) pure returns (uint32) funcPtr) private {
    stateVar = funcPtr(888);
}

function userFunc(uint256 x, uint256 y) external {
    if (x > y)
        doStuff(func1);
    else
        doStuff(func2);
}

Function userFunc is the only function which can be executed by an external user.

When executed, it calls function doStuff and passes it a pointer to either func1 or func2.

When function doStuff is executed, it calls the function whose pointer it has received as input.

As you can see, there is only a handful of “unusual syntax” involved here.

First, the passing of functions func1 and func2 as input to function doStuff:

doStuff(func1);
doStuff(func2);

Second, the function-pointer which function doStuff takes as input argument:

function (uint16) pure returns (uint32) funcPtr

The 1st set of parenthesis indicates the types which funcPtr takes as input.
The 2nd set of parenthesis indicates the types which funcPtr returns as output.
In this example, the pointed function takes a uint16 input and returns a uint32 output.

3 Likes