Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/tests/method_resolution.rs')
| -rw-r--r-- | crates/hir-ty/src/tests/method_resolution.rs | 1792 |
1 files changed, 1792 insertions, 0 deletions
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs new file mode 100644 index 0000000000..68463dc068 --- /dev/null +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -0,0 +1,1792 @@ +use expect_test::expect; + +use crate::tests::check; + +use super::{check_infer, check_no_mismatches, check_types}; + +#[test] +fn infer_slice_method() { + check_types( + r#" +impl<T> [T] { + fn foo(&self) -> T { + loop {} + } +} + +fn test(x: &[u8]) { + <[_]>::foo(x); + //^^^^^^^^^^^^^ u8 +} + "#, + ); +} + +#[test] +fn cross_crate_primitive_method() { + check_types( + r#" +//- /main.rs crate:main deps:other_crate +fn test() { + let x = 1f32; + x.foo(); +} //^^^^^^^ f32 + +//- /lib.rs crate:other_crate +mod foo { + impl f32 { + pub fn foo(self) -> f32 { 0. } + } +} +"#, + ); +} + +#[test] +fn infer_array_inherent_impl() { + check_types( + r#" +impl<T, const N: usize> [T; N] { + fn foo(&self) -> T { + loop {} + } +} +fn test(x: &[u8; 0]) { + <[_; 0]>::foo(x); + //^^^^^^^^^^^^^^^^ u8 +} + "#, + ); +} + +#[test] +fn infer_associated_method_struct() { + check_infer( + r#" + struct A { x: u32 } + + impl A { + fn new() -> A { + A { x: 0 } + } + } + fn test() { + let a = A::new(); + a.x; + } + "#, + expect![[r#" + 48..74 '{ ... }': A + 58..68 'A { x: 0 }': A + 65..66 '0': u32 + 87..121 '{ ...a.x; }': () + 97..98 'a': A + 101..107 'A::new': fn new() -> A + 101..109 'A::new()': A + 115..116 'a': A + 115..118 'a.x': u32 + "#]], + ); +} + +#[test] +fn infer_associated_method_struct_in_local_scope() { + check_infer( + r#" + fn mismatch() { + struct A; + + impl A { + fn from(_: i32, _: i32) -> Self { + A + } + } + + let _a = A::from(1, 2); + } + "#, + expect![[r#" + 14..146 '{ ... 2); }': () + 125..127 '_a': A + 130..137 'A::from': fn from(i32, i32) -> A + 130..143 'A::from(1, 2)': A + 138..139 '1': i32 + 141..142 '2': i32 + 60..61 '_': i32 + 68..69 '_': i32 + 84..109 '{ ... }': A + 98..99 'A': A + "#]], + ); +} + +#[test] +fn infer_associated_method_enum() { + check_infer( + r#" + enum A { B, C } + + impl A { + pub fn b() -> A { + A::B + } + pub fn c() -> A { + A::C + } + } + fn test() { + let a = A::b(); + a; + let c = A::c(); + c; + } + "#, + expect![[r#" + 46..66 '{ ... }': A + 56..60 'A::B': A + 87..107 '{ ... }': A + 97..101 'A::C': A + 120..177 '{ ... c; }': () + 130..131 'a': A + 134..138 'A::b': fn b() -> A + 134..140 'A::b()': A + 146..147 'a': A + 157..158 'c': A + 161..165 'A::c': fn c() -> A + 161..167 'A::c()': A + 173..174 'c': A + "#]], + ); +} + +#[test] +fn infer_associated_method_with_modules() { + check_infer( + r#" + mod a { + struct A; + impl A { pub fn thing() -> A { A {} }} + } + + mod b { + struct B; + impl B { pub fn thing() -> u32 { 99 }} + + mod c { + struct C; + impl C { pub fn thing() -> C { C {} }} + } + } + use b::c; + + fn test() { + let x = a::A::thing(); + let y = b::B::thing(); + let z = c::C::thing(); + } + "#, + expect![[r#" + 55..63 '{ A {} }': A + 57..61 'A {}': A + 125..131 '{ 99 }': u32 + 127..129 '99': u32 + 201..209 '{ C {} }': C + 203..207 'C {}': C + 240..324 '{ ...g(); }': () + 250..251 'x': A + 254..265 'a::A::thing': fn thing() -> A + 254..267 'a::A::thing()': A + 277..278 'y': u32 + 281..292 'b::B::thing': fn thing() -> u32 + 281..294 'b::B::thing()': u32 + 304..305 'z': C + 308..319 'c::C::thing': fn thing() -> C + 308..321 'c::C::thing()': C + "#]], + ); +} + +#[test] +fn infer_associated_method_generics() { + check_infer( + r#" + struct Gen<T> { + val: T + } + + impl<T> Gen<T> { + pub fn make(val: T) -> Gen<T> { + Gen { val } + } + } + + fn test() { + let a = Gen::make(0u32); + } + "#, + expect![[r#" + 63..66 'val': T + 81..108 '{ ... }': Gen<T> + 91..102 'Gen { val }': Gen<T> + 97..100 'val': T + 122..154 '{ ...32); }': () + 132..133 'a': Gen<u32> + 136..145 'Gen::make': fn make<u32>(u32) -> Gen<u32> + 136..151 'Gen::make(0u32)': Gen<u32> + 146..150 '0u32': u32 + "#]], + ); +} + +#[test] +fn infer_associated_method_generics_without_args() { + check_infer( + r#" + struct Gen<T> { + val: T + } + + impl<T> Gen<T> { + pub fn make() -> Gen<T> { + loop { } + } + } + + fn test() { + let a = Gen::<u32>::make(); + } + "#, + expect![[r#" + 75..99 '{ ... }': Gen<T> + 85..93 'loop { }': ! + 90..93 '{ }': () + 113..148 '{ ...e(); }': () + 123..124 'a': Gen<u32> + 127..143 'Gen::<...::make': fn make<u32>() -> Gen<u32> + 127..145 'Gen::<...make()': Gen<u32> + "#]], + ); +} + +#[test] +fn infer_associated_method_generics_2_type_params_without_args() { + check_infer( + r#" + struct Gen<T, U> { + val: T, + val2: U, + } + + impl<T> Gen<u32, T> { + pub fn make() -> Gen<u32,T> { + loop { } + } + } + + fn test() { + let a = Gen::<u32, u64>::make(); + } + "#, + expect![[r#" + 101..125 '{ ... }': Gen<u32, T> + 111..119 'loop { }': ! + 116..119 '{ }': () + 139..179 '{ ...e(); }': () + 149..150 'a': Gen<u32, u64> + 153..174 'Gen::<...::make': fn make<u64>() -> Gen<u32, u64> + 153..176 'Gen::<...make()': Gen<u32, u64> + "#]], + ); +} + +#[test] +fn cross_crate_associated_method_call() { + check_types( + r#" +//- /main.rs crate:main deps:other_crate +fn test() { + let x = other_crate::foo::S::thing(); + x; +} //^ i128 + +//- /lib.rs crate:other_crate +pub mod foo { + pub struct S; + impl S { + pub fn thing() -> i128 { 0 } + } +} +"#, + ); +} + +#[test] +fn infer_trait_method_simple() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_types( + r#" +trait Trait1 { + fn method(&self) -> u32; +} +struct S1; +impl Trait1 for S1 {} +trait Trait2 { + fn method(&self) -> i128; +} +struct S2; +impl Trait2 for S2 {} +fn test() { + S1.method(); + //^^^^^^^^^^^ u32 + S2.method(); // -> i128 + //^^^^^^^^^^^ i128 +} + "#, + ); +} + +#[test] +fn infer_trait_method_scoped() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_types( + r#" +struct S; +mod foo { + pub trait Trait1 { + fn method(&self) -> u32; + } + impl Trait1 for super::S {} +} +mod bar { + pub trait Trait2 { + fn method(&self) -> i128; + } + impl Trait2 for super::S {} +} + +mod foo_test { + use super::S; + use super::foo::Trait1; + fn test() { + S.method(); + //^^^^^^^^^^ u32 + } +} + +mod bar_test { + use super::S; + use super::bar::Trait2; + fn test() { + S.method(); + //^^^^^^^^^^ i128 + } +} + "#, + ); +} + +#[test] +fn infer_trait_method_generic_1() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_types( + r#" +trait Trait<T> { + fn method(&self) -> T; +} +struct S; +impl Trait<u32> for S {} +fn test() { + S.method(); + //^^^^^^^^^^ u32 +} + "#, + ); +} + +#[test] +fn infer_trait_method_generic_more_params() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_types( + r#" +trait Trait<T1, T2, T3> { + fn method1(&self) -> (T1, T2, T3); + fn method2(&self) -> (T3, T2, T1); +} +struct S1; +impl Trait<u8, u16, u32> for S1 {} +struct S2; +impl<T> Trait<i8, i16, T> for S2 {} +fn test() { + S1.method1(); + //^^^^^^^^^^^^ (u8, u16, u32) + S1.method2(); + //^^^^^^^^^^^^ (u32, u16, u8) + S2.method1(); + //^^^^^^^^^^^^ (i8, i16, {unknown}) + S2.method2(); + //^^^^^^^^^^^^ ({unknown}, i16, i8) +} + "#, + ); +} + +#[test] +fn infer_trait_method_generic_2() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_types( + r#" +trait Trait<T> { + fn method(&self) -> T; +} +struct S<T>(T); +impl<U> Trait<U> for S<U> {} +fn test() { + S(1u32).method(); + //^^^^^^^^^^^^^^^^ u32 +} + "#, + ); +} + +#[test] +fn infer_trait_assoc_method() { + check_infer( + r#" + trait Default { + fn default() -> Self; + } + struct S; + impl Default for S {} + fn test() { + let s1: S = Default::default(); + let s2 = S::default(); + let s3 = <S as Default>::default(); + } + "#, + expect![[r#" + 86..192 '{ ...t(); }': () + 96..98 's1': S + 104..120 'Defaul...efault': fn default<S>() -> S + 104..122 'Defaul...ault()': S + 132..134 's2': S + 137..147 'S::default': fn default<S>() -> S + 137..149 'S::default()': S + 159..161 's3': S + 164..187 '<S as ...efault': fn default<S>() -> S + 164..189 '<S as ...ault()': S + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_1() { + check_infer( + r#" + trait Trait<T> { + fn make() -> T; + } + struct S; + impl Trait<u32> for S {} + struct G<T>; + impl<T> Trait<T> for G<T> {} + fn test() { + let a = S::make(); + let b = G::<u64>::make(); + let c: f64 = G::make(); + } + "#, + expect![[r#" + 126..210 '{ ...e(); }': () + 136..137 'a': u32 + 140..147 'S::make': fn make<S, u32>() -> u32 + 140..149 'S::make()': u32 + 159..160 'b': u64 + 163..177 'G::<u64>::make': fn make<G<u64>, u64>() -> u64 + 163..179 'G::<u6...make()': u64 + 189..190 'c': f64 + 198..205 'G::make': fn make<G<f64>, f64>() -> f64 + 198..207 'G::make()': f64 + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_2() { + check_infer( + r#" + trait Trait<T> { + fn make<U>() -> (T, U); + } + struct S; + impl Trait<u32> for S {} + struct G<T>; + impl<T> Trait<T> for G<T> {} + fn test() { + let a = S::make::<i64>(); + let b: (_, i64) = S::make(); + let c = G::<u32>::make::<i64>(); + let d: (u32, _) = G::make::<i64>(); + let e: (u32, i64) = G::make(); + } + "#, + expect![[r#" + 134..312 '{ ...e(); }': () + 144..145 'a': (u32, i64) + 148..162 'S::make::<i64>': fn make<S, u32, i64>() -> (u32, i64) + 148..164 'S::mak...i64>()': (u32, i64) + 174..175 'b': (u32, i64) + 188..195 'S::make': fn make<S, u32, i64>() -> (u32, i64) + 188..197 'S::make()': (u32, i64) + 207..208 'c': (u32, i64) + 211..232 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) + 211..234 'G::<u3...i64>()': (u32, i64) + 244..245 'd': (u32, i64) + 258..272 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (u32, i64) + 258..274 'G::mak...i64>()': (u32, i64) + 284..285 'e': (u32, i64) + 300..307 'G::make': fn make<G<u32>, u32, i64>() -> (u32, i64) + 300..309 'G::make()': (u32, i64) + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_3() { + check_infer( + r#" + trait Trait<T> { + fn make() -> (Self, T); + } + struct S<T>; + impl Trait<i64> for S<i32> {} + fn test() { + let a = S::make(); + } + "#, + expect![[r#" + 100..126 '{ ...e(); }': () + 110..111 'a': (S<i32>, i64) + 114..121 'S::make': fn make<S<i32>, i64>() -> (S<i32>, i64) + 114..123 'S::make()': (S<i32>, i64) + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_4() { + check_infer( + r#" + trait Trait<T> { + fn make() -> (Self, T); + } + struct S<T>; + impl Trait<i64> for S<u64> {} + impl Trait<i32> for S<u32> {} + fn test() { + let a: (S<u64>, _) = S::make(); + let b: (_, i32) = S::make(); + } + "#, + expect![[r#" + 130..202 '{ ...e(); }': () + 140..141 'a': (S<u64>, i64) + 157..164 'S::make': fn make<S<u64>, i64>() -> (S<u64>, i64) + 157..166 'S::make()': (S<u64>, i64) + 176..177 'b': (S<u32>, i32) + 190..197 'S::make': fn make<S<u32>, i32>() -> (S<u32>, i32) + 190..199 'S::make()': (S<u32>, i32) + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_5() { + check_infer( + r#" + trait Trait<T> { + fn make<U>() -> (Self, T, U); + } + struct S<T>; + impl Trait<i64> for S<u64> {} + fn test() { + let a = <S as Trait<i64>>::make::<u8>(); + let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>(); + } + "#, + expect![[r#" + 106..210 '{ ...>(); }': () + 116..117 'a': (S<u64>, i64, u8) + 120..149 '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) + 120..151 '<S as ...<u8>()': (S<u64>, i64, u8) + 161..162 'b': (S<u64>, i64, u8) + 181..205 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (S<u64>, i64, u8) + 181..207 'Trait:...<u8>()': (S<u64>, i64, u8) + "#]], + ); +} + +#[test] +fn infer_call_trait_method_on_generic_param_1() { + check_infer( + r#" + trait Trait { + fn method(&self) -> u32; + } + fn test<T: Trait>(t: T) { + t.method(); + } + "#, + expect![[r#" + 29..33 'self': &Self + 63..64 't': T + 69..88 '{ ...d(); }': () + 75..76 't': T + 75..85 't.method()': u32 + "#]], + ); +} + +#[test] +fn infer_call_trait_method_on_generic_param_2() { + check_infer( + r#" + trait Trait<T> { + fn method(&self) -> T; + } + fn test<U, T: Trait<U>>(t: T) { + t.method(); + } + "#, + expect![[r#" + 32..36 'self': &Self + 70..71 't': T + 76..95 '{ ...d(); }': () + 82..83 't': T + 82..92 't.method()': U + "#]], + ); +} + +#[test] +fn infer_with_multiple_trait_impls() { + check_infer( + r#" + trait Into<T> { + fn into(self) -> T; + } + struct S; + impl Into<u32> for S {} + impl Into<u64> for S {} + fn test() { + let x: u32 = S.into(); + let y: u64 = S.into(); + let z = Into::<u64>::into(S); + } + "#, + expect![[r#" + 28..32 'self': Self + 110..201 '{ ...(S); }': () + 120..121 'x': u32 + 129..130 'S': S + 129..137 'S.into()': u32 + 147..148 'y': u64 + 156..157 'S': S + 156..164 'S.into()': u64 + 174..175 'z': u64 + 178..195 'Into::...::into': fn into<S, u64>(S) -> u64 + 178..198 'Into::...nto(S)': u64 + 196..197 'S': S + "#]], + ); +} + +#[test] +fn method_resolution_unify_impl_self_type() { + check_types( + r#" +struct S<T>; +impl S<u32> { fn foo(&self) -> u8 { 0 } } +impl S<i32> { fn foo(&self) -> i8 { 0 } } +fn test() { (S::<u32>.foo(), S::<i32>.foo()); } + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (u8, i8) +"#, + ); +} + +#[test] +fn method_resolution_trait_before_autoref() { + check_types( + r#" +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(&self) -> i8 { 0 } } +impl Trait for S { fn foo(self) -> u128 { 0 } } +fn test() { S.foo(); } + //^^^^^^^ u128 +"#, + ); +} + +#[test] +fn method_resolution_by_value_before_autoref() { + check_types( + r#" +trait Clone { fn clone(&self) -> Self; } +struct S; +impl Clone for S {} +impl Clone for &S {} +fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S) +"#, + ); +} + +#[test] +fn method_resolution_trait_before_autoderef() { + check_types( + r#" +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(self) -> i8 { 0 } } +impl Trait for &S { fn foo(self) -> u128 { 0 } } +fn test() { (&S).foo(); } + //^^^^^^^^^^ u128 +"#, + ); +} + +#[test] +fn method_resolution_impl_before_trait() { + check_types( + r#" +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(self) -> i8 { 0 } } +impl Trait for S { fn foo(self) -> u128 { 0 } } +fn test() { S.foo(); } + //^^^^^^^ i8 +"#, + ); +} + +#[test] +fn method_resolution_impl_ref_before_trait() { + check_types( + r#" +trait Trait { fn foo(self) -> u128; } +struct S; +impl S { fn foo(&self) -> i8 { 0 } } +impl Trait for &S { fn foo(self) -> u128 { 0 } } +fn test() { S.foo(); } + //^^^^^^^ i8 +"#, + ); +} + +#[test] +fn method_resolution_trait_autoderef() { + check_types( + r#" +trait Trait { fn foo(self) -> u128; } +struct S; +impl Trait for S { fn foo(self) -> u128 { 0 } } +fn test() { (&S).foo(); } + //^^^^^^^^^^ u128 +"#, + ); +} + +#[test] +fn method_resolution_unsize_array() { + check_types( + r#" +//- minicore: slice +fn test() { + let a = [1, 2, 3]; + a.len(); +} //^^^^^^^ usize +"#, + ); +} + +#[test] +fn method_resolution_trait_from_prelude() { + check_types( + r#" +//- /main.rs crate:main deps:core +struct S; +impl Clone for S {} + +fn test() { + S.clone(); + //^^^^^^^^^ S +} + +//- /lib.rs crate:core +pub mod prelude { + pub mod rust_2018 { + pub trait Clone { + fn clone(&self) -> Self; + } + } +} +"#, + ); +} + +#[test] +fn method_resolution_where_clause_for_unknown_trait() { + // The blanket impl currently applies because we ignore the unresolved where clause + check_types( + r#" +trait Trait { fn foo(self) -> u128; } +struct S; +impl<T> Trait for T where T: UnknownTrait {} +fn test() { (&S).foo(); } + //^^^^^^^^^^ u128 +"#, + ); +} + +#[test] +fn method_resolution_where_clause_not_met() { + // The blanket impl shouldn't apply because we can't prove S: Clone + // This is also to make sure that we don't resolve to the foo method just + // because that's the only method named foo we can find, which would make + // the below tests not work + check_types( + r#" +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl<T> Trait for T where T: Clone {} +fn test() { (&S).foo(); } + //^^^^^^^^^^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_where_clause_inline_not_met() { + // The blanket impl shouldn't apply because we can't prove S: Clone + check_types( + r#" +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl<T: Clone> Trait for T {} +fn test() { (&S).foo(); } + //^^^^^^^^^^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_where_clause_1() { + check_types( + r#" +trait Clone {} +trait Trait { fn foo(self) -> u128; } +struct S; +impl Clone for S {} +impl<T> Trait for T where T: Clone {} +fn test() { S.foo(); } + //^^^^^^^ u128 +"#, + ); +} + +#[test] +fn method_resolution_where_clause_2() { + check_types( + r#" +trait Into<T> { fn into(self) -> T; } +trait From<T> { fn from(other: T) -> Self; } +struct S1; +struct S2; +impl From<S2> for S1 {} +impl<T, U> Into<U> for T where U: From<T> {} +fn test() { S2.into(); } + //^^^^^^^^^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_where_clause_inline() { + check_types( + r#" +trait Into<T> { fn into(self) -> T; } +trait From<T> { fn from(other: T) -> Self; } +struct S1; +struct S2; +impl From<S2> for S1 {} +impl<T, U: From<T>> Into<U> for T {} +fn test() { S2.into(); } + //^^^^^^^^^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_overloaded_method() { + check_types( + r#" +struct Wrapper<T>(T); +struct Foo<T>(T); +struct Bar<T>(T); + +impl<T> Wrapper<Foo<T>> { + pub fn new(foo_: T) -> Self { + Wrapper(Foo(foo_)) + } +} + +impl<T> Wrapper<Bar<T>> { + pub fn new(bar_: T) -> Self { + Wrapper(Bar(bar_)) + } +} + +fn main() { + let a = Wrapper::<Foo<f32>>::new(1.0); + let b = Wrapper::<Bar<f32>>::new(1.0); + (a, b); + //^^^^^^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>) +} +"#, + ); +} + +#[test] +fn method_resolution_overloaded_const() { + cov_mark::check!(const_candidate_self_type_mismatch); + check_types( + r#" +struct Wrapper<T>(T); +struct Foo<T>(T); +struct Bar<T>(T); + +impl<T> Wrapper<Foo<T>> { + pub const VALUE: Foo<T>; +} + +impl<T> Wrapper<Bar<T>> { + pub const VALUE: Bar<T>; +} + +fn main() { + let a = Wrapper::<Foo<f32>>::VALUE; + let b = Wrapper::<Bar<f32>>::VALUE; + (a, b); + //^^^^^^ (Foo<f32>, Bar<f32>) +} +"#, + ); +} + +#[test] +fn method_resolution_encountering_fn_type() { + check_types( + r#" +//- /main.rs +fn foo() {} +trait FnOnce { fn call(self); } +fn test() { foo.call(); } + //^^^^^^^^^^ {unknown} +"#, + ); +} + +#[test] +fn super_trait_impl_return_trait_method_resolution() { + check_infer( + r#" + //- minicore: sized + trait Base { + fn foo(self) -> usize; + } + + trait Super : Base {} + + fn base1() -> impl Base { loop {} } + fn super1() -> impl Super { loop {} } + + fn test(base2: impl Base, super2: impl Super) { + base1().foo(); + super1().foo(); + base2.foo(); + super2.foo(); + } + "#, + expect![[r#" + 24..28 'self': Self + 90..101 '{ loop {} }': ! + 92..99 'loop {}': ! + 97..99 '{}': () + 128..139 '{ loop {} }': ! + 130..137 'loop {}': ! + 135..137 '{}': () + 149..154 'base2': impl Base + 167..173 'super2': impl Super + 187..264 '{ ...o(); }': () + 193..198 'base1': fn base1() -> impl Base + 193..200 'base1()': impl Base + 193..206 'base1().foo()': usize + 212..218 'super1': fn super1() -> impl Super + 212..220 'super1()': impl Super + 212..226 'super1().foo()': usize + 232..237 'base2': impl Base + 232..243 'base2.foo()': usize + 249..255 'super2': impl Super + 249..261 'super2.foo()': usize + "#]], + ); +} + +#[test] +fn method_resolution_non_parameter_type() { + check_types( + r#" +mod a { + pub trait Foo { + fn foo(&self); + } +} + +struct Wrapper<T>(T); +fn foo<T>(t: Wrapper<T>) +where + Wrapper<T>: a::Foo, +{ + t.foo(); +} //^^^^^^^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_3373() { + check_types( + r#" +struct A<T>(T); + +impl A<i32> { + fn from(v: i32) -> A<i32> { A(v) } +} + +fn main() { + A::from(3); +} //^^^^^^^^^^ A<i32> +"#, + ); +} + +#[test] +fn method_resolution_slow() { + // this can get quite slow if we set the solver size limit too high + check_types( + r#" +trait SendX {} + +struct S1; impl SendX for S1 {} +struct S2; impl SendX for S2 {} +struct U1; + +trait Trait { fn method(self); } + +struct X1<A, B> {} +impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {} + +struct S<B, C> {} + +trait FnX {} + +impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {} + +fn test() { (S {}).method(); } + //^^^^^^^^^^^^^^^ () +"#, + ); +} + +#[test] +fn dyn_trait_super_trait_not_in_scope() { + check_infer( + r#" + mod m { + pub trait SuperTrait { + fn foo(&self) -> u32 { 0 } + } + } + trait Trait: m::SuperTrait {} + + struct S; + impl m::SuperTrait for S {} + impl Trait for S {} + + fn test(d: &dyn Trait) { + d.foo(); + } + "#, + expect![[r#" + 51..55 'self': &Self + 64..69 '{ 0 }': u32 + 66..67 '0': u32 + 176..177 'd': &dyn Trait + 191..207 '{ ...o(); }': () + 197..198 'd': &dyn Trait + 197..204 'd.foo()': u32 + "#]], + ); +} + +#[test] +fn method_resolution_foreign_opaque_type() { + check_infer( + r#" +extern "C" { + type S; + fn f() -> &'static S; +} + +impl S { + fn foo(&self) -> bool { + true + } +} + +fn test() { + let s = unsafe { f() }; + s.foo(); +} +"#, + expect![[r#" + 75..79 'self': &S + 89..109 '{ ... }': bool + 99..103 'true': bool + 123..167 '{ ...o(); }': () + 133..134 's': &S + 137..151 'unsafe { f() }': &S + 137..151 'unsafe { f() }': &S + 146..147 'f': fn f() -> &S + 146..149 'f()': &S + 157..158 's': &S + 157..164 's.foo()': bool + "#]], + ); +} + +#[test] +fn method_with_allocator_box_self_type() { + check_types( + r#" +struct Slice<T> {} +struct Box<T, A> {} + +impl<T> Slice<T> { + pub fn into_vec<A>(self: Box<Self, A>) { } +} + +fn main() { + let foo: Slice<u32>; + foo.into_vec(); // we shouldn't crash on this at least +} //^^^^^^^^^^^^^^ {unknown} +"#, + ); +} + +#[test] +fn method_on_dyn_impl() { + check_types( + r#" +trait Foo {} + +impl Foo for u32 {} +impl dyn Foo + '_ { + pub fn dyn_foo(&self) -> u32 { + 0 + } +} + +fn main() { + let f = &42u32 as &dyn Foo; + f.dyn_foo(); + // ^^^^^^^^^^^ u32 +} +"#, + ); +} + +#[test] +fn autoderef_visibility_field() { + check( + r#" +//- minicore: deref +mod a { + pub struct Foo(pub char); + pub struct Bar(i32); + impl Bar { + pub fn new() -> Self { + Self(0) + } + } + impl core::ops::Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { + &Foo('z') + } + } +} +mod b { + fn foo() { + let x = super::a::Bar::new().0; + // ^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(Some(OverloadedDeref(Not))) + // ^^^^^^^^^^^^^^^^^^^^^^ type: char + } +} +"#, + ) +} + +#[test] +fn autoderef_visibility_method() { + cov_mark::check!(autoderef_candidate_not_visible); + check( + r#" +//- minicore: deref +mod a { + pub struct Foo(pub char); + impl Foo { + pub fn mango(&self) -> char { + self.0 + } + } + pub struct Bar(i32); + impl Bar { + pub fn new() -> Self { + Self(0) + } + fn mango(&self) -> i32 { + self.0 + } + } + impl core::ops::Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { + &Foo('z') + } + } +} +mod b { + fn foo() { + let x = super::a::Bar::new().mango(); + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: char + } +} +"#, + ) +} + +#[test] +fn trait_vs_private_inherent_const() { + cov_mark::check!(const_candidate_not_visible); + check( + r#" +mod a { + pub struct Foo; + impl Foo { + const VALUE: u32 = 2; + } + pub trait Trait { + const VALUE: usize; + } + impl Trait for Foo { + const VALUE: usize = 3; + } + + fn foo() { + let x = Foo::VALUE; + // ^^^^^^^^^^ type: u32 + } +} +use a::Trait; +fn foo() { + let x = a::Foo::VALUE; + // ^^^^^^^^^^^^^ type: usize +} +"#, + ) +} + +#[test] +fn trait_impl_in_unnamed_const() { + check_types( + r#" +struct S; + +trait Tr { + fn method(&self) -> u16; +} + +const _: () = { + impl Tr for S {} +}; + +fn f() { + S.method(); + //^^^^^^^^^^ u16 +} + "#, + ); +} + +#[test] +fn trait_impl_in_synstructure_const() { + check_types( + r#" +struct S; + +trait Tr { + fn method(&self) -> u16; +} + +const _DERIVE_Tr_: () = { + impl Tr for S {} +}; + +fn f() { + S.method(); + //^^^^^^^^^^ u16 +} + "#, + ); +} + +#[test] +fn inherent_impl_in_unnamed_const() { + check_types( + r#" +struct S; + +const _: () = { + impl S { + fn method(&self) -> u16 { 0 } + + pub(super) fn super_method(&self) -> u16 { 0 } + + pub(crate) fn crate_method(&self) -> u16 { 0 } + + pub fn pub_method(&self) -> u16 { 0 } + } +}; + +fn f() { + S.method(); + //^^^^^^^^^^ u16 + + S.super_method(); + //^^^^^^^^^^^^^^^^ u16 + + S.crate_method(); + //^^^^^^^^^^^^^^^^ u16 + + S.pub_method(); + //^^^^^^^^^^^^^^ u16 +} + "#, + ); +} + +#[test] +fn resolve_const_generic_array_methods() { + check_types( + r#" +#[lang = "array"] +impl<T, const N: usize> [T; N] { + pub fn map<F, U>(self, f: F) -> [U; N] + where + F: FnMut(T) -> U, + { loop {} } +} + +#[lang = "slice"] +impl<T> [T] { + pub fn map<F, U>(self, f: F) -> &[U] + where + F: FnMut(T) -> U, + { loop {} } +} + +fn f() { + let v = [1, 2].map::<_, usize>(|x| -> x * 2); + v; + //^ [usize; 2] +} + "#, + ); +} + +#[test] +fn resolve_const_generic_method() { + check_types( + r#" +struct Const<const N: usize>; + +#[lang = "array"] +impl<T, const N: usize> [T; N] { + pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X] + where + F: FnMut(T) -> U, + { loop {} } +} + +#[lang = "slice"] +impl<T> [T] { + pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U] + where + F: FnMut(T) -> U, + { loop {} } +} + +fn f<const C: usize, P>() { + let v = [1, 2].my_map::<_, (), 12>(|x| -> x * 2, Const::<12>); + v; + //^ [(); 12] + let v = [1, 2].my_map::<_, P, C>(|x| -> x * 2, Const::<C>); + v; + //^ [P; C] +} + "#, + ); +} + +#[test] +fn const_generic_type_alias() { + check_types( + r#" +struct Const<const N: usize>; +type U2 = Const<2>; +type U5 = Const<5>; + +impl U2 { + fn f(self) -> Const<12> { + loop {} + } +} + +impl U5 { + fn f(self) -> Const<15> { + loop {} + } +} + +fn f(x: U2) { + let y = x.f(); + //^ Const<12> +} + "#, + ); +} + +#[test] +fn skip_array_during_method_dispatch() { + check_types( + r#" +//- /main2018.rs crate:main2018 deps:core +use core::IntoIterator; + +fn f() { + let v = [4].into_iter(); + v; + //^ &i32 + + let a = [0, 1].into_iter(); + a; + //^ &i32 +} + +//- /main2021.rs crate:main2021 deps:core edition:2021 +use core::IntoIterator; + +fn f() { + let v = [4].into_iter(); + v; + //^ i32 + + let a = [0, 1].into_iter(); + a; + //^ &i32 +} + +//- /core.rs crate:core +#[rustc_skip_array_during_method_dispatch] +pub trait IntoIterator { + type Out; + fn into_iter(self) -> Self::Out; +} + +impl<T> IntoIterator for [T; 1] { + type Out = T; + fn into_iter(self) -> Self::Out { loop {} } +} +impl<'a, T> IntoIterator for &'a [T] { + type Out = &'a T; + fn into_iter(self) -> Self::Out { loop {} } +} + "#, + ); +} + +#[test] +fn sized_blanket_impl() { + check_infer( + r#" +//- minicore: sized +trait Foo { fn foo() -> u8; } +impl<T: Sized> Foo for T {} +fn f<S: Sized, T, U: ?Sized>() { + u32::foo; + S::foo; + T::foo; + U::foo; + <[u32]>::foo; +} +"#, + expect![[r#" + 89..160 '{ ...foo; }': () + 95..103 'u32::foo': fn foo<u32>() -> u8 + 109..115 'S::foo': fn foo<S>() -> u8 + 121..127 'T::foo': fn foo<T>() -> u8 + 133..139 'U::foo': {unknown} + 145..157 '<[u32]>::foo': {unknown} + "#]], + ); +} + +#[test] +fn local_impl() { + check_types( + r#" +fn main() { + struct SomeStruct(i32); + + impl SomeStruct { + fn is_even(&self) -> bool { + self.0 % 2 == 0 + } + } + + let o = SomeStruct(3); + let is_even = o.is_even(); + // ^^^^^^^ bool +} + "#, + ); +} + +#[test] +fn deref_fun_1() { + check_types( + r#" +//- minicore: deref + +struct A<T, U>(T, U); +struct B<T>(T); +struct C<T>(T); + +impl<T> core::ops::Deref for A<B<T>, u32> { + type Target = B<T>; + fn deref(&self) -> &B<T> { &self.0 } +} +impl core::ops::Deref for B<isize> { + type Target = C<isize>; + fn deref(&self) -> &C<isize> { loop {} } +} + +impl<T: Copy> C<T> { + fn thing(&self) -> T { self.0 } +} + +fn make<T>() -> T { loop {} } + +fn test() { + let a1 = A(make(), make()); + let _: usize = (*a1).0; + a1; + //^^ A<B<usize>, u32> + + let a2 = A(make(), make()); + a2.thing(); + //^^^^^^^^^^ isize + a2; + //^^ A<B<isize>, u32> +} +"#, + ); +} + +#[test] +fn deref_fun_2() { + check_types( + r#" +//- minicore: deref + +struct A<T, U>(T, U); +struct B<T>(T); +struct C<T>(T); + +impl<T> core::ops::Deref for A<B<T>, u32> { + type Target = B<T>; + fn deref(&self) -> &B<T> { &self.0 } +} +impl core::ops::Deref for B<isize> { + type Target = C<isize>; + fn deref(&self) -> &C<isize> { loop {} } +} + +impl<T> core::ops::Deref for A<C<T>, i32> { + type Target = C<T>; + fn deref(&self) -> &C<T> { &self.0 } +} + +impl<T: Copy> C<T> { + fn thing(&self) -> T { self.0 } +} + +fn make<T>() -> T { loop {} } + +fn test() { + let a1 = A(make(), 1u32); + a1.thing(); + a1; + //^^ A<B<isize>, u32> + + let a2 = A(make(), 1i32); + let _: &str = a2.thing(); + a2; + //^^ A<C<&str>, i32> +} +"#, + ); +} + +#[test] +fn receiver_adjustment_autoref() { + check( + r#" +struct Foo; +impl Foo { + fn foo(&self) {} +} +fn test() { + Foo.foo(); + //^^^ adjustments: Borrow(Ref(Not)) + (&Foo).foo(); + // ^^^^ adjustments: , +} +"#, + ); +} + +#[test] +fn receiver_adjustment_unsize_array() { + // FIXME not quite correct + check( + r#" +//- minicore: slice +fn test() { + let a = [1, 2, 3]; + a.len(); +} //^ adjustments: Pointer(Unsize), Borrow(Ref(Not)) +"#, + ); +} + +#[test] +fn bad_inferred_reference_1() { + check_no_mismatches( + r#" +//- minicore: sized +pub trait Into<T>: Sized { + fn into(self) -> T; +} +impl<T> Into<T> for T { + fn into(self) -> T { self } +} + +trait ExactSizeIterator { + fn len(&self) -> usize; +} + +pub struct Foo; +impl Foo { + fn len(&self) -> usize { 0 } +} + +pub fn test(generic_args: impl Into<Foo>) { + let generic_args = generic_args.into(); + generic_args.len(); + let _: Foo = generic_args; +} +"#, + ); +} + +#[test] +fn bad_inferred_reference_2() { + check_no_mismatches( + r#" +//- minicore: deref +trait ExactSizeIterator { + fn len(&self) -> usize; +} + +pub struct Foo; +impl Foo { + fn len(&self) -> usize { 0 } +} + +pub fn test() { + let generic_args; + generic_args.len(); + let _: Foo = generic_args; +} +"#, + ); +} + +#[test] +fn resolve_minicore_iterator() { + check_types( + r#" +//- minicore: iterators, sized +fn foo() { + let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); +} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Option<i32> +"#, + ); +} + +#[test] +fn primitive_assoc_fn_shadowed_by_use() { + check_types( + r#" +//- /lib.rs crate:lib deps:core +use core::u16; + +fn f() -> u16 { + let x = u16::from_le_bytes(); + x + //^ u16 +} + +//- /core.rs crate:core +pub mod u16 {} + +impl u16 { + pub fn from_le_bytes() -> Self { 0 } +} + "#, + ) +} |