diff options
Diffstat (limited to 'src/test/ui/methods')
76 files changed, 3088 insertions, 0 deletions
diff --git a/src/test/ui/methods/assign-to-method.rs b/src/test/ui/methods/assign-to-method.rs new file mode 100644 index 000000000..85beaee8d --- /dev/null +++ b/src/test/ui/methods/assign-to-method.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zsave-analysis +// Also regression test for #69409 + +struct Cat { + meows : usize, + how_hungry : isize, +} + +impl Cat { + pub fn speak(&self) { self.meows += 1; } +} + +fn cat(in_x : usize, in_y : isize) -> Cat { + Cat { + meows: in_x, + how_hungry: in_y + } +} + +fn main() { + let nyan : Cat = cat(52, 99); + nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method + nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method +} diff --git a/src/test/ui/methods/assign-to-method.stderr b/src/test/ui/methods/assign-to-method.stderr new file mode 100644 index 000000000..cafe9abae --- /dev/null +++ b/src/test/ui/methods/assign-to-method.stderr @@ -0,0 +1,19 @@ +error[E0615]: attempted to take value of method `speak` on type `Cat` + --> $DIR/assign-to-method.rs:22:10 + | +LL | nyan.speak = || println!("meow"); + | ^^^^^ method, not a field + | + = help: methods are immutable and cannot be assigned to + +error[E0615]: attempted to take value of method `speak` on type `Cat` + --> $DIR/assign-to-method.rs:23:10 + | +LL | nyan.speak += || println!("meow"); + | ^^^^^ method, not a field + | + = help: methods are immutable and cannot be assigned to + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0615`. diff --git a/src/test/ui/methods/auxiliary/ambig_impl_2_lib.rs b/src/test/ui/methods/auxiliary/ambig_impl_2_lib.rs new file mode 100644 index 000000000..0ed68bf69 --- /dev/null +++ b/src/test/ui/methods/auxiliary/ambig_impl_2_lib.rs @@ -0,0 +1,4 @@ +pub trait Me { + fn me(&self) -> usize; +} +impl Me for usize { fn me(&self) -> usize { *self } } diff --git a/src/test/ui/methods/auxiliary/macro-in-other-crate.rs b/src/test/ui/methods/auxiliary/macro-in-other-crate.rs new file mode 100644 index 000000000..feda08463 --- /dev/null +++ b/src/test/ui/methods/auxiliary/macro-in-other-crate.rs @@ -0,0 +1,9 @@ +#[macro_export] +macro_rules! mac { + ($ident:ident) => { let $ident = 42; } +} + +#[macro_export] +macro_rules! inline { + () => () +} diff --git a/src/test/ui/methods/auxiliary/method_self_arg1.rs b/src/test/ui/methods/auxiliary/method_self_arg1.rs new file mode 100644 index 000000000..f89019fe5 --- /dev/null +++ b/src/test/ui/methods/auxiliary/method_self_arg1.rs @@ -0,0 +1,35 @@ +#![crate_type = "lib"] + +static mut COUNT: u64 = 1; + +pub fn get_count() -> u64 { unsafe { COUNT } } + +#[derive(Copy, Clone)] +pub struct Foo; + +impl Foo { + pub fn foo(self, x: &Foo) { + unsafe { COUNT *= 2; } + // Test internal call. + Foo::bar(&self); + Foo::bar(x); + + Foo::baz(self); + Foo::baz(*x); + + Foo::qux(Box::new(self)); + Foo::qux(Box::new(*x)); + } + + pub fn bar(&self) { + unsafe { COUNT *= 3; } + } + + pub fn baz(self) { + unsafe { COUNT *= 5; } + } + + pub fn qux(self: Box<Foo>) { + unsafe { COUNT *= 7; } + } +} diff --git a/src/test/ui/methods/auxiliary/method_self_arg2.rs b/src/test/ui/methods/auxiliary/method_self_arg2.rs new file mode 100644 index 000000000..967254562 --- /dev/null +++ b/src/test/ui/methods/auxiliary/method_self_arg2.rs @@ -0,0 +1,52 @@ +#![crate_type = "lib"] + +static mut COUNT: u64 = 1; + +pub fn get_count() -> u64 { unsafe { COUNT } } + +#[derive(Copy, Clone)] +pub struct Foo; + +impl Foo { + pub fn run_trait(self) { + unsafe { COUNT *= 17; } + // Test internal call. + Bar::foo1(&self); + Bar::foo2(self); + Bar::foo3(Box::new(self)); + + Bar::bar1(&self); + Bar::bar2(self); + Bar::bar3(Box::new(self)); + } +} + +pub trait Bar : Sized { + fn foo1(&self); + fn foo2(self); + fn foo3(self: Box<Self>); + + fn bar1(&self) { + unsafe { COUNT *= 7; } + } + fn bar2(self) { + unsafe { COUNT *= 11; } + } + fn bar3(self: Box<Self>) { + unsafe { COUNT *= 13; } + } +} + +impl Bar for Foo { + fn foo1(&self) { + unsafe { COUNT *= 2; } + } + + fn foo2(self) { + unsafe { COUNT *= 3; } + } + + fn foo3(self: Box<Foo>) { + unsafe { COUNT *= 5; } + } +} diff --git a/src/test/ui/methods/issues/issue-61525.rs b/src/test/ui/methods/issues/issue-61525.rs new file mode 100644 index 000000000..c5ca0326e --- /dev/null +++ b/src/test/ui/methods/issues/issue-61525.rs @@ -0,0 +1,20 @@ +pub trait Example { + fn query<Q>(self, q: Q); +} + +impl Example for i32 { + fn query<Q>(self, _: Q) { + unimplemented!() + } +} + +mod nested { + use super::Example; + fn example() { + 1.query::<dyn ToString>("") + //~^ ERROR the size for values of type `dyn ToString` cannot be known at compilation time + //~| ERROR mismatched types + } +} + +fn main() {} diff --git a/src/test/ui/methods/issues/issue-61525.stderr b/src/test/ui/methods/issues/issue-61525.stderr new file mode 100644 index 000000000..aec968d7c --- /dev/null +++ b/src/test/ui/methods/issues/issue-61525.stderr @@ -0,0 +1,39 @@ +error[E0277]: the size for values of type `dyn ToString` cannot be known at compilation time + --> $DIR/issue-61525.rs:14:33 + | +LL | 1.query::<dyn ToString>("") + | ----- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `dyn ToString` +note: required by a bound in `Example::query` + --> $DIR/issue-61525.rs:2:14 + | +LL | fn query<Q>(self, q: Q); + | ^ required by this bound in `Example::query` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn query<Q: ?Sized>(self, q: Q); + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-61525.rs:14:33 + | +LL | 1.query::<dyn ToString>("") + | --------------------- ^^ expected trait object `dyn ToString`, found `&str` + | | + | arguments to this function are incorrect + | + = note: expected trait object `dyn ToString` + found reference `&'static str` +note: associated function defined here + --> $DIR/issue-61525.rs:2:8 + | +LL | fn query<Q>(self, q: Q); + | ^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/methods/issues/issue-84495.rs b/src/test/ui/methods/issues/issue-84495.rs new file mode 100644 index 000000000..28c094bf2 --- /dev/null +++ b/src/test/ui/methods/issues/issue-84495.rs @@ -0,0 +1,4 @@ +fn main() { + let x: i32 = 1; + println!("{:?}", x.count()); //~ ERROR is not an iterator +} diff --git a/src/test/ui/methods/issues/issue-84495.stderr b/src/test/ui/methods/issues/issue-84495.stderr new file mode 100644 index 000000000..b0217a7c8 --- /dev/null +++ b/src/test/ui/methods/issues/issue-84495.stderr @@ -0,0 +1,13 @@ +error[E0599]: `i32` is not an iterator + --> $DIR/issue-84495.rs:3:24 + | +LL | println!("{:?}", x.count()); + | ^^^^^ `i32` is not an iterator + | + = note: the following trait bounds were not satisfied: + `i32: Iterator` + which is required by `&mut i32: Iterator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/methods/issues/issue-90315.rs b/src/test/ui/methods/issues/issue-90315.rs new file mode 100644 index 000000000..01bf9f484 --- /dev/null +++ b/src/test/ui/methods/issues/issue-90315.rs @@ -0,0 +1,7 @@ +fn main() { + let arr = &[0,1,2,3]; + for _i in 0..arr.len().rev() { //~ERROR not an iterator + // The above error used to say “the method `rev` exists for type `usize`”. + // This regression test ensures it doesn't say that any more. + } +} diff --git a/src/test/ui/methods/issues/issue-90315.stderr b/src/test/ui/methods/issues/issue-90315.stderr new file mode 100644 index 000000000..c6a76c9e7 --- /dev/null +++ b/src/test/ui/methods/issues/issue-90315.stderr @@ -0,0 +1,13 @@ +error[E0599]: `usize` is not an iterator + --> $DIR/issue-90315.rs:3:26 + | +LL | for _i in 0..arr.len().rev() { + | ^^^ `usize` is not an iterator + | + = note: the following trait bounds were not satisfied: + `usize: Iterator` + which is required by `&mut usize: Iterator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/methods/issues/issue-94581.rs b/src/test/ui/methods/issues/issue-94581.rs new file mode 100644 index 000000000..df393e91d --- /dev/null +++ b/src/test/ui/methods/issues/issue-94581.rs @@ -0,0 +1,7 @@ +fn get_slice() -> &'static [i32] { + &[1, 2, 3, 4] +} + +fn main() { + let sqsum = get_slice().map(|i| i * i).sum(); //~ ERROR [E0599] +} diff --git a/src/test/ui/methods/issues/issue-94581.stderr b/src/test/ui/methods/issues/issue-94581.stderr new file mode 100644 index 000000000..d6be29cf5 --- /dev/null +++ b/src/test/ui/methods/issues/issue-94581.stderr @@ -0,0 +1,15 @@ +error[E0599]: `&'static [i32]` is not an iterator + --> $DIR/issue-94581.rs:6:29 + | +LL | let sqsum = get_slice().map(|i| i * i).sum(); + | ^^^ `&'static [i32]` is not an iterator; try calling `.iter()` + | + = note: the following trait bounds were not satisfied: + `&'static [i32]: Iterator` + which is required by `&mut &'static [i32]: Iterator` + `[i32]: Iterator` + which is required by `&mut [i32]: Iterator` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs new file mode 100644 index 000000000..7b2fc34e1 --- /dev/null +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.rs @@ -0,0 +1,36 @@ +// 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) -> isize; +} + +impl Foo for Vec<usize> { + fn foo(&self) -> isize {1} +} + +impl Foo for Vec<isize> { + fn foo(&self) -> isize {2} +} + +// This is very hokey: we have heuristics to suppress messages about +// type annotations needed. 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 needed + x.foo(); //~ ERROR type annotations needed +} + +fn m2() { + let mut x = Vec::new(); + + // ...but we still resolved `foo()` to the trait and hence know the return type. + let y: usize = x.foo(); //~ ERROR mismatched types +} + +fn main() { } diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr new file mode 100644 index 000000000..e0f8a5447 --- /dev/null +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -0,0 +1,47 @@ +error[E0282]: type annotations needed for `Vec<T>` + --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:9 + | +LL | let mut x = Vec::new(); + | ^^^^^ + | +help: consider giving `x` an explicit type, where the type for type parameter `T` is specified + | +LL | let mut x: Vec<T> = Vec::new(); + | ++++++++ + +error[E0283]: type annotations needed + --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7 + | +LL | x.foo(); + | ^^^ + | +note: multiple `impl`s satisfying `Vec<_>: Foo` found + --> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1 + | +LL | impl Foo for Vec<usize> { + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | impl Foo for Vec<isize> { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: try using a fully qualified path to specify the expected types + | +LL | <Vec<T> as Foo>::foo(&x); + | ++++++++++++++++++++++ ~ + +error[E0308]: mismatched types + --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20 + | +LL | let y: usize = x.foo(); + | ----- ^^^^^^^ expected `usize`, found `isize` + | | + | expected due to this + | +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit + | +LL | let y: usize = x.foo().try_into().unwrap(); + | ++++++++++++++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0282, E0283, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.rs b/src/test/ui/methods/method-ambig-two-traits-cross-crate.rs new file mode 100644 index 000000000..006e315b0 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.rs @@ -0,0 +1,11 @@ +// 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) -> usize; +} +impl Me2 for usize { fn me(&self) -> usize { *self } } +fn main() { 1_usize.me(); } //~ ERROR E0034 diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr new file mode 100644 index 000000000..4b2597eed --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -0,0 +1,24 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-ambig-two-traits-cross-crate.rs:11:21 + | +LL | fn main() { 1_usize.me(); } + | ^^ multiple `me` found + | + = note: candidate #1 is defined in an impl of the trait `Me` for the type `usize` +note: candidate #2 is defined in an impl of the trait `Me2` for the type `usize` + --> $DIR/method-ambig-two-traits-cross-crate.rs:10:22 + | +LL | impl Me2 for usize { fn me(&self) -> usize { *self } } + | ^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | fn main() { Me::me(&1_usize); } + | ~~~~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | fn main() { Me2::me(&1_usize); } + | ~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-ambig-two-traits-from-bounds.rs b/src/test/ui/methods/method-ambig-two-traits-from-bounds.rs new file mode 100644 index 000000000..e3cc5557f --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-bounds.rs @@ -0,0 +1,8 @@ +trait A { fn foo(&self); } +trait B { fn foo(&self); } + +fn foo<T:A + B>(t: T) { + t.foo(); //~ ERROR E0034 +} + +fn main() {} diff --git a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr new file mode 100644 index 000000000..1feaa2c73 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr @@ -0,0 +1,28 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-ambig-two-traits-from-bounds.rs:5:7 + | +LL | t.foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in the trait `A` + --> $DIR/method-ambig-two-traits-from-bounds.rs:1:11 + | +LL | trait A { fn foo(&self); } + | ^^^^^^^^^^^^^^ +note: candidate #2 is defined in the trait `B` + --> $DIR/method-ambig-two-traits-from-bounds.rs:2:11 + | +LL | trait B { fn foo(&self); } + | ^^^^^^^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | A::foo(t); + | ~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | B::foo(t); + | ~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.rs b/src/test/ui/methods/method-ambig-two-traits-from-impls.rs new file mode 100644 index 000000000..22bf84066 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.rs @@ -0,0 +1,16 @@ +trait A { fn foo(self); } +trait B { fn foo(self); } + +struct AB {} + +impl A for AB { + fn foo(self) {} +} + +impl B for AB { + fn foo(self) {} +} + +fn main() { + AB {}.foo(); //~ ERROR E0034 +} diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr new file mode 100644 index 000000000..f69b56892 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr @@ -0,0 +1,28 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-ambig-two-traits-from-impls.rs:15:11 + | +LL | AB {}.foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls.rs:7:5 + | +LL | fn foo(self) {} + | ^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls.rs:11:5 + | +LL | fn foo(self) {} + | ^^^^^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | A::foo(AB {}); + | ~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | B::foo(AB {}); + | ~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs b/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs new file mode 100644 index 000000000..0a96c1223 --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.rs @@ -0,0 +1,16 @@ +trait A { fn foo(); } +trait B { fn foo(); } + +struct AB {} + +impl A for AB { + fn foo() {} +} + +impl B for AB { + fn foo() {} +} + +fn main() { + AB::foo(); //~ ERROR E0034 +} diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr new file mode 100644 index 000000000..4ba778e0e --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -0,0 +1,28 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-ambig-two-traits-from-impls2.rs:15:9 + | +LL | AB::foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls2.rs:7:5 + | +LL | fn foo() {} + | ^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `AB` + --> $DIR/method-ambig-two-traits-from-impls2.rs:11:5 + | +LL | fn foo() {} + | ^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | <AB as A>::foo(); + | ~~~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | <AB as B>::foo(); + | ~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.rs b/src/test/ui/methods/method-ambig-two-traits-with-default-method.rs new file mode 100644 index 000000000..aa7094b9e --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.rs @@ -0,0 +1,13 @@ +// 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 usize {} +impl Bar for usize {} + +fn main() { + 1_usize.method(); //~ ERROR E0034 +} diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr new file mode 100644 index 000000000..e84dff8ba --- /dev/null +++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr @@ -0,0 +1,28 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/method-ambig-two-traits-with-default-method.rs:12:13 + | +LL | 1_usize.method(); + | ^^^^^^ multiple `method` found + | +note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize` + --> $DIR/method-ambig-two-traits-with-default-method.rs:5:13 + | +LL | trait Foo { fn method(&self) {} } + | ^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize` + --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13 + | +LL | trait Bar { fn method(&self) {} } + | ^^^^^^^^^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | Foo::method(&1_usize); + | ~~~~~~~~~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | Bar::method(&1_usize); + | ~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-argument-inference-associated-type.rs b/src/test/ui/methods/method-argument-inference-associated-type.rs new file mode 100644 index 000000000..a3c31fab1 --- /dev/null +++ b/src/test/ui/methods/method-argument-inference-associated-type.rs @@ -0,0 +1,28 @@ +// run-pass +pub struct ClientMap; +pub struct ClientMap2; + +pub trait Service { + type Request; + fn call(&self, _req: Self::Request); +} + +pub struct S<T>(#[allow(unused_tuple_struct_fields)] T); + +impl Service for ClientMap { + type Request = S<Box<dyn Fn(i32)>>; + fn call(&self, _req: Self::Request) {} +} + + +impl Service for ClientMap2 { + type Request = (Box<dyn Fn(i32)>,); + fn call(&self, _req: Self::Request) {} +} + + +fn main() { + ClientMap.call(S { 0: Box::new(|_msgid| ()) }); + ClientMap.call(S(Box::new(|_msgid| ()))); + ClientMap2.call((Box::new(|_msgid| ()),)); +} diff --git a/src/test/ui/methods/method-call-err-msg.rs b/src/test/ui/methods/method-call-err-msg.rs new file mode 100644 index 000000000..d53ef445a --- /dev/null +++ b/src/test/ui/methods/method-call-err-msg.rs @@ -0,0 +1,22 @@ +// Test that parameter cardinality or missing method error gets span exactly. + +pub struct Foo; +impl Foo { + fn zero(self) -> Foo { self } + fn one(self, _: isize) -> Foo { self } + fn two(self, _: isize, _: isize) -> Foo { self } + fn three<T>(self, _: T, _: T, _: T) -> Foo { self } +} + +fn main() { + let x = Foo; + x.zero(0) //~ ERROR this function takes 0 arguments but 1 argument was supplied + .one() //~ ERROR this function takes 1 argument but 0 arguments were supplied + .two(0); //~ ERROR this function takes 2 arguments but 1 argument was supplied + + let y = Foo; + y.zero() + .take() //~ ERROR not an iterator + .one(0); + y.three::<usize>(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied +} diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr new file mode 100644 index 000000000..690fe8fa7 --- /dev/null +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -0,0 +1,92 @@ +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/method-call-err-msg.rs:13:7 + | +LL | x.zero(0) + | ^^^^ - argument of type `{integer}` unexpected + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:5:8 + | +LL | fn zero(self) -> Foo { self } + | ^^^^ ---- +help: remove the extra argument + | +LL | x.zero() + | ~~~~~~ + +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/method-call-err-msg.rs:14:7 + | +LL | .one() + | ^^^-- an argument of type `isize` is missing + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:6:8 + | +LL | fn one(self, _: isize) -> Foo { self } + | ^^^ ---- -------- +help: provide the argument + | +LL | .one(/* isize */) + | ~~~~~~~~~~~~~~~~ + +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/method-call-err-msg.rs:15:7 + | +LL | .two(0); + | ^^^--- an argument of type `isize` is missing + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:7:8 + | +LL | fn two(self, _: isize, _: isize) -> Foo { self } + | ^^^ ---- -------- -------- +help: provide the argument + | +LL | .two(0, /* isize */); + | ~~~~~~~~~~~~~~~~~~~ + +error[E0599]: `Foo` is not an iterator + --> $DIR/method-call-err-msg.rs:19:7 + | +LL | pub struct Foo; + | -------------- + | | + | method `take` not found for this struct + | doesn't satisfy `Foo: Iterator` +... +LL | .take() + | ^^^^ `Foo` is not an iterator + | + = note: the following trait bounds were not satisfied: + `Foo: Iterator` + which is required by `&mut Foo: Iterator` +note: the following trait must be implemented + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + | +LL | pub trait Iterator { + | ^^^^^^^^^^^^^^^^^^ + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `take`, perhaps you need to implement it: + candidate #1: `Iterator` + +error[E0061]: this function takes 3 arguments but 0 arguments were supplied + --> $DIR/method-call-err-msg.rs:21:7 + | +LL | y.three::<usize>(); + | ^^^^^^^^^^^^^^-- three arguments of type `usize`, `usize`, and `usize` are missing + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:8:8 + | +LL | fn three<T>(self, _: T, _: T, _: T) -> Foo { self } + | ^^^^^ ---- ---- ---- ---- +help: provide the arguments + | +LL | y.three::<usize>(/* usize */, /* usize */, /* usize */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0061, E0599. +For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/methods/method-call-lifetime-args-fail.rs b/src/test/ui/methods/method-call-lifetime-args-fail.rs new file mode 100644 index 000000000..6bf55844d --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-fail.rs @@ -0,0 +1,72 @@ +struct S; + +impl S { + fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + fn late_implicit(self, _: &u8, _: &u8) {} + fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } + fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } + fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } + fn life_and_type<'a, T>(self) -> &'a T { loop {} } +} + +fn method_call() { + S.early(); // OK + S.early::<'static>(); + //~^ ERROR this associated function takes 2 lifetime arguments but 1 lifetime argument + S.early::<'static, 'static, 'static>(); + //~^ ERROR this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied + let _: &u8 = S.life_and_type::<'static>(); + S.life_and_type::<u8>(); + S.life_and_type::<'static, u8>(); +} + +fn ufcs() { + S::late(S, &0, &0); // OK + S::late::<'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late::<'static, 'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late::<'static, 'static, 'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_early(S, &0); // OK + S::late_early::<'static, 'static>(S, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_early::<'static, 'static, 'static>(S, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + + S::late_implicit(S, &0, &0); // OK + S::late_implicit::<'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_implicit::<'static, 'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_implicit::<'static, 'static, 'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_implicit_early(S, &0); // OK + S::late_implicit_early::<'static, 'static>(S, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_implicit_early::<'static, 'static, 'static>(S, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_implicit_self_early(&S); // OK + S::late_implicit_self_early::<'static, 'static>(&S); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_implicit_self_early::<'static, 'static, 'static>(&S); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_unused_early(S); // OK + S::late_unused_early::<'static, 'static>(S); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_unused_early::<'static, 'static, 'static>(S); + //~^ ERROR cannot specify lifetime arguments explicitly + + S::early(S); // OK + S::early::<'static>(S); + //~^ ERROR this associated function takes 2 lifetime arguments but 1 lifetime argument + S::early::<'static, 'static, 'static>(S); + //~^ ERROR this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied + let _: &u8 = S::life_and_type::<'static>(S); + S::life_and_type::<u8>(S); + S::life_and_type::<'static, u8>(S); +} + +fn main() {} diff --git a/src/test/ui/methods/method-call-lifetime-args-fail.stderr b/src/test/ui/methods/method-call-lifetime-args-fail.stderr new file mode 100644 index 000000000..835edb4b0 --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-fail.stderr @@ -0,0 +1,235 @@ +error[E0107]: this associated function takes 2 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/method-call-lifetime-args-fail.rs:16:7 + | +LL | S.early::<'static>(); + | ^^^^^ ------- supplied 1 lifetime argument + | | + | expected 2 lifetime arguments + | +note: associated function defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/method-call-lifetime-args-fail.rs:6:8 + | +LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } + | ^^^^^ -- -- +help: add missing lifetime argument + | +LL | S.early::<'static, 'b>(); + | ++++ + +error[E0107]: this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied + --> $DIR/method-call-lifetime-args-fail.rs:18:7 + | +LL | S.early::<'static, 'static, 'static>(); + | ^^^^^ ------- help: remove this lifetime argument + | | + | expected 2 lifetime arguments + | +note: associated function defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/method-call-lifetime-args-fail.rs:6:8 + | +LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } + | ^^^^^ -- -- + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:27:15 + | +LL | S::late::<'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:4:13 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | ^^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:29:15 + | +LL | S::late::<'static, 'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:4:13 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | ^^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:31:15 + | +LL | S::late::<'static, 'static, 'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:4:13 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | ^^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:34:21 + | +LL | S::late_early::<'static, 'static>(S, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:7:19 + | +LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + | ^^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:36:21 + | +LL | S::late_early::<'static, 'static, 'static>(S, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:7:19 + | +LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + | ^^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:40:24 + | +LL | S::late_implicit::<'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:5:31 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | ^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:42:24 + | +LL | S::late_implicit::<'static, 'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:5:31 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | ^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:44:24 + | +LL | S::late_implicit::<'static, 'static, 'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:5:31 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | ^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:47:30 + | +LL | S::late_implicit_early::<'static, 'static>(S, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:8:41 + | +LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + | ^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:49:30 + | +LL | S::late_implicit_early::<'static, 'static, 'static>(S, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:8:41 + | +LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + | ^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:52:35 + | +LL | S::late_implicit_self_early::<'static, 'static>(&S); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:9:37 + | +LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } + | ^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:54:35 + | +LL | S::late_implicit_self_early::<'static, 'static, 'static>(&S); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:9:37 + | +LL | fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} } + | ^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:57:28 + | +LL | S::late_unused_early::<'static, 'static>(S); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:10:26 + | +LL | fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } + | ^^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-fail.rs:59:28 + | +LL | S::late_unused_early::<'static, 'static, 'static>(S); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args-fail.rs:10:26 + | +LL | fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} } + | ^^ + +error[E0107]: this associated function takes 2 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/method-call-lifetime-args-fail.rs:63:8 + | +LL | S::early::<'static>(S); + | ^^^^^ ------- supplied 1 lifetime argument + | | + | expected 2 lifetime arguments + | +note: associated function defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/method-call-lifetime-args-fail.rs:6:8 + | +LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } + | ^^^^^ -- -- +help: add missing lifetime argument + | +LL | S::early::<'static, 'b>(S); + | ++++ + +error[E0107]: this associated function takes 2 lifetime arguments but 3 lifetime arguments were supplied + --> $DIR/method-call-lifetime-args-fail.rs:65:8 + | +LL | S::early::<'static, 'static, 'static>(S); + | ^^^^^ ------- help: remove this lifetime argument + | | + | expected 2 lifetime arguments + | +note: associated function defined here, with 2 lifetime parameters: `'a`, `'b` + --> $DIR/method-call-lifetime-args-fail.rs:6:8 + | +LL | fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} } + | ^^^^^ -- -- + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/methods/method-call-lifetime-args-lint-fail.rs b/src/test/ui/methods/method-call-lifetime-args-lint-fail.rs new file mode 100644 index 000000000..23893911e --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-lint-fail.rs @@ -0,0 +1,87 @@ +#![deny(late_bound_lifetime_arguments)] +#![allow(unused)] + +struct S; + +impl S { + fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + fn late_implicit(self, _: &u8, _: &u8) {} + fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + + // 'late lifetimes here belong to nested types not to the tested functions. + fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8), + _: Box<dyn for<'late> Fn(&'late u8)>) + -> &'a u8 { loop {} } + fn early_tricky_implicit<'a>(_: fn(&u8), + _: Box<dyn Fn(&u8)>) + -> &'a u8 { loop {} } +} + +fn method_call() { + S.late(&0, &0); // OK + S.late::<'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late::<'static, 'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late::<'static, 'static, 'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_early(&0); // OK + S.late_early::<'static>(&0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_early::<'static, 'static>(&0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_early::<'static, 'static, 'static>(&0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + + S.late_implicit(&0, &0); // OK + S.late_implicit::<'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_implicit::<'static, 'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_implicit::<'static, 'static, 'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_implicit_early(&0); // OK + S.late_implicit_early::<'static>(&0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_implicit_early::<'static, 'static>(&0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + S.late_implicit_early::<'static, 'static, 'static>(&0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + + S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK + S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK +} + +fn ufcs() { + S::late_early::<'static>(S, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + + S::late_implicit_early::<'static>(S, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted +} + +fn lint_not_inference_error() { + fn f<'early, 'late, T: 'early>() {} + + // Make sure `u8` is substituted and not replaced with an inference variable + f::<'static, u8>; + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted +} + +fn main() {} diff --git a/src/test/ui/methods/method-call-lifetime-args-lint-fail.stderr b/src/test/ui/methods/method-call-lifetime-args-lint-fail.stderr new file mode 100644 index 000000000..9e07d5ea3 --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-lint-fail.stderr @@ -0,0 +1,187 @@ +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:23:14 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | -- the late bound lifetime parameter is introduced here +... +LL | S.late::<'static>(&0, &0); + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/method-call-lifetime-args-lint-fail.rs:1:9 + | +LL | #![deny(late_bound_lifetime_arguments)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:26:14 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | -- the late bound lifetime parameter is introduced here +... +LL | S.late::<'static, 'static>(&0, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:29:14 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | -- the late bound lifetime parameter is introduced here +... +LL | S.late::<'static, 'static, 'static>(&0, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:33:20 + | +LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + | -- the late bound lifetime parameter is introduced here +... +LL | S.late_early::<'static>(&0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:36:20 + | +LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + | -- the late bound lifetime parameter is introduced here +... +LL | S.late_early::<'static, 'static>(&0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:39:20 + | +LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + | -- the late bound lifetime parameter is introduced here +... +LL | S.late_early::<'static, 'static, 'static>(&0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:44:23 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | - the late bound lifetime parameter is introduced here +... +LL | S.late_implicit::<'static>(&0, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:47:23 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | - the late bound lifetime parameter is introduced here +... +LL | S.late_implicit::<'static, 'static>(&0, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:50:23 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | - the late bound lifetime parameter is introduced here +... +LL | S.late_implicit::<'static, 'static, 'static>(&0, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:54:29 + | +LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + | - the late bound lifetime parameter is introduced here +... +LL | S.late_implicit_early::<'static>(&0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:57:29 + | +LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + | - the late bound lifetime parameter is introduced here +... +LL | S.late_implicit_early::<'static, 'static>(&0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:60:29 + | +LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + | - the late bound lifetime parameter is introduced here +... +LL | S.late_implicit_early::<'static, 'static, 'static>(&0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:69:21 + | +LL | fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} } + | -- the late bound lifetime parameter is introduced here +... +LL | S::late_early::<'static>(S, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:73:30 + | +LL | fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} } + | - the late bound lifetime parameter is introduced here +... +LL | S::late_implicit_early::<'static>(S, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint-fail.rs:82:9 + | +LL | fn f<'early, 'late, T: 'early>() {} + | ----- the late bound lifetime parameter is introduced here +... +LL | f::<'static, u8>; + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: aborting due to 15 previous errors + diff --git a/src/test/ui/methods/method-call-lifetime-args-lint.rs b/src/test/ui/methods/method-call-lifetime-args-lint.rs new file mode 100644 index 000000000..14729e1e2 --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-lint.rs @@ -0,0 +1,21 @@ +#![deny(late_bound_lifetime_arguments)] +#![allow(unused)] + +struct S; + +impl S { + fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + fn late_implicit(self, _: &u8, _: &u8) {} +} + +fn method_call() { + S.late::<'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted + + S.late_implicit::<'static>(&0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + //~| WARN this was previously accepted +} + +fn main() {} diff --git a/src/test/ui/methods/method-call-lifetime-args-lint.stderr b/src/test/ui/methods/method-call-lifetime-args-lint.stderr new file mode 100644 index 000000000..f31f510a3 --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-lint.stderr @@ -0,0 +1,31 @@ +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint.rs:12:14 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | -- the late bound lifetime parameter is introduced here +... +LL | S.late::<'static>(&0, &0); + | ^^^^^^^ + | +note: the lint level is defined here + --> $DIR/method-call-lifetime-args-lint.rs:1:9 + | +LL | #![deny(late_bound_lifetime_arguments)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-lint.rs:16:23 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | - the late bound lifetime parameter is introduced here +... +LL | S.late_implicit::<'static>(&0, &0); + | ^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/methods/method-call-lifetime-args-subst-index.rs b/src/test/ui/methods/method-call-lifetime-args-subst-index.rs new file mode 100644 index 000000000..8df58a348 --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-subst-index.rs @@ -0,0 +1,15 @@ +// build-pass (FIXME(62277): could be check-pass?) +#![allow(unused)] + +struct S; + +impl S { + fn early_and_type<'a, T>(self) -> &'a T { loop {} } +} + +fn test() { + S.early_and_type::<u16>(); +} + + +fn main() {} diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.rs b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs new file mode 100644 index 000000000..ba7231070 --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.rs @@ -0,0 +1,6 @@ +fn main() { + 0.clone::<'a>(); + //~^ ERROR use of undeclared lifetime name `'a` + //~| WARN cannot specify lifetime arguments explicitly if late bound + //~| WARN this was previously accepted by the compiler +} diff --git a/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr new file mode 100644 index 000000000..78af19586 --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args-unresolved.stderr @@ -0,0 +1,26 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/method-call-lifetime-args-unresolved.rs:2:15 + | +LL | fn main() { + | - help: consider introducing lifetime `'a` here: `<'a>` +LL | 0.clone::<'a>(); + | ^^ undeclared lifetime + +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args-unresolved.rs:2:15 + | +LL | 0.clone::<'a>(); + | ^^ + | + ::: $SRC_DIR/core/src/clone.rs:LL:COL + | +LL | fn clone(&self) -> Self; + | - the late bound lifetime parameter is introduced here + | + = note: `#[warn(late_bound_lifetime_arguments)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868> + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0261`. diff --git a/src/test/ui/methods/method-call-lifetime-args.rs b/src/test/ui/methods/method-call-lifetime-args.rs new file mode 100644 index 000000000..3292e9fcd --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args.rs @@ -0,0 +1,15 @@ +struct S; + +impl S { + fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + fn late_implicit(self, _: &u8, _: &u8) {} +} + +fn ufcs() { + S::late::<'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly + S::late_implicit::<'static>(S, &0, &0); + //~^ ERROR cannot specify lifetime arguments explicitly +} + +fn main() {} diff --git a/src/test/ui/methods/method-call-lifetime-args.stderr b/src/test/ui/methods/method-call-lifetime-args.stderr new file mode 100644 index 000000000..64ae79e9b --- /dev/null +++ b/src/test/ui/methods/method-call-lifetime-args.stderr @@ -0,0 +1,26 @@ +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args.rs:9:15 + | +LL | S::late::<'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args.rs:4:13 + | +LL | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | ^^ + +error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/method-call-lifetime-args.rs:11:24 + | +LL | S::late_implicit::<'static>(S, &0, &0); + | ^^^^^^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/method-call-lifetime-args.rs:5:31 + | +LL | fn late_implicit(self, _: &u8, _: &u8) {} + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/methods/method-call-type-binding.rs b/src/test/ui/methods/method-call-type-binding.rs new file mode 100644 index 000000000..f547ca8d1 --- /dev/null +++ b/src/test/ui/methods/method-call-type-binding.rs @@ -0,0 +1,3 @@ +fn main() { + 0.clone::<T = u8>(); //~ ERROR associated type bindings are not allowed here +} diff --git a/src/test/ui/methods/method-call-type-binding.stderr b/src/test/ui/methods/method-call-type-binding.stderr new file mode 100644 index 000000000..4b93082ac --- /dev/null +++ b/src/test/ui/methods/method-call-type-binding.stderr @@ -0,0 +1,9 @@ +error[E0229]: associated type bindings are not allowed here + --> $DIR/method-call-type-binding.rs:2:15 + | +LL | 0.clone::<T = u8>(); + | ^^^^^^ associated type not allowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs new file mode 100644 index 000000000..9e53ff079 --- /dev/null +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.rs @@ -0,0 +1,179 @@ +#![feature(arbitrary_self_types, coerce_unsized, dispatch_from_dyn, unsize)] +#![feature(unsized_locals, unsized_fn_params)] +//~^ WARN the feature `unsized_locals` is incomplete + +// This tests a few edge-cases around `arbitrary_self_types`. Most specifically, +// it checks that the `ObjectCandidate` you get from method matching can't +// match a trait with the same DefId as a supertrait but a bad type parameter. + +use std::marker::PhantomData; + +mod internal { + use std::ops::{CoerceUnsized, Deref, DispatchFromDyn}; + use std::marker::{PhantomData, Unsize}; + + pub struct Smaht<T: ?Sized, MISC>(pub Box<T>, pub PhantomData<MISC>); + + impl<T: ?Sized, MISC> Deref for Smaht<T, MISC> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> CoerceUnsized<Smaht<U, MISC>> + for Smaht<T, MISC> + {} + impl<T: ?Sized + Unsize<U>, U: ?Sized, MISC> DispatchFromDyn<Smaht<U, MISC>> + for Smaht<T, MISC> + {} + + pub trait Foo: X<u32> {} + pub trait X<T> { + fn foo(self: Smaht<Self, T>) -> T; + } + + impl X<u32> for () { + fn foo(self: Smaht<Self, u32>) -> u32 { + 0 + } + } + + pub trait Marker {} + impl Marker for dyn Foo {} + impl<T: Marker + ?Sized> X<u64> for T { + fn foo(self: Smaht<Self, u64>) -> u64 { + 1 + } + } + + impl Deref for dyn Foo { + type Target = (); + fn deref(&self) -> &() { &() } + } + + impl Foo for () {} +} + +pub trait FinalFoo { + fn foo(&self) -> u8; +} + +impl FinalFoo for () { + fn foo(&self) -> u8 { 0 } +} + +mod nuisance_foo { + pub trait NuisanceFoo { + fn foo(self); + } + + impl<T: ?Sized> NuisanceFoo for T { + fn foo(self) {} + } +} + + +fn objectcandidate_impl() { + let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht<dyn internal::Foo, u32> = x; + + // This picks `<dyn internal::Foo as X<u32>>::foo` via `ObjectCandidate`. + // + // The `TraitCandidate` is not relevant because `X` is not in scope. + let z = x.foo(); + + // Observe the type of `z` is `u32` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected `()`, found `u32` +} + +fn traitcandidate_impl() { + use internal::X; + + let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht<dyn internal::Foo, u64> = x; + + // This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`. + // + // The `ObjectCandidate` does not apply, as it only applies to + // `X<u32>` (and not `X<u64>`). + let z = x.foo(); + + // Observe the type of `z` is `u64` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected `()`, found `u64` +} + +fn traitcandidate_impl_with_nuisance() { + use internal::X; + use nuisance_foo::NuisanceFoo; + + let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht<dyn internal::Foo, u64> = x; + + // This picks `<dyn internal::Foo as X<u64>>::foo` via `TraitCandidate`. + // + // The `ObjectCandidate` does not apply, as it only applies to + // `X<u32>` (and not `X<u64>`). + // + // The NuisanceFoo impl has the same priority as the `X` impl, + // so we get a conflict. + let z = x.foo(); //~ ERROR multiple applicable items in scope +} + + +fn neither_impl() { + let x: internal::Smaht<(), u64> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht<dyn internal::Foo, u64> = x; + + // This can't pick the `TraitCandidate` impl, because `Foo` is not + // imported. However, this also can't pick the `ObjectCandidate` + // impl, because it only applies to `X<u32>` (and not `X<u64>`). + // + // Therefore, neither of the candidates is applicable, and we pick + // the `FinalFoo` impl after another deref, which will return `u8`. + let z = x.foo(); + + // Observe the type of `z` is `u8` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected `()`, found `u8` +} + +fn both_impls() { + use internal::X; + + let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht<dyn internal::Foo, u32> = x; + + // This can pick both the `TraitCandidate` and the `ObjectCandidate` impl. + // + // However, the `ObjectCandidate` is considered an "inherent candidate", + // and therefore has priority over both the `TraitCandidate` as well as + // any other "nuisance" candidate" (if present). + let z = x.foo(); + + // Observe the type of `z` is `u32` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected `()`, found `u32` +} + + +fn both_impls_with_nuisance() { + // Similar to the `both_impls` example, except with a nuisance impl to + // make sure the `ObjectCandidate` indeed has a higher priority. + + use internal::X; + use nuisance_foo::NuisanceFoo; + + let x: internal::Smaht<(), u32> = internal::Smaht(Box::new(()), PhantomData); + let x: internal::Smaht<dyn internal::Foo, u32> = x; + let z = x.foo(); + + // Observe the type of `z` is `u32` + let _seetype: () = z; //~ ERROR mismatched types + //~| expected `()`, found `u32` +} + +fn main() { +} diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr new file mode 100644 index 000000000..59075397e --- /dev/null +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -0,0 +1,87 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:2:12 + | +LL | #![feature(unsized_locals, unsized_fn_params)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:87:24 + | +LL | let _seetype: () = z; + | -- ^ expected `()`, found `u32` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:104:24 + | +LL | let _seetype: () = z; + | -- ^ expected `()`, found `u64` + | | + | expected due to this + +error[E0034]: multiple applicable items in scope + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:122:15 + | +LL | let z = x.foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `X` for the type `T` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:45:9 + | +LL | fn foo(self: Smaht<Self, u64>) -> u64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:72:9 + | +LL | fn foo(self) {} + | ^^^^^^^^^^^^ +note: candidate #3 is defined in the trait `FinalFoo` + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:59:5 + | +LL | fn foo(&self) -> u8; + | ^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the associated function for candidate #1 + | +LL | let z = X::foo(x); + | ~~~~~~~~~ +help: disambiguate the associated function for candidate #2 + | +LL | let z = NuisanceFoo::foo(x); + | ~~~~~~~~~~~~~~~~~~~ +help: disambiguate the associated function for candidate #3 + | +LL | let z = FinalFoo::foo(x); + | ~~~~~~~~~~~~~~~~ + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:139:24 + | +LL | let _seetype: () = z; + | -- ^ expected `()`, found `u8` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:157:24 + | +LL | let _seetype: () = z; + | -- ^ expected `()`, found `u32` + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:174:24 + | +LL | let _seetype: () = z; + | -- ^ expected `()`, found `u32` + | | + | expected due to this + +error: aborting due to 6 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0034, E0308. +For more information about an error, try `rustc --explain E0034`. diff --git a/src/test/ui/methods/method-early-bound-lifetimes-on-self.rs b/src/test/ui/methods/method-early-bound-lifetimes-on-self.rs new file mode 100644 index 000000000..f2ace32c6 --- /dev/null +++ b/src/test/ui/methods/method-early-bound-lifetimes-on-self.rs @@ -0,0 +1,31 @@ +// run-pass +// Check that we successfully handle methods where the `self` type has +// an early-bound lifetime. Issue #18208. + +// pretty-expanded FIXME #23616 + +#![allow(dead_code)] + +use std::marker; + +struct Cursor<'a> { + m: marker::PhantomData<&'a ()> +} + +trait CursorNavigator { + fn init_cursor<'a, 'b:'a>(&'a self, cursor: &mut Cursor<'b>) -> bool; +} + +struct SimpleNavigator; + +impl CursorNavigator for SimpleNavigator { + fn init_cursor<'a, 'b: 'a>(&'a self, _cursor: &mut Cursor<'b>) -> bool { + false + } +} + +fn main() { + let mut c = Cursor { m: marker::PhantomData }; + let n = SimpleNavigator; + n.init_cursor(&mut c); +} diff --git a/src/test/ui/methods/method-lookup-order.rs b/src/test/ui/methods/method-lookup-order.rs new file mode 100644 index 000000000..986fe103c --- /dev/null +++ b/src/test/ui/methods/method-lookup-order.rs @@ -0,0 +1,190 @@ +// ignore-tidy-linelength + +// run-pass + +// There are five cfg's below. I explored the set of all non-empty combinations +// of the below five cfg's, which is 2^5 - 1 = 31 combinations. +// +// Of the 31, 11 resulted in ambiguous method resolutions; while it may be good +// to have a test for all of the eleven variations of that error, I am not sure +// this particular test is the best way to encode it. So they are skipped in +// this revisions list (but not in the expansion mapping the binary encoding to +// the corresponding cfg flags). +// +// Notable, here are the cases that will be incompatible if something does not override them first: +// {bar_for_foo, valbar_for_et_foo}: these are higher precedent than the `&mut self` method on `Foo`, and so no case matching bx1x1x is included. +// {mutbar_for_foo, valbar_for_etmut_foo} (which are lower precedent than the inherent `&mut self` method on `Foo`; e.g. b10101 *is* included. + +// revisions: b00001 b00010 b00011 b00100 b00101 b00110 b00111 b01000 b01001 b01100 b01101 b10000 b10001 b10010 b10011 b10101 b10111 b11000 b11001 b11101 + +//[b00001]compile-flags: --cfg inherent_mut +//[b00010]compile-flags: --cfg bar_for_foo +//[b00011]compile-flags: --cfg inherent_mut --cfg bar_for_foo +//[b00100]compile-flags: --cfg mutbar_for_foo +//[b00101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo +//[b00110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo +//[b00111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo +//[b01000]compile-flags: --cfg valbar_for_et_foo +//[b01001]compile-flags: --cfg inherent_mut --cfg valbar_for_et_foo +//[b01010]compile-flags: --cfg bar_for_foo --cfg valbar_for_et_foo +//[b01011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_et_foo +//[b01100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_et_foo +//[b01101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_et_foo +//[b01110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo +//[b01111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo +//[b10000]compile-flags: --cfg valbar_for_etmut_foo +//[b10001]compile-flags: --cfg inherent_mut --cfg valbar_for_etmut_foo +//[b10010]compile-flags: --cfg bar_for_foo --cfg valbar_for_etmut_foo +//[b10011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_etmut_foo +//[b10100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_etmut_foo +//[b10101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_etmut_foo +//[b10110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_etmut_foo +//[b10111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_etmut_foo +//[b11000]compile-flags: --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo +//[b11001]compile-flags: --cfg inherent_mut --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo +//[b11010]compile-flags: --cfg bar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo +//[b11011]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo +//[b11100]compile-flags: --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo +//[b11101]compile-flags: --cfg inherent_mut --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo +//[b11110]compile-flags: --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo +//[b11111]compile-flags: --cfg inherent_mut --cfg bar_for_foo --cfg mutbar_for_foo --cfg valbar_for_et_foo --cfg valbar_for_etmut_foo + +struct Foo {} + +type S = &'static str; + +trait Bar { + fn bar(&self, _: &str) -> S; +} + +trait MutBar { + fn bar(&mut self, _: &str) -> S; +} + +trait ValBar { + fn bar(self, _: &str) -> S; +} + +#[cfg(inherent_mut)] +impl Foo { + fn bar(&mut self, _: &str) -> S { + "In struct impl!" + } +} + +#[cfg(bar_for_foo)] +impl Bar for Foo { + fn bar(&self, _: &str) -> S { + "In trait &self impl!" + } +} + +#[cfg(mutbar_for_foo)] +impl MutBar for Foo { + fn bar(&mut self, _: &str) -> S { + "In trait &mut self impl!" + } +} + +#[cfg(valbar_for_et_foo)] +impl ValBar for &Foo { + fn bar(self, _: &str) -> S { + "In trait self impl for &Foo!" + } +} + +#[cfg(valbar_for_etmut_foo)] +impl ValBar for &mut Foo { + fn bar(self, _: &str) -> S { + "In trait self impl for &mut Foo!" + } +} + +fn main() { + #![allow(unused_mut)] // some of the impls above will want it. + + #![allow(unreachable_patterns)] // the cfg-coding pattern below generates unreachable patterns. + + { + macro_rules! all_variants_on_value { + ($e:expr) => { + match $e { + #[cfg(bar_for_foo)] + x => assert_eq!(x, "In trait &self impl!"), + + #[cfg(valbar_for_et_foo)] + x => assert_eq!(x, "In trait self impl for &Foo!"), + + #[cfg(inherent_mut)] + x => assert_eq!(x, "In struct impl!"), + + #[cfg(mutbar_for_foo)] + x => assert_eq!(x, "In trait &mut self impl!"), + + #[cfg(valbar_for_etmut_foo)] + x => assert_eq!(x, "In trait self impl for &mut Foo!"), + } + } + } + + let mut f = Foo {}; + all_variants_on_value!(f.bar("f.bar")); + + let f_mr = &mut Foo {}; + all_variants_on_value!((*f_mr).bar("(*f_mr).bar")); + } + + // This is sort of interesting: `&mut Foo` ends up with a significantly + // different resolution order than what was devised above. Presumably this + // is because we can get to a `&self` method by first a deref of the given + // `&mut Foo` and then an autoref, and that is a longer path than a mere + // auto-ref of a `Foo`. + + { + let f_mr = &mut Foo {}; + + match f_mr.bar("f_mr.bar") { + #[cfg(inherent_mut)] + x => assert_eq!(x, "In struct impl!"), + + #[cfg(valbar_for_etmut_foo)] + x => assert_eq!(x, "In trait self impl for &mut Foo!"), + + #[cfg(mutbar_for_foo)] + x => assert_eq!(x, "In trait &mut self impl!"), + + #[cfg(valbar_for_et_foo)] + x => assert_eq!(x, "In trait self impl for &Foo!"), + + #[cfg(bar_for_foo)] + x => assert_eq!(x, "In trait &self impl!"), + } + } + + + // Note that this isn't actually testing a resolution order; if both of these are + // enabled, it yields an ambiguous method resolution error. The test tries to embed + // that fact by testing *both* orders (and so the only way that can be right is if + // they are not actually compatible). + #[cfg(any(bar_for_foo, valbar_for_et_foo))] + { + let f_r = &Foo {}; + + match f_r.bar("f_r.bar") { + #[cfg(bar_for_foo)] + x => assert_eq!(x, "In trait &self impl!"), + + #[cfg(valbar_for_et_foo)] + x => assert_eq!(x, "In trait self impl for &Foo!"), + } + + match f_r.bar("f_r.bar") { + #[cfg(valbar_for_et_foo)] + x => assert_eq!(x, "In trait self impl for &Foo!"), + + #[cfg(bar_for_foo)] + x => assert_eq!(x, "In trait &self impl!"), + } + } + +} diff --git a/src/test/ui/methods/method-macro-backtrace.rs b/src/test/ui/methods/method-macro-backtrace.rs new file mode 100644 index 000000000..00fe32b7c --- /dev/null +++ b/src/test/ui/methods/method-macro-backtrace.rs @@ -0,0 +1,25 @@ +// forbid-output: in this expansion of + +macro_rules! make_method { + ($name:ident) => ( fn $name(&self) { } ) +} + +struct S; + +impl S { + // We had a bug where these wouldn't clean up macro backtrace frames. + make_method!(foo1); + make_method!(foo2); + make_method!(foo3); + make_method!(foo4); + make_method!(foo5); + make_method!(foo6); + make_method!(foo7); + make_method!(foo8); + + // Cause an error. It shouldn't have any macro backtrace frames. + fn bar(&self) { } + fn bar(&self) { } //~ ERROR duplicate definitions +} + +fn main() { } diff --git a/src/test/ui/methods/method-macro-backtrace.stderr b/src/test/ui/methods/method-macro-backtrace.stderr new file mode 100644 index 000000000..7ae00835c --- /dev/null +++ b/src/test/ui/methods/method-macro-backtrace.stderr @@ -0,0 +1,11 @@ +error[E0201]: duplicate definitions with name `bar`: + --> $DIR/method-macro-backtrace.rs:22:5 + | +LL | fn bar(&self) { } + | ------------- previous definition of `bar` here +LL | fn bar(&self) { } + | ^^^^^^^^^^^^^ duplicate definition + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0201`. diff --git a/src/test/ui/methods/method-missing-call.rs b/src/test/ui/methods/method-missing-call.rs new file mode 100644 index 000000000..7ce1e9a4f --- /dev/null +++ b/src/test/ui/methods/method-missing-call.rs @@ -0,0 +1,30 @@ +// Tests to make sure that parens are needed for method calls without arguments. +// outputs text to make sure either an anonymous function is provided or +// open-close '()' parens are given + + +struct Point { + x: isize, + y: isize +} +impl Point { + fn new() -> Point { + Point{x:0, y:0} + } + fn get_x(&self) -> isize { + self.x + } +} + +fn main() { + let point: Point = Point::new(); + let px: isize = point + .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point` + + // Ensure the span is useful + let ys = &[1,2,3,4,5,6,7]; + let a = ys.iter() + .map(|x| x) + .filter(|&&x| x == 1) + .filter_map; //~ ERROR attempted to take value of method `filter_map` on type +} diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr new file mode 100644 index 000000000..040a65d16 --- /dev/null +++ b/src/test/ui/methods/method-missing-call.stderr @@ -0,0 +1,25 @@ +error[E0615]: attempted to take value of method `get_x` on type `Point` + --> $DIR/method-missing-call.rs:22:26 + | +LL | .get_x; + | ^^^^^ method, not a field + | +help: use parentheses to call the method + | +LL | .get_x(); + | ++ + +error[E0615]: attempted to take value of method `filter_map` on type `Filter<Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:23]>, [closure@$DIR/method-missing-call.rs:28:23: 28:28]>` + --> $DIR/method-missing-call.rs:29:16 + | +LL | .filter_map; + | ^^^^^^^^^^ method, not a field + | +help: use parentheses to call the method + | +LL | .filter_map(_); + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0615`. diff --git a/src/test/ui/methods/method-mut-self-modifies-mut-slice-lvalue.rs b/src/test/ui/methods/method-mut-self-modifies-mut-slice-lvalue.rs new file mode 100644 index 000000000..daff037b2 --- /dev/null +++ b/src/test/ui/methods/method-mut-self-modifies-mut-slice-lvalue.rs @@ -0,0 +1,44 @@ +// run-pass +// Test that an `&mut self` method, when invoked on a place whose +// type is `&mut [u8]`, passes in a pointer to the place and not a +// temporary. Issue #19147. + +use std::slice; +use std::cmp; + +trait MyWriter { + fn my_write(&mut self, buf: &[u8]) -> Result<(), ()>; +} + +impl<'a> MyWriter for &'a mut [u8] { + fn my_write(&mut self, buf: &[u8]) -> Result<(), ()> { + let amt = cmp::min(self.len(), buf.len()); + self[..amt].clone_from_slice(&buf[..amt]); + + let write_len = buf.len(); + unsafe { + *self = slice::from_raw_parts_mut( + self.as_mut_ptr().add(write_len), + self.len() - write_len + ); + } + + Ok(()) + } +} + +fn main() { + let mut buf = [0; 6]; + + { + let mut writer: &mut [_] = &mut buf; + writer.my_write(&[0, 1, 2]).unwrap(); + writer.my_write(&[3, 4, 5]).unwrap(); + } + + // If `my_write` is not modifying `buf` in place, then we will + // wind up with `[3, 4, 5, 0, 0, 0]` because the first call to + // `my_write()` doesn't update the starting point for the write. + + assert_eq!(buf, [0, 1, 2, 3, 4, 5]); +} diff --git a/src/test/ui/methods/method-normalize-bounds-issue-20604.rs b/src/test/ui/methods/method-normalize-bounds-issue-20604.rs new file mode 100644 index 000000000..9c0b95284 --- /dev/null +++ b/src/test/ui/methods/method-normalize-bounds-issue-20604.rs @@ -0,0 +1,61 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(stable_features)] + +// Test that we handle projection types which wind up important for +// resolving methods. This test was reduced from a larger example; the +// call to `foo()` at the end was failing to resolve because the +// winnowing stage of method resolution failed to handle an associated +// type projection. + +// pretty-expanded FIXME #23616 + +#![feature(associated_types)] + +trait Hasher { + type Output; + fn finish(&self) -> Self::Output; +} + +trait Hash<H: Hasher> { + fn hash(&self, h: &mut H); +} + +trait HashState { + type Wut: Hasher; + fn hasher(&self) -> Self::Wut; +} + +struct SipHasher; +impl Hasher for SipHasher { + type Output = u64; + fn finish(&self) -> u64 { 4 } +} + +impl Hash<SipHasher> for isize { + fn hash(&self, h: &mut SipHasher) {} +} + +struct SipState; +impl HashState for SipState { + type Wut = SipHasher; + fn hasher(&self) -> SipHasher { SipHasher } +} + +struct Map<S> { + s: S, +} + +impl<S> Map<S> + where S: HashState, + <S as HashState>::Wut: Hasher<Output=u64>, +{ + fn foo<K>(&self, k: K) where K: Hash< <S as HashState>::Wut> {} +} + +fn foo<K: Hash<SipHasher>>(map: &Map<SipState>) { + map.foo(22); +} + +fn main() {} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs new file mode 100644 index 000000000..799ced5e9 --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.rs @@ -0,0 +1,106 @@ +// Test for issue 81576 +// Remove generic arguments if no method is found for all possible generic argument + +use std::marker::PhantomData; + +struct Wrapper2<'a, T, const C: usize> { + x: &'a T, +} + +impl<'a, const C: usize> Wrapper2<'a, i8, C> { + fn method(&self) {} +} + +impl<'a, const C: usize> Wrapper2<'a, i16, C> { + fn method(&self) {} +} + +impl<'a, const C: usize> Wrapper2<'a, i32, C> { + fn method(&self) {} +} +struct Wrapper<T>(T); + +impl Wrapper<i8> { + fn method(&self) {} +} + +impl Wrapper<i16> { + fn method(&self) {} +} + +impl Wrapper<i32> { + fn method(&self) {} +} + +impl Wrapper<i64> { + fn method(&self) {} +} + +impl Wrapper<u8> { + fn method(&self) {} +} + +impl Wrapper<u16> { + fn method(&self) {} +} + +struct Point<T> { + x: T, + y: T, +} + +impl Point<f64> { + fn distance(&self) -> f64 { + self.x.hypot(self.y) + } +} + +struct Other; + +impl Other { + fn other(&self) {} +} + +struct Struct<T> { + _phatom: PhantomData<T>, +} + +impl<T> Default for Struct<T> { + fn default() -> Self { + Self { _phatom: PhantomData } + } +} + +impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> { + fn method(&self) {} +} + +fn main() { + let point_f64 = Point { x: 1_f64, y: 1_f64 }; + let d = point_f64.distance(); + let point_i32 = Point { x: 1_i32, y: 1_i32 }; + let d = point_i32.distance(); + //~^ ERROR no method named `distance` found for struct `Point<i32> + let d = point_i32.other(); + //~^ ERROR no method named `other` found for struct `Point + let v = vec![1_i32, 2, 3]; + v.iter().map(|x| x * x).extend(std::iter::once(100)); + //~^ ERROR no method named `extend` found for struct `Map + let wrapper = Wrapper(true); + wrapper.method(); + //~^ ERROR no method named `method` found for struct `Wrapper<bool> + wrapper.other(); + //~^ ERROR no method named `other` found for struct `Wrapper + let boolean = true; + let wrapper = Wrapper2::<'_, _, 3> { x: &boolean }; + wrapper.method(); + //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3> + wrapper.other(); + //~^ ERROR no method named `other` found for struct `Wrapper2 + let a = vec![1, 2, 3]; + a.not_found(); + //~^ ERROR no method named `not_found` found for struct `Vec + let s = Struct::<f64>::default(); + s.method(); + //~^ ERROR the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied +} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr new file mode 100644 index 000000000..fc42d1a4d --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr @@ -0,0 +1,97 @@ +error[E0599]: no method named `distance` found for struct `Point<i32>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:82:23 + | +LL | struct Point<T> { + | --------------- method `distance` not found for this struct +... +LL | let d = point_i32.distance(); + | ^^^^^^^^ method not found in `Point<i32>` + | + = note: the method was found for + - `Point<f64>` + +error[E0599]: no method named `other` found for struct `Point` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:84:23 + | +LL | struct Point<T> { + | --------------- method `other` not found for this struct +... +LL | let d = point_i32.other(); + | ^^^^^ method not found in `Point<i32>` + +error[E0599]: no method named `extend` found for struct `Map` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:87:29 + | +LL | v.iter().map(|x| x * x).extend(std::iter::once(100)); + | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:21]>` + +error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:90:13 + | +LL | struct Wrapper<T>(T); + | ----------------- method `method` not found for this struct +... +LL | wrapper.method(); + | ^^^^^^ method not found in `Wrapper<bool>` + | + = note: the method was found for + - `Wrapper<i8>` + - `Wrapper<i16>` + - `Wrapper<i32>` + - `Wrapper<i64>` + and 2 more types + +error[E0599]: no method named `other` found for struct `Wrapper` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:92:13 + | +LL | struct Wrapper<T>(T); + | ----------------- method `other` not found for this struct +... +LL | wrapper.other(); + | ^^^^^ method not found in `Wrapper<bool>` + +error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:96:13 + | +LL | struct Wrapper2<'a, T, const C: usize> { + | -------------------------------------- method `method` not found for this struct +... +LL | wrapper.method(); + | ^^^^^^ method not found in `Wrapper2<'_, bool, 3>` + | + = note: the method was found for + - `Wrapper2<'a, i8, C>` + - `Wrapper2<'a, i16, C>` + - `Wrapper2<'a, i32, C>` + +error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:98:13 + | +LL | struct Wrapper2<'a, T, const C: usize> { + | -------------------------------------- method `other` not found for this struct +... +LL | wrapper.other(); + | ^^^^^ method not found in `Wrapper2<'_, bool, 3>` + +error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:101:7 + | +LL | a.not_found(); + | ^^^^^^^^^ method not found in `Vec<{integer}>` + +error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied + --> $DIR/method-not-found-generic-arg-elision.rs:104:7 + | +LL | struct Struct<T> { + | ---------------- method `method` not found for this struct +... +LL | s.method(); + | ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `f64: Eq` + `f64: Ord` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/methods/method-on-ambiguous-numeric-type.rs b/src/test/ui/methods/method-on-ambiguous-numeric-type.rs new file mode 100644 index 000000000..82f47438d --- /dev/null +++ b/src/test/ui/methods/method-on-ambiguous-numeric-type.rs @@ -0,0 +1,32 @@ +// aux-build:macro-in-other-crate.rs + +#[macro_use] extern crate macro_in_other_crate; + +macro_rules! local_mac { + ($ident:ident) => { let $ident = 42; } +} + +fn main() { + let x = 2.0.neg(); + //~^ ERROR can't call method `neg` on ambiguous numeric type `{float}` + + let y = 2.0; + let x = y.neg(); + //~^ ERROR can't call method `neg` on ambiguous numeric type `{float}` + println!("{:?}", x); + + for i in 0..100 { + println!("{}", i.pow(2)); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` + } + + local_mac!(local_bar); + local_bar.pow(2); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` +} + +fn qux() { + mac!(bar); + bar.pow(2); + //~^ ERROR can't call method `pow` on ambiguous numeric type `{integer}` +} diff --git a/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr b/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr new file mode 100644 index 000000000..0af58bc61 --- /dev/null +++ b/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr @@ -0,0 +1,56 @@ +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` + --> $DIR/method-on-ambiguous-numeric-type.rs:10:17 + | +LL | let x = 2.0.neg(); + | ^^^ + | +help: you must specify a concrete type for this numeric value, like `f32` + | +LL | let x = 2.0_f32.neg(); + | ~~~~~~~ + +error[E0689]: can't call method `neg` on ambiguous numeric type `{float}` + --> $DIR/method-on-ambiguous-numeric-type.rs:14:15 + | +LL | let x = y.neg(); + | ^^^ + | +help: you must specify a type for this binding, like `f32` + | +LL | let y: f32 = 2.0; + | ~~~~~~ + +error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` + --> $DIR/method-on-ambiguous-numeric-type.rs:19:26 + | +LL | for i in 0..100 { + | - you must specify a type for this binding, like `i32` +LL | println!("{}", i.pow(2)); + | ^^^ + +error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` + --> $DIR/method-on-ambiguous-numeric-type.rs:24:15 + | +LL | local_bar.pow(2); + | ^^^ + | +help: you must specify a type for this binding, like `i32` + | +LL | ($ident:ident) => { let $ident: i32 = 42; } + | ~~~~~~~~~~~ + +error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` + --> $DIR/method-on-ambiguous-numeric-type.rs:30:9 + | +LL | bar.pow(2); + | ^^^ + | +help: you must specify a type for this binding, like `i32` + --> $DIR/auxiliary/macro-in-other-crate.rs:3:29 + | +LL | ($ident:ident) => { let $ident: i32 = 42; } + | ~~~~~~~~~~~ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0689`. diff --git a/src/test/ui/methods/method-path-in-pattern.rs b/src/test/ui/methods/method-path-in-pattern.rs new file mode 100644 index 000000000..406453095 --- /dev/null +++ b/src/test/ui/methods/method-path-in-pattern.rs @@ -0,0 +1,32 @@ +struct Foo; + +impl Foo { + fn bar(&self) {} +} + +trait MyTrait { + fn trait_bar() {} +} + +impl MyTrait for Foo {} + +fn main() { + match 0u32 { + Foo::bar => {} + //~^ ERROR expected unit struct, unit variant or constant, found associated function + } + match 0u32 { + <Foo>::bar => {} + //~^ ERROR expected unit struct, unit variant or constant, found associated function + } + match 0u32 { + <Foo>::trait_bar => {} + //~^ ERROR expected unit struct, unit variant or constant, found associated function + } + if let Foo::bar = 0u32 {} + //~^ ERROR expected unit struct, unit variant or constant, found associated function + if let <Foo>::bar = 0u32 {} + //~^ ERROR expected unit struct, unit variant or constant, found associated function + if let Foo::trait_bar = 0u32 {} + //~^ ERROR expected unit struct, unit variant or constant, found associated function +} diff --git a/src/test/ui/methods/method-path-in-pattern.stderr b/src/test/ui/methods/method-path-in-pattern.stderr new file mode 100644 index 000000000..1d1bdb6b0 --- /dev/null +++ b/src/test/ui/methods/method-path-in-pattern.stderr @@ -0,0 +1,39 @@ +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` + --> $DIR/method-path-in-pattern.rs:15:9 + | +LL | Foo::bar => {} + | ^^^^^^^^ + +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` + --> $DIR/method-path-in-pattern.rs:19:9 + | +LL | <Foo>::bar => {} + | ^^^^^^^^^^ + +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::trait_bar` + --> $DIR/method-path-in-pattern.rs:23:9 + | +LL | <Foo>::trait_bar => {} + | ^^^^^^^^^^^^^^^^ + +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` + --> $DIR/method-path-in-pattern.rs:26:12 + | +LL | if let Foo::bar = 0u32 {} + | ^^^^^^^^ + +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` + --> $DIR/method-path-in-pattern.rs:28:12 + | +LL | if let <Foo>::bar = 0u32 {} + | ^^^^^^^^^^ + +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::trait_bar` + --> $DIR/method-path-in-pattern.rs:30:12 + | +LL | if let Foo::trait_bar = 0u32 {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0533`. diff --git a/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs b/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs new file mode 100644 index 000000000..ec41b7117 --- /dev/null +++ b/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs @@ -0,0 +1,60 @@ +// run-pass +// Check that method matching does not make "guesses" depending on +// Deref impls that don't eventually end up being picked. + +use std::ops::Deref; + +// An impl with less derefs will get called over an impl with more derefs, +// so `(t: Foo<_>).my_fn()` will use `<Foo<u32> as MyTrait1>::my_fn(t)`, +// and does *not* force the `_` to equal `()`, because the Deref impl +// was *not* used. + +trait MyTrait1 { + fn my_fn(&self) {} +} + +impl MyTrait1 for Foo<u32> {} + +struct Foo<T>(#[allow(unused_tuple_struct_fields)] T); + +impl Deref for Foo<()> { + type Target = dyn MyTrait1 + 'static; + fn deref(&self) -> &(dyn MyTrait1 + 'static) { + panic!() + } +} + +// ...but if there is no impl with less derefs, the "guess" will be +// forced, so `(t: Bar<_>).my_fn2()` is `<dyn MyTrait2 as MyTrait2>::my_fn2(*t)`, +// and because the deref impl is used, the `_` is forced to equal `u8`. + +trait MyTrait2 { + fn my_fn2(&self) {} +} + +impl MyTrait2 for u32 {} +struct Bar<T>(#[allow(unused_tuple_struct_fields)] T, u32); +impl Deref for Bar<u8> { + type Target = dyn MyTrait2 + 'static; + fn deref(&self) -> &(dyn MyTrait2 + 'static) { + &self.1 + } +} + +// actually invoke things + +fn main() { + let mut foo: Option<Foo<_>> = None; + let mut bar: Option<Bar<_>> = None; + let mut first_iter = true; + loop { + if !first_iter { + foo.as_ref().unwrap().my_fn(); + bar.as_ref().unwrap().my_fn2(); + break; + } + foo = Some(Foo(0)); + bar = Some(Bar(Default::default(), 0)); + first_iter = false; + } +} diff --git a/src/test/ui/methods/method-projection.rs b/src/test/ui/methods/method-projection.rs new file mode 100644 index 000000000..21d983f19 --- /dev/null +++ b/src/test/ui/methods/method-projection.rs @@ -0,0 +1,61 @@ +// run-pass +// Test that we can use method notation to call methods based on a +// projection bound from a trait. Issue #20469. + +trait MakeString { + fn make_string(&self) -> String; +} + +impl MakeString for isize { + fn make_string(&self) -> String { + format!("{}", *self) + } +} + +impl MakeString for usize { + fn make_string(&self) -> String { + format!("{}", *self) + } +} + +trait Foo { + type F: MakeString; + + fn get(&self) -> &Self::F; +} + +fn foo<F:Foo>(f: &F) -> String { + f.get().make_string() +} + +struct SomeStruct { + field: isize, +} + +impl Foo for SomeStruct { + type F = isize; + + fn get(&self) -> &isize { + &self.field + } +} + +struct SomeOtherStruct { + field: usize, +} + +impl Foo for SomeOtherStruct { + type F = usize; + + fn get(&self) -> &usize { + &self.field + } +} + +fn main() { + let x = SomeStruct { field: 22 }; + assert_eq!(foo(&x), format!("22")); + + let x = SomeOtherStruct { field: 44 }; + assert_eq!(foo(&x), format!("44")); +} diff --git a/src/test/ui/methods/method-recursive-blanket-impl.rs b/src/test/ui/methods/method-recursive-blanket-impl.rs new file mode 100644 index 000000000..a2db75b4e --- /dev/null +++ b/src/test/ui/methods/method-recursive-blanket-impl.rs @@ -0,0 +1,41 @@ +// run-pass +#![allow(unused_variables)] +#![allow(unused_imports)] +// Test that we don't trigger on the blanket impl for all `&'a T` but +// rather keep autoderefing and trigger on the underlying impl. To +// know not to stop at the blanket, we have to recursively evaluate +// the `T:Foo` bound. + +// pretty-expanded FIXME #23616 + +use std::marker::Sized; + +// Note: this must be generic for the problem to show up +trait Foo<A> { + fn foo(&self, a: A); +} + +impl Foo<u8> for [u8] { + fn foo(&self, a: u8) {} +} + +impl<'a, A, T> Foo<A> for &'a T where T: Foo<A> { + fn foo(&self, a: A) { + Foo::foo(*self, a) + } +} + +trait Bar { + fn foo(&self); +} + +struct MyType; + +impl Bar for MyType { + fn foo(&self) {} +} + +fn main() { + let mut m = MyType; + (&mut m).foo() +} diff --git a/src/test/ui/methods/method-resolvable-path-in-pattern.rs b/src/test/ui/methods/method-resolvable-path-in-pattern.rs new file mode 100644 index 000000000..2973800a4 --- /dev/null +++ b/src/test/ui/methods/method-resolvable-path-in-pattern.rs @@ -0,0 +1,14 @@ +struct Foo; + +trait MyTrait { + fn trait_bar() {} +} + +impl MyTrait for Foo {} + +fn main() { + match 0u32 { + <Foo as MyTrait>::trait_bar => {} + //~^ ERROR expected unit struct, unit variant or constant, found associated function + } +} diff --git a/src/test/ui/methods/method-resolvable-path-in-pattern.stderr b/src/test/ui/methods/method-resolvable-path-in-pattern.stderr new file mode 100644 index 000000000..7c454a9a7 --- /dev/null +++ b/src/test/ui/methods/method-resolvable-path-in-pattern.stderr @@ -0,0 +1,9 @@ +error[E0532]: expected unit struct, unit variant or constant, found associated function `MyTrait::trait_bar` + --> $DIR/method-resolvable-path-in-pattern.rs:11:9 + | +LL | <Foo as MyTrait>::trait_bar => {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/methods/method-self-arg-1.rs b/src/test/ui/methods/method-self-arg-1.rs new file mode 100644 index 000000000..f589f20d8 --- /dev/null +++ b/src/test/ui/methods/method-self-arg-1.rs @@ -0,0 +1,17 @@ +// Test method calls with self as an argument cannot subvert type checking. + +struct Foo; + +impl Foo { + fn bar(&self) {} +} + +fn main() { + let x = Foo; + Foo::bar(x); //~ ERROR mismatched types + //~| expected `&Foo`, found struct `Foo` + Foo::bar(&42); //~ ERROR mismatched types + //~| expected struct `Foo`, found integer + //~| expected reference `&Foo` + //~| found reference `&{integer}` +} diff --git a/src/test/ui/methods/method-self-arg-1.stderr b/src/test/ui/methods/method-self-arg-1.stderr new file mode 100644 index 000000000..01fec6fca --- /dev/null +++ b/src/test/ui/methods/method-self-arg-1.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/method-self-arg-1.rs:11:14 + | +LL | Foo::bar(x); + | -------- ^ + | | | + | | expected `&Foo`, found struct `Foo` + | | help: consider borrowing here: `&x` + | arguments to this function are incorrect + | +note: associated function defined here + --> $DIR/method-self-arg-1.rs:6:8 + | +LL | fn bar(&self) {} + | ^^^ ----- + +error[E0308]: mismatched types + --> $DIR/method-self-arg-1.rs:13:14 + | +LL | Foo::bar(&42); + | -------- ^^^ expected struct `Foo`, found integer + | | + | arguments to this function are incorrect + | + = note: expected reference `&Foo` + found reference `&{integer}` +note: associated function defined here + --> $DIR/method-self-arg-1.rs:6:8 + | +LL | fn bar(&self) {} + | ^^^ ----- + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/methods/method-self-arg-2.rs b/src/test/ui/methods/method-self-arg-2.rs new file mode 100644 index 000000000..0f8c048ac --- /dev/null +++ b/src/test/ui/methods/method-self-arg-2.rs @@ -0,0 +1,25 @@ +// Test method calls with self as an argument cannot subvert borrow checking. + + + +struct Foo; + +impl Foo { + fn bar(&self) {} + fn baz(&mut self) {} +} + +fn main() { + let mut x = Foo; + let y = &mut x; + Foo::bar(&x); //~ERROR cannot borrow `x` + y.use_mut(); + + let mut x = Foo; + let y = &mut x; + Foo::baz(&mut x); //~ERROR cannot borrow `x` + y.use_mut(); +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/src/test/ui/methods/method-self-arg-2.stderr b/src/test/ui/methods/method-self-arg-2.stderr new file mode 100644 index 000000000..b98f7a786 --- /dev/null +++ b/src/test/ui/methods/method-self-arg-2.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/method-self-arg-2.rs:15:14 + | +LL | let y = &mut x; + | ------ mutable borrow occurs here +LL | Foo::bar(&x); + | ^^ immutable borrow occurs here +LL | y.use_mut(); + | ----------- mutable borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/method-self-arg-2.rs:20:14 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | Foo::baz(&mut x); + | ^^^^^^ second mutable borrow occurs here +LL | y.use_mut(); + | ----------- first borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0499, E0502. +For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/methods/method-self-arg-aux1.rs b/src/test/ui/methods/method-self-arg-aux1.rs new file mode 100644 index 000000000..79b70a17c --- /dev/null +++ b/src/test/ui/methods/method-self-arg-aux1.rs @@ -0,0 +1,18 @@ +// run-pass +// Test method calls with self as an argument (cross-crate) + +// aux-build:method_self_arg1.rs +extern crate method_self_arg1; +use method_self_arg1::Foo; + +fn main() { + let x = Foo; + // Test external call. + Foo::bar(&x); + Foo::baz(x); + Foo::qux(Box::new(x)); + + x.foo(&x); + + assert_eq!(method_self_arg1::get_count(), 2*3*3*3*5*5*5*7*7*7); +} diff --git a/src/test/ui/methods/method-self-arg-aux2.rs b/src/test/ui/methods/method-self-arg-aux2.rs new file mode 100644 index 000000000..16487b54f --- /dev/null +++ b/src/test/ui/methods/method-self-arg-aux2.rs @@ -0,0 +1,22 @@ +// run-pass +// Test method calls with self as an argument (cross-crate) + +// aux-build:method_self_arg2.rs +extern crate method_self_arg2; +use method_self_arg2::{Foo, Bar}; + +fn main() { + let x = Foo; + // Test external call. + Bar::foo1(&x); + Bar::foo2(x); + Bar::foo3(Box::new(x)); + + Bar::bar1(&x); + Bar::bar2(x); + Bar::bar3(Box::new(x)); + + x.run_trait(); + + assert_eq!(method_self_arg2::get_count(), 2*2*3*3*5*5*7*7*11*11*13*13*17); +} diff --git a/src/test/ui/methods/method-self-arg-trait.rs b/src/test/ui/methods/method-self-arg-trait.rs new file mode 100644 index 000000000..ffa7a552b --- /dev/null +++ b/src/test/ui/methods/method-self-arg-trait.rs @@ -0,0 +1,67 @@ +// run-pass +// Test method calls with self as an argument + +static mut COUNT: u64 = 1; + +#[derive(Copy, Clone)] +struct Foo; + +trait Bar : Sized { + fn foo1(&self); + fn foo2(self); + fn foo3(self: Box<Self>); + + fn bar1(&self) { + unsafe { COUNT *= 7; } + } + fn bar2(self) { + unsafe { COUNT *= 11; } + } + fn bar3(self: Box<Self>) { + unsafe { COUNT *= 13; } + } +} + +impl Bar for Foo { + fn foo1(&self) { + unsafe { COUNT *= 2; } + } + + fn foo2(self) { + unsafe { COUNT *= 3; } + } + + fn foo3(self: Box<Foo>) { + unsafe { COUNT *= 5; } + } +} + +impl Foo { + fn baz(self) { + unsafe { COUNT *= 17; } + // Test internal call. + Bar::foo1(&self); + Bar::foo2(self); + Bar::foo3(Box::new(self)); + + Bar::bar1(&self); + Bar::bar2(self); + Bar::bar3(Box::new(self)); + } +} + +fn main() { + let x = Foo; + // Test external call. + Bar::foo1(&x); + Bar::foo2(x); + Bar::foo3(Box::new(x)); + + Bar::bar1(&x); + Bar::bar2(x); + Bar::bar3(Box::new(x)); + + x.baz(); + + unsafe { assert_eq!(COUNT, 2*2*3*3*5*5*7*7*11*11*13*13*17); } +} diff --git a/src/test/ui/methods/method-self-arg.rs b/src/test/ui/methods/method-self-arg.rs new file mode 100644 index 000000000..f738fa19c --- /dev/null +++ b/src/test/ui/methods/method-self-arg.rs @@ -0,0 +1,46 @@ +// run-pass +// Test method calls with self as an argument + +static mut COUNT: usize = 1; + +#[derive(Copy, Clone)] +struct Foo; + +impl Foo { + fn foo(self, x: &Foo) { + unsafe { COUNT *= 2; } + // Test internal call. + Foo::bar(&self); + Foo::bar(x); + + Foo::baz(self); + Foo::baz(*x); + + Foo::qux(Box::new(self)); + Foo::qux(Box::new(*x)); + } + + fn bar(&self) { + unsafe { COUNT *= 3; } + } + + fn baz(self) { + unsafe { COUNT *= 5; } + } + + fn qux(self: Box<Foo>) { + unsafe { COUNT *= 7; } + } +} + +fn main() { + let x = Foo; + // Test external call. + Foo::bar(&x); + Foo::baz(x); + Foo::qux(Box::new(x)); + + x.foo(&x); + + unsafe { assert_eq!(COUNT, 2*3*3*3*5*5*5*7*7*7); } +} diff --git a/src/test/ui/methods/method-trait-object-with-hrtb.rs b/src/test/ui/methods/method-trait-object-with-hrtb.rs new file mode 100644 index 000000000..d1bee676c --- /dev/null +++ b/src/test/ui/methods/method-trait-object-with-hrtb.rs @@ -0,0 +1,41 @@ +// build-pass (FIXME(62277): could be check-pass?) + +// Check that method probing ObjectCandidate works in the presence of +// auto traits and/or HRTBs. + +mod internal { + pub trait MyObject<'a> { + type Output; + + fn foo(&self) -> Self::Output; + } + + impl<'a> MyObject<'a> for () { + type Output = &'a u32; + + fn foo(&self) -> Self::Output { &4 } + } +} + +fn t1(d: &dyn for<'a> internal::MyObject<'a, Output=&'a u32>) { + d.foo(); +} + +fn t2(d: &dyn internal::MyObject<'static, Output=&'static u32>) { + d.foo(); +} + +fn t3(d: &(dyn for<'a> internal::MyObject<'a, Output=&'a u32> + Sync)) { + d.foo(); +} + +fn t4(d: &(dyn internal::MyObject<'static, Output=&'static u32> + Sync)) { + d.foo(); +} + +fn main() { + t1(&()); + t2(&()); + t3(&()); + t4(&()); +} diff --git a/src/test/ui/methods/method-two-trait-defer-resolution-1.rs b/src/test/ui/methods/method-two-trait-defer-resolution-1.rs new file mode 100644 index 000000000..b768620cd --- /dev/null +++ b/src/test/ui/methods/method-two-trait-defer-resolution-1.rs @@ -0,0 +1,37 @@ +// run-pass +#![allow(non_camel_case_types)] + +// 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) -> i32; +} + +impl foo for Vec<u32> { + fn foo(&self) -> i32 {1} +} + +impl foo for Vec<i32> { + fn foo(&self) -> i32 {2} +} + +fn call_foo_uint() -> i32 { + let mut x = Vec::new(); + let y = x.foo(); + x.push(0u32); + y +} + +fn call_foo_int() -> i32 { + let mut x = Vec::new(); + let y = x.foo(); + x.push(0i32); + y +} + +fn main() { + assert_eq!(call_foo_uint(), 1); + assert_eq!(call_foo_int(), 2); +} diff --git a/src/test/ui/methods/method-two-trait-defer-resolution-2.rs b/src/test/ui/methods/method-two-trait-defer-resolution-2.rs new file mode 100644 index 000000000..fc5766da9 --- /dev/null +++ b/src/test/ui/methods/method-two-trait-defer-resolution-2.rs @@ -0,0 +1,46 @@ +// run-pass +// Test that when we write `x.foo()`, we do not have to know the +// complete type of `x` in order to type-check the method call. In +// this case, we know that `x: Vec<_1>`, but we don't know what type +// `_1` is (because the call to `push` comes later). To pick between +// the impls, we would have to know `_1`, since we have to know +// whether `_1: MyCopy` or `_1 == Box<i32>`. However (and this is the +// point of the test), we don't have to pick between the two impls -- +// it is enough to know that `foo` comes from the `Foo` trait. We can +// codegen the call as `Foo::foo(&x)` and let the specific impl get +// chosen later. + +trait Foo { + fn foo(&self) -> isize; +} + +trait MyCopy { fn foo(&self) { } } +impl MyCopy for i32 { } + +impl<T:MyCopy> Foo for Vec<T> { + fn foo(&self) -> isize {1} +} + +impl Foo for Vec<Box<i32>> { + fn foo(&self) -> isize {2} +} + +fn call_foo_copy() -> isize { + let mut x = Vec::new(); + let y = x.foo(); + x.push(0_i32); + y +} + +fn call_foo_other() -> isize { + let mut x: Vec<_> = Vec::new(); + let y = x.foo(); + let z: Box<i32> = Box::new(0); + x.push(z); + y +} + +fn main() { + assert_eq!(call_foo_copy(), 1); + assert_eq!(call_foo_other(), 2); +} diff --git a/src/test/ui/methods/method-two-traits-distinguished-via-where-clause.rs b/src/test/ui/methods/method-two-traits-distinguished-via-where-clause.rs new file mode 100644 index 000000000..d820d2ad0 --- /dev/null +++ b/src/test/ui/methods/method-two-traits-distinguished-via-where-clause.rs @@ -0,0 +1,27 @@ +// run-pass +// Test that we select between traits A and B. To do that, we must +// consider the `Sized` bound. + +// pretty-expanded FIXME #23616 + +trait A { + fn foo(self); +} + +trait B { + fn foo(self); +} + +impl<T: Sized> A for *const T { + fn foo(self) {} +} + +impl<T> B for *const [T] { + fn foo(self) {} +} + +fn main() { + let x: [isize; 4] = [1,2,3,4]; + let xptr = &x[..] as *const [isize]; + xptr.foo(); +} diff --git a/src/test/ui/methods/method-where-clause.rs b/src/test/ui/methods/method-where-clause.rs new file mode 100644 index 000000000..01692abf9 --- /dev/null +++ b/src/test/ui/methods/method-where-clause.rs @@ -0,0 +1,34 @@ +// run-pass +// Test that we can use method notation to call methods based on a +// where clause type, and not only type parameters. + + +trait Foo { + fn foo(&self) -> i32; +} + +impl Foo for Option<i32> +{ + fn foo(&self) -> i32 { + self.unwrap_or(22) + } +} + +impl Foo for Option<u32> +{ + fn foo(&self) -> i32 { + self.unwrap_or(22) as i32 + } +} + +fn check<T>(x: Option<T>) -> (i32, i32) + where Option<T> : Foo +{ + let y: Option<T> = None; + (x.foo(), y.foo()) +} + +fn main() { + assert_eq!(check(Some(23u32)), (23, 22)); + assert_eq!(check(Some(23)), (23, 22)); +} |