E3035

E3035 — A method name that more than one impl block defines for the same type. The impls are kept in a hash map, so which body a call reached used to change from one run of the compiler to the next; refusing the call is the only answer that is the same twice. Naming the trait, as in Display::fmt(&x, f), chooses one impl.

What the compiler reports

E3035
Method 'describe' on 'i64' is defined by more than one impl (Loud, Quiet); name the … trait to choose one, as in 'Loud::describe(..)'

The fragments the test suite holds the compiler to. An ellipsis marks text the test does not constrain; the emitted message also carries a source location.

A program that triggers it

//
// Part of the Vx Project, under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// Two traits define `describe` for `i64`, and `x.describe()` does not say which one it means.
// Naming the trait, `Loud::describe(&x)`, does: see
// tests/backend/pass/trait_qualified_call_picks_the_trait.vx.
//
// This has to be refused rather than resolved: the impl blocks live in a hash map, and the
// body a call reached used to be whichever came first in that order. Three runs of this
// program printed 1, 1 and 2. The diagnostic names both impls, so the reader knows what to
// rename.
//
// Two impls of ONE trait are a different case and are no longer refused: their methods take
// different types, so the argument says which is meant. That is
// tests/backend/pass/static_call_picks_the_impl_by_argument.vx. What is left here is the case
// no argument can decide, because both signatures are identical.
//
// The call is an instance call. Static dispatch narrows by argument type; instance dispatch
// does not, because `resolve_method_in_impls` is not given the argument types -- so this file
// would be refused either way, and it is not evidence about the static path.
//
trait Loud {
  fn describe(self : &i64) -> i32;
}

trait Quiet {
  fn describe(self : &i64) -> i32;
}

impl Loud for i64 {
  fn describe(self : &i64) -> i32 {
    return 1;
  }
}

impl Quiet for i64 {
  fn describe(self : &i64) -> i32 {
    return 2;
  }
}

fn main() -> i32 {
  let x : i64 = 5;
  print(x.describe());
  return 0;
}

From tests/frontend/fail/two_impls_one_method_is_refused.vx, which asserts this diagnostic on every commit.

Related