Repository: rust-analyzer/rust-analyzer
Pull request #5127 (2020-06-29 15:24:56)

Update the rest of the tests


bors r+
🤖


Patch:
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index f7a885eb3e..26b3c813a1 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -41,6 +41,10 @@ pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextSize) ->
     ancestors_at_offset(syntax, offset).find_map(N::cast)
 }
 
+pub fn find_node_at_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<N> {
+    find_covering_element(syntax, range).ancestors().find_map(N::cast)
+}
+
 /// Skip to next non `trivia` token
 pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> {
     while token.kind().is_trivia() {


Test patch:
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 9c2c6959dd..0481a7b12a 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -154,6 +154,19 @@ impl TestDB {
         });
         (buf, count)
     }
+
+    pub fn all_files(&self) -> Vec<FileId> {
+        let mut res = Vec::new();
+        let crate_graph = self.crate_graph();
+        for krate in crate_graph.iter() {
+            let crate_def_map = self.crate_def_map(krate);
+            for (module_id, _) in crate_def_map.modules.iter() {
+                let file_id = crate_def_map[module_id].origin.file_id();
+                res.extend(file_id)
+            }
+        }
+        res
+    }
 }
 
 impl TestDB {
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 2a85ce85d6..5424e6bb19 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -17,17 +17,18 @@ use hir_def::{
     item_scope::ItemScope,
     keys,
     nameres::CrateDefMap,
-    AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
+    AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
 };
 use hir_expand::{db::AstDatabase, InFile};
 use insta::assert_snapshot;
-use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
+use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase};
 use ra_syntax::{
     algo,
     ast::{self, AstNode},
     SyntaxNode,
 };
 use stdx::format_to;
+use test_utils::extract_annotations;
 
 use crate::{
     db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
@@ -37,21 +38,38 @@ use crate::{
 // against snapshots of the expected results using insta. Use cargo-insta to
 // update the snapshots.
 
-fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
-    type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
+fn check_types(ra_fixture: &str) {
+    check_types_impl(ra_fixture, false)
 }
 
-fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String {
-    type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap())
+fn check_types_source_code(ra_fixture: &str) {
+    check_types_impl(ra_fixture, true)
 }
 
-fn type_at_pos_displayed(
-    db: &TestDB,
-    pos: FilePosition,
-    display_fn: impl FnOnce(&Ty, ModuleId) -> String,
-) -> String {
+fn check_types_impl(ra_fixture: &str, display_source: bool) {
+    let db = TestDB::with_files(ra_fixture);
+    let mut checked_one = false;
+    for file_id in db.all_files() {
+        let text = db.parse(file_id).syntax_node().to_string();
+        let annotations = extract_annotations(&text);
+        for (range, expected) in annotations {
+            let ty = type_at_range(&db, FileRange { file_id, range });
+            let actual = if display_source {
+                let module = db.module_for_file(file_id);
+                ty.display_source_code(&db, module).unwrap()
+            } else {
+                ty.display(&db).to_string()
+            };
+            assert_eq!(expected, actual);
+            checked_one = true;
+        }
+    }
+    assert!(checked_one, "no `//^` annotations found");
+}
+
+fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
     let file = db.parse(pos.file_id).ok().unwrap();
-    let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
+    let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap();
     let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
     let module = db.module_for_file(pos.file_id);
     let func = *module.child_by_source(db)[keys::FUNCTION]
@@ -61,17 +79,11 @@ fn type_at_pos_displayed(
     let (_body, source_map) = db.body_with_source_map(func.into());
     if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
         let infer = db.infer(func.into());
-        let ty = &infer[expr_id];
-        return display_fn(ty, module);
+        return infer[expr_id].clone();
     }
     panic!("Can't find expression")
 }
 
-fn type_at(ra_fixture: &str) -> String {
-    let (db, file_pos) = TestDB::with_position(ra_fixture);
-    type_at_pos(&db, file_pos)
-}
-
 fn infer(ra_fixture: &str) -> String {
     infer_with_mismatches(ra_fixture, false)
 }
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 5a1c6ccc35..136d28a916 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,7 +1,8 @@
-use super::infer_with_mismatches;
 use insta::assert_snapshot;
 use test_utils::mark;
 
+use super::infer_with_mismatches;
+
 // Infer with some common definitions and impls.
 fn infer(source: &str) -> String {
     let defs = r#"
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs
index 5dfa0a0145..b502135d8e 100644
--- a/crates/ra_hir_ty/src/tests/display_source_code.rs
+++ b/crates/ra_hir_ty/src/tests/display_source_code.rs
@@ -1,50 +1,41 @@
-use super::displayed_source_at_pos;
-use crate::test_db::TestDB;
-use ra_db::fixture::WithFixture;
+use super::check_types_source_code;
 
 #[test]
 fn qualify_path_to_submodule() {
-    let (db, pos) = TestDB::with_position(
+    check_types_source_code(
         r#"
-//- /main.rs
-
 mod foo {
     pub struct Foo;
 }
 
 fn bar() {
     let foo: foo::Foo = foo::Foo;
-    foo<|>
-}
+    foo
+}  //^ foo::Foo
 
 "#,
     );
-    assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos));
 }
 
 #[test]
 fn omit_default_type_parameters() {
-    let (db, pos) = TestDB::with_position(
-        r"
-        //- /main.rs
-        struct Foo<T = u8> { t: T }
-        fn main() {
-            let foo = Foo { t: 5u8 };
-            foo<|>;
-        }
-        ",
+    check_types_source_code(
+        r#"
+struct Foo<T = u8> { t: T }
+fn main() {
+    let foo = Foo { t: 5u8 };
+    foo;
+}  //^ Foo
+"#,
     );
-    assert_eq!("Foo", displayed_source_at_pos(&db, pos));
 
-    let (db, pos) = TestDB::with_position(
-        r"
-        //- /main.rs
-        struct Foo<K, T = u8> { k: K, t: T }
-        fn main() {
-            let foo = Foo { k: 400, t: 5u8 };
-            foo<|>;
-        }
-        ",
+    check_types_source_code(
+        r#"
+struct Foo<K, T = u8> { k: K, t: T }
+fn main() {
+    let foo = Foo { k: 400, t: 5u8 };
+    foo;
+}   //^ Foo<i32>
+"#,
     );
-    assert_eq!("Foo<i32>", displayed_source_at_pos(&db, pos));
 }
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index be2b48dcc0..45c4e309e2 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -1,16 +1,13 @@
 use std::fs;
 
 use insta::assert_snapshot;
-use ra_db::fixture::WithFixture;
 use test_utils::project_dir;
 
-use crate::test_db::TestDB;
-
-use super::{infer, type_at, type_at_pos};
+use super::{check_types, infer};
 
 #[test]
 fn cfg_impl_def() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:foo cfg:test
 use foo::S as T;
@@ -28,8 +25,8 @@ impl S {
 
 fn test() {
     let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
-    t<|>;
-}
+    t;
+} //^ (i32, {unknown}, i32, {unknown})
 
 //- /foo.rs crate:foo
 struct S;
@@ -45,7 +42,6 @@ impl S {
 }
 "#,
     );
-    assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -253,26 +249,24 @@ fn foo() {
 
 #[test]
 fn processes_impls_generated_by_macros() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 macro_rules! m {
     ($ident:ident) => (impl Trait for $ident {})
 }
 trait Trait { fn foo(self) -> u128 {} }
 struct S;
 m!(S);
-fn test() { S.foo()<|>; }
+fn test() { S.foo(); }
+                //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn infer_assoc_items_generated_by_macros() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 macro_rules! m {
     () => (fn foo(&self) -> u128 {0})
 }
@@ -281,17 +275,16 @@ impl S {
     m!();
 }
 
-fn test() { S.foo()<|>; }
+fn test() { S.foo(); }
+                //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn infer_assoc_items_generated_by_macros_chain() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 macro_rules! m_inner {
     () => {fn foo(&self) -> u128 {0}}
 }
@@ -304,21 +297,21 @@ impl S {
     m!();
 }
 
-fn test() { S.foo()<|>; }
+fn test() { S.foo(); }
+                //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn infer_macro_with_dollar_crate_is_correct_in_expr() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:foo
 fn test() {
     let x = (foo::foo!(1), foo::foo!(2));
-    x<|>;
-}
+    x;
+} //^ (i32, usize)
 
 //- /lib.rs crate:foo
 #[macro_export]
