ethereum / fe

Emerging smart contract language for the Ethereum blockchain.
https://fe-lang.org
Other
1.6k stars 178 forks source link

[FOLLOW UP] Type check #996

Open Y-Nak opened 4 months ago

Y-Nak commented 4 months ago

struct S {}

impl Trait for S { fn method(self) -> i32 { 1 } }

impl Trait for S { fn method(self) -> u32 { 1 } }

fn foo() -> u32 { let s = S {}; s.method() }


This could be achieved by maintaining the mapping between a canonical type and a given receiver type in a call site. 
Also, the method selector needs to return a `TraitInst` that relates to the receiver type. In the above example, it will be `Canonical<Trait<S, ?0>>`.  The below one is a more complex case,
```rust
trait Default {
    fn default() -> Self
}

trait Foo<T, U> {
    fn foo(self) -> (T, U)
}

struct S<T> {
    t: T,
}

impl<T> S<T> {
    fn new() -> Self
    where
        T: Default,
    {
        Self { t: T::default() }
    }
}

impl<T> Foo<i32, T> for S<T> {
    fn foo(self) -> (i32, T) {
        (1, self.t)
    }
}

impl<T> Foo<u32, T> for S<T> {
    fn foo(self) -> (u32, T) {
        (1, self.t)
    }
}

fn bar() -> (u32, i32) {
    let s = S::new()
    s.foo()
}

In this case, assuming the type of s is S<?10> in the inference context and its canonical form is Canonical<S<?0>>, then the method selector needs to return Canonical<Trait<S<?0>, ?1, ?0>> as a candidate for s.foo. Then, it should be decanonicalized to Trait<S<?10>, ?fresh, ?10> in the inference context, where ?fresh is a new type variable.


fn bar() { let opt = Some("FOO") foo(t: opt, u: "FOO") }

emits the below error currently.

error[6-0003]: trait bound is not satisfied ┌─ foo.fe:12:5 │ 12 │ foo(t: opt, u: "FOO") │ ^^^ String<3> doesn't implement Copy


To address this issue generally, we need to maintain how the generic parameter relates to the argument/return type given by the call site in the type inference phase.