FuelLabs / sway

🌴 Empowering everyone to build reliable and efficient smart contracts.
https://docs.fuel.network/docs/sway/
Apache License 2.0
62.64k stars 5.36k forks source link

Generic function monomorphization is incorrectly done. #4719

Closed esdrubal closed 1 year ago

esdrubal commented 1 year ago

The following script should not fail on the assert.

script;

use std::assert::*;

trait Trait {
    fn method(self) -> u64;
}

impl Trait for u64 {
    fn method(self) -> u64{
        42
    }
}

struct CallTrait<V> {}

#[inline(never)]
fn call_trait<T>(t: T) -> u64 where T: Trait {
    t.method()
}

impl<K> CallTrait<K> where K: Trait {
    pub fn call_trait(self, key: K) -> u64 {
        call_trait(key)
    }
}

fn main() -> bool {
    let _  = call_trait(1);
    let ct = CallTrait::<u64> {};
    assert(ct.call_trait(1) == 42);
    true
}

In the generated IR we can see that call_trait_7 is returning undef:

entry fn main() -> bool, !1 {
    entry():
    v0 = const u64 1, !2
    v1 = call call_trait_0(v0), !3
    v2 = const u64 1, !4
    v3 = call call_trait_7(v2), !7
    v4 = const u64 42, !8
    v5 = cmp eq v3 v4, !9
    v6 = const bool false, !11
    v7 = cmp eq v5 v6, !15
    cbr v7, assert_2_block0(), assert_2_block1(), !16

    assert_2_block0():
    v8 = const u64 18446744073709486084, !18
    revert v8, !22

    assert_2_block1():
    v9 = const bool true, !23
    ret bool v9
}

fn call_trait_0(t !24: u64) -> u64, !27 {
    entry(t: u64):
    v0 = const u64 42, !28
    ret u64 v0
}

fn call_trait_7(t !24: u64) -> u64, !29 {
    entry(t: u64):
    v0 = const u64 undef
    ret u64 v0
}

We should make sure that the compiler no longer fails silently while compiling generic methods.

tritao commented 1 year ago

Do you know if this is a frontend or codegen issue?

I've seen IR gen happily insert undef before instead of asserting, when given IR that is not fully correctly typed. Just something to keep in mind.

esdrubal commented 1 year ago

This looks like a frontend bug that the backend could catch.

Here is the line of code that is adding the undef, I tried to replace it by a compile error but it is required as it says on the comments for diverging control flow and implicit returns. https://github.com/FuelLabs/sway/blob/0d45b890c9eaa75b88093a9a4cbecbf5ca8c0731/sway-core/src/ir_generation/compile.rs#L491-L496