@@ -335,12 +328,11 @@ macro_rules! bar {
 pub fn baz() -> usize { 31usize }
 "#,
     );
-    assert_eq!("(i32, usize)", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:foo
 use foo::Trait;
@@ -348,7 +340,8 @@ use foo::Trait;
 fn test() {
     let msg = foo::Message(foo::MessageRef);
     let r = msg.deref();
-    r<|>;
+    r;
+  //^ &MessageRef
 }
 
 //- /lib.rs crate:foo
@@ -375,7 +368,6 @@ macro_rules! expand {
 expand!();
 "#,
     );
-    assert_eq!("&MessageRef", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -429,13 +421,13 @@ fn main() {
 
 #[test]
 fn infer_local_inner_macros() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:foo
 fn test() {
     let x = foo::foo!(1);
-    x<|>;
-}
+    x;
+} //^ i32
 
 //- /lib.rs crate:foo
 #[macro_export(local_inner_macros)]
@@ -450,7 +442,6 @@ macro_rules! bar {
 
 "#,
     );
-    assert_eq!("i32", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -531,7 +522,7 @@ fn main() {
 
 #[test]
 fn infer_builtin_macros_include() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs
 #[rustc_builtin_macro]
@@ -540,14 +531,13 @@ macro_rules! include {() => {}}
 include!("foo.rs");
 
 fn main() {
-    bar()<|>;
-}
+    bar();
+}     //^ u32
 
 //- /foo.rs
 fn bar() -> u32 {0}
 "#,
     );
-    assert_eq!("u32", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -565,18 +555,17 @@ macro_rules! include {() => {}}
 include!("foo.rs");
 
 fn main() {
-    RegisterBlock { }<|>;
+    RegisterBlock { };
+                  //^ RegisterBlock
 }
     "#;
     let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file);
-
-    let (db, pos) = TestDB::with_position(&fixture);
-    assert_eq!("RegisterBlock", type_at_pos(&db, pos));
+    check_types(&fixture);
 }
 
 #[test]
 fn infer_builtin_macros_include_concat() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs
 #[rustc_builtin_macro]
@@ -588,19 +577,18 @@ macro_rules! concat {() => {}}
 include!(concat!("f", "oo.rs"));
 
 fn main() {
-    bar()<|>;
-}
+    bar();
+}     //^ u32
 
 //- /foo.rs
 fn bar() -> u32 {0}
 "#,
     );
-    assert_eq!("u32", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_builtin_macros_include_concat_with_bad_env_should_failed() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs
 #[rustc_builtin_macro]
@@ -615,32 +603,29 @@ macro_rules! env {() => {}}
 include!(concat!(env!("OUT_DIR"), "/foo.rs"));
 
 fn main() {
-    bar()<|>;
-}
+    bar();
+}     //^ {unknown}
 
 //- /foo.rs
 fn bar() -> u32 {0}
 "#,
     );
-    assert_eq!("{unknown}", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_builtin_macros_include_itself_should_failed() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
-//- /main.rs
 #[rustc_builtin_macro]
 macro_rules! include {() => {}}
 
 include!("main.rs");
 
 fn main() {
-    0<|>
-}
+    0
+} //^ i32
 "#,
     );
-    assert_eq!("i32", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -686,14 +671,14 @@ fn main() {
 
 #[test]
 fn infer_derive_clone_simple() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
 #[derive(Clone)]
 struct S;
 fn test() {
-    S.clone()<|>;
-}
+    S.clone();
+}         //^ S
 
 //- /lib.rs crate:core
 #[prelude_import]
@@ -705,12 +690,11 @@ mod clone {
 }
 "#,
     );
-    assert_eq!("S", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_derive_clone_in_core() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /lib.rs crate:core
 #[prelude_import]
@@ -726,16 +710,15 @@ pub struct S;
 //- /main.rs crate:main deps:core
 use core::S;
 fn test() {
-    S.clone()<|>;
-}
+    S.clone();
+}         //^ S
 "#,
     );
