mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00

If we get lifetime variables back in autoderef, just immediately replace them by static lifetimes for now. Method resolution doesn't really deal correctly with new variables being introduced (this needs to be fixed more properly). This fixes `rust-analyzer analysis-stats --with-deps` crashing in the RA repo.
1015 lines
24 KiB
Rust
1015 lines
24 KiB
Rust
use expect_test::expect;
|
|
|
|
use super::{check_infer, check_types};
|
|
|
|
#[test]
|
|
fn bug_484() {
|
|
check_infer(
|
|
r#"
|
|
fn test() {
|
|
let x = if true {};
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
10..37 '{ ... {}; }': ()
|
|
20..21 'x': ()
|
|
24..34 'if true {}': ()
|
|
27..31 'true': bool
|
|
32..34 '{}': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn no_panic_on_field_of_enum() {
|
|
check_infer(
|
|
r#"
|
|
enum X {}
|
|
|
|
fn test(x: X) {
|
|
x.some_field;
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
19..20 'x': X
|
|
25..46 '{ ...eld; }': ()
|
|
31..32 'x': X
|
|
31..43 'x.some_field': {unknown}
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn bug_585() {
|
|
check_infer(
|
|
r#"
|
|
fn test() {
|
|
X {};
|
|
match x {
|
|
A::B {} => (),
|
|
A::Y() => (),
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
10..88 '{ ... } }': ()
|
|
16..20 'X {}': {unknown}
|
|
26..86 'match ... }': ()
|
|
32..33 'x': {unknown}
|
|
44..51 'A::B {}': {unknown}
|
|
55..57 '()': ()
|
|
67..73 'A::Y()': {unknown}
|
|
77..79 '()': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn bug_651() {
|
|
check_infer(
|
|
r#"
|
|
fn quux() {
|
|
let y = 92;
|
|
1 + y;
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
10..40 '{ ...+ y; }': ()
|
|
20..21 'y': i32
|
|
24..26 '92': i32
|
|
32..33 '1': i32
|
|
32..37 '1 + y': i32
|
|
36..37 'y': i32
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_vars() {
|
|
cov_mark::check!(type_var_cycles_resolve_completely);
|
|
cov_mark::check!(type_var_cycles_resolve_as_possible);
|
|
check_infer(
|
|
r#"
|
|
fn test() {
|
|
let y = unknown;
|
|
[y, &y];
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
10..47 '{ ...&y]; }': ()
|
|
20..21 'y': &{unknown}
|
|
24..31 'unknown': &{unknown}
|
|
37..44 '[y, &y]': [&&{unknown}; _]
|
|
38..39 'y': &{unknown}
|
|
41..43 '&y': &&{unknown}
|
|
42..43 'y': &{unknown}
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_vars_2() {
|
|
check_infer(
|
|
r#"
|
|
fn test() {
|
|
let x = unknown;
|
|
let y = unknown;
|
|
[(x, y), (&y, &x)];
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
10..79 '{ ...x)]; }': ()
|
|
20..21 'x': &&{unknown}
|
|
24..31 'unknown': &&{unknown}
|
|
41..42 'y': &&{unknown}
|
|
45..52 'unknown': &&{unknown}
|
|
58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); _]
|
|
59..65 '(x, y)': (&&&{unknown}, &&&{unknown})
|
|
60..61 'x': &&{unknown}
|
|
63..64 'y': &&{unknown}
|
|
67..75 '(&y, &x)': (&&&{unknown}, &&&{unknown})
|
|
68..70 '&y': &&&{unknown}
|
|
69..70 'y': &&{unknown}
|
|
72..74 '&x': &&&{unknown}
|
|
73..74 'x': &&{unknown}
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_std_crash_1() {
|
|
// caused stack overflow, taken from std
|
|
check_infer(
|
|
r#"
|
|
enum Maybe<T> {
|
|
Real(T),
|
|
Fake,
|
|
}
|
|
|
|
fn write() {
|
|
match something_unknown {
|
|
Maybe::Real(ref mut something) => (),
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
53..138 '{ ... } }': ()
|
|
59..136 'match ... }': ()
|
|
65..82 'someth...nknown': Maybe<{unknown}>
|
|
93..123 'Maybe:...thing)': Maybe<{unknown}>
|
|
105..122 'ref mu...ething': &mut {unknown}
|
|
127..129 '()': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_std_crash_2() {
|
|
cov_mark::check!(type_var_resolves_to_int_var);
|
|
// caused "equating two type variables, ...", taken from std
|
|
check_infer(
|
|
r#"
|
|
fn test_line_buffer() {
|
|
&[0, b'\n', 1, b'\n'];
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
22..52 '{ ...n']; }': ()
|
|
28..49 '&[0, b...b'\n']': &[u8; _]
|
|
29..49 '[0, b'...b'\n']': [u8; _]
|
|
30..31 '0': u8
|
|
33..38 'b'\n'': u8
|
|
40..41 '1': u8
|
|
43..48 'b'\n'': u8
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_std_crash_3() {
|
|
// taken from rustc
|
|
check_infer(
|
|
r#"
|
|
pub fn compute() {
|
|
match nope!() {
|
|
SizeSkeleton::Pointer { non_zero: true, tail } => {}
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
17..107 '{ ... } }': ()
|
|
23..105 'match ... }': ()
|
|
29..36 'nope!()': {unknown}
|
|
47..93 'SizeSk...tail }': {unknown}
|
|
81..85 'true': bool
|
|
81..85 'true': bool
|
|
87..91 'tail': {unknown}
|
|
97..99 '{}': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_std_crash_4() {
|
|
// taken from rustc
|
|
check_infer(
|
|
r#"
|
|
pub fn primitive_type() {
|
|
match *self {
|
|
BorrowedRef { type_: Primitive(p), ..} => {},
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
24..105 '{ ... } }': ()
|
|
30..103 'match ... }': ()
|
|
36..41 '*self': {unknown}
|
|
37..41 'self': {unknown}
|
|
52..90 'Borrow...), ..}': {unknown}
|
|
73..85 'Primitive(p)': {unknown}
|
|
83..84 'p': {unknown}
|
|
94..96 '{}': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_std_crash_5() {
|
|
// taken from rustc
|
|
check_infer(
|
|
r#"
|
|
fn extra_compiler_flags() {
|
|
for content in doesnt_matter {
|
|
let name = if doesnt_matter {
|
|
first
|
|
} else {
|
|
&content
|
|
};
|
|
|
|
let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
|
|
name
|
|
} else {
|
|
content
|
|
};
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
26..322 '{ ... } }': ()
|
|
32..320 'for co... }': ()
|
|
36..43 'content': &{unknown}
|
|
47..60 'doesnt_matter': {unknown}
|
|
61..320 '{ ... }': ()
|
|
75..79 'name': &&{unknown}
|
|
82..166 'if doe... }': &&{unknown}
|
|
85..98 'doesnt_matter': bool
|
|
99..128 '{ ... }': &&{unknown}
|
|
113..118 'first': &&{unknown}
|
|
134..166 '{ ... }': &&{unknown}
|
|
148..156 '&content': &&{unknown}
|
|
149..156 'content': &{unknown}
|
|
181..188 'content': &{unknown}
|
|
191..313 'if ICE... }': &{unknown}
|
|
194..231 'ICE_RE..._VALUE': {unknown}
|
|
194..247 'ICE_RE...&name)': bool
|
|
241..246 '&name': &&&{unknown}
|
|
242..246 'name': &&{unknown}
|
|
248..276 '{ ... }': &&{unknown}
|
|
262..266 'name': &&{unknown}
|
|
282..313 '{ ... }': &{unknown}
|
|
296..303 'content': &{unknown}
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_nested_generics_crash() {
|
|
// another crash found typechecking rustc
|
|
check_infer(
|
|
r#"
|
|
struct Canonical<V> {
|
|
value: V,
|
|
}
|
|
struct QueryResponse<V> {
|
|
value: V,
|
|
}
|
|
fn test<R>(query_response: Canonical<QueryResponse<R>>) {
|
|
&query_response.value;
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
91..105 'query_response': Canonical<QueryResponse<R>>
|
|
136..166 '{ ...lue; }': ()
|
|
142..163 '&query....value': &QueryResponse<R>
|
|
143..157 'query_response': Canonical<QueryResponse<R>>
|
|
143..163 'query_....value': QueryResponse<R>
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_paren_macro_call() {
|
|
check_infer(
|
|
r#"
|
|
macro_rules! bar { () => {0u32} }
|
|
fn test() {
|
|
let a = (bar!());
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
!0..4 '0u32': u32
|
|
44..69 '{ ...()); }': ()
|
|
54..55 'a': u32
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn infer_array_macro_call() {
|
|
check_infer(
|
|
r#"
|
|
macro_rules! bar { () => {0u32} }
|
|
fn test() {
|
|
let a = [bar!()];
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
!0..4 '0u32': u32
|
|
44..69 '{ ...()]; }': ()
|
|
54..55 'a': [u32; _]
|
|
58..66 '[bar!()]': [u32; _]
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn bug_1030() {
|
|
check_infer(
|
|
r#"
|
|
struct HashSet<T, H>;
|
|
struct FxHasher;
|
|
type FxHashSet<T> = HashSet<T, FxHasher>;
|
|
|
|
impl<T, H> HashSet<T, H> {
|
|
fn default() -> HashSet<T, H> {}
|
|
}
|
|
|
|
pub fn main_loop() {
|
|
FxHashSet::default();
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
143..145 '{}': ()
|
|
168..197 '{ ...t(); }': ()
|
|
174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher>
|
|
174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher>
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_2669() {
|
|
check_infer(
|
|
r#"
|
|
trait A {}
|
|
trait Write {}
|
|
struct Response<T> {}
|
|
|
|
trait D {
|
|
fn foo();
|
|
}
|
|
|
|
impl<T:A> D for Response<T> {
|
|
fn foo() {
|
|
end();
|
|
fn end<W: Write>() {
|
|
let _x: T = loop {};
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
119..214 '{ ... }': ()
|
|
129..132 'end': fn end<{unknown}>()
|
|
129..134 'end()': ()
|
|
163..208 '{ ... }': ()
|
|
181..183 '_x': !
|
|
190..197 'loop {}': !
|
|
195..197 '{}': ()
|
|
"#]],
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn issue_2705() {
|
|
check_infer(
|
|
r#"
|
|
trait Trait {}
|
|
fn test() {
|
|
<Trait<u32>>::foo()
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
25..52 '{ ...oo() }': ()
|
|
31..48 '<Trait...>::foo': {unknown}
|
|
31..50 '<Trait...:foo()': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_2683_chars_impl() {
|
|
check_types(
|
|
r#"
|
|
//- /main.rs crate:main deps:std
|
|
fn test() {
|
|
let chars: std::str::Chars<'_>;
|
|
(chars.next(), chars.nth(1));
|
|
} //^ (Option<char>, Option<char>)
|
|
|
|
//- /std.rs crate:std
|
|
#[prelude_import]
|
|
use prelude::*;
|
|
|
|
pub mod prelude {
|
|
pub use crate::iter::Iterator;
|
|
pub use crate::option::Option;
|
|
}
|
|
|
|
pub mod iter {
|
|
pub use self::traits::Iterator;
|
|
pub mod traits {
|
|
pub use self::iterator::Iterator;
|
|
|
|
pub mod iterator {
|
|
pub trait Iterator {
|
|
type Item;
|
|
fn next(&mut self) -> Option<Self::Item>;
|
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod option {
|
|
pub enum Option<T> {}
|
|
}
|
|
|
|
pub mod str {
|
|
pub struct Chars<'a> {}
|
|
impl<'a> Iterator for Chars<'a> {
|
|
type Item = char;
|
|
fn next(&mut self) -> Option<char> {}
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_3642_bad_macro_stackover() {
|
|
check_types(
|
|
r#"
|
|
#[macro_export]
|
|
macro_rules! match_ast {
|
|
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
|
|
|
|
(match ($node:expr) {
|
|
$( ast::$ast:ident($it:ident) => $res:expr, )*
|
|
_ => $catch_all:expr $(,)?
|
|
}) => {{
|
|
$( if let Some($it) = ast::$ast::cast($node.clone()) { $res } else )*
|
|
{ $catch_all }
|
|
}};
|
|
}
|
|
|
|
fn main() {
|
|
let anchor = match_ast! {
|
|
//^ ()
|
|
match parent {
|
|
as => {},
|
|
_ => return None
|
|
}
|
|
};
|
|
}"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_3999_slice() {
|
|
check_infer(
|
|
r#"
|
|
fn foo(params: &[usize]) {
|
|
match params {
|
|
[ps @ .., _] => {}
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
7..13 'params': &[usize]
|
|
25..80 '{ ... } }': ()
|
|
31..78 'match ... }': ()
|
|
37..43 'params': &[usize]
|
|
54..66 '[ps @ .., _]': [usize]
|
|
55..62 'ps @ ..': &[usize]
|
|
60..62 '..': [usize]
|
|
64..65 '_': usize
|
|
70..72 '{}': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_3999_struct() {
|
|
// rust-analyzer should not panic on seeing this malformed
|
|
// record pattern.
|
|
check_infer(
|
|
r#"
|
|
struct Bar {
|
|
a: bool,
|
|
}
|
|
fn foo(b: Bar) {
|
|
match b {
|
|
Bar { a: .. } => {},
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
35..36 'b': Bar
|
|
43..95 '{ ... } }': ()
|
|
49..93 'match ... }': ()
|
|
55..56 'b': Bar
|
|
67..80 'Bar { a: .. }': Bar
|
|
76..78 '..': bool
|
|
84..86 '{}': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4235_name_conflicts() {
|
|
check_infer(
|
|
r#"
|
|
struct FOO {}
|
|
static FOO:FOO = FOO {};
|
|
|
|
impl FOO {
|
|
fn foo(&self) {}
|
|
}
|
|
|
|
fn main() {
|
|
let a = &FOO;
|
|
a.foo();
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
31..37 'FOO {}': FOO
|
|
63..67 'self': &FOO
|
|
69..71 '{}': ()
|
|
85..119 '{ ...o(); }': ()
|
|
95..96 'a': &FOO
|
|
99..103 '&FOO': &FOO
|
|
100..103 'FOO': FOO
|
|
109..110 'a': &FOO
|
|
109..116 'a.foo()': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4465_dollar_crate_at_type() {
|
|
check_infer(
|
|
r#"
|
|
pub struct Foo {}
|
|
pub fn anything<T>() -> T {
|
|
loop {}
|
|
}
|
|
macro_rules! foo {
|
|
() => {{
|
|
let r: $crate::Foo = anything();
|
|
r
|
|
}};
|
|
}
|
|
fn main() {
|
|
let _a = foo!();
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
44..59 '{ loop {} }': T
|
|
50..57 'loop {}': !
|
|
55..57 '{}': ()
|
|
!0..31 '{letr:...g();r}': Foo
|
|
!4..5 'r': Foo
|
|
!18..26 'anything': fn anything<Foo>() -> Foo
|
|
!18..28 'anything()': Foo
|
|
!29..30 'r': Foo
|
|
163..187 '{ ...!(); }': ()
|
|
173..175 '_a': Foo
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6811() {
|
|
check_infer(
|
|
r#"
|
|
macro_rules! profile_function {
|
|
() => {
|
|
let _a = 1;
|
|
let _b = 1;
|
|
};
|
|
}
|
|
fn main() {
|
|
profile_function!();
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
!3..5 '_a': i32
|
|
!6..7 '1': i32
|
|
!11..13 '_b': i32
|
|
!14..15 '1': i32
|
|
103..131 '{ ...!(); }': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4053_diesel_where_clauses() {
|
|
check_infer(
|
|
r#"
|
|
trait BoxedDsl<DB> {
|
|
type Output;
|
|
fn internal_into_boxed(self) -> Self::Output;
|
|
}
|
|
|
|
struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> {
|
|
order: Order,
|
|
}
|
|
|
|
trait QueryFragment<DB: Backend> {}
|
|
|
|
trait Into<T> { fn into(self) -> T; }
|
|
|
|
impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB>
|
|
for SelectStatement<F, S, D, W, O, LOf, G>
|
|
where
|
|
O: Into<dyn QueryFragment<DB>>,
|
|
{
|
|
type Output = XXX;
|
|
|
|
fn internal_into_boxed(self) -> Self::Output {
|
|
self.order.into();
|
|
}
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
65..69 'self': Self
|
|
267..271 'self': Self
|
|
466..470 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
|
|
488..522 '{ ... }': ()
|
|
498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
|
|
498..508 'self.order': O
|
|
498..515 'self.o...into()': dyn QueryFragment<DB>
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4953() {
|
|
check_infer(
|
|
r#"
|
|
pub struct Foo(pub i64);
|
|
impl Foo {
|
|
fn test() -> Self { Self(0i64) }
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
58..72 '{ Self(0i64) }': Foo
|
|
60..64 'Self': Foo(i64) -> Foo
|
|
60..70 'Self(0i64)': Foo
|
|
65..69 '0i64': i64
|
|
"#]],
|
|
);
|
|
check_infer(
|
|
r#"
|
|
pub struct Foo<T>(pub T);
|
|
impl Foo<i64> {
|
|
fn test() -> Self { Self(0i64) }
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
64..78 '{ Self(0i64) }': Foo<i64>
|
|
66..70 'Self': Foo<i64>(i64) -> Foo<i64>
|
|
66..76 'Self(0i64)': Foo<i64>
|
|
71..75 '0i64': i64
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4931() {
|
|
check_infer(
|
|
r#"
|
|
trait Div<T> {
|
|
type Output;
|
|
}
|
|
|
|
trait CheckedDiv: Div<()> {}
|
|
|
|
trait PrimInt: CheckedDiv<Output = ()> {
|
|
fn pow(self);
|
|
}
|
|
|
|
fn check<T: PrimInt>(i: T) {
|
|
i.pow();
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
117..121 'self': Self
|
|
148..149 'i': T
|
|
154..170 '{ ...w(); }': ()
|
|
160..161 'i': T
|
|
160..167 'i.pow()': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4885() {
|
|
check_infer(
|
|
r#"
|
|
#[lang = "coerce_unsized"]
|
|
pub trait CoerceUnsized<T> {}
|
|
|
|
trait Future {
|
|
type Output;
|
|
}
|
|
trait Foo<R> {
|
|
type Bar;
|
|
}
|
|
fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar>
|
|
where
|
|
K: Foo<R>,
|
|
{
|
|
bar(key)
|
|
}
|
|
fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar>
|
|
where
|
|
K: Foo<R>,
|
|
{
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
136..139 'key': &K
|
|
198..214 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
|
|
204..207 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
|
|
204..212 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
|
|
208..211 'key': &K
|
|
228..231 'key': &K
|
|
290..293 '{ }': ()
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4800() {
|
|
check_infer(
|
|
r#"
|
|
trait Debug {}
|
|
|
|
struct Foo<T>;
|
|
|
|
type E1<T> = (T, T, T);
|
|
type E2<T> = E1<E1<E1<(T, T, T)>>>;
|
|
|
|
impl Debug for Foo<E2<()>> {}
|
|
|
|
struct Request;
|
|
|
|
pub trait Future {
|
|
type Output;
|
|
}
|
|
|
|
pub struct PeerSet<D>;
|
|
|
|
impl<D> Service<Request> for PeerSet<D>
|
|
where
|
|
D: Discover,
|
|
D::Key: Debug,
|
|
{
|
|
type Error = ();
|
|
type Future = dyn Future<Output = Self::Error>;
|
|
|
|
fn call(&mut self) -> Self::Future {
|
|
loop {}
|
|
}
|
|
}
|
|
|
|
pub trait Discover {
|
|
type Key;
|
|
}
|
|
|
|
pub trait Service<Request> {
|
|
type Error;
|
|
type Future: Future<Output = Self::Error>;
|
|
fn call(&mut self) -> Self::Future;
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
379..383 'self': &mut PeerSet<D>
|
|
401..424 '{ ... }': dyn Future<Output = ()>
|
|
411..418 'loop {}': !
|
|
416..418 '{}': ()
|
|
575..579 'self': &mut Self
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_4966() {
|
|
check_infer(
|
|
r#"
|
|
pub trait IntoIterator {
|
|
type Item;
|
|
}
|
|
|
|
struct Repeat<A> { element: A }
|
|
|
|
struct Map<F> { f: F }
|
|
|
|
struct Vec<T> {}
|
|
|
|
#[lang = "deref"]
|
|
pub trait Deref {
|
|
type Target;
|
|
}
|
|
|
|
impl<T> Deref for Vec<T> {
|
|
type Target = [T];
|
|
}
|
|
|
|
fn from_iter<A, T: IntoIterator<Item = A>>(iter: T) -> Vec<A> {}
|
|
|
|
fn main() {
|
|
let inner = Map { f: |_: &f64| 0.0 };
|
|
|
|
let repeat = Repeat { element: inner };
|
|
|
|
let vec = from_iter(repeat);
|
|
|
|
vec.foo_bar();
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
270..274 'iter': T
|
|
289..291 '{}': ()
|
|
303..447 '{ ...r(); }': ()
|
|
313..318 'inner': Map<|&f64| -> f64>
|
|
321..345 'Map { ... 0.0 }': Map<|&f64| -> f64>
|
|
330..343 '|_: &f64| 0.0': |&f64| -> f64
|
|
331..332 '_': &f64
|
|
340..343 '0.0': f64
|
|
356..362 'repeat': Repeat<Map<|&f64| -> f64>>
|
|
365..390 'Repeat...nner }': Repeat<Map<|&f64| -> f64>>
|
|
383..388 'inner': Map<|&f64| -> f64>
|
|
401..404 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
|
|
407..416 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>, Repeat<Map<|&f64| -> f64>>>(Repeat<Map<|&f64| -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
|
|
407..424 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
|
|
417..423 'repeat': Repeat<Map<|&f64| -> f64>>
|
|
431..434 'vec': Vec<IntoIterator::Item<Repeat<Map<|&f64| -> f64>>>>
|
|
431..444 'vec.foo_bar()': {unknown}
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6628() {
|
|
check_infer(
|
|
r#"
|
|
#[lang = "fn_once"]
|
|
pub trait FnOnce<Args> {
|
|
type Output;
|
|
}
|
|
|
|
struct S<T>();
|
|
impl<T> S<T> {
|
|
fn f(&self, _t: T) {}
|
|
fn g<F: FnOnce(&T)>(&self, _f: F) {}
|
|
}
|
|
fn main() {
|
|
let s = S();
|
|
s.g(|_x| {});
|
|
s.f(10);
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
105..109 'self': &S<T>
|
|
111..113 '_t': T
|
|
118..120 '{}': ()
|
|
146..150 'self': &S<T>
|
|
152..154 '_f': F
|
|
159..161 '{}': ()
|
|
174..225 '{ ...10); }': ()
|
|
184..185 's': S<i32>
|
|
188..189 'S': S<i32>() -> S<i32>
|
|
188..191 'S()': S<i32>
|
|
197..198 's': S<i32>
|
|
197..209 's.g(|_x| {})': ()
|
|
201..208 '|_x| {}': |&i32| -> ()
|
|
202..204 '_x': &i32
|
|
206..208 '{}': ()
|
|
215..216 's': S<i32>
|
|
215..222 's.f(10)': ()
|
|
219..221 '10': i32
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_6852() {
|
|
check_infer(
|
|
r#"
|
|
#[lang = "deref"]
|
|
pub trait Deref {
|
|
type Target;
|
|
}
|
|
|
|
struct BufWriter {}
|
|
|
|
struct Mutex<T> {}
|
|
struct MutexGuard<'a, T> {}
|
|
impl<T> Mutex<T> {
|
|
fn lock(&self) -> MutexGuard<'_, T> {}
|
|
}
|
|
impl<'a, T: 'a> Deref for MutexGuard<'a, T> {
|
|
type Target = T;
|
|
}
|
|
fn flush(&self) {
|
|
let w: &Mutex<BufWriter>;
|
|
*(w.lock());
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
156..160 'self': &Mutex<T>
|
|
183..185 '{}': ()
|
|
267..271 'self': &{unknown}
|
|
273..323 '{ ...()); }': ()
|
|
283..284 'w': &Mutex<BufWriter>
|
|
309..320 '*(w.lock())': BufWriter
|
|
311..312 'w': &Mutex<BufWriter>
|
|
311..319 'w.lock()': MutexGuard<BufWriter>
|
|
"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn param_overrides_fn() {
|
|
check_types(
|
|
r#"
|
|
fn example(example: i32) {
|
|
fn f() {}
|
|
example;
|
|
//^^^^^^^ i32
|
|
}
|
|
"#,
|
|
)
|
|
}
|
|
|
|
#[test]
|
|
fn lifetime_from_chalk_during_deref() {
|
|
check_types(
|
|
r#"
|
|
#[lang = "deref"]
|
|
pub trait Deref {
|
|
type Target;
|
|
}
|
|
|
|
struct Box<T: ?Sized> {}
|
|
impl<T> Deref for Box<T> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
loop {}
|
|
}
|
|
}
|
|
|
|
trait Iterator {
|
|
type Item;
|
|
}
|
|
|
|
pub struct Iter<'a, T: 'a> {
|
|
inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
|
|
}
|
|
|
|
trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
|
|
fn clone_box(&self);
|
|
}
|
|
|
|
fn clone_iter<T>(s: Iter<T>) {
|
|
s.inner.clone_box();
|
|
//^^^^^^^^^^^^^^^^^^^ ()
|
|
}
|
|
"#,
|
|
)
|
|
}
|