2019-01-05 12:42:47 +00:00
|
|
|
use std::sync::Arc;
|
2018-12-23 11:05:54 +00:00
|
|
|
use std::fmt::Write;
|
2018-12-20 20:56:28 +00:00
|
|
|
|
2019-02-23 11:32:25 +00:00
|
|
|
use ra_db::{SourceDatabase, salsa::Database, FilePosition};
|
|
|
|
use ra_syntax::{algo, ast::{self, AstNode}};
|
2019-01-26 22:57:03 +00:00
|
|
|
use test_utils::covers;
|
2018-12-20 20:56:28 +00:00
|
|
|
|
|
|
|
use crate::{
|
2018-12-23 11:15:46 +00:00
|
|
|
source_binder,
|
2018-12-20 20:56:28 +00:00
|
|
|
mock::MockDatabase,
|
|
|
|
};
|
|
|
|
|
2018-12-24 14:36:54 +00:00
|
|
|
// These tests compare the inference results for all expressions in a file
|
2019-01-21 21:52:35 +00:00
|
|
|
// against snapshots of the expected results using insta. Run the tests with
|
|
|
|
// INSTA_UPDATE=1 to update the snapshots.
|
2018-12-24 14:36:54 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_basics() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_basics",
|
2018-12-24 14:36:54 +00:00
|
|
|
r#"
|
|
|
|
fn test(a: u32, b: isize, c: !, d: &str) {
|
|
|
|
a;
|
|
|
|
b;
|
|
|
|
c;
|
|
|
|
d;
|
|
|
|
1usize;
|
|
|
|
1isize;
|
|
|
|
"test";
|
|
|
|
1.0f32;
|
|
|
|
}"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_let() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_let",
|
2018-12-24 14:36:54 +00:00
|
|
|
r#"
|
|
|
|
fn test() {
|
|
|
|
let a = 1isize;
|
|
|
|
let b: usize = 1;
|
|
|
|
let c = b;
|
|
|
|
}
|
|
|
|
}"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_paths() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_paths",
|
2018-12-24 14:36:54 +00:00
|
|
|
r#"
|
|
|
|
fn a() -> u32 { 1 }
|
|
|
|
|
|
|
|
mod b {
|
|
|
|
fn c() -> u32 { 1 }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test() {
|
|
|
|
a();
|
|
|
|
b::c();
|
|
|
|
}
|
|
|
|
}"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-12-24 18:07:48 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_struct() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_struct",
|
2018-12-24 18:07:48 +00:00
|
|
|
r#"
|
|
|
|
struct A {
|
|
|
|
b: B,
|
|
|
|
c: C,
|
|
|
|
}
|
|
|
|
struct B;
|
|
|
|
struct C(usize);
|
|
|
|
|
|
|
|
fn test() {
|
|
|
|
let c = C(1);
|
|
|
|
B;
|
2018-12-24 20:00:14 +00:00
|
|
|
let a: A = A { b: B, c: C(1) };
|
2018-12-24 18:07:48 +00:00
|
|
|
a.b;
|
|
|
|
a.c;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-08 15:01:19 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_enum() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_enum",
|
2019-01-08 15:01:19 +00:00
|
|
|
r#"
|
|
|
|
enum E {
|
|
|
|
V1 { field: u32 },
|
|
|
|
V2
|
|
|
|
}
|
|
|
|
fn test() {
|
|
|
|
E::V1 { field: 1 };
|
|
|
|
E::V2;
|
|
|
|
}"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-12-25 16:17:39 +00:00
|
|
|
#[test]
|
2019-01-06 18:51:42 +00:00
|
|
|
fn infer_refs() {
|
2018-12-25 16:17:39 +00:00
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_refs",
|
2018-12-25 16:17:39 +00:00
|
|
|
r#"
|
|
|
|
fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
|
|
|
|
a;
|
|
|
|
*a;
|
|
|
|
&a;
|
|
|
|
&mut a;
|
|
|
|
b;
|
|
|
|
*b;
|
|
|
|
&b;
|
|
|
|
c;
|
|
|
|
*c;
|
|
|
|
d;
|
|
|
|
*d;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-10 12:54:58 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_literals() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_literals",
|
2019-01-14 19:56:14 +00:00
|
|
|
r##"
|
2019-01-10 12:54:58 +00:00
|
|
|
fn test() {
|
|
|
|
5i32;
|
|
|
|
"hello";
|
|
|
|
b"bytes";
|
|
|
|
'c';
|
|
|
|
b'b';
|
|
|
|
3.14;
|
|
|
|
5000;
|
2019-01-10 17:08:54 +00:00
|
|
|
false;
|
2019-01-14 18:30:21 +00:00
|
|
|
true;
|
2019-01-14 19:56:14 +00:00
|
|
|
r#"
|
|
|
|
//! doc
|
|
|
|
// non-doc
|
|
|
|
mod foo {}
|
|
|
|
"#;
|
|
|
|
br#"yolo"#;
|
|
|
|
}
|
|
|
|
"##,
|
2019-01-10 12:54:58 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-14 22:15:16 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_unary_op() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_unary_op",
|
2019-01-14 22:15:16 +00:00
|
|
|
r#"
|
|
|
|
enum SomeType {}
|
|
|
|
|
|
|
|
fn test(x: SomeType) {
|
|
|
|
let b = false;
|
|
|
|
let c = !b;
|
|
|
|
let a = 100;
|
|
|
|
let d: i128 = -a;
|
|
|
|
let e = -100;
|
|
|
|
let f = !!!true;
|
2019-01-28 14:52:43 +00:00
|
|
|
let g = !42;
|
|
|
|
let h = !10u32;
|
|
|
|
let j = !a;
|
2019-01-14 22:15:16 +00:00
|
|
|
-3.14;
|
2019-01-28 14:52:43 +00:00
|
|
|
!3;
|
2019-01-14 22:15:16 +00:00
|
|
|
-x;
|
|
|
|
!x;
|
|
|
|
-"hello";
|
2019-01-28 14:52:43 +00:00
|
|
|
!"hello";
|
2019-01-14 22:15:16 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-12-26 16:00:42 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_backwards() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_backwards",
|
2018-12-26 16:00:42 +00:00
|
|
|
r#"
|
|
|
|
fn takes_u32(x: u32) {}
|
|
|
|
|
|
|
|
struct S { i32_field: i32 }
|
|
|
|
|
|
|
|
fn test() -> &mut &f64 {
|
|
|
|
let a = unknown_function();
|
|
|
|
takes_u32(a);
|
|
|
|
let b = unknown_function();
|
|
|
|
S { i32_field: b };
|
|
|
|
let c = unknown_function();
|
|
|
|
&mut &c
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-12-26 20:28:05 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_self() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_self",
|
2018-12-26 20:28:05 +00:00
|
|
|
r#"
|
|
|
|
struct S;
|
|
|
|
|
|
|
|
impl S {
|
|
|
|
fn test(&self) {
|
|
|
|
self;
|
|
|
|
}
|
|
|
|
fn test2(self: &Self) {
|
|
|
|
self;
|
|
|
|
}
|
2019-02-04 19:44:06 +00:00
|
|
|
fn test3() -> Self {
|
|
|
|
S {}
|
|
|
|
}
|
|
|
|
fn test4() -> Self {
|
|
|
|
Self {}
|
|
|
|
}
|
2018-12-26 20:28:05 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-05 20:28:30 +00:00
|
|
|
#[test]
|
2019-01-07 19:11:31 +00:00
|
|
|
fn infer_binary_op() {
|
2019-01-05 20:28:30 +00:00
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_binary_op",
|
2019-01-05 20:28:30 +00:00
|
|
|
r#"
|
2019-01-06 20:39:36 +00:00
|
|
|
fn f(x: bool) -> i32 {
|
|
|
|
0i32
|
|
|
|
}
|
|
|
|
|
2019-01-14 18:30:21 +00:00
|
|
|
fn test() -> bool {
|
2019-01-05 20:28:30 +00:00
|
|
|
let x = a && b;
|
|
|
|
let y = true || false;
|
|
|
|
let z = x == y;
|
2019-02-18 07:09:44 +00:00
|
|
|
let t = x != y;
|
2019-01-07 19:11:31 +00:00
|
|
|
let minus_forty: isize = -40isize;
|
|
|
|
let h = minus_forty <= CONST_2;
|
2019-01-06 20:39:36 +00:00
|
|
|
let c = f(z || y) + 5;
|
|
|
|
let d = b;
|
2019-01-07 19:11:31 +00:00
|
|
|
let g = minus_forty ^= i;
|
|
|
|
let ten: usize = 10;
|
|
|
|
let ten_is_eleven = ten == some_num;
|
2019-01-05 20:28:30 +00:00
|
|
|
|
2019-01-07 19:11:31 +00:00
|
|
|
ten < 3
|
2019-01-05 20:28:30 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-06 18:51:42 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_field_autoderef() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_field_autoderef",
|
2019-01-06 18:51:42 +00:00
|
|
|
r#"
|
|
|
|
struct A {
|
|
|
|
b: B,
|
|
|
|
}
|
|
|
|
struct B;
|
|
|
|
|
|
|
|
fn test1(a: A) {
|
|
|
|
let a1 = a;
|
|
|
|
a1.b;
|
|
|
|
let a2 = &a;
|
|
|
|
a2.b;
|
|
|
|
let a3 = &mut a;
|
|
|
|
a3.b;
|
|
|
|
let a4 = &&&&&&&a;
|
|
|
|
a4.b;
|
|
|
|
let a5 = &mut &&mut &&mut a;
|
|
|
|
a5.b;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test2(a1: *const A, a2: *mut A) {
|
|
|
|
a1.b;
|
|
|
|
a2.b;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-10 21:49:43 +00:00
|
|
|
#[test]
|
2019-01-21 21:52:35 +00:00
|
|
|
fn bug_484() {
|
2019-01-10 21:49:43 +00:00
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"bug_484",
|
2019-01-10 21:49:43 +00:00
|
|
|
r#"
|
|
|
|
fn test() {
|
|
|
|
let x = if true {};
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-26 21:23:07 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_in_elseif() {
|
|
|
|
check_inference(
|
|
|
|
"infer_in_elseif",
|
|
|
|
r#"
|
|
|
|
struct Foo { field: i32 }
|
|
|
|
fn main(foo: Foo) {
|
|
|
|
if true {
|
|
|
|
|
|
|
|
} else if false {
|
|
|
|
foo.field
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-01-07 12:44:54 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_inherent_method() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_inherent_method",
|
2019-01-07 12:44:54 +00:00
|
|
|
r#"
|
|
|
|
struct A;
|
|
|
|
|
|
|
|
impl A {
|
|
|
|
fn foo(self, x: u32) -> i32 {}
|
|
|
|
}
|
|
|
|
|
|
|
|
mod b {
|
|
|
|
impl super::A {
|
|
|
|
fn bar(&self, x: u64) -> i64 {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test(a: A) {
|
|
|
|
a.foo(1);
|
|
|
|
(&a).bar(1);
|
|
|
|
a.bar(1);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-13 11:51:05 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_tuple() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_tuple",
|
2019-01-13 11:51:05 +00:00
|
|
|
r#"
|
2019-01-13 13:01:33 +00:00
|
|
|
fn test(x: &str, y: isize) {
|
2019-01-13 11:51:05 +00:00
|
|
|
let a: (u32, &str) = (1, "a");
|
2019-01-13 13:01:33 +00:00
|
|
|
let b = (a, x);
|
|
|
|
let c = (y, x);
|
|
|
|
let d = (c, x);
|
|
|
|
let e = (1, "e");
|
|
|
|
let f = (e, "d");
|
2019-01-13 11:51:05 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-13 13:46:52 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_array() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_array",
|
2019-01-13 13:46:52 +00:00
|
|
|
r#"
|
|
|
|
fn test(x: &str, y: isize) {
|
|
|
|
let a = [x];
|
|
|
|
let b = [a, a];
|
|
|
|
let c = [b, b];
|
|
|
|
|
2019-01-15 00:30:18 +00:00
|
|
|
let d = [y, 1, 2, 3];
|
|
|
|
let d = [1, y, 2, 3];
|
2019-01-14 13:52:05 +00:00
|
|
|
let e = [y];
|
|
|
|
let f = [d, d];
|
|
|
|
let g = [e, e];
|
|
|
|
|
|
|
|
let h = [1, 2];
|
|
|
|
let i = ["a", "b"];
|
2019-01-13 13:46:52 +00:00
|
|
|
|
|
|
|
let b = [a, ["b"]];
|
2019-01-14 13:52:05 +00:00
|
|
|
let x: [u8; 0] = [];
|
2019-01-30 20:14:26 +00:00
|
|
|
let z: &[u8] = &[1, 2, 3];
|
2019-01-13 13:46:52 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-15 14:24:04 +00:00
|
|
|
#[test]
|
2019-01-17 12:40:45 +00:00
|
|
|
fn infer_pattern() {
|
2019-01-15 14:24:04 +00:00
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_pattern",
|
2019-01-15 14:24:04 +00:00
|
|
|
r#"
|
|
|
|
fn test(x: &i32) {
|
|
|
|
let y = x;
|
|
|
|
let &z = x;
|
|
|
|
let a = z;
|
|
|
|
let (c, d) = (1, "hello");
|
2019-01-17 09:28:10 +00:00
|
|
|
|
|
|
|
for (e, f) in some_iter {
|
|
|
|
let g = e;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let [val] = opt {
|
|
|
|
let h = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
let lambda = |a: u64, b, c: i32| { a + b; c };
|
2019-01-17 12:08:18 +00:00
|
|
|
|
|
|
|
let ref ref_to_x = x;
|
|
|
|
let mut mut_x = x;
|
|
|
|
let ref mut mut_ref_to_x = x;
|
2019-01-17 12:40:45 +00:00
|
|
|
let k = mut_ref_to_x;
|
2019-01-16 16:47:59 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_adt_pattern() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_adt_pattern",
|
2019-01-16 16:47:59 +00:00
|
|
|
r#"
|
|
|
|
enum E {
|
|
|
|
A { x: usize },
|
|
|
|
B
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S(u32, E);
|
2019-01-15 17:47:37 +00:00
|
|
|
|
2019-01-16 16:47:59 +00:00
|
|
|
fn test() {
|
2019-01-15 17:47:37 +00:00
|
|
|
let e = E::A { x: 3 };
|
2019-01-16 16:47:59 +00:00
|
|
|
|
|
|
|
let S(y, z) = foo;
|
|
|
|
let E::A { x: new_var } = e;
|
2019-01-16 23:08:10 +00:00
|
|
|
|
|
|
|
match e {
|
|
|
|
E::A { x } => x,
|
2019-01-28 22:06:11 +00:00
|
|
|
E::B if foo => 1,
|
|
|
|
E::B => 10,
|
2019-01-16 23:08:10 +00:00
|
|
|
};
|
2019-01-17 12:40:45 +00:00
|
|
|
|
|
|
|
let ref d @ E::A { .. } = e;
|
|
|
|
d;
|
2019-01-15 14:24:04 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-12 17:47:43 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_struct_generics() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_struct_generics",
|
2019-01-12 17:47:43 +00:00
|
|
|
r#"
|
|
|
|
struct A<T> {
|
|
|
|
x: T,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test(a1: A<u32>, i: i32) {
|
|
|
|
a1.x;
|
|
|
|
let a2 = A { x: i };
|
|
|
|
a2.x;
|
|
|
|
let a3 = A::<i128> { x: 1 };
|
|
|
|
a3.x;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-20 21:36:54 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_tuple_struct_generics() {
|
|
|
|
check_inference(
|
|
|
|
"infer_tuple_struct_generics",
|
|
|
|
r#"
|
|
|
|
struct A<T>(T);
|
|
|
|
enum Option<T> { Some(T), None };
|
|
|
|
use Option::*;
|
|
|
|
|
|
|
|
fn test() {
|
|
|
|
A(42);
|
|
|
|
A(42u128);
|
|
|
|
Some("x");
|
|
|
|
Option::Some("x");
|
|
|
|
None;
|
|
|
|
let x: Option<i64> = None;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-19 14:48:55 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_generics_in_patterns() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_generics_in_patterns",
|
2019-01-19 14:48:55 +00:00
|
|
|
r#"
|
|
|
|
struct A<T> {
|
|
|
|
x: T,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Option<T> {
|
|
|
|
Some(T),
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test(a1: A<u32>, o: Option<u64>) {
|
|
|
|
let A { x: x2 } = a1;
|
|
|
|
let A::<i64> { x: x3 } = A { x: 1 };
|
|
|
|
match o {
|
|
|
|
Option::Some(t) => t,
|
|
|
|
_ => 1,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-12 17:47:43 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_function_generics() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_function_generics",
|
2019-01-12 17:47:43 +00:00
|
|
|
r#"
|
|
|
|
fn id<T>(t: T) -> T { t }
|
|
|
|
|
|
|
|
fn test() {
|
|
|
|
id(1u32);
|
|
|
|
id::<i128>(1);
|
|
|
|
let x: u64 = id(1);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-16 19:29:36 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_impl_generics() {
|
|
|
|
check_inference(
|
|
|
|
"infer_impl_generics",
|
|
|
|
r#"
|
|
|
|
struct A<T1, T2> {
|
|
|
|
x: T1,
|
|
|
|
y: T2,
|
|
|
|
}
|
|
|
|
impl<Y, X> A<X, Y> {
|
|
|
|
fn x(self) -> X {
|
|
|
|
self.x
|
|
|
|
}
|
|
|
|
fn y(self) -> Y {
|
|
|
|
self.y
|
|
|
|
}
|
|
|
|
fn z<T>(self, t: T) -> (X, Y, T) {
|
|
|
|
(self.x, self.y, t)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test() -> i128 {
|
|
|
|
let a = A { x: 1u64, y: 1i64 };
|
|
|
|
a.x();
|
|
|
|
a.y();
|
|
|
|
a.z(1i128);
|
|
|
|
a.z::<u128>(1);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-17 13:43:59 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_impl_generics_with_autoderef() {
|
|
|
|
check_inference(
|
|
|
|
"infer_impl_generics_with_autoderef",
|
|
|
|
r#"
|
|
|
|
enum Option<T> {
|
|
|
|
Some(T),
|
|
|
|
None,
|
|
|
|
}
|
|
|
|
impl<T> Option<T> {
|
|
|
|
fn as_ref(&self) -> Option<&T> {}
|
|
|
|
}
|
|
|
|
fn test(o: Option<u32>) {
|
|
|
|
(&o).as_ref();
|
|
|
|
o.as_ref();
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-12 17:47:43 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_generic_chain() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"infer_generic_chain",
|
2019-01-12 17:47:43 +00:00
|
|
|
r#"
|
|
|
|
struct A<T> {
|
|
|
|
x: T,
|
|
|
|
}
|
|
|
|
impl<T2> A<T2> {
|
|
|
|
fn x(self) -> T2 {
|
|
|
|
self.x
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn id<T>(t: T) -> T { t }
|
|
|
|
|
|
|
|
fn test() -> i128 {
|
|
|
|
let x = 1;
|
|
|
|
let y = id(x);
|
|
|
|
let a = A { x: id(y) };
|
|
|
|
let z = id(a.x);
|
|
|
|
let b = A { x: z };
|
|
|
|
b.x()
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-20 17:08:25 +00:00
|
|
|
#[test]
|
2019-02-21 10:04:14 +00:00
|
|
|
fn infer_associated_const() {
|
|
|
|
check_inference(
|
|
|
|
"infer_associated_const",
|
|
|
|
r#"
|
|
|
|
struct Struct;
|
|
|
|
|
|
|
|
impl Struct {
|
|
|
|
const FOO: u32 = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Enum;
|
|
|
|
|
|
|
|
impl Enum {
|
|
|
|
const BAR: u32 = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
trait Trait {
|
|
|
|
const ID: u32;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct TraitTest;
|
|
|
|
|
|
|
|
impl Trait for TraitTest {
|
|
|
|
const ID: u32 = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test() {
|
|
|
|
let x = Struct::FOO;
|
|
|
|
let y = Enum::BAR;
|
|
|
|
let z = TraitTest::ID;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_associated_method_struct() {
|
|
|
|
check_inference(
|
|
|
|
"infer_associated_method_struct",
|
|
|
|
r#"
|
|
|
|
struct A { x: u32 };
|
|
|
|
|
|
|
|
impl A {
|
|
|
|
fn new() -> A {
|
|
|
|
A { x: 0 }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn test() {
|
|
|
|
let a = A::new();
|
|
|
|
a.x;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_associated_method_enum() {
|
|
|
|
check_inference(
|
|
|
|
"infer_associated_method_enum",
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_associated_method_with_modules() {
|
|
|
|
check_inference(
|
|
|
|
"infer_associated_method_with_modules",
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_associated_method_generics() {
|
|
|
|
check_inference(
|
|
|
|
"infer_associated_method_generics",
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-24 16:25:41 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_type_alias() {
|
|
|
|
check_inference(
|
|
|
|
"infer_type_alias",
|
|
|
|
r#"
|
|
|
|
struct A<X, Y> { x: X, y: Y };
|
|
|
|
type Foo = A<u32, i128>;
|
|
|
|
type Bar<T> = A<T, u128>;
|
|
|
|
type Baz<U, V> = A<V, U>;
|
|
|
|
fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
|
|
|
|
x.x;
|
|
|
|
x.y;
|
|
|
|
y.x;
|
|
|
|
y.y;
|
|
|
|
z.x;
|
|
|
|
z.y;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-02-24 16:29:07 +00:00
|
|
|
#[test]
|
|
|
|
#[should_panic] // we currently can't handle this
|
|
|
|
fn recursive_type_alias() {
|
|
|
|
check_inference(
|
|
|
|
"recursive_type_alias",
|
|
|
|
r#"
|
|
|
|
struct A<X> {};
|
|
|
|
type Foo = Foo;
|
|
|
|
type Bar = A<Bar>;
|
|
|
|
fn test(x: Foo) {}
|
|
|
|
"#,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-02-21 10:04:14 +00:00
|
|
|
#[test]
|
2019-01-20 17:08:25 +00:00
|
|
|
fn no_panic_on_field_of_enum() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"no_panic_on_field_of_enum",
|
2019-01-20 17:08:25 +00:00
|
|
|
r#"
|
|
|
|
enum X {}
|
|
|
|
|
|
|
|
fn test(x: X) {
|
|
|
|
x.some_field;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-21 20:42:19 +00:00
|
|
|
#[test]
|
|
|
|
fn bug_585() {
|
|
|
|
check_inference(
|
2019-01-21 21:52:35 +00:00
|
|
|
"bug_585",
|
2019-01-21 20:42:19 +00:00
|
|
|
r#"
|
|
|
|
fn test() {
|
|
|
|
X {};
|
|
|
|
match x {
|
|
|
|
A::B {} => (),
|
|
|
|
A::Y() => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-01-25 20:32:49 +00:00
|
|
|
#[test]
|
|
|
|
fn bug_651() {
|
|
|
|
check_inference(
|
|
|
|
"bug_651",
|
|
|
|
r#"
|
|
|
|
fn quux() {
|
|
|
|
let y = 92;
|
|
|
|
1 + y;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2019-01-26 22:48:01 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn recursive_vars() {
|
2019-01-26 22:57:03 +00:00
|
|
|
covers!(type_var_cycles_resolve_completely);
|
|
|
|
covers!(type_var_cycles_resolve_as_possible);
|
2019-01-26 22:48:01 +00:00
|
|
|
check_inference(
|
|
|
|
"recursive_vars",
|
|
|
|
r#"
|
|
|
|
fn test() {
|
|
|
|
let y = unknown;
|
|
|
|
[y, &y];
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn recursive_vars_2() {
|
2019-01-26 22:57:03 +00:00
|
|
|
covers!(type_var_cycles_resolve_completely);
|
|
|
|
covers!(type_var_cycles_resolve_as_possible);
|
2019-01-26 22:48:01 +00:00
|
|
|
check_inference(
|
|
|
|
"recursive_vars_2",
|
|
|
|
r#"
|
|
|
|
fn test() {
|
|
|
|
let x = unknown;
|
|
|
|
let y = unknown;
|
|
|
|
[(x, y), (&y, &x)];
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2019-01-25 20:16:02 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_type_param() {
|
|
|
|
check_inference(
|
2019-01-27 16:59:09 +00:00
|
|
|
"infer_type_param",
|
2019-01-25 20:16:02 +00:00
|
|
|
r#"
|
|
|
|
fn id<T>(x: T) -> T {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clone<T>(x: &T) -> T {
|
|
|
|
x
|
|
|
|
}
|
|
|
|
|
|
|
|
fn test() {
|
|
|
|
let y = 10u32;
|
|
|
|
id(y);
|
|
|
|
let x: bool = clone(z);
|
2019-01-27 16:59:09 +00:00
|
|
|
id::<i128>(1);
|
2019-01-25 20:16:02 +00:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
2019-01-25 20:32:49 +00:00
|
|
|
|
2019-02-09 17:24:54 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_std_crash_1() {
|
|
|
|
// caused stack overflow, taken from std
|
|
|
|
check_inference(
|
|
|
|
"infer_std_crash_1",
|
|
|
|
r#"
|
|
|
|
enum Maybe<T> {
|
|
|
|
Real(T),
|
|
|
|
Fake,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write() {
|
|
|
|
match something_unknown {
|
|
|
|
Maybe::Real(ref mut something) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_std_crash_2() {
|
2019-02-09 21:03:01 +00:00
|
|
|
covers!(type_var_resolves_to_int_var);
|
2019-02-09 17:24:54 +00:00
|
|
|
// caused "equating two type variables, ...", taken from std
|
|
|
|
check_inference(
|
|
|
|
"infer_std_crash_2",
|
|
|
|
r#"
|
|
|
|
fn test_line_buffer() {
|
|
|
|
&[0, b'\n', 1, b'\n'];
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-09 18:07:35 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_std_crash_3() {
|
|
|
|
// taken from rustc
|
|
|
|
check_inference(
|
|
|
|
"infer_std_crash_3",
|
|
|
|
r#"
|
|
|
|
pub fn compute() {
|
|
|
|
match _ {
|
|
|
|
SizeSkeleton::Pointer { non_zero: true, tail } => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-09 19:55:51 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_std_crash_4() {
|
|
|
|
// taken from rustc
|
|
|
|
check_inference(
|
|
|
|
"infer_std_crash_4",
|
|
|
|
r#"
|
|
|
|
pub fn primitive_type() {
|
|
|
|
match *self {
|
|
|
|
BorrowedRef { type_: box Primitive(p), ..} => {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-09 20:31:31 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_std_crash_5() {
|
|
|
|
// taken from rustc
|
|
|
|
check_inference(
|
|
|
|
"infer_std_crash_5",
|
|
|
|
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
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-11 22:01:52 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_nested_generics_crash() {
|
|
|
|
// another crash found typechecking rustc
|
|
|
|
check_inference(
|
|
|
|
"infer_nested_generics_crash",
|
|
|
|
r#"
|
|
|
|
struct Canonical<V> {
|
|
|
|
value: V,
|
|
|
|
}
|
|
|
|
struct QueryResponse<V> {
|
|
|
|
value: V,
|
|
|
|
}
|
|
|
|
fn test<R>(query_response: Canonical<QueryResponse<R>>) {
|
|
|
|
&query_response.value;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-23 11:32:25 +00:00
|
|
|
#[test]
|
|
|
|
fn cross_crate_associated_method_call() {
|
|
|
|
let (mut db, pos) = MockDatabase::with_position(
|
|
|
|
r#"
|
|
|
|
//- /main.rs
|
|
|
|
fn test() {
|
|
|
|
let x = other_crate::foo::S::thing();
|
|
|
|
x<|>;
|
|
|
|
}
|
|
|
|
|
|
|
|
//- /lib.rs
|
|
|
|
mod foo {
|
|
|
|
struct S;
|
|
|
|
impl S {
|
|
|
|
fn thing() -> i128 {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
db.set_crate_graph_from_fixture(crate_graph! {
|
|
|
|
"main": ("/main.rs", ["other_crate"]),
|
|
|
|
"other_crate": ("/lib.rs", []),
|
|
|
|
});
|
|
|
|
assert_eq!("i128", type_at_pos(&db, pos));
|
|
|
|
}
|
|
|
|
|
2019-02-25 07:27:47 +00:00
|
|
|
#[test]
|
|
|
|
fn infer_const() {
|
|
|
|
check_inference(
|
|
|
|
"infer_const",
|
|
|
|
r#"
|
|
|
|
struct Foo;
|
|
|
|
impl Foo { const ASSOC_CONST: u32 = 0; }
|
|
|
|
const GLOBAL_CONST: u32 = 101;
|
|
|
|
fn test() {
|
|
|
|
const LOCAL_CONST: u32 = 99;
|
|
|
|
let x = LOCAL_CONST;
|
|
|
|
let z = GLOBAL_CONST;
|
|
|
|
let id = Foo::ASSOC_CONST;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn infer_static() {
|
|
|
|
check_inference(
|
|
|
|
"infer_static",
|
|
|
|
r#"
|
|
|
|
static GLOBAL_STATIC: u32 = 101;
|
|
|
|
static mut GLOBAL_STATIC_MUT: u32 = 101;
|
|
|
|
fn test() {
|
|
|
|
static LOCAL_STATIC: u32 = 99;
|
|
|
|
static mut LOCAL_STATIC_MUT: u32 = 99;
|
|
|
|
let x = LOCAL_STATIC;
|
|
|
|
let y = LOCAL_STATIC_MUT;
|
|
|
|
let z = GLOBAL_STATIC;
|
|
|
|
let w = GLOBAL_STATIC_MUT;
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-02-23 11:32:25 +00:00
|
|
|
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
|
|
|
let func = source_binder::function_from_position(db, pos).unwrap();
|
|
|
|
let body_syntax_mapping = func.body_syntax_mapping(db);
|
|
|
|
let inference_result = func.infer(db);
|
|
|
|
let (_, syntax) = func.source(db);
|
|
|
|
let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap();
|
|
|
|
let expr = body_syntax_mapping.node_expr(node).unwrap();
|
|
|
|
let ty = &inference_result[expr];
|
|
|
|
ty.to_string()
|
|
|
|
}
|
|
|
|
|
2018-12-24 14:36:54 +00:00
|
|
|
fn infer(content: &str) -> String {
|
2018-12-23 11:15:46 +00:00
|
|
|
let (db, _, file_id) = MockDatabase::with_single_file(content);
|
2019-01-26 08:51:36 +00:00
|
|
|
let source_file = db.parse(file_id);
|
2018-12-23 11:05:54 +00:00
|
|
|
let mut acc = String::new();
|
2019-02-08 11:49:43 +00:00
|
|
|
for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) {
|
2019-01-15 15:13:11 +00:00
|
|
|
let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap();
|
2019-01-15 17:54:18 +00:00
|
|
|
let inference_result = func.infer(&db);
|
2019-01-15 16:04:49 +00:00
|
|
|
let body_syntax_mapping = func.body_syntax_mapping(&db);
|
2019-01-06 22:01:33 +00:00
|
|
|
let mut types = Vec::new();
|
2019-01-06 22:57:39 +00:00
|
|
|
for (pat, ty) in inference_result.type_of_pat.iter() {
|
2019-01-07 00:10:29 +00:00
|
|
|
let syntax_ptr = match body_syntax_mapping.pat_syntax(pat) {
|
|
|
|
Some(sp) => sp,
|
|
|
|
None => continue,
|
2019-01-06 15:47:59 +00:00
|
|
|
};
|
2019-01-06 22:01:33 +00:00
|
|
|
types.push((syntax_ptr, ty));
|
2019-01-06 15:47:59 +00:00
|
|
|
}
|
2019-01-06 22:57:39 +00:00
|
|
|
for (expr, ty) in inference_result.type_of_expr.iter() {
|
2019-01-07 00:10:29 +00:00
|
|
|
let syntax_ptr = match body_syntax_mapping.expr_syntax(expr) {
|
|
|
|
Some(sp) => sp,
|
|
|
|
None => continue,
|
2019-01-06 15:47:59 +00:00
|
|
|
};
|
2019-01-06 22:01:33 +00:00
|
|
|
types.push((syntax_ptr, ty));
|
2019-01-06 15:47:59 +00:00
|
|
|
}
|
2019-01-06 22:01:33 +00:00
|
|
|
// sort ranges for consistency
|
|
|
|
types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end()));
|
2019-01-06 15:47:59 +00:00
|
|
|
for (syntax_ptr, ty) in &types {
|
2019-01-23 14:37:10 +00:00
|
|
|
let node = syntax_ptr.to_node(&source_file);
|
2018-12-23 11:15:46 +00:00
|
|
|
write!(
|
|
|
|
acc,
|
|
|
|
"{} '{}': {}\n",
|
|
|
|
syntax_ptr.range(),
|
|
|
|
ellipsize(node.text().to_string().replace("\n", " "), 15),
|
|
|
|
ty
|
|
|
|
)
|
|
|
|
.unwrap();
|
2018-12-20 20:56:28 +00:00
|
|
|
}
|
|
|
|
}
|
2018-12-23 11:05:54 +00:00
|
|
|
acc
|
|
|
|
}
|
|
|
|
|
2019-01-21 21:52:35 +00:00
|
|
|
fn check_inference(name: &str, content: &str) {
|
2018-12-24 14:36:54 +00:00
|
|
|
let result = infer(content);
|
|
|
|
|
2019-01-21 21:52:35 +00:00
|
|
|
insta::assert_snapshot_matches!(&name, &result);
|
2018-12-24 14:36:54 +00:00
|
|
|
}
|
|
|
|
|
2018-12-23 11:05:54 +00:00
|
|
|
fn ellipsize(mut text: String, max_len: usize) -> String {
|
|
|
|
if text.len() <= max_len {
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
let ellipsis = "...";
|
|
|
|
let e_len = ellipsis.len();
|
|
|
|
let mut prefix_len = (max_len - e_len) / 2;
|
|
|
|
while !text.is_char_boundary(prefix_len) {
|
|
|
|
prefix_len += 1;
|
|
|
|
}
|
|
|
|
let mut suffix_len = max_len - e_len - prefix_len;
|
|
|
|
while !text.is_char_boundary(text.len() - suffix_len) {
|
|
|
|
suffix_len += 1;
|
|
|
|
}
|
|
|
|
text.replace_range(prefix_len..text.len() - suffix_len, ellipsis);
|
|
|
|
text
|
2018-12-20 20:56:28 +00:00
|
|
|
}
|
|
|
|
|
2019-01-05 12:42:47 +00:00
|
|
|
#[test]
|
|
|
|
fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
|
|
|
|
let (mut db, pos) = MockDatabase::with_position(
|
|
|
|
"
|
|
|
|
//- /lib.rs
|
|
|
|
fn foo() -> i32 {
|
|
|
|
<|>1 + 1
|
|
|
|
}
|
|
|
|
",
|
|
|
|
);
|
2019-01-15 15:13:11 +00:00
|
|
|
let func = source_binder::function_from_position(&db, pos).unwrap();
|
2019-01-05 12:42:47 +00:00
|
|
|
{
|
|
|
|
let events = db.log_executed(|| {
|
2019-01-15 17:54:18 +00:00
|
|
|
func.infer(&db);
|
2019-01-05 12:42:47 +00:00
|
|
|
});
|
|
|
|
assert!(format!("{:?}", events).contains("infer"))
|
|
|
|
}
|
|
|
|
|
|
|
|
let new_text = "
|
|
|
|
fn foo() -> i32 {
|
|
|
|
1
|
|
|
|
+
|
|
|
|
1
|
|
|
|
}
|
|
|
|
"
|
|
|
|
.to_string();
|
|
|
|
|
2019-02-08 11:49:43 +00:00
|
|
|
db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text));
|
2019-01-05 12:42:47 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
let events = db.log_executed(|| {
|
2019-01-15 17:54:18 +00:00
|
|
|
func.infer(&db);
|
2019-01-05 12:42:47 +00:00
|
|
|
});
|
|
|
|
assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events)
|
|
|
|
}
|
|
|
|
}
|