-    assert_eq!("S", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_derive_clone_with_params() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
 #[derive(Clone)]
@@ -744,7 +727,8 @@ struct S;
 struct Wrapper<T>(T);
 struct NonClone;
 fn test() {
-    (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
+    (Wrapper(S).clone(), Wrapper(NonClone).clone());
+  //^ (Wrapper<S>, {unknown})
 }
 
 //- /lib.rs crate:core
@@ -757,13 +741,12 @@ mod clone {
 }
 "#,
     );
-    assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_custom_derive_simple() {
     // FIXME: this test current now do nothing
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main
 use foo::Foo;
@@ -772,11 +755,10 @@ use foo::Foo;
 struct S{}
 
 fn test() {
-    S{}<|>;
-}
+    S{};
+}   //^ S
 "#,
     );
-    assert_eq!("S", type_at_pos(&db, pos));
 }
 
 #[test]
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 20329bae47..9c8f223141 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -1,7 +1,6 @@
-use super::{infer, type_at, type_at_pos};
-use crate::test_db::TestDB;
 use insta::assert_snapshot;
-use ra_db::fixture::WithFixture;
+
+use super::{check_types, infer};
 
 #[test]
 fn infer_slice_method() {
@@ -246,13 +245,13 @@ fn test() {
 
 #[test]
 fn cross_crate_associated_method_call() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:other_crate
 fn test() {
     let x = other_crate::foo::S::thing();
-    x<|>;
-}
+    x;
+} //^ i128
 
 //- /lib.rs crate:other_crate
 mod foo {
@@ -263,7 +262,6 @@ mod foo {
 }
 "#,
     );
-    assert_eq!("i128", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -684,135 +682,127 @@ fn test() {
 
 #[test]
 fn method_resolution_unify_impl_self_type() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct S<T>;
 impl S<u32> { fn foo(&self) -> u8 {} }
 impl S<i32> { fn foo(&self) -> i8 {} }
-fn test() { (S::<u32>.foo(), S::<i32>.foo())<|>; }
+fn test() { (S::<u32>.foo(), S::<i32>.foo()); }
+          //^ (u8, i8)
 "#,
     );
-    assert_eq!(t, "(u8, i8)");
 }
 
 #[test]
 fn method_resolution_trait_before_autoref() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 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()<|>; }
+fn test() { S.foo(); }
+                //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn method_resolution_by_value_before_autoref() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Clone { fn clone(&self) -> Self; }
 struct S;
 impl Clone for S {}
 impl Clone for &S {}
-fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; }
+fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
+          //^ (S, S, &S)
 "#,
     );
-    assert_eq!(t, "(S, S, &S)");
 }
 
 #[test]
 fn method_resolution_trait_before_autoderef() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 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()<|>; }
+fn test() { (&S).foo(); }
+                   //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn method_resolution_impl_before_trait() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 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()<|>; }
+fn test() { S.foo(); }
+                //^ i8
 "#,
     );
-    assert_eq!(t, "i8");
 }
 
 #[test]
 fn method_resolution_impl_ref_before_trait() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 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()<|>; }
+fn test() { S.foo(); }
+                //^ i8
 "#,
     );
-    assert_eq!(t, "i8");
 }
 
 #[test]
 fn method_resolution_trait_autoderef() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl Trait for S { fn foo(self) -> u128 { 0 } }
-fn test() { (&S).foo()<|>; }
+fn test() { (&S).foo(); }
+                   //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn method_resolution_unsize_array() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 #[lang = "slice"]
 impl<T> [T] {
     fn len(&self) -> usize { loop {} }
 }
 fn test() {
     let a = [1, 2, 3];
-    a.len()<|>;
-}
+    a.len();
+}       //^ usize
 "#,
     );
-    assert_eq!(t, "usize");
 }
 
 #[test]
 fn method_resolution_trait_from_prelude() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:other_crate
 struct S;
 impl Clone for S {}
 
 fn test() {
-    S.clone()<|>;
+    S.clone();
+          //^ S
 }
 
 //- /lib.rs crate:other_crate
@@ -825,115 +815,107 @@ mod foo {
 }
 "#,
     );
-    assert_eq!("S", type_at_pos(&db, pos));
 }
 
 #[test]
 fn method_resolution_where_clause_for_unknown_trait() {
     // The blanket impl currently applies because we ignore the unresolved where clause
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl<T> Trait for T where T: UnknownTrait {}
-fn test() { (&S).foo()<|>; }
+fn test() { (&S).foo(); }
+                   //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn method_resolution_where_clause_not_met() {
     // The blanket impl shouldn't apply because we can't prove S: Clone
-    let t = type_at(
+    // 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#"
-//- /main.rs
 trait Clone {}
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl<T> Trait for T where T: Clone {}
-fn test() { (&S).foo()<|>; }
+fn test() { (&S).foo(); }
+                   //^ {unknown}
 "#,
     );
-    // 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
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn method_resolution_where_clause_inline_not_met() {
     // The blanket impl shouldn't apply because we can't prove S: Clone
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Clone {}
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl<T: Clone> Trait for T {}
-fn test() { (&S).foo()<|>; }
+fn test() { (&S).foo(); }
+                   //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn method_resolution_where_clause_1() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Clone {}
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl Clone for S {}
 impl<T> Trait for T where T: Clone {}
-fn test() { S.foo()<|>; }
+fn test() { S.foo(); }
+                //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn method_resolution_where_clause_2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Into<T> { fn into(self) -> T; }
 trait From<T> { fn from(other: T) -> Self; }
 struct S1;
 struct S2;
 impl From<S2> for S1 {}
 impl<T, U> Into<U> for T where U: From<T> {}
-fn test() { S2.into()<|>; }
+fn test() { S2.into(); }
+                  //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn method_resolution_where_clause_inline() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Into<T> { fn into(self) -> T; }
 trait From<T> { fn from(other: T) -> Self; }
 struct S1;
 struct S2;
 impl From<S2> for S1 {}
 impl<T, U: From<T>> Into<U> for T {}
-fn test() { S2.into()<|>; }
+fn test() { S2.into(); }
+                  //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn method_resolution_overloaded_method() {
     test_utils::mark::check!(impl_self_type_match_without_receiver);
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct Wrapper<T>(T);
 struct Foo<T>(T);
 struct Bar<T>(T);
@@ -953,30 +935,30 @@ impl<T> Wrapper<Bar<T>> {
 fn main() {
     let a = Wrapper::<Foo<f32>>::new(1.0);
     let b = Wrapper::<Bar<f32>>::new(1.0);
-    (a, b)<|>;
+    (a, b);
+  //^ (Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)
 }
 "#,
     );
-    assert_eq!(t, "(Wrapper<Foo<f32>>, Wrapper<Bar<f32>>)")
 }
 
 #[test]
 fn method_resolution_encountering_fn_type() {
-    type_at(
+    check_types(
         r#"
 //- /main.rs
 fn foo() {}
 trait FnOnce { fn call(self); }
-fn test() { foo.call()<|>; }
+fn test() { foo.call(); }
+                   //^ {unknown}
 "#,
     );
 }
 
 #[test]
 fn method_resolution_non_parameter_type() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 mod a {
     pub trait Foo {
         fn foo(&self);
@@ -988,18 +970,16 @@ fn foo<T>(t: Wrapper<T>)
 where
     Wrapper<T>: a::Foo,
 {
-    t.foo()<|>;
-}
+    t.foo();
+}       //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn method_resolution_3373() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct A<T>(T);
 
 impl A<i32> {
@@ -1007,19 +987,17 @@ impl A<i32> {
 }
 
 fn main() {
-    A::from(3)<|>;
-}
+    A::from(3);
+}          //^ A<i32>
 "#,
     );
-    assert_eq!(t, "A<i32>");
 }
 
 #[test]
 fn method_resolution_slow() {
     // this can get quite slow if we set the solver size limit too high
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait SendX {}
 
 struct S1; impl SendX for S1 {}
@@ -1037,10 +1015,10 @@ trait FnX {}
 
 impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
 
-fn test() { (S {}).method()<|>; }
+fn test() { (S {}).method(); }
+                        //^ ()
 "#,
     );
-    assert_eq!(t, "()");
 }
 
 #[test]
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs
index ab9a990f59..64d421d405 100644
--- a/crates/ra_hir_ty/src/tests/never_type.rs
+++ b/crates/ra_hir_ty/src/tests/never_type.rs
@@ -1,99 +1,91 @@
 use insta::assert_snapshot;
 
-use super::{infer_with_mismatches, type_at};
+use super::{check_types, infer_with_mismatches};
 
 #[test]
 fn infer_never1() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test() {
     let t = return;
-    t<|>;
-}
+    t;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn infer_never2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn gen<T>() -> T { loop {} }
 
 fn test() {
     let a = gen();
     if false { a } else { loop {} };
-    a<|>;
-}
+    a;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn infer_never3() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn gen<T>() -> T { loop {} }
 
 fn test() {
     let a = gen();
     if false { loop {} } else { a };
-    a<|>;
+    a;
+  //^ !
 }
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn never_type_in_generic_args() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { None, Some(T) }
 
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
-    a<|>;
-}
+    a;
+} //^ Option<!>
 "#,
     );
-    assert_eq!(t, "Option<!>");
 }
 
 #[test]
 fn never_type_can_be_reinferred1() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn gen<T>() -> T { loop {} }
 
 fn test() {
     let a = gen();
     if false { loop {} } else { a };
-    a<|>;
+    a;
+  //^ ()
     if false { a };
 }
 "#,
     );
-    assert_eq!(t, "()");
 }
 
 #[test]
 fn never_type_can_be_reinferred2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { None, Some(T) }
 
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
-    a<|>;
+    a;
+  //^ Option<i32>
     match 42 {
         42 => a,
         _ => Option::Some(42),
@@ -101,19 +93,18 @@ fn test() {
 }
 "#,
     );
-    assert_eq!(t, "Option<i32>");
 }
 
 #[test]
 fn never_type_can_be_reinferred3() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { None, Some(T) }
 
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
-    a<|>;
+    a;
+  //^ Option<&str>
     match 42 {
         42 => a,
         _ => Option::Some("str"),
@@ -121,82 +112,72 @@ fn test() {
 }
 "#,
     );
-    assert_eq!(t, "Option<&str>");
 }
 
 #[test]
 fn match_no_arm() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 enum Void {}
 
 fn test(a: Void) {
     let t = match a {};
-    t<|>;
-}
+    t;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn match_unknown_arm() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: Option) {
     let t = match 0 {
         _ => unknown,
     };
-    t<|>;
-}
+    t;
+} //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn if_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test() {
     let i = if true {
         loop {}
     } else {
         3.0
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn if_else_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(input: bool) {
     let i = if input {
         2.0
     } else {
         return
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn match_first_arm_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         1 => return,
@@ -204,18 +185,16 @@ fn test(a: i32) {
         3 => loop {},
         _ => 3.0,
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn match_second_arm_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         1 => 3.0,
@@ -223,45 +202,40 @@ fn test(a: i32) {
         3 => 3.0,
         _ => return,
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
 fn match_all_arms_never() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         2 => return,
         _ => loop {},
     };
-    i<|>;
-}
+    i;
+} //^ !
 "#,
     );
-    assert_eq!(t, "!");
 }
 
 #[test]
 fn match_no_never_arms() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 fn test(a: i32) {
     let i = match a {
         2 => 2.0,
         _ => 3.0,
     };
-    i<|>;
-}
+    i;
+} //^ f64
 "#,
     );
-    assert_eq!(t, "f64");
 }
 
 #[test]
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index aa37326dff..d806e0ffb3 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -1,10 +1,7 @@
 use insta::assert_snapshot;
-use ra_db::fixture::WithFixture;
 use test_utils::mark;
 
-use crate::test_db::TestDB;
-
-use super::infer;
+use super::{check_types, infer};
 
 #[test]
 fn bug_484() {
@@ -404,13 +401,13 @@ fn test() {
 
 #[test]
 fn issue_2683_chars_impl() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
 fn test() {
     let chars: std::str::Chars<'_>;
-    (chars.next(), chars.nth(1))<|>;
-}
+    (chars.next(), chars.nth(1));
+} //^ (Option<char>, Option<char>)
 
 //- /std.rs crate:std
 #[prelude_import]
@@ -449,15 +446,12 @@ pub mod str {
 }
 "#,
     );
-
-    assert_eq!("(Option<char>, Option<char>)", super::type_at_pos(&db, pos));
 }
 
 #[test]
 fn issue_3642_bad_macro_stackover() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
