From 6a77ec7bbe6ddbf663dce9529d11d1bb56c5489a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 16:35:29 +0200 Subject: Rename ra_hir_ty -> hir_ty --- crates/hir_ty/src/tests/method_resolution.rs | 1053 ++++++++++++++++++++++++++ 1 file changed, 1053 insertions(+) create mode 100644 crates/hir_ty/src/tests/method_resolution.rs (limited to 'crates/hir_ty/src/tests/method_resolution.rs') 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 000000000..fa68355aa --- /dev/null +++ b/crates/hir_ty/src/tests/method_resolution.rs @@ -0,0 +1,1053 @@ +use expect::expect; + +use super::{check_infer, check_types}; + +#[test] +fn infer_slice_method() { + check_infer( + r#" + #[lang = "slice"] + impl [T] { + fn foo(&self) -> T { + loop {} + } + } + + #[lang = "slice_alloc"] + impl [T] {} + + fn test(x: &[u8]) { + <[_]>::foo(x); + } + "#, + expect![[r#" + 44..48 'self': &[T] + 55..78 '{ ... }': T + 65..72 'loop {}': ! + 70..72 '{}': () + 130..131 'x': &[u8] + 140..162 '{ ...(x); }': () + 146..156 '<[_]>::foo': fn foo(&[u8]) -> u8 + 146..159 '<[_]>::foo(x)': u8 + 157..158 '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_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 { + val: T + } + + impl Gen { + pub fn make(val: T) -> Gen { + Gen { val } + } + } + + fn test() { + let a = Gen::make(0u32); + } + "#, + expect![[r#" + 63..66 'val': T + 81..108 '{ ... }': Gen + 91..102 'Gen { val }': Gen + 97..100 'val': T + 122..154 '{ ...32); }': () + 132..133 'a': Gen + 136..145 'Gen::make': fn make(u32) -> Gen + 136..151 'Gen::make(0u32)': Gen + 146..150 '0u32': u32 + "#]], + ); +} + +#[test] +fn infer_associated_method_generics_without_args() { + check_infer( + r#" + struct Gen { + val: T + } + + impl Gen { + pub fn make() -> Gen { + loop { } + } + } + + fn test() { + let a = Gen::::make(); + } + "#, + expect![[r#" + 75..99 '{ ... }': Gen + 85..93 'loop { }': ! + 90..93 '{ }': () + 113..148 '{ ...e(); }': () + 123..124 'a': Gen + 127..143 'Gen::<...::make': fn make() -> Gen + 127..145 'Gen::<...make()': Gen + "#]], + ); +} + +#[test] +fn infer_associated_method_generics_2_type_params_without_args() { + check_infer( + r#" + struct Gen { + val: T, + val2: U, + } + + impl Gen { + pub fn make() -> Gen { + loop { } + } + } + + fn test() { + let a = Gen::::make(); + } + "#, + expect![[r#" + 101..125 '{ ... }': Gen + 111..119 'loop { }': ! + 116..119 '{ }': () + 139..179 '{ ...e(); }': () + 149..150 'a': Gen + 153..174 'Gen::<...::make': fn make() -> Gen + 153..176 'Gen::<...make()': Gen + "#]], + ); +} + +#[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 +mod foo { + struct S; + impl S { + fn thing() -> i128 {} + } +} +"#, + ); +} + +#[test] +fn infer_trait_method_simple() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_infer( + 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 + } + "#, + expect![[r#" + 30..34 'self': &Self + 109..113 'self': &Self + 169..227 '{ ...i128 }': () + 175..177 'S1': S1 + 175..186 'S1.method()': u32 + 202..204 'S2': S2 + 202..213 'S2.method()': i128 + "#]], + ); +} + +#[test] +fn infer_trait_method_scoped() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_infer( + 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 + } + } + "#, + expect![[r#" + 62..66 'self': &Self + 168..172 'self': &Self + 299..336 '{ ... }': () + 309..310 'S': S + 309..319 'S.method()': u32 + 415..453 '{ ... }': () + 425..426 'S': S + 425..435 'S.method()': i128 + "#]], + ); +} + +#[test] +fn infer_trait_method_generic_1() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_infer( + r#" + trait Trait { + fn method(&self) -> T; + } + struct S; + impl Trait for S {} + fn test() { + S.method(); + } + "#, + expect![[r#" + 32..36 'self': &Self + 91..110 '{ ...d(); }': () + 97..98 'S': S + 97..107 'S.method()': u32 + "#]], + ); +} + +#[test] +fn infer_trait_method_generic_more_params() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_infer( + r#" + trait Trait { + fn method1(&self) -> (T1, T2, T3); + fn method2(&self) -> (T3, T2, T1); + } + struct S1; + impl Trait for S1 {} + struct S2; + impl Trait for S2 {} + fn test() { + S1.method1(); // u8, u16, u32 + S1.method2(); // u32, u16, u8 + S2.method1(); // i8, i16, {unknown} + S2.method2(); // {unknown}, i16, i8 + } + "#, + expect![[r#" + 42..46 'self': &Self + 81..85 'self': &Self + 209..360 '{ ..., i8 }': () + 215..217 'S1': S1 + 215..227 'S1.method1()': (u8, u16, u32) + 249..251 'S1': S1 + 249..261 'S1.method2()': (u32, u16, u8) + 283..285 'S2': S2 + 283..295 'S2.method1()': (i8, i16, {unknown}) + 323..325 'S2': S2 + 323..335 'S2.method2()': ({unknown}, i16, i8) + "#]], + ); +} + +#[test] +fn infer_trait_method_generic_2() { + // the trait implementation is intentionally incomplete -- it shouldn't matter + check_infer( + r#" + trait Trait { + fn method(&self) -> T; + } + struct S(T); + impl Trait for S {} + fn test() { + S(1u32).method(); + } + "#, + expect![[r#" + 32..36 'self': &Self + 101..126 '{ ...d(); }': () + 107..108 'S': S(u32) -> S + 107..114 'S(1u32)': S + 107..123 'S(1u32...thod()': u32 + 109..113 '1u32': 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 = ::default(); + } + "#, + expect![[r#" + 86..192 '{ ...t(); }': () + 96..98 's1': S + 104..120 'Defaul...efault': fn default() -> S + 104..122 'Defaul...ault()': S + 132..134 's2': S + 137..147 'S::default': fn default() -> S + 137..149 'S::default()': S + 159..161 's3': S + 164..187 '() -> S + 164..189 ' { + fn make() -> T; + } + struct S; + impl Trait for S {} + struct G; + impl Trait for G {} + fn test() { + let a = S::make(); + let b = G::::make(); + let c: f64 = G::make(); + } + "#, + expect![[r#" + 126..210 '{ ...e(); }': () + 136..137 'a': u32 + 140..147 'S::make': fn make() -> u32 + 140..149 'S::make()': u32 + 159..160 'b': u64 + 163..177 'G::::make': fn make, u64>() -> u64 + 163..179 'G::, f64>() -> f64 + 198..207 'G::make()': f64 + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_2() { + check_infer( + r#" + trait Trait { + fn make() -> (T, U); + } + struct S; + impl Trait for S {} + struct G; + impl Trait for G {} + fn test() { + let a = S::make::(); + let b: (_, i64) = S::make(); + let c = G::::make::(); + let d: (u32, _) = G::make::(); + let e: (u32, i64) = G::make(); + } + "#, + expect![[r#" + 134..312 '{ ...e(); }': () + 144..145 'a': (u32, i64) + 148..162 'S::make::': fn make() -> (u32, i64) + 148..164 'S::mak...i64>()': (u32, i64) + 174..175 'b': (u32, i64) + 188..195 'S::make': fn make() -> (u32, i64) + 188..197 'S::make()': (u32, i64) + 207..208 'c': (u32, i64) + 211..232 'G::': fn make, u32, i64>() -> (u32, i64) + 211..234 'G::()': (u32, i64) + 244..245 'd': (u32, i64) + 258..272 'G::make::': fn make, u32, i64>() -> (u32, i64) + 258..274 'G::mak...i64>()': (u32, i64) + 284..285 'e': (u32, i64) + 300..307 'G::make': fn make, u32, i64>() -> (u32, i64) + 300..309 'G::make()': (u32, i64) + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_3() { + check_infer( + r#" + trait Trait { + fn make() -> (Self, T); + } + struct S; + impl Trait for S {} + fn test() { + let a = S::make(); + } + "#, + expect![[r#" + 100..126 '{ ...e(); }': () + 110..111 'a': (S, i64) + 114..121 'S::make': fn make, i64>() -> (S, i64) + 114..123 'S::make()': (S, i64) + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_4() { + check_infer( + r#" + trait Trait { + fn make() -> (Self, T); + } + struct S; + impl Trait for S {} + impl Trait for S {} + fn test() { + let a: (S, _) = S::make(); + let b: (_, i32) = S::make(); + } + "#, + expect![[r#" + 130..202 '{ ...e(); }': () + 140..141 'a': (S, i64) + 157..164 'S::make': fn make, i64>() -> (S, i64) + 157..166 'S::make()': (S, i64) + 176..177 'b': (S, i32) + 190..197 'S::make': fn make, i32>() -> (S, i32) + 190..199 'S::make()': (S, i32) + "#]], + ); +} + +#[test] +fn infer_trait_assoc_method_generics_5() { + check_infer( + r#" + trait Trait { + fn make() -> (Self, T, U); + } + struct S; + impl Trait for S {} + fn test() { + let a = >::make::(); + let b: (S, _, _) = Trait::::make::(); + } + "#, + expect![[r#" + 106..210 '{ ...>(); }': () + 116..117 'a': (S, i64, u8) + 120..149 '': fn make, i64, u8>() -> (S, i64, u8) + 120..151 '()': (S, i64, u8) + 161..162 'b': (S, i64, u8) + 181..205 'Trait:...::': fn make, i64, u8>() -> (S, i64, u8) + 181..207 'Trait:...()': (S, i64, u8) + "#]], + ); +} + +#[test] +fn infer_call_trait_method_on_generic_param_1() { + check_infer( + r#" + trait Trait { + fn method(&self) -> u32; + } + fn test(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 { + fn method(&self) -> T; + } + fn test>(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 { + fn into(self) -> T; + } + struct S; + impl Into for S {} + impl Into for S {} + fn test() { + let x: u32 = S.into(); + let y: u64 = S.into(); + let z = Into::::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 + 178..198 'Into::...nto(S)': u64 + 196..197 'S': S + "#]], + ); +} + +#[test] +fn method_resolution_unify_impl_self_type() { + check_types( + r#" +struct S; +impl S { fn foo(&self) -> u8 {} } +impl S { fn foo(&self) -> i8 {} } +fn test() { (S::.foo(), S::.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#" +#[lang = "slice"] +impl [T] { + fn len(&self) -> usize { loop {} } +} +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:other_crate +struct S; +impl Clone for S {} + +fn test() { + S.clone(); + //^ S +} + +//- /lib.rs crate:other_crate +#[prelude_import] use foo::*; + +mod foo { + 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 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 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 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 Trait for T where T: Clone {} +fn test() { S.foo(); } + //^ u128 +"#, + ); +} + +#[test] +fn method_resolution_where_clause_2() { + check_types( + r#" +trait Into { fn into(self) -> T; } +trait From { fn from(other: T) -> Self; } +struct S1; +struct S2; +impl From for S1 {} +impl Into for T where U: From {} +fn test() { S2.into(); } + //^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_where_clause_inline() { + check_types( + r#" +trait Into { fn into(self) -> T; } +trait From { fn from(other: T) -> Self; } +struct S1; +struct S2; +impl From for S1 {} +impl> Into for T {} +fn test() { S2.into(); } + //^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_overloaded_method() { + test_utils::mark::check!(impl_self_type_match_without_receiver); + check_types( + r#" +struct Wrapper(T); +struct Foo(T); +struct Bar(T); + +impl Wrapper> { + pub fn new(foo_: T) -> Self { + Wrapper(Foo(foo_)) + } +} + +impl Wrapper> { + pub fn new(bar_: T) -> Self { + Wrapper(Bar(bar_)) + } +} + +fn main() { + let a = Wrapper::>::new(1.0); + let b = Wrapper::>::new(1.0); + (a, b); + //^ (Wrapper>, Wrapper>) +} +"#, + ); +} + +#[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 method_resolution_non_parameter_type() { + check_types( + r#" +mod a { + pub trait Foo { + fn foo(&self); + } +} + +struct Wrapper(T); +fn foo(t: Wrapper) +where + Wrapper: a::Foo, +{ + t.foo(); +} //^ {unknown} +"#, + ); +} + +#[test] +fn method_resolution_3373() { + check_types( + r#" +struct A(T); + +impl A { + fn from(v: i32) -> A { A(v) } +} + +fn main() { + A::from(3); +} //^ A +"#, + ); +} + +#[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 {} +impl SendX for X1 where A: SendX, B: SendX {} + +struct S {} + +trait FnX {} + +impl Trait for S 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 + "#]], + ); +} -- cgit v1.2.3