ethereum/fe

[FOLLOW UP] Type check

Opened this issue · 0 comments

  • Refine name resolution cache functionality and merge path analysis pass with def analysis, this probably should be done before implementing #988

  • Integrate method selection into type inference context properly. For example, s.foo should be resolved to Trait<u32>::method without any ambiguity. (Resolved in #1007)
trait Trait<T> {
    fn method(self) -> T
}

struct S {}

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

impl Trait<u32> 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,

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.


  • Improve error message when function call doesn't satisfy constraints.
    Currently, the error message is not so good when function argument/return type doesn't satisfy the constraints.
    e.g.,
fn foo<T: Copy>(t: Option<T>, u: T) {}

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.