-//- /main.rs
 #[macro_export]
 macro_rules! match_ast {
     (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
@@ -472,7 +466,8 @@ macro_rules! match_ast {
 }
 
 fn main() {
-    let anchor<|> = match_ast! {
+    let anchor = match_ast! {
+       //^ ()
         match parent {
             as => {},
             _ => return None
@@ -480,8 +475,6 @@ fn main() {
     };
 }"#,
     );
-
-    assert_eq!("()", super::type_at_pos(&db, pos));
 }
 
 #[test]
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 5e3f2bd3c8..de63f4ccea 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -1,19 +1,17 @@
-use super::{infer, type_at, type_at_pos};
-use crate::test_db::TestDB;
 use insta::assert_snapshot;
-use ra_db::fixture::WithFixture;
+
+use super::{check_types, infer};
 
 #[test]
 fn infer_box() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
-
 fn test() {
     let x = box 1;
     let t = (x, box x, box &1, box [1]);
-    t<|>;
-}
+    t;
+} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)
 
 //- /std.rs crate:std
 #[prelude_import] use prelude::*;
@@ -25,29 +23,24 @@ mod boxed {
         inner: *mut T,
     }
 }
-
 "#,
     );
-    assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_adt_self() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
-//- /main.rs
 enum Nat { Succ(Self), Demo(Nat), Zero }
 
 fn test() {
     let foo: Nat = Nat::Zero;
     if let Nat::Succ(x) = foo {
-        x<|>
-    }
+        x
+    } //^ Nat
 }
-
 "#,
     );
-    assert_eq!("Nat", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -93,7 +86,7 @@ fn foo() {
 
 #[test]
 fn infer_ranges() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
 fn test() {
@@ -105,8 +98,8 @@ fn test() {
     let f = 'a'..='z';
 
     let t = (a, b, c, d, e, f);
-    t<|>;
-}
+    t;
+} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
 
 //- /core.rs crate:core
 #[prelude_import] use prelude::*;
@@ -135,29 +128,22 @@ pub mod ops {
 }
 "#,
     );
-    assert_eq!(
-        "(RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)",
-        type_at_pos(&db, pos),
-    );
 }
 
 #[test]
 fn infer_while_let() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
-//- /main.rs
 enum Option<T> { Some(T), None }
 
 fn test() {
     let foo: Option<f32> = None;
     while let Option::Some(x) = foo {
-        <|>x
-    }
+        x
+    } //^ f32
 }
-
 "#,
     );
-    assert_eq!("f32", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -1687,9 +1673,8 @@ fn test() {
 
 #[test]
 fn shadowing_primitive() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct i32;
 struct Foo;
 
@@ -1697,15 +1682,15 @@ impl i32 { fn foo(&self) -> Foo { Foo } }
 
 fn main() {
     let x: i32 = i32;
-    x.foo()<|>;
+    x.foo();
+        //^ Foo
 }"#,
     );
-    assert_eq!(t, "Foo");
 }
 
 #[test]
 fn not_shadowing_primitive_by_module() {
-    let t = type_at(
+    check_types(
         r#"
 //- /str.rs
 fn foo() {}
@@ -1715,15 +1700,15 @@ mod str;
 fn foo() -> &'static str { "" }
 
 fn main() {
-    foo()<|>;
+    foo();
+      //^ &str
 }"#,
     );
-    assert_eq!(t, "&str");
 }
 
 #[test]
 fn not_shadowing_module_by_primitive() {
-    let t = type_at(
+    check_types(
         r#"
 //- /str.rs
 fn foo() -> u32 {0}
@@ -1733,10 +1718,10 @@ mod str;
 fn foo() -> &'static str { "" }
 
 fn main() {
-    str::foo()<|>;
+    str::foo();
+           //^ u32
 }"#,
     );
-    assert_eq!(t, "u32");
 }
 
 // This test is actually testing the shadowing behavior within ra_hir_def. It
@@ -1744,27 +1729,7 @@ fn main() {
 // capable of asserting the necessary conditions.
 #[test]
 fn should_be_shadowing_imports() {
-    let t = type_at(
-        r#"
-mod a {
-    pub fn foo() -> i8 {0}
-    pub struct foo { a: i8 }
-}
-mod b { pub fn foo () -> u8 {0} }
-mod c { pub struct foo { a: u8 } }
-mod d {
-    pub use super::a::*;
-    pub use super::c::foo;
-    pub use super::b::foo;
-}
-
-fn main() {
-    d::foo()<|>;
-}"#,
-    );
-    assert_eq!(t, "u8");
-
-    let t = type_at(
+    check_types(
         r#"
 mod a {
     pub fn foo() -> i8 {0}
@@ -1779,10 +1744,12 @@ mod d {
 }
 
 fn main() {
-    d::foo{a:0<|>};
+    d::foo();
+         //^ u8
+    d::foo{a:0};
+           //^ u8
 }"#,
     );
-    assert_eq!(t, "u8");
 }
 
 #[test]
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 71c0c2d27e..01c919a7ec 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,17 +1,13 @@
 use insta::assert_snapshot;
-use ra_db::fixture::WithFixture;
 use test_utils::mark;
 
-use crate::test_db::TestDB;
-
-use super::{infer, infer_with_mismatches, type_at, type_at_pos};
+use super::{check_types, infer, infer_with_mismatches};
 
 #[test]
 fn infer_await() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
-
 struct IntFuture;
 
 impl Future for IntFuture {
@@ -21,8 +17,8 @@ impl Future for IntFuture {
 fn test() {
     let r = IntFuture;
     let v = r.await;
-    v<|>;
-}
+    v;
+} //^ u64
 
 //- /core.rs crate:core
 #[prelude_import] use future::*;
@@ -32,18 +28,15 @@ mod future {
         type Output;
     }
 }
-
 "#,
     );
-    assert_eq!("u64", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_async() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
-
 async fn foo() -> u64 {
     128
 }
@@ -51,8 +44,8 @@ async fn foo() -> u64 {
 fn test() {
     let r = foo();
     let v = r.await;
-    v<|>;
-}
+    v;
+} //^ u64
 
 //- /core.rs crate:core
 #[prelude_import] use future::*;
@@ -62,26 +55,23 @@ mod future {
         type Output;
     }
 }
-
 "#,
     );
-    assert_eq!("u64", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_desugar_async() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
-
 async fn foo() -> u64 {
     128
 }
 
 fn test() {
     let r = foo();
-    r<|>;
-}
+    r;
+} //^ impl Future<Output = u64>
 
 //- /core.rs crate:core
 #[prelude_import] use future::*;
@@ -93,23 +83,20 @@ mod future {
 
 "#,
     );
-    assert_eq!("impl Future<Output = u64>", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_try() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
-
 fn test() {
     let r: Result<i32, u64> = Result::Ok(1);
     let v = r?;
-    v<|>;
-}
+    v;
+} //^ i32
 
 //- /core.rs crate:core
-
 #[prelude_import] use ops::*;
 mod ops {
     trait Try {
@@ -130,30 +117,26 @@ mod result {
         type Error = E;
     }
 }
-
 "#,
     );
-    assert_eq!("i32", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_for_loop() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core,alloc
-
 use alloc::collections::Vec;
 
 fn test() {
     let v = Vec::new();
     v.push("foo");
     for x in v {
-        x<|>;
-    }
+        x;
+    } //^ &str
 }
 
 //- /core.rs crate:core
-
 #[prelude_import] use iter::*;
 mod iter {
     trait IntoIterator {
@@ -162,7 +145,6 @@ mod iter {
 }
 
 //- /alloc.rs crate:alloc deps:core
-
 mod collections {
     struct Vec<T> {}
     impl<T> Vec<T> {
@@ -176,15 +158,13 @@ mod collections {
 }
 "#,
     );
-    assert_eq!("&str", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_ops_neg() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
-
 struct Bar;
 struct Foo;
 
@@ -195,11 +175,10 @@ impl std::ops::Neg for Bar {
 fn test() {
     let a = Bar;
     let b = -a;
-    b<|>;
-}
+    b;
+} //^ Foo
 
 //- /std.rs crate:std
-
 #[prelude_import] use ops::*;
 mod ops {
     #[lang = "neg"]
@@ -209,15 +188,13 @@ mod ops {
 }
 "#,
     );
-    assert_eq!("Foo", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_ops_not() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
-
 struct Bar;
 struct Foo;
 
@@ -228,11 +205,10 @@ impl std::ops::Not for Bar {
 fn test() {
     let a = Bar;
     let b = !a;
-    b<|>;
-}
+    b;
+} //^ Foo
 
 //- /std.rs crate:std
-
 #[prelude_import] use ops::*;
 mod ops {
     #[lang = "not"]
@@ -242,7 +218,6 @@ mod ops {
 }
 "#,
     );
-    assert_eq!("Foo", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -537,10 +512,9 @@ fn indexing_arrays() {
 
 #[test]
 fn infer_ops_index() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
-
 struct Bar;
 struct Foo;
 
@@ -551,11 +525,10 @@ impl std::ops::Index<u32> for Bar {
 fn test() {
     let a = Bar;
     let b = a[1u32];
-    b<|>;
-}
+    b;
+} //^ Foo
 
 //- /std.rs crate:std
-
 #[prelude_import] use ops::*;
 mod ops {
     #[lang = "index"]
@@ -565,19 +538,18 @@ mod ops {
 }
 "#,
     );
-    assert_eq!("Foo", type_at_pos(&db, pos));
 }
 
 #[test]
 fn infer_ops_index_autoderef() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
 fn test() {
     let a = &[1u32, 2, 3];
     let b = a[1u32];
-    b<|>;
-}
+    b;
+} //^ u32
 
 //- /std.rs crate:std
 impl<T> ops::Index<u32> for [T] {
@@ -593,14 +565,12 @@ mod ops {
 }
 "#,
     );
-    assert_eq!("u32", type_at_pos(&db, pos));
 }
 
 #[test]
 fn deref_trait() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 #[lang = "deref"]
 trait Deref {
     type Target;
@@ -618,16 +588,15 @@ impl S {
 }
 
 fn test(s: Arc<S>) {
-    (*s, s.foo())<|>;
-}
+    (*s, s.foo());
+} //^ (S, u128)
 "#,
     );
-    assert_eq!(t, "(S, u128)");
 }
 
 #[test]
 fn deref_trait_with_inference_var() {
-    let t = type_at(
+    check_types(
         r#"
 //- /main.rs
 #[lang = "deref"]
@@ -647,19 +616,18 @@ fn foo(a: Arc<S>) {}
 
 fn test() {
     let a = new_arc();
-    let b = (*a)<|>;
+    let b = (*a);
+          //^ S
     foo(a);
 }
 "#,
     );
-    assert_eq!(t, "S");
 }
 
 #[test]
 fn deref_trait_infinite_recursion() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 #[lang = "deref"]
 trait Deref {
     type Target;
@@ -673,18 +641,16 @@ impl Deref for S {
 }
 
 fn test(s: S) {
-    s.foo()<|>;
-}
+    s.foo();
+}       //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn deref_trait_with_question_mark_size() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 #[lang = "deref"]
 trait Deref {
     type Target;
@@ -702,18 +668,16 @@ impl S {
 }
 
 fn test(s: Arc<S>) {
-    (*s, s.foo())<|>;
-}
+    (*s, s.foo());
+} //^ (S, u128)
 "#,
     );
-    assert_eq!(t, "(S, u128)");
 }
 
 #[test]
 fn obligation_from_function_clause() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct S;
 
 trait Trait<T> {}
@@ -722,16 +686,15 @@ impl Trait<u32> for S {}
 fn foo<T: Trait<U>, U>(t: T) -> U {}
 
 fn test(s: S) {
-    foo(s)<|>;
-}
+    (foo(s));
+} //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
 fn obligation_from_method_clause() {
-    let t = type_at(
+    check_types(
         r#"
 //- /main.rs
 struct S;
@@ -745,18 +708,16 @@ impl O {
 }
 
 fn test() {
-    O.foo(S)<|>;
-}
+    O.foo(S);
+}      //^ isize
 "#,
     );
-    assert_eq!(t, "isize");
 }
 
 #[test]
 fn obligation_from_self_method_clause() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct S;
 
 trait Trait<T> {}
@@ -767,18 +728,16 @@ impl S {
 }
 
 fn test() {
-    S.foo()<|>;
-}
+    S.foo();
+}       //^ i64
 "#,
     );
-    assert_eq!(t, "i64");
 }
 
 #[test]
 fn obligation_from_impl_clause() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct S;
 
 trait Trait<T> {}
@@ -790,32 +749,30 @@ impl<U, T: Trait<U>> O<T> {
 }
 
 fn test(o: O<S>) {
-    o.foo()<|>;
-}
+    o.foo();
+}       //^ &str
 "#,
     );
-    assert_eq!(t, "&str");
 }
 
 #[test]
 fn generic_param_env_1() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Clone {}
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl Clone for S {}
 impl<T> Trait for T where T: Clone {}
-fn test<T: Clone>(t: T) { t.foo()<|>; }
+fn test<T: Clone>(t: T) { t.foo(); }
+                             //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn generic_param_env_1_not_met() {
-    let t = type_at(
+    check_types(
         r#"
 //- /main.rs
 trait Clone {}
@@ -823,45 +780,42 @@ trait Trait { fn foo(self) -> u128; }
 struct S;
 impl Clone for S {}
 impl<T> Trait for T where T: Clone {}
-fn test<T>(t: T) { t.foo()<|>; }
+fn test<T>(t: T) { t.foo(); }
+                       //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn generic_param_env_2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl Trait for S {}
-fn test<T: Trait>(t: T) { t.foo()<|>; }
+fn test<T: Trait>(t: T) { t.foo(); }
+                              //^ u128
 "#,
     );
-    assert_eq!(t, "u128");
 }
 
 #[test]
 fn generic_param_env_2_not_met() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait { fn foo(self) -> u128; }
 struct S;
 impl Trait for S {}
-fn test<T>(t: T) { t.foo()<|>; }
+fn test<T>(t: T) { t.foo(); }
+                       //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn generic_param_env_deref() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 #[lang = "deref"]
 trait Deref {
     type Target;
@@ -870,17 +824,17 @@ trait Trait {}
 impl<T> Deref for T where T: Trait {
     type Target = i128;
 }
-fn test<T: Trait>(t: T) { (*t)<|>; }
+fn test<T: Trait>(t: T) { (*t); }
+                        //^ i128
 "#,
     );
-    assert_eq!(t, "i128");
 }
 
 #[test]
 fn associated_type_placeholder() {
-    let t = type_at(
+    // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
+    check_types(
         r#"
-//- /main.rs
 pub trait ApplyL {
     type Out;
 }
@@ -893,19 +847,16 @@ impl<T> ApplyL for RefMutL<T> {
 
 fn test<T: ApplyL>() {
     let y: <RefMutL<T> as ApplyL>::Out = no_matter;
-    y<|>;
-}
+    y;
+} //^ ApplyL::Out<T>
 "#,
     );
-    // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
-    assert_eq!(t, "ApplyL::Out<T>");
 }
 
 #[test]
 fn associated_type_placeholder_2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 pub trait ApplyL {
     type Out;
 }
@@ -913,11 +864,10 @@ fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
 
 fn test<T: ApplyL>(t: T) {
     let y = foo(t);
-    y<|>;
-}
+    y;
+} //^ ApplyL::Out<T>
 "#,
     );
-    assert_eq!(t, "ApplyL::Out<T>");
 }
 
 #[test]
@@ -1398,19 +1348,17 @@ fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl (
 #[test]
 #[ignore]
 fn error_bound_chalk() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait {
     fn foo(&self) -> u32 {}
 }
 
 fn test(x: (impl Trait + UnknownTrait)) {
-    x.foo()<|>;
-}
+    x.foo();
+}       //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
@@ -1480,7 +1428,7 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
 
 #[test]
 fn impl_trait_assoc_binding_projection_bug() {
-    let (db, pos) = TestDB::with_position(
+    check_types(
         r#"
 //- /main.rs crate:main deps:std
 pub trait Language {
@@ -1499,8 +1447,8 @@ trait Clone {
 
 fn api_walkthrough() {
     for node in foo() {
-        node.clone()<|>;
-    }
+        node.clone();
+    }            //^ {unknown}
 }
 
 //- /std.rs crate:std
@@ -1518,7 +1466,6 @@ mod iter {
 }
 "#,
     );
-    assert_eq!("{unknown}", type_at_pos(&db, pos));
 }
 
 #[test]
@@ -1549,9 +1496,8 @@ fn test<T: Trait1<Type = u32>>(x: T) {
 
 #[test]
 fn where_clause_trait_in_scope_for_method_resolution() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 mod foo {
     trait Trait {
         fn foo(&self) -> u32 {}
@@ -1559,11 +1505,10 @@ mod foo {
 }
 
 fn test<T: foo::Trait>(x: T) {
-    x.foo()<|>;
-}
+    x.foo();
+}      //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
@@ -2012,7 +1957,7 @@ fn test() {
 
 #[test]
 fn unselected_projection_in_trait_env_1() {
-    let t = type_at(
+    check_types(
         r#"
 //- /main.rs
 trait Trait {
@@ -2025,18 +1970,16 @@ trait Trait2 {
 
 fn test<T: Trait>() where T::Item: Trait2 {
     let x: T::Item = no_matter;
-    x.foo()<|>;
-}
+    x.foo();
+}       //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
 fn unselected_projection_in_trait_env_2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait<T> {
     type Item;
 }
@@ -2047,11 +1990,10 @@ trait Trait2 {
 
 fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
     let x: T::Item = no_matter;
-    x.foo()<|>;
-}
+    x.foo();
+}       //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
@@ -2097,9 +2039,8 @@ impl Trait for S2 {
 
 #[test]
 fn unselected_projection_on_trait_self() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait {
     type Item;
 
@@ -2112,18 +2053,16 @@ impl Trait for S {
 }
 
 fn test() {
-    S.f()<|>;
-}
+    S.f();
+}     //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
 fn unselected_projection_chalk_fold() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Interner {}
 trait Fold<I: Interner, TI = I> {
     type Result;
@@ -2142,18 +2081,16 @@ where
 }
 
 fn foo<I: Interner>(interner: &I, t: Ty<I>) {
-    fold(interner, t)<|>;
-}
+    fold(interner, t);
+}     //^ Ty<I>
 "#,
     );
-    assert_eq!(t, "Ty<I>");
 }
 
 #[test]
 fn trait_impl_self_ty() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait<T> {
    fn foo(&self);
 }
@@ -2163,18 +2100,16 @@ struct S;
 impl Trait<Self> for S {}
 
 fn test() {
-    S.foo()<|>;
-}
+    S.foo();
+}       //^ ()
 "#,
     );
-    assert_eq!(t, "()");
 }
 
 #[test]
 fn trait_impl_self_ty_cycle() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Trait {
    fn foo(&self);
 }
@@ -2184,18 +2119,17 @@ struct S<T>;
 impl Trait for S<Self> {}
 
 fn test() {
-    S.foo()<|>;
-}
+    S.foo();
+}       //^ {unknown}
 "#,
     );
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn unselected_projection_in_trait_env_cycle_1() {
-    let t = type_at(
+    // this is a legitimate cycle
+    check_types(
         r#"
-//- /main.rs
 trait Trait {
     type Item;
 }
@@ -2203,17 +2137,16 @@ trait Trait {
 trait Trait2<T> {}
 
 fn test<T: Trait>() where T: Trait2<T::Item> {
-    let x: T::Item = no_matter<|>;
-}
+    let x: T::Item = no_matter;
+}                       //^ {unknown}
 "#,
     );
-    // this is a legitimate cycle
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn unselected_projection_in_trait_env_cycle_2() {
-    let t = type_at(
+    // this is a legitimate cycle
+    check_types(
         r#"
 //- /main.rs
 trait Trait<T> {
@@ -2221,19 +2154,16 @@ trait Trait<T> {
 }
 
 fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
-    let x: T::Item = no_matter<|>;
-}
+    let x: T::Item = no_matter;
+}                   //^ {unknown}
 "#,
     );
-    // this is a legitimate cycle
-    assert_eq!(t, "{unknown}");
 }
 
 #[test]
 fn inline_assoc_type_bounds_1() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Iterator {
     type Item;
 }
@@ -2249,29 +2179,26 @@ impl<T: Iterator> Iterator for S<T> {
 
 fn test<I: Iterator<Item: OtherTrait<u32>>>() {
     let x: <S<I> as Iterator>::Item;
-    x.foo()<|>;
-}
+    x.foo();
+}       //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
 fn inline_assoc_type_bounds_2() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 trait Iterator {
     type Item;
 }
 
 fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
     let x: <<I as Iterator>::Item as Iterator>::Item;
-    x<|>;
-}
+    x;
+} //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
@@ -2445,9 +2372,8 @@ fn main() {
 
 #[test]
 fn associated_type_bound() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 pub trait Trait {
     type Item: OtherTrait<u32>;
 }
@@ -2463,18 +2389,16 @@ impl<T: Trait> Trait for S<T> {
 
 fn test<T: Trait>() {
     let y: <S<T> as Trait>::Item = no_matter;
-    y.foo()<|>;
-}
+    y.foo();
+}       //^ u32
 "#,
     );
-    assert_eq!(t, "u32");
 }
 
 #[test]
 fn dyn_trait_through_chalk() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct Box<T> {}
 #[lang = "deref"]
 trait Deref {
@@ -2488,18 +2412,16 @@ trait Trait {
 }
 
 fn test(x: Box<dyn Trait>) {
-    x.foo()<|>;
-}
+    x.foo();
+}       //^ ()
 "#,
     );
-    assert_eq!(t, "()");
 }
 
 #[test]
 fn string_to_owned() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct String {}
 pub trait ToOwned {
     type Owned;
@@ -2509,11 +2431,10 @@ impl ToOwned for str {
     type Owned = String;
 }
 fn test() {
-    "foo".to_owned()<|>;
-}
+    "foo".to_owned();
+}               //^ String
 "#,
     );
-    assert_eq!(t, "String");
 }
 
 #[test]
@@ -2637,9 +2558,8 @@ fn main() {
 
 #[test]
 fn nested_assoc() {
-    let t = type_at(
+    check_types(
         r#"
-//- /main.rs
 struct Bar;
 struct Foo;
 
@@ -2662,11 +2582,10 @@ impl<T:A> B for T {
 }
 
 fn main() {
-    Bar::foo()<|>;
-}
+    Bar::foo();
+}          //^ Foo
 "#,
     );
-    assert_eq!(t, "Foo");
 }
 
 #[test]
@@ -2846,12 +2765,12 @@ fn test() {
 
 #[test]
 fn integer_range_iterate() {
-    let t = type_at(
+    check_types(
         r#"
 //- /main.rs crate:main deps:core
 fn test() {
-    for x in 0..100 { x<|>; }
-}
+    for x in 0..100 { x; }
+}                   //^ i32
 
 //- /core.rs crate:core
 pub mod ops {
@@ -2886,7 +2805,6 @@ impl<A: Step> iter::Iterator for ops::Range<A> {
 }
 "#,
     );
-    assert_eq!(t, "i32");
 }
 
 #[test]
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index eaeeeb97b1..caf847273b 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -16,6 +16,7 @@ use std::{
 };
 
 use serde_json::Value;
+use stdx::lines_with_ends;
 use text_size::{TextRange, TextSize};
 
 pub use difference::Changeset as __Changeset;
@@ -159,6 +160,41 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
     res
 }
 
+/// Extracts `//^ some text` annotations
+pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
+    let mut res = Vec::new();
+    let mut prev_line_start: Option<TextSize> = None;
+    let mut line_start: TextSize = 0.into();
+    for line in lines_with_ends(text) {
+        if let Some(idx) = line.find("//^") {
+            let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]);
+            let data = line[idx + "//^".len()..].trim().to_string();
+            res.push((TextRange::at(offset, 1.into()), data))
+        }
+        prev_line_start = Some(line_start);
+        line_start += TextSize::of(line);
+    }
+    res
+}
+
+#[test]
+fn test_extract_annotations() {
+    let text = stdx::trim_indent(
+        r#"
+fn main() {
+    let x = 92;
+      //^ def
+    z + 1
+} //^ i32
+    "#,
+    );
+    let res = extract_annotations(&text)
+        .into_iter()
+        .map(|(range, ann)| (&text[range], ann))
+        .collect::<Vec<_>>();
+    assert_eq!(res, vec![("x", "def".into()), ("z", "i32".into()),]);
+}
+
 // Comparison functionality borrowed from cargo:
 
 /// Compare a line with an expected pattern.