use insta::assert_snapshot; use ra_db::fixture::WithFixture; use test_utils::covers; use super::{infer, infer_with_mismatches, type_at, type_at_pos}; use crate::test_db::TestDB; #[test] fn infer_await() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std struct IntFuture; impl Future for IntFuture { type Output = u64; } fn test() { let r = IntFuture; let v = r.await; v<|>; } //- /std.rs crate:std #[prelude_import] use future::*; mod future { #[lang = "future_trait"] trait Future { type Output; } } "#, ); assert_eq!("u64", type_at_pos(&db, pos)); } #[test] fn infer_async() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std async fn foo() -> u64 { 128 } fn test() { let r = foo(); let v = r.await; v<|>; } //- /std.rs crate:std #[prelude_import] use future::*; mod future { #[lang = "future_trait"] trait Future { type Output; } } "#, ); assert_eq!("u64", type_at_pos(&db, pos)); } #[test] fn infer_desugar_async() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std async fn foo() -> u64 { 128 } fn test() { let r = foo(); r<|>; } //- /std.rs crate:std #[prelude_import] use future::*; mod future { trait Future { type Output; } } "#, ); assert_eq!("impl Future", type_at_pos(&db, pos)); } #[test] fn infer_try() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std fn test() { let r: Result = Result::Ok(1); let v = r?; v<|>; } //- /std.rs crate:std #[prelude_import] use ops::*; mod ops { trait Try { type Ok; type Error; } } #[prelude_import] use result::*; mod result { enum Result { Ok(O), Err(E) } impl crate::ops::Try for Result { type Ok = O; type Error = E; } } "#, ); assert_eq!("i32", type_at_pos(&db, pos)); } #[test] fn infer_for_loop() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std use std::collections::Vec; fn test() { let v = Vec::new(); v.push("foo"); for x in v { x<|>; } } //- /std.rs crate:std #[prelude_import] use iter::*; mod iter { trait IntoIterator { type Item; } } mod collections { struct Vec {} impl Vec { fn new() -> Self { Vec {} } fn push(&mut self, t: T) { } } impl crate::iter::IntoIterator for Vec { type Item=T; } } "#, ); assert_eq!("&str", type_at_pos(&db, pos)); } #[test] fn infer_ops_neg() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std struct Bar; struct Foo; impl std::ops::Neg for Bar { type Output = Foo; } fn test() { let a = Bar; let b = -a; b<|>; } //- /std.rs crate:std #[prelude_import] use ops::*; mod ops { #[lang = "neg"] pub trait Neg { type Output; } } "#, ); assert_eq!("Foo", type_at_pos(&db, pos)); } #[test] fn infer_ops_not() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std struct Bar; struct Foo; impl std::ops::Not for Bar { type Output = Foo; } fn test() { let a = Bar; let b = !a; b<|>; } //- /std.rs crate:std #[prelude_import] use ops::*; mod ops { #[lang = "not"] pub trait Not { type Output; } } "#, ); assert_eq!("Foo", type_at_pos(&db, pos)); } #[test] fn infer_from_bound_1() { assert_snapshot!( infer(r#" trait Trait {} struct S(T); impl Trait for S {} fn foo>(t: T) {} fn test() { let s = S(unknown); foo(s); } "#), @r###" [86; 87) 't': T [92; 94) '{}': () [105; 144) '{ ...(s); }': () [115; 116) 's': S [119; 120) 'S': S(T) -> S [119; 129) 'S(unknown)': S [121; 128) 'unknown': u32 [135; 138) 'foo': fn foo>(T) -> () [135; 141) 'foo(s)': () [139; 140) 's': S "### ); } #[test] fn infer_from_bound_2() { assert_snapshot!( infer(r#" trait Trait {} struct S(T); impl Trait for S {} fn foo>(t: T) -> U {} fn test() { let s = S(unknown); let x: u32 = foo(s); } "#), @r###" [87; 88) 't': T [98; 100) '{}': () [111; 163) '{ ...(s); }': () [121; 122) 's': S [125; 126) 'S': S(T) -> S [125; 135) 'S(unknown)': S [127; 134) 'unknown': u32 [145; 146) 'x': u32 [154; 157) 'foo': fn foo>(T) -> U [154; 160) 'foo(s)': u32 [158; 159) 's': S "### ); } #[test] fn infer_project_associated_type() { // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 assert_snapshot!( infer(r#" trait Iterable { type Item; } struct S; impl Iterable for S { type Item = u32; } fn test() { let x: ::Item = 1; let y: ::Item = no_matter; let z: T::Item = no_matter; let a: ::Item = no_matter; } "#), @r###" [108; 261) '{ ...ter; }': () [118; 119) 'x': u32 [145; 146) '1': u32 [156; 157) 'y': {unknown} [183; 192) 'no_matter': {unknown} [202; 203) 'z': {unknown} [215; 224) 'no_matter': {unknown} [234; 235) 'a': {unknown} [249; 258) 'no_matter': {unknown} "### ); } #[test] fn infer_return_associated_type() { assert_snapshot!( infer(r#" trait Iterable { type Item; } struct S; impl Iterable for S { type Item = u32; } fn foo1(t: T) -> T::Item {} fn foo2(t: T) -> ::Item {} fn foo3(t: T) -> ::Item {} fn test() { let x = foo1(S); let y = foo2(S); let z = foo3(S); } "#), @r###" [106; 107) 't': T [123; 125) '{}': () [147; 148) 't': T [178; 180) '{}': () [202; 203) 't': T [221; 223) '{}': () [234; 300) '{ ...(S); }': () [244; 245) 'x': u32 [248; 252) 'foo1': fn foo1(T) -> ::Item [248; 255) 'foo1(S)': u32 [253; 254) 'S': S [265; 266) 'y': u32 [269; 273) 'foo2': fn foo2(T) -> ::Item [269; 276) 'foo2(S)': u32 [274; 275) 'S': S [286; 287) 'z': u32 [290; 294) 'foo3': fn foo3(T) -> ::Item [290; 297) 'foo3(S)': u32 [295; 296) 'S': S "### ); } #[test] fn infer_associated_type_bound() { assert_snapshot!( infer(r#" trait Iterable { type Item; } fn test>() { let y: T::Item = unknown; } "#), @r###" [67; 100) '{ ...own; }': () [77; 78) 'y': {unknown} [90; 97) 'unknown': {unknown} "### ); } #[test] fn infer_const_body() { assert_snapshot!( infer(r#" const A: u32 = 1 + 1; static B: u64 = { let x = 1; x }; "#), @r###" [16; 17) '1': u32 [16; 21) '1 + 1': u32 [20; 21) '1': u32 [39; 55) '{ let ...1; x }': u64 [45; 46) 'x': u64 [49; 50) '1': u64 [52; 53) 'x': u64 "### ); } #[test] fn tuple_struct_fields() { assert_snapshot!( infer(r#" struct S(i32, u64); fn test() -> u64 { let a = S(4, 6); let b = a.0; a.1 } "#), @r###" [38; 87) '{ ... a.1 }': u64 [48; 49) 'a': S [52; 53) 'S': S(i32, u64) -> S [52; 59) 'S(4, 6)': S [54; 55) '4': i32 [57; 58) '6': u64 [69; 70) 'b': i32 [73; 74) 'a': S [73; 76) 'a.0': i32 [82; 83) 'a': S [82; 85) 'a.1': u64 "### ); } #[test] fn tuple_struct_with_fn() { assert_snapshot!( infer(r#" struct S(fn(u32) -> u64); fn test() -> u64 { let a = S(|i| 2*i); let b = a.0(4); a.0(2) } "#), @r###" [44; 102) '{ ...0(2) }': u64 [54; 55) 'a': S [58; 59) 'S': S(fn(u32) -> u64) -> S [58; 68) 'S(|i| 2*i)': S [60; 67) '|i| 2*i': |u32| -> u64 [61; 62) 'i': u32 [64; 65) '2': u32 [64; 67) '2*i': u32 [66; 67) 'i': u32 [78; 79) 'b': u64 [82; 83) 'a': S [82; 85) 'a.0': fn(u32) -> u64 [82; 88) 'a.0(4)': u64 [86; 87) '4': u32 [94; 95) 'a': S [94; 97) 'a.0': fn(u32) -> u64 [94; 100) 'a.0(2)': u64 [98; 99) '2': u32 "### ); } #[test] fn indexing_arrays() { assert_snapshot!( infer("fn main() { &mut [9][2]; }"), @r###" [10; 26) '{ &mut...[2]; }': () [12; 23) '&mut [9][2]': &mut {unknown} [17; 20) '[9]': [i32;_] [17; 23) '[9][2]': {unknown} [18; 19) '9': i32 [21; 22) '2': i32 "### ) } #[test] fn infer_ops_index() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std struct Bar; struct Foo; impl std::ops::Index for Bar { type Output = Foo; } fn test() { let a = Bar; let b = a[1]; b<|>; } //- /std.rs crate:std #[prelude_import] use ops::*; mod ops { #[lang = "index"] pub trait Index { type Output; } } "#, ); assert_eq!("Foo", type_at_pos(&db, pos)); } #[test] fn deref_trait() { let t = type_at( r#" //- /main.rs #[lang = "deref"] trait Deref { type Target; fn deref(&self) -> &Self::Target; } struct Arc; impl Deref for Arc { type Target = T; } struct S; impl S { fn foo(&self) -> u128 {} } fn test(s: Arc) { (*s, s.foo())<|>; } "#, ); assert_eq!(t, "(S, u128)"); } #[test] fn deref_trait_with_inference_var() { let t = type_at( r#" //- /main.rs #[lang = "deref"] trait Deref { type Target; fn deref(&self) -> &Self::Target; } struct Arc; fn new_arc() -> Arc {} impl Deref for Arc { type Target = T; } struct S; fn foo(a: Arc) {} fn test() { let a = new_arc(); let b = (*a)<|>; foo(a); } "#, ); assert_eq!(t, "S"); } #[test] fn deref_trait_infinite_recursion() { let t = type_at( r#" //- /main.rs #[lang = "deref"] trait Deref { type Target; fn deref(&self) -> &Self::Target; } struct S; impl Deref for S { type Target = S; } fn test(s: S) { s.foo()<|>; } "#, ); assert_eq!(t, "{unknown}"); } #[test] fn deref_trait_with_question_mark_size() { let t = type_at( r#" //- /main.rs #[lang = "deref"] trait Deref { type Target; fn deref(&self) -> &Self::Target; } struct Arc; impl Deref for Arc { type Target = T; } struct S; impl S { fn foo(&self) -> u128 {} } fn test(s: Arc) { (*s, s.foo())<|>; } "#, ); assert_eq!(t, "(S, u128)"); } #[test] fn obligation_from_function_clause() { let t = type_at( r#" //- /main.rs struct S; trait Trait {} impl Trait for S {} fn foo, U>(t: T) -> U {} fn test(s: S) { foo(s)<|>; } "#, ); assert_eq!(t, "u32"); } #[test] fn obligation_from_method_clause() { let t = type_at( r#" //- /main.rs struct S; trait Trait {} impl Trait for S {} struct O; impl O { fn foo, U>(&self, t: T) -> U {} } fn test() { O.foo(S)<|>; } "#, ); assert_eq!(t, "isize"); } #[test] fn obligation_from_self_method_clause() { let t = type_at( r#" //- /main.rs struct S; trait Trait {} impl Trait for S {} impl S { fn foo(&self) -> U where Self: Trait {} } fn test() { S.foo()<|>; } "#, ); assert_eq!(t, "i64"); } #[test] fn obligation_from_impl_clause() { let t = type_at( r#" //- /main.rs struct S; trait Trait {} impl Trait<&str> for S {} struct O; impl> O { fn foo(&self) -> U {} } fn test(o: O) { o.foo()<|>; } "#, ); assert_eq!(t, "&str"); } #[test] fn generic_param_env_1() { let t = type_at( r#" //- /main.rs trait Clone {} trait Trait { fn foo(self) -> u128; } struct S; impl Clone for S {} impl Trait for T where T: Clone {} fn test(t: T) { t.foo()<|>; } "#, ); assert_eq!(t, "u128"); } #[test] fn generic_param_env_1_not_met() { let t = type_at( r#" //- /main.rs trait Clone {} trait Trait { fn foo(self) -> u128; } struct S; impl Clone for S {} impl Trait for T where T: Clone {} fn test(t: T) { t.foo()<|>; } "#, ); assert_eq!(t, "{unknown}"); } #[test] fn generic_param_env_2() { let t = type_at( r#" //- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S {} fn test(t: T) { t.foo()<|>; } "#, ); assert_eq!(t, "u128"); } #[test] fn generic_param_env_2_not_met() { let t = type_at( r#" //- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S {} fn test(t: T) { t.foo()<|>; } "#, ); assert_eq!(t, "{unknown}"); } #[test] fn generic_param_env_deref() { let t = type_at( r#" //- /main.rs #[lang = "deref"] trait Deref { type Target; } trait Trait {} impl Deref for T where T: Trait { type Target = i128; } fn test(t: T) { (*t)<|>; } "#, ); assert_eq!(t, "i128"); } #[test] fn associated_type_placeholder() { let t = type_at( r#" //- /main.rs pub trait ApplyL { type Out; } pub struct RefMutL; impl ApplyL for RefMutL { type Out = ::Out; } fn test() { let y: as ApplyL>::Out = no_matter; y<|>; } "#, ); // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. // FIXME: fix type parameter names going missing when going through Chalk assert_eq!(t, "ApplyL::Out<[missing name]>"); } #[test] fn associated_type_placeholder_2() { let t = type_at( r#" //- /main.rs pub trait ApplyL { type Out; } fn foo(t: T) -> ::Out; fn test(t: T) { let y = foo(t); y<|>; } "#, ); // FIXME here Chalk doesn't normalize the type to a placeholder. I think we // need to add a rule like Normalize(::Out -> ApplyL::Out) // to the trait env ourselves here; probably Chalk can't do this by itself. // assert_eq!(t, "ApplyL::Out<[missing name]>"); assert_eq!(t, "{unknown}"); } #[test] fn impl_trait() { assert_snapshot!( infer(r#" trait Trait { fn foo(&self) -> T; fn foo2(&self) -> i64; } fn bar() -> impl Trait {} fn test(x: impl Trait, y: &impl Trait) { x; y; let z = bar(); x.foo(); y.foo(); z.foo(); x.foo2(); y.foo2(); z.foo2(); } "#), @r###" [30; 34) 'self': &Self [55; 59) 'self': &Self [99; 101) '{}': () [111; 112) 'x': impl Trait [131; 132) 'y': &impl Trait [152; 269) '{ ...2(); }': () [158; 159) 'x': impl Trait [165; 166) 'y': &impl Trait [176; 177) 'z': impl Trait [180; 183) 'bar': fn bar() -> impl Trait [180; 185) 'bar()': impl Trait [191; 192) 'x': impl Trait [191; 198) 'x.foo()': u64 [204; 205) 'y': &impl Trait [204; 211) 'y.foo()': u64 [217; 218) 'z': impl Trait [217; 224) 'z.foo()': u64 [230; 231) 'x': impl Trait [230; 238) 'x.foo2()': i64 [244; 245) 'y': &impl Trait [244; 252) 'y.foo2()': i64 [258; 259) 'z': impl Trait [258; 266) 'z.foo2()': i64 "### ); } #[test] fn dyn_trait() { assert_snapshot!( infer(r#" trait Trait { fn foo(&self) -> T; fn foo2(&self) -> i64; } fn bar() -> dyn Trait {} fn test(x: dyn Trait, y: &dyn Trait) { x; y; let z = bar(); x.foo(); y.foo(); z.foo(); x.foo2(); y.foo2(); z.foo2(); } "#), @r###" [30; 34) 'self': &Self [55; 59) 'self': &Self [98; 100) '{}': () [110; 111) 'x': dyn Trait [129; 130) 'y': &dyn Trait [149; 266) '{ ...2(); }': () [155; 156) 'x': dyn Trait [162; 163) 'y': &dyn Trait [173; 174) 'z': dyn Trait [177; 180) 'bar': fn bar() -> dyn Trait [177; 182) 'bar()': dyn Trait [188; 189) 'x': dyn Trait [188; 195) 'x.foo()': u64 [201; 202) 'y': &dyn Trait [201; 208) 'y.foo()': u64 [214; 215) 'z': dyn Trait [214; 221) 'z.foo()': u64 [227; 228) 'x': dyn Trait [227; 235) 'x.foo2()': i64 [241; 242) 'y': &dyn Trait [241; 249) 'y.foo2()': i64 [255; 256) 'z': dyn Trait [255; 263) 'z.foo2()': i64 "### ); } #[test] fn dyn_trait_bare() { assert_snapshot!( infer(r#" trait Trait { fn foo(&self) -> u64; } fn bar() -> Trait {} fn test(x: Trait, y: &Trait) -> u64 { x; y; let z = bar(); x.foo(); y.foo(); z.foo(); } "#), @r###" [27; 31) 'self': &Self [61; 63) '{}': () [73; 74) 'x': dyn Trait [83; 84) 'y': &dyn Trait [101; 176) '{ ...o(); }': () [107; 108) 'x': dyn Trait [114; 115) 'y': &dyn Trait [125; 126) 'z': dyn Trait [129; 132) 'bar': fn bar() -> dyn Trait [129; 134) 'bar()': dyn Trait [140; 141) 'x': dyn Trait [140; 147) 'x.foo()': u64 [153; 154) 'y': &dyn Trait [153; 160) 'y.foo()': u64 [166; 167) 'z': dyn Trait [166; 173) 'z.foo()': u64 "### ); } #[test] fn weird_bounds() { assert_snapshot!( infer(r#" trait Trait {} fn test() { let a: impl Trait + 'lifetime = foo; let b: impl 'lifetime = foo; let b: impl (Trait) = foo; let b: impl ('lifetime) = foo; let d: impl ?Sized = foo; let e: impl Trait + ?Sized = foo; } "#), @r###" [26; 237) '{ ...foo; }': () [36; 37) 'a': impl Trait + {error} [64; 67) 'foo': impl Trait + {error} [77; 78) 'b': impl {error} [97; 100) 'foo': impl {error} [110; 111) 'b': impl Trait [128; 131) 'foo': impl Trait [141; 142) 'b': impl {error} [163; 166) 'foo': impl {error} [176; 177) 'd': impl {error} [193; 196) 'foo': impl {error} [206; 207) 'e': impl Trait + {error} [231; 234) 'foo': impl Trait + {error} "### ); } #[test] fn error_bound_chalk() { let t = type_at( r#" //- /main.rs trait Trait { fn foo(&self) -> u32 {} } fn test(x: (impl Trait + UnknownTrait)) { x.foo()<|>; } "#, ); assert_eq!(t, "u32"); } #[test] fn assoc_type_bindings() { assert_snapshot!( infer(r#" trait Trait { type Type; } fn get(t: T) -> ::Type {} fn get2>(t: T) -> U {} fn set>(t: T) -> T {t} struct S; impl Trait for S { type Type = T; } fn test>(x: T, y: impl Trait) { get(x); get2(x); get(y); get2(y); get(set(S)); get2(set(S)); get2(S::); } "#), @r###" [50; 51) 't': T [78; 80) '{}': () [112; 113) 't': T [123; 125) '{}': () [155; 156) 't': T [166; 169) '{t}': T [167; 168) 't': T [257; 258) 'x': T [263; 264) 'y': impl Trait [290; 398) '{ ...r>); }': () [296; 299) 'get': fn get(T) -> ::Type [296; 302) 'get(x)': {unknown} [300; 301) 'x': T [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U [308; 315) 'get2(x)': {unknown} [313; 314) 'x': T [321; 324) 'get': fn get>(T) -> ::Type [321; 327) 'get(y)': {unknown} [325; 326) 'y': impl Trait [333; 337) 'get2': fn get2<{unknown}, impl Trait>(T) -> U [333; 340) 'get2(y)': {unknown} [338; 339) 'y': impl Trait [346; 349) 'get': fn get>(T) -> ::Type [346; 357) 'get(set(S))': u64 [350; 353) 'set': fn set>(T) -> T [350; 356) 'set(S)': S [354; 355) 'S': S [363; 367) 'get2': fn get2>(T) -> U [363; 375) 'get2(set(S))': u64 [368; 371) 'set': fn set>(T) -> T [368; 374) 'set(S)': S [372; 373) 'S': S [381; 385) 'get2': fn get2>(T) -> U [381; 395) 'get2(S::)': str [386; 394) 'S::': S "### ); } #[test] fn impl_trait_assoc_binding_projection_bug() { let (db, pos) = TestDB::with_position( r#" //- /main.rs crate:main deps:std pub trait Language { type Kind; } pub enum RustLanguage {} impl Language for RustLanguage { type Kind = SyntaxKind; } struct SyntaxNode {} fn foo() -> impl Iterator> {} trait Clone { fn clone(&self) -> Self; } fn api_walkthrough() { for node in foo() { node.clone()<|>; } } //- /std.rs crate:std #[prelude_import] use iter::*; mod iter { trait IntoIterator { type Item; } trait Iterator { type Item; } impl IntoIterator for T { type Item = ::Item; } } "#, ); assert_eq!("{unknown}", type_at_pos(&db, pos)); } #[test] fn projection_eq_within_chalk() { // std::env::set_var("CHALK_DEBUG", "1"); assert_snapshot!( infer(r#" trait Trait1 { type Type; } trait Trait2 { fn foo(self) -> T; } impl Trait2 for U where U: Trait1 {} fn test>(x: T) { x.foo(); } "#), @r###" [62; 66) 'self': Self [164; 165) 'x': T [170; 186) '{ ...o(); }': () [176; 177) 'x': T [176; 183) 'x.foo()': {unknown} "### ); } #[test] fn where_clause_trait_in_scope_for_method_resolution() { let t = type_at( r#" //- /main.rs mod foo { trait Trait { fn foo(&self) -> u32 {} } } fn test(x: T) { x.foo()<|>; } "#, ); assert_eq!(t, "u32"); } #[test] fn super_trait_method_resolution() { assert_snapshot!( infer(r#" mod foo { trait SuperTrait { fn foo(&self) -> u32 {} } } trait Trait1: foo::SuperTrait {} trait Trait2 where Self: foo::SuperTrait {} fn test(x: T, y: U) { x.foo(); y.foo(); } "#), @r###" [50; 54) 'self': &Self [63; 65) '{}': () [182; 183) 'x': T [188; 189) 'y': U [194; 223) '{ ...o(); }': () [200; 201) 'x': T [200; 207) 'x.foo()': u32 [213; 214) 'y': U [213; 220) 'y.foo()': u32 "### ); } #[test] fn super_trait_cycle() { // This just needs to not crash assert_snapshot!( infer(r#" trait A: B {} trait B: A {} fn test(x: T) { x.foo(); } "#), @r###" [44; 45) 'x': T [50; 66) '{ ...o(); }': () [56; 57) 'x': T [56; 63) 'x.foo()': {unknown} "### ); } #[test] fn super_trait_assoc_type_bounds() { assert_snapshot!( infer(r#" trait SuperTrait { type Type; } trait Trait where Self: SuperTrait {} fn get2>(t: T) -> U {} fn set>(t: T) -> T {t} struct S; impl SuperTrait for S { type Type = T; } impl Trait for S {} fn test() { get2(set(S)); } "#), @r###" [103; 104) 't': T [114; 116) '{}': () [146; 147) 't': T [157; 160) '{t}': T [158; 159) 't': T [259; 280) '{ ...S)); }': () [265; 269) 'get2': fn get2>(T) -> U [265; 277) 'get2(set(S))': u64 [270; 273) 'set': fn set>(T) -> T [270; 276) 'set(S)': S [274; 275) 'S': S "### ); } #[test] fn fn_trait() { assert_snapshot!( infer(r#" trait FnOnce { type Output; fn call_once(self, args: Args) -> >::Output; } fn test u128>(f: F) { f.call_once((1, 2)); } "#), @r###" [57; 61) 'self': Self [63; 67) 'args': Args [150; 151) 'f': F [156; 184) '{ ...2)); }': () [162; 163) 'f': F [162; 181) 'f.call...1, 2))': {unknown} [174; 180) '(1, 2)': (u32, u64) [175; 176) '1': u32 [178; 179) '2': u64 "### ); } #[test] fn closure_1() { assert_snapshot!( infer(r#" #[lang = "fn_once"] trait FnOnce { type Output; } enum Option { Some(T), None } impl Option { fn map U>(self, f: F) -> Option {} } fn test() { let x = Option::Some(1u32); x.map(|v| v + 1); x.map(|_v| 1u64); let y: Option = x.map(|_v| 1); } "#), @r###" [148; 152) 'self': Option [154; 155) 'f': F [173; 175) '{}': () [189; 308) '{ ... 1); }': () [199; 200) 'x': Option [203; 215) 'Option::Some': Some(T) -> Option [203; 221) 'Option...(1u32)': Option [216; 220) '1u32': u32 [227; 228) 'x': Option [227; 243) 'x.map(...v + 1)': Option [233; 242) '|v| v + 1': |u32| -> u32 [234; 235) 'v': u32 [237; 238) 'v': u32 [237; 242) 'v + 1': u32 [241; 242) '1': u32 [249; 250) 'x': Option [249; 265) 'x.map(... 1u64)': Option [255; 264) '|_v| 1u64': |u32| -> u64 [256; 258) '_v': u32 [260; 264) '1u64': u64 [275; 276) 'y': Option [292; 293) 'x': Option [292; 305) 'x.map(|_v| 1)': Option [298; 304) '|_v| 1': |u32| -> i64 [299; 301) '_v': u32 [303; 304) '1': i64 "### ); } #[test] fn closure_2() { assert_snapshot!( infer(r#" trait FnOnce { type Output; } fn test u64>(f: F) { f(1); let g = |v| v + 1; g(1u64); let h = |v| 1u128 + v; } "#), @r###" [73; 74) 'f': F [79; 155) '{ ...+ v; }': () [85; 86) 'f': F [85; 89) 'f(1)': {unknown} [87; 88) '1': i32 [99; 100) 'g': |u64| -> i32 [103; 112) '|v| v + 1': |u64| -> i32 [104; 105) 'v': u64 [107; 108) 'v': u64 [107; 112) 'v + 1': i32 [111; 112) '1': i32 [118; 119) 'g': |u64| -> i32 [118; 125) 'g(1u64)': i32 [120; 124) '1u64': u64 [135; 136) 'h': |u128| -> u128 [139; 152) '|v| 1u128 + v': |u128| -> u128 [140; 141) 'v': u128 [143; 148) '1u128': u128 [143; 152) '1u128 + v': u128 [151; 152) 'v': u128 "### ); } #[test] fn closure_as_argument_inference_order() { assert_snapshot!( infer(r#" #[lang = "fn_once"] trait FnOnce { type Output; } fn foo1 U>(x: T, f: F) -> U {} fn foo2 U>(f: F, x: T) -> U {} struct S; impl S { fn method(self) -> u64; fn foo1 U>(self, x: T, f: F) -> U {} fn foo2 U>(self, f: F, x: T) -> U {} } fn test() { let x1 = foo1(S, |s| s.method()); let x2 = foo2(|s| s.method(), S); let x3 = S.foo1(S, |s| s.method()); let x4 = S.foo2(|s| s.method(), S); } "#), @r###" [95; 96) 'x': T [101; 102) 'f': F [112; 114) '{}': () [148; 149) 'f': F [154; 155) 'x': T [165; 167) '{}': () [202; 206) 'self': S [254; 258) 'self': S [260; 261) 'x': T [266; 267) 'f': F [277; 279) '{}': () [317; 321) 'self': S [323; 324) 'f': F [329; 330) 'x': T [340; 342) '{}': () [356; 515) '{ ... S); }': () [366; 368) 'x1': u64 [371; 375) 'foo1': fn foo1 u64>(T, F) -> U [371; 394) 'foo1(S...hod())': u64 [376; 377) 'S': S [379; 393) '|s| s.method()': |S| -> u64 [380; 381) 's': S [383; 384) 's': S [383; 393) 's.method()': u64 [404; 406) 'x2': u64 [409; 413) 'foo2': fn foo2 u64>(F, T) -> U [409; 432) 'foo2(|...(), S)': u64 [414; 428) '|s| s.method()': |S| -> u64 [415; 416) 's': S [418; 419) 's': S [418; 428) 's.method()': u64 [430; 431) 'S': S [442; 444) 'x3': u64 [447; 448) 'S': S [447; 472) 'S.foo1...hod())': u64 [454; 455) 'S': S [457; 471) '|s| s.method()': |S| -> u64 [458; 459) 's': S [461; 462) 's': S [461; 471) 's.method()': u64 [482; 484) 'x4': u64 [487; 488) 'S': S [487; 512) 'S.foo2...(), S)': u64 [494; 508) '|s| s.method()': |S| -> u64 [495; 496) 's': S [498; 499) 's': S [498; 508) 's.method()': u64 [510; 511) 'S': S "### ); } #[test] fn unselected_projection_in_trait_env_1() { let t = type_at( r#" //- /main.rs trait Trait { type Item; } trait Trait2 { fn foo(&self) -> u32; } fn test() where T::Item: Trait2 { let x: T::Item = no_matter; x.foo()<|>; } "#, ); assert_eq!(t, "u32"); } #[test] fn unselected_projection_in_trait_env_2() { let t = type_at( r#" //- /main.rs trait Trait { type Item; } trait Trait2 { fn foo(&self) -> u32; } fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { let x: T::Item = no_matter; x.foo()<|>; } "#, ); assert_eq!(t, "u32"); } #[test] fn trait_impl_self_ty() { let t = type_at( r#" //- /main.rs trait Trait { fn foo(&self); } struct S; impl Trait for S {} fn test() { S.foo()<|>; } "#, ); assert_eq!(t, "()"); } #[test] fn trait_impl_self_ty_cycle() { let t = type_at( r#" //- /main.rs trait Trait { fn foo(&self); } struct S; impl Trait for S {} fn test() { S.foo()<|>; } "#, ); assert_eq!(t, "{unknown}"); } #[test] fn unselected_projection_in_trait_env_cycle_1() { let t = type_at( r#" //- /main.rs trait Trait { type Item; } trait Trait2 {} fn test() where T: Trait2 { let x: T::Item = no_matter<|>; } "#, ); // this is a legitimate cycle assert_eq!(t, "{unknown}"); } #[test] fn unselected_projection_in_trait_env_cycle_2() { let t = type_at( r#" //- /main.rs trait Trait { type Item; } fn test() where T: Trait, U: Trait { let x: T::Item = no_matter<|>; } "#, ); // this is a legitimate cycle assert_eq!(t, "{unknown}"); } #[test] fn unify_impl_trait() { covers!(insert_vars_for_impl_trait); assert_snapshot!( infer_with_mismatches(r#" trait Trait {} fn foo(x: impl Trait) { loop {} } fn bar(x: impl Trait) -> T { loop {} } struct S(T); impl Trait for S {} fn default() -> T { loop {} } fn test() -> impl Trait { let s1 = S(default()); foo(s1); let x: i32 = bar(S(default())); S(default()) } "#, true), @r###" [27; 28) 'x': impl Trait [47; 58) '{ loop {} }': () [49; 56) 'loop {}': ! [54; 56) '{}': () [69; 70) 'x': impl Trait [92; 103) '{ loop {} }': T [94; 101) 'loop {}': ! [99; 101) '{}': () [172; 183) '{ loop {} }': T [174; 181) 'loop {}': ! [179; 181) '{}': () [214; 310) '{ ...t()) }': S [224; 226) 's1': S [229; 230) 'S': S(T) -> S [229; 241) 'S(default())': S [231; 238) 'default': fn default() -> T [231; 240) 'default()': u32 [247; 250) 'foo': fn foo(impl Trait) -> () [247; 254) 'foo(s1)': () [251; 253) 's1': S [264; 265) 'x': i32 [273; 276) 'bar': fn bar(impl Trait) -> T [273; 290) 'bar(S(...lt()))': i32 [277; 278) 'S': S(T) -> S [277; 289) 'S(default())': S [279; 286) 'default': fn default() -> T [279; 288) 'default()': i32 [296; 297) 'S': S(T) -> S [296; 308) 'S(default())': S [298; 305) 'default': fn default() -> T [298; 307) 'default()': i32 "### ); }