diff --git a/src/test/compile-fail/method-ambig-one-trait-coerce.rs b/src/test/compile-fail/method-ambig-one-trait-coerce.rs new file mode 100644 index 0000000000000..e5c3da10df8e9 --- /dev/null +++ b/src/test/compile-fail/method-ambig-one-trait-coerce.rs @@ -0,0 +1,44 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that when we pick a trait based on coercion, versus subtyping, +// we consider all possible coercions equivalent and don't try to pick +// a best one. + +trait Object { } + +trait foo { + fn foo(self) -> int; +} + +impl foo for Box { + fn foo(self) -> int {1} +} + +impl foo for Box { + fn foo(self) -> int {2} +} + +fn test1(x: Box) { + // Ambiguous because we could coerce to either impl: + x.foo(); //~ ERROR E0034 +} + +fn test2(x: Box) { + // Not ambiguous because it is a precise match: + x.foo(); +} + +fn test3(x: Box) { + // Not ambiguous because it is a precise match: + x.foo(); +} + +fn main() { } diff --git a/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs new file mode 100644 index 0000000000000..e211db2dcd296 --- /dev/null +++ b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs @@ -0,0 +1,45 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we invoking `foo()` successfully resolves to the trait `foo` +// (prompting the mismatched types error) but does not influence the choice +// of what kind of `Vec` we have, eventually leading to a type error. + +trait foo { + fn foo(&self) -> int; +} + +impl foo for Vec { + fn foo(&self) -> int {1} +} + +impl foo for Vec { + fn foo(&self) -> int {2} +} + +// This is very hokey: we have heuristics to suppress messages about +// type annotations required. But placing these two bits of code into +// distinct functions, in this order, causes us to print out both +// errors I'd like to see. + +fn m1() { + // we couldn't infer the type of the vector just based on calling foo()... + let mut x = Vec::new(); //~ ERROR type annotations required + x.foo(); +} + +fn m2() { + let mut x = Vec::new(); + + // ...but we still resolved `foo()` to the trait and hence know the return type. + let y: uint = x.foo(); //~ ERROR mismatched types +} + +fn main() { } diff --git a/src/test/compile-fail/ambig_impl_2_exe.rs b/src/test/compile-fail/method-ambig-two-traits-cross-crate.rs similarity index 74% rename from src/test/compile-fail/ambig_impl_2_exe.rs rename to src/test/compile-fail/method-ambig-two-traits-cross-crate.rs index 13cceaa71ae06..30e635149c442 100644 --- a/src/test/compile-fail/ambig_impl_2_exe.rs +++ b/src/test/compile-fail/method-ambig-two-traits-cross-crate.rs @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test an ambiguity scenario where one copy of the method is available +// from a trait imported from another crate. + // aux-build:ambig_impl_2_lib.rs extern crate ambig_impl_2_lib; use ambig_impl_2_lib::me; trait me2 { fn me(&self) -> uint; } -impl me2 for uint { fn me(&self) -> uint { *self } } //~ NOTE is `uint.me2::me` -fn main() { 1u.me(); } //~ ERROR multiple applicable methods in scope -//~^ NOTE is `ambig_impl_2_lib::uint.me::me` +impl me2 for uint { fn me(&self) -> uint { *self } } +fn main() { 1u.me(); } //~ ERROR E0034 + diff --git a/src/test/compile-fail/ambig_impl_bounds.rs b/src/test/compile-fail/method-ambig-two-traits-from-bounds.rs similarity index 76% rename from src/test/compile-fail/ambig_impl_bounds.rs rename to src/test/compile-fail/method-ambig-two-traits-from-bounds.rs index 9f26e5ae9b380..184927c01357a 100644 --- a/src/test/compile-fail/ambig_impl_bounds.rs +++ b/src/test/compile-fail/method-ambig-two-traits-from-bounds.rs @@ -12,9 +12,7 @@ trait A { fn foo(&self); } trait B { fn foo(&self); } fn foo(t: T) { - t.foo(); //~ ERROR multiple applicable methods in scope - //~^ NOTE candidate #1 derives from the bound `A` - //~^^ NOTE candidate #2 derives from the bound `B` + t.foo(); //~ ERROR E0034 } fn main() {} diff --git a/src/test/compile-fail/ambig-default-method.rs b/src/test/compile-fail/method-ambig-two-traits-with-default-method.rs similarity index 65% rename from src/test/compile-fail/ambig-default-method.rs rename to src/test/compile-fail/method-ambig-two-traits-with-default-method.rs index 56ab6d7da3f89..87efaed4e3dda 100644 --- a/src/test/compile-fail/ambig-default-method.rs +++ b/src/test/compile-fail/method-ambig-two-traits-with-default-method.rs @@ -8,12 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo { fn method(&self) {} } //~ NOTE `Foo::method` -trait Bar { fn method(&self) {} } //~ NOTE `Bar::method` +// Test that we correctly report an ambiguity where two applicable traits +// are in scope and the method being invoked is a default method not +// defined directly in the impl. + +trait Foo { fn method(&self) {} } +trait Bar { fn method(&self) {} } impl Foo for uint {} impl Bar for uint {} fn main() { - 1u.method(); //~ ERROR multiple applicable methods in scope + 1u.method(); //~ ERROR E0034 } diff --git a/src/test/compile-fail/method-commit-to-trait.rs b/src/test/compile-fail/method-commit-to-trait.rs new file mode 100644 index 0000000000000..6e4b5e088c9fc --- /dev/null +++ b/src/test/compile-fail/method-commit-to-trait.rs @@ -0,0 +1,33 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we pick `Foo`, and also pick the `impl`, even though in +// this case the vector type `T` is not copyable. This is because +// there is no other reasonable choice. The error you see is thus +// about `T` being non-copyable, not about `Foo` being +// unimplemented. This is better for user too, since it suggests minimal +// diff requird to fix program. + +trait Object { } + +trait Foo { + fn foo(self) -> int; +} + +impl Foo for Vec { + fn foo(self) -> int {1} +} + +fn test1(x: Vec) { + x.foo(); + //~^ ERROR `core::kinds::Copy` is not implemented for the type `T` +} + +fn main() { } diff --git a/src/test/compile-fail/ambig_impl_unify.rs b/src/test/run-pass/method-two-trait-defer-resolution-1.rs similarity index 56% rename from src/test/compile-fail/ambig_impl_unify.rs rename to src/test/run-pass/method-two-trait-defer-resolution-1.rs index 67b7a5a7f3700..e4ae33c1c5055 100644 --- a/src/test/compile-fail/ambig_impl_unify.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-1.rs @@ -8,20 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that we pick which version of `foo` to run based on the +// type that is (ultimately) inferred for `x`. trait foo { fn foo(&self) -> int; } impl foo for Vec { - fn foo(&self) -> int {1} //~ NOTE candidate #1 is `Vec.foo::foo` + fn foo(&self) -> int {1} } impl foo for Vec { - fn foo(&self) -> int {2} //~ NOTE candidate #2 is `Vec.foo::foo` + fn foo(&self) -> int {2} +} + +fn call_foo_uint() -> int { + let mut x = Vec::new(); + let y = x.foo(); + x.push(0u); + y +} + +fn call_foo_int() -> int { + let mut x = Vec::new(); + let y = x.foo(); + x.push(0i); + y } fn main() { - let x = Vec::new(); - x.foo(); //~ ERROR multiple applicable methods in scope + assert_eq!(call_foo_uint(), 1); + assert_eq!(call_foo_int(), 2); } diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs new file mode 100644 index 0000000000000..cae783e7ea84a --- /dev/null +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -0,0 +1,48 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we pick which version of `Foo` to run based on whether +// the type we (ultimately) inferred for `x` is copyable or not. +// +// In this case, the two versions are both impls of same trait, and +// hence we we can resolve method even without knowing yet which +// version will run (note that the `push` occurs after the call to +// `foo()`). + +trait Foo { + fn foo(&self) -> int; +} + +impl Foo for Vec { + fn foo(&self) -> int {1} +} + +impl Foo for Vec> { + fn foo(&self) -> int {2} +} + +fn call_foo_copy() -> int { + let mut x = Vec::new(); + let y = x.foo(); + x.push(0u); + y +} + +fn call_foo_other() -> int { + let mut x = Vec::new(); + let y = x.foo(); + x.push(box 0i); + y +} + +fn main() { + assert_eq!(call_foo_copy(), 1); + assert_eq!(call_foo_other(), 2); +}