FuelLabs / sway

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

Trait Coherence bug #6232

Open Braqzen opened 3 months ago

Braqzen commented 3 months ago

Context

A contract calls another contract to return a struct. This results in an error message indicating that AbiDecode trait must be implemented. Upon implementing a template AbiDecode trait the subsequent forc build errors with a Trait Coherence error meaning the attached repo cannot be built with or without the trait - blocking production in a deadlock.

Check out the following minimal repo which pins the version to 0.60.0

https://github.com/Braqzen/sway-trait-coherence-bug

Braqzen commented 3 months ago

Once fixed the repo will be deleted.

ironcev commented 3 months ago

How does the original struct looks like? Does it contains anything that cannot be automatically encoded/decoded?

I ask because in the minimum repro, the empty MyType will get the auto-generated AbiDecode implementation which will clash with the one implemented manually. I assume that's the reason for the trait coherence error.

The question is why the original type cannot be encoded/decoded. And if it can't, there should be no auto-impl and thus no trait coherence issues if an implementation is provided.

CC: @xunilrj

SwayStar123 commented 3 months ago

I dont know if this is the intended solution but simply importing the type in contract a will allow the contract to be compiled aka


use libraries::{ContractA, ContractB, MyType};
use std::constants::ZERO_B256;

impl ContractA for Contract {
    fn contract_a_call() {             
        let contract_b = abi(ContractB, ZERO_B256);
        let _ = contract_b.contract_b_call();
    }
}

Incase it is the intended solution the error should be improved. Either way, i hope you can use that as a workaround for now

Braqzen commented 3 months ago

If MyType has fields, but is not imported as above, the error persists.

Once it is imported into ContractA as per Sway's suggestion, the error disappears regardless of whether it has fields.

xunilrj commented 3 months ago

I think this is already fixed by this commit: https://github.com/FuelLabs/sway/commit/f4f9c1391330dde06ce47a94c6439965fff0cbda

Braqzen commented 2 months ago

In version 0.61.2 the following code produces the trait coherence error

contract;

use std::constants::ZERO_B256;

abi MyContract {
    fn call_a();
}

abi Module {
    fn call_b();
}

configurable {
    CONTRACT: ContractId = ContractId::from(ZERO_B256),
}

impl MyContract for Contract {
    fn call_a() {
        let a = abi(Module, CONTRACT.bits());
        let b = abi(Module, CONTRACT.bits());
    }
}

The problem is CONTRACT.bits() for var b. If we extract the clean method call into another line id = CONTRACT.bits() and then use the id in place of CONTRACT.bits() then it works.

Strange bug. We should be able to write the code above instead of extracting into another line to pass in the variable into the abi

@xunilrj

1