Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(forge): new flatten implementation #6936

Merged
merged 11 commits into from
Feb 2, 2024

Conversation

klkvr
Copy link
Member

@klkvr klkvr commented Jan 29, 2024

@klkvr klkvr changed the title [WIP] feat(forge) New flatten implementation feat(forge) New flatten implementation Jan 29, 2024
@klkvr klkvr marked this pull request as ready for review January 29, 2024 16:33
@DaniPopes
Copy link
Member

DaniPopes commented Jan 29, 2024

(You have to write "closes" before each PR, preferably each on a new line)

@avniculae
Copy link

@klkvr Great work, congrats! I run your version of flatten on a project that uses prb math (both UD60x18 and SD59x18) and I can see that the resulted file has some issues renamed variables in assembly blocks. For example, in the code below uUNIT was not replaced with the renamed version (uUNIT_1, _2, ...)

assembly ("memory-safe") {
        switch x
        case 1 { result := mul(uUNIT, sub(0, 18)) }
        case 10 { result := mul(uUNIT, sub(1, 18)) }
        case 100 { result := mul(uUNIT, sub(2, 18)) }
        case 1000 { result := mul(uUNIT, sub(3, 18)) }
        case 10000 { result := mul(uUNIT, sub(4, 18)) }
.....

Is this an easy fix for you?

Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!!

nice work

@DaniPopes DaniPopes changed the title feat(forge) New flatten implementation feat(forge): new flatten implementation Jan 29, 2024
@klkvr
Copy link
Member Author

klkvr commented Jan 29, 2024

@avniculae ah, assembly blocks are not in scope of renaming atm

It shouldn't be hard to fix, could you please drop a link to the contract you are flattening or a minimal repro so it's easier to debug?

@avniculae
Copy link

avniculae commented Jan 29, 2024

@avniculae ah, assembly blocks are not in scope of renaming atm

It shouldn't be hard to fix, could you please drop a link to the contract you are flattening or a minimal repro so it's easier to debug?

Thanks for letting me know! I run it on a private repo, but I think this file should represent a good test.

@avniculae
Copy link

@klkvr another point worth mentioning: docs comments are also not updated during flattening, preventing the final file from compiling successfully. For example:

abstract contract UUPSImplementation is IUUPSImplementation_0, ProxyStorage {
    /**
     * @inheritdoc IUUPSImplementation
     */

@avniculae
Copy link

@klkvr another point: if the contract renames an import (e.g., import { mul as mulUD } from "..."), the flatten command fails to rename mulUD to the new renaming

@klkvr
Copy link
Member Author

klkvr commented Jan 29, 2024

@avniculae thanks for all the points, will try to fix all of them

regarding imports renaming could you please give a bit more context as this case was addressed directly during development and it shouldn't fail

which entity is the mulUD? I mean variable/enum/struct etc

@avniculae
Copy link

avniculae commented Jan 29, 2024

@klkvr I am experiencing issues with function renaming (mul is a function here)

Later Edit: I am experiencing the same issue with some imported variables as well, which are not renamed in the original import at all. Does the code work for constant variables as well (that are freely declared in a file -- i.e. not within a contract?)

Later Edit 2: I think the bigger problem here might be that identifiers are not replaced when prepended or appended with characters such as . or (: for example a.mul(b) or f(ZERO)

@klkvr
Copy link
Member Author

klkvr commented Jan 29, 2024

@avniculae

I can't reproduce this behavior locally, maybe I got something wrong?
So, I am creating 2 files:

mul.sol:

function mul(uint256 a, uint256 b) pure returns(uint256) {
    return a * b;
}

test.sol

pragma solidity 0.8.6;

import {mul as mulUD} from "./mul.sol";

contract Test {
    function foo() public {
        mulMD(1, 2);
    }
}

And test.sol is getting flattened to

pragma solidity 0.8.6;
function mul(uint256 a, uint256 b) pure returns(uint256) {
    return a * b;
}

uint256 constant someVar = 1;

contract Test {
    function foo(uint256 a) public {
        mul(1, 2);
    }
}

which seems correct

klkvr and others added 2 commits January 29, 2024 23:28
Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
@avniculae
Copy link

@klkvr Here's a small counterexample:

SFixed.sol

pragma solidity 0.8.19;

type SFixed256x18 is int256;

using {add} for SFixed256x18 global;

function add(SFixed256x18 a, SFixed256x18 b) pure returns (SFixed256x18) {
    return SFixed256x18.wrap(SFixed256x18.unwrap(a) + SFixed256x18.unwrap(b));
}

UFixed.sol

pragma solidity 0.8.19;

type UFixed256x18 is uint256;

using {add} for UFixed256x18 global;

function add(UFixed256x18 a, UFixed256x18 b) pure returns (UFixed256x18) {
    return UFixed256x18.wrap(UFixed256x18.unwrap(a) + UFixed256x18.unwrap(b));
}

Contract.sol

pragma solidity 0.8.19;

import {SFixed256x18} from "./SFixed.sol";
import {UFixed256x18} from "./UFixed.sol";

contract Test {
    function fun() public pure returns (SFixed256x18, UFixed256x18) {
      SFixed256x18 a = SFixed256x18.wrap(10);
      SFixed256x18 b = SFixed256x18.wrap(-90);
      SFixed256x18 c = a.add(b);

      UFixed256x18 d = UFixed256x18.wrap(20);
      UFixed256x18 e = UFixed256x18.wrap(30);
      UFixed256x18 f = d.add(e);

      return (c, f);
    }
}

In the flattened version, a.add(b) is replaced by add_0(b), while d.add(e) is replaced by add_1(e). However, on the project I'm running it (which uses PRB-Math heavily), the command often leaves these functions unchanged ( e.g., a.add(b)).

Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥

@klkvr
Copy link
Member Author

klkvr commented Jan 31, 2024

hey @avniculae thank you once again for all the edge cases

I belive that all of them should be fixed now, could you please pull this PRs version and try once again if they are working for you?

@avniculae
Copy link

@klkvr Thanks for pushing these fixes! I re-run the latest version and I now get the following error:

The application panicked (crashed).
Message:  called `Option::unwrap()` on a `None` value
Location: .../foundry-compilers-0.3.0/src/flatten.rs:450

This is a bug. Consider reporting it at https://github.com/foundry-rs/foundry

  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                                ⋮ 8 frames hidden ⋮                               
   9: core::panicking::panic::h40561ff494e2b577
      at <unknown source file>:<unknown line>
  10: foundry_compilers::flatten::Flattener::flatten::hf4ff1bfccf30ce3e
      at <unknown source file>:<unknown line>
  11: forge::main::h82dc03aed91a2c0a
      at <unknown source file>:<unknown line>
  12: std::sys_common::backtrace::__rust_begin_short_backtrace::hb40b21b17ab48be9
      at <unknown source file>:<unknown line>
  13: std::rt::lang_start::h39e6cad84a7b22b7
      at <unknown source file>:<unknown line>
  14: _main<unknown>
      at <unknown source file>:<unknown line>

However, it's hard to tell what's causing this error since the flattened code has over 11k loc, and I wasn't able to reproduce it with small examples

@mattsse
Copy link
Member

mattsse commented Feb 1, 2024

@avniculae is this repo public?

@klkvr
Copy link
Member Author

klkvr commented Feb 1, 2024

@avniculae this happens while updating @inheritdoc tags, do you have any uncommon patters in those? Like using aliases, qualified imports? Or all values are just straight contract/interface names?

@avniculae
Copy link

avniculae commented Feb 1, 2024

@klkvr They should all be standard, like this example (I'm less sure about dependencies though)

  /**
   * @inheritdoc InterfaceName
   */

@mattsse Unfortunately it isn't yet :(

@klkvr
Copy link
Member Author

klkvr commented Feb 1, 2024

@avniculae any chance you can share names of other dependencies besides prb-math?

@avniculae
Copy link

@klkvr I think the main ones are prb-math and @openzeppelin/contracts/

@klkvr klkvr marked this pull request as draft February 1, 2024 19:01
mattsse added a commit to foundry-rs/compilers that referenced this pull request Feb 2, 2024
Ref
foundry-rs/foundry#6936 (comment)

Not sure why exactly this unwrap is failing, adding `None` variant
handling and some logs to debug it.

---------

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
@mattsse mattsse marked this pull request as ready for review February 2, 2024 12:13
@mattsse
Copy link
Member

mattsse commented Feb 2, 2024

This includes a ton of improvements, but might still have some limitations which we can fix as soon as they get reported.

@mattsse mattsse merged commit e2d3278 into foundry-rs:master Feb 2, 2024
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment