Update the rest of the tests

This commit is contained in:
Aleksey Kladov 2020-06-29 17:22:47 +02:00
parent e805e8c1d5
commit bbc4dc9956
9 changed files with 311 additions and 446 deletions

View file

@ -17,11 +17,11 @@ use hir_def::{
item_scope::ItemScope, item_scope::ItemScope,
keys, keys,
nameres::CrateDefMap, nameres::CrateDefMap,
AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId, AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
}; };
use hir_expand::{db::AstDatabase, InFile}; use hir_expand::{db::AstDatabase, InFile};
use insta::assert_snapshot; 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::{ use ra_syntax::{
algo, algo,
ast::{self, AstNode}, ast::{self, AstNode},
@ -39,13 +39,27 @@ use crate::{
// update the snapshots. // update the snapshots.
fn check_types(ra_fixture: &str) { fn check_types(ra_fixture: &str) {
check_types_impl(ra_fixture, false)
}
fn check_types_source_code(ra_fixture: &str) {
check_types_impl(ra_fixture, true)
}
fn check_types_impl(ra_fixture: &str, display_source: bool) {
let db = TestDB::with_files(ra_fixture); let db = TestDB::with_files(ra_fixture);
let mut checked_one = false; let mut checked_one = false;
for file_id in db.all_files() { for file_id in db.all_files() {
let text = db.parse(file_id).syntax_node().to_string(); let text = db.parse(file_id).syntax_node().to_string();
let annotations = extract_annotations(&text); let annotations = extract_annotations(&text);
for (offset, expected) in annotations { for (range, expected) in annotations {
let actual = type_at_pos(&db, FilePosition { file_id, offset }); 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); assert_eq!(expected, actual);
checked_one = true; checked_one = true;
} }
@ -53,21 +67,9 @@ fn check_types(ra_fixture: &str) {
assert!(checked_one, "no `//^` annotations found"); assert!(checked_one, "no `//^` annotations found");
} }
fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
}
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 type_at_pos_displayed(
db: &TestDB,
pos: FilePosition,
display_fn: impl FnOnce(&Ty, ModuleId) -> String,
) -> String {
let file = db.parse(pos.file_id).ok().unwrap(); 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 fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
let module = db.module_for_file(pos.file_id); let module = db.module_for_file(pos.file_id);
let func = *module.child_by_source(db)[keys::FUNCTION] let func = *module.child_by_source(db)[keys::FUNCTION]
@ -77,17 +79,11 @@ fn type_at_pos_displayed(
let (_body, source_map) = db.body_with_source_map(func.into()); 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)) { if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
let infer = db.infer(func.into()); let infer = db.infer(func.into());
let ty = &infer[expr_id]; return infer[expr_id].clone();
return display_fn(ty, module);
} }
panic!("Can't find expression") 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 { fn infer(ra_fixture: &str) -> String {
infer_with_mismatches(ra_fixture, false) infer_with_mismatches(ra_fixture, false)
} }

View file

@ -1,7 +1,8 @@
use super::infer_with_mismatches;
use insta::assert_snapshot; use insta::assert_snapshot;
use test_utils::mark; use test_utils::mark;
use super::infer_with_mismatches;
// Infer with some common definitions and impls. // Infer with some common definitions and impls.
fn infer(source: &str) -> String { fn infer(source: &str) -> String {
let defs = r#" let defs = r#"

View file

@ -1,50 +1,41 @@
use super::displayed_source_at_pos; use super::check_types_source_code;
use crate::test_db::TestDB;
use ra_db::fixture::WithFixture;
#[test] #[test]
fn qualify_path_to_submodule() { fn qualify_path_to_submodule() {
let (db, pos) = TestDB::with_position( check_types_source_code(
r#" r#"
//- /main.rs
mod foo { mod foo {
pub struct Foo; pub struct Foo;
} }
fn bar() { fn bar() {
let foo: foo::Foo = foo::Foo; let foo: foo::Foo = foo::Foo;
foo<|> foo
} } //^ foo::Foo
"#, "#,
); );
assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos));
} }
#[test] #[test]
fn omit_default_type_parameters() { fn omit_default_type_parameters() {
let (db, pos) = TestDB::with_position( check_types_source_code(
r" r#"
//- /main.rs struct Foo<T = u8> { t: T }
struct Foo<T = u8> { t: T } fn main() {
fn main() { let foo = Foo { t: 5u8 };
let foo = Foo { t: 5u8 }; foo;
foo<|>; } //^ Foo
} "#,
",
); );
assert_eq!("Foo", displayed_source_at_pos(&db, pos));
let (db, pos) = TestDB::with_position( check_types_source_code(
r" r#"
//- /main.rs struct Foo<K, T = u8> { k: K, t: T }
struct Foo<K, T = u8> { k: K, t: T } fn main() {
fn main() { let foo = Foo { k: 400, t: 5u8 };
let foo = Foo { k: 400, t: 5u8 }; foo;
foo<|>; } //^ Foo<i32>
} "#,
",
); );
assert_eq!("Foo<i32>", displayed_source_at_pos(&db, pos));
} }

View file

@ -1,16 +1,13 @@
use std::fs; use std::fs;
use insta::assert_snapshot; use insta::assert_snapshot;
use ra_db::fixture::WithFixture;
use test_utils::project_dir; use test_utils::project_dir;
use crate::test_db::TestDB; use super::{check_types, infer};
use super::{infer, type_at, type_at_pos};
#[test] #[test]
fn cfg_impl_def() { fn cfg_impl_def() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:foo cfg:test //- /main.rs crate:main deps:foo cfg:test
use foo::S as T; use foo::S as T;
@ -28,8 +25,8 @@ impl S {
fn test() { fn test() {
let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
t<|>; t;
} } //^ (i32, {unknown}, i32, {unknown})
//- /foo.rs crate:foo //- /foo.rs crate:foo
struct S; struct S;
@ -45,7 +42,6 @@ impl S {
} }
"#, "#,
); );
assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -253,26 +249,24 @@ fn foo() {
#[test] #[test]
fn processes_impls_generated_by_macros() { fn processes_impls_generated_by_macros() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
macro_rules! m { macro_rules! m {
($ident:ident) => (impl Trait for $ident {}) ($ident:ident) => (impl Trait for $ident {})
} }
trait Trait { fn foo(self) -> u128 {} } trait Trait { fn foo(self) -> u128 {} }
struct S; struct S;
m!(S); m!(S);
fn test() { S.foo()<|>; } fn test() { S.foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn infer_assoc_items_generated_by_macros() { fn infer_assoc_items_generated_by_macros() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
macro_rules! m { macro_rules! m {
() => (fn foo(&self) -> u128 {0}) () => (fn foo(&self) -> u128 {0})
} }
@ -281,17 +275,16 @@ impl S {
m!(); m!();
} }
fn test() { S.foo()<|>; } fn test() { S.foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn infer_assoc_items_generated_by_macros_chain() { fn infer_assoc_items_generated_by_macros_chain() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
macro_rules! m_inner { macro_rules! m_inner {
() => {fn foo(&self) -> u128 {0}} () => {fn foo(&self) -> u128 {0}}
} }
@ -304,21 +297,21 @@ impl S {
m!(); m!();
} }
fn test() { S.foo()<|>; } fn test() { S.foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn infer_macro_with_dollar_crate_is_correct_in_expr() { fn infer_macro_with_dollar_crate_is_correct_in_expr() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:foo //- /main.rs crate:main deps:foo
fn test() { fn test() {
let x = (foo::foo!(1), foo::foo!(2)); let x = (foo::foo!(1), foo::foo!(2));
x<|>; x;
} } //^ (i32, usize)
//- /lib.rs crate:foo //- /lib.rs crate:foo
#[macro_export] #[macro_export]
@ -335,12 +328,11 @@ macro_rules! bar {
pub fn baz() -> usize { 31usize } pub fn baz() -> usize { 31usize }
"#, "#,
); );
assert_eq!("(i32, usize)", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:foo //- /main.rs crate:main deps:foo
use foo::Trait; use foo::Trait;
@ -348,7 +340,8 @@ use foo::Trait;
fn test() { fn test() {
let msg = foo::Message(foo::MessageRef); let msg = foo::Message(foo::MessageRef);
let r = msg.deref(); let r = msg.deref();
r<|>; r;
//^ &MessageRef
} }
//- /lib.rs crate:foo //- /lib.rs crate:foo
@ -375,7 +368,6 @@ macro_rules! expand {
expand!(); expand!();
"#, "#,
); );
assert_eq!("&MessageRef", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -429,13 +421,13 @@ fn main() {
#[test] #[test]
fn infer_local_inner_macros() { fn infer_local_inner_macros() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:foo //- /main.rs crate:main deps:foo
fn test() { fn test() {
let x = foo::foo!(1); let x = foo::foo!(1);
x<|>; x;
} } //^ i32
//- /lib.rs crate:foo //- /lib.rs crate:foo
#[macro_export(local_inner_macros)] #[macro_export(local_inner_macros)]
@ -450,7 +442,6 @@ macro_rules! bar {
"#, "#,
); );
assert_eq!("i32", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -531,7 +522,7 @@ fn main() {
#[test] #[test]
fn infer_builtin_macros_include() { fn infer_builtin_macros_include() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs //- /main.rs
#[rustc_builtin_macro] #[rustc_builtin_macro]
@ -540,14 +531,13 @@ macro_rules! include {() => {}}
include!("foo.rs"); include!("foo.rs");
fn main() { fn main() {
bar()<|>; bar();
} } //^ u32
//- /foo.rs //- /foo.rs
fn bar() -> u32 {0} fn bar() -> u32 {0}
"#, "#,
); );
assert_eq!("u32", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -565,18 +555,17 @@ macro_rules! include {() => {}}
include!("foo.rs"); include!("foo.rs");
fn main() { fn main() {
RegisterBlock { }<|>; RegisterBlock { };
//^ RegisterBlock
} }
"#; "#;
let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file);
check_types(&fixture);
let (db, pos) = TestDB::with_position(&fixture);
assert_eq!("RegisterBlock", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_builtin_macros_include_concat() { fn infer_builtin_macros_include_concat() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs //- /main.rs
#[rustc_builtin_macro] #[rustc_builtin_macro]
@ -588,19 +577,18 @@ macro_rules! concat {() => {}}
include!(concat!("f", "oo.rs")); include!(concat!("f", "oo.rs"));
fn main() { fn main() {
bar()<|>; bar();
} } //^ u32
//- /foo.rs //- /foo.rs
fn bar() -> u32 {0} fn bar() -> u32 {0}
"#, "#,
); );
assert_eq!("u32", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { fn infer_builtin_macros_include_concat_with_bad_env_should_failed() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs //- /main.rs
#[rustc_builtin_macro] #[rustc_builtin_macro]
@ -615,32 +603,29 @@ macro_rules! env {() => {}}
include!(concat!(env!("OUT_DIR"), "/foo.rs")); include!(concat!(env!("OUT_DIR"), "/foo.rs"));
fn main() { fn main() {
bar()<|>; bar();
} } //^ {unknown}
//- /foo.rs //- /foo.rs
fn bar() -> u32 {0} fn bar() -> u32 {0}
"#, "#,
); );
assert_eq!("{unknown}", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_builtin_macros_include_itself_should_failed() { fn infer_builtin_macros_include_itself_should_failed() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs
#[rustc_builtin_macro] #[rustc_builtin_macro]
macro_rules! include {() => {}} macro_rules! include {() => {}}
include!("main.rs"); include!("main.rs");
fn main() { fn main() {
0<|> 0
} } //^ i32
"#, "#,
); );
assert_eq!("i32", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -686,14 +671,14 @@ fn main() {
#[test] #[test]
fn infer_derive_clone_simple() { fn infer_derive_clone_simple() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
#[derive(Clone)] #[derive(Clone)]
struct S; struct S;
fn test() { fn test() {
S.clone()<|>; S.clone();
} } //^ S
//- /lib.rs crate:core //- /lib.rs crate:core
#[prelude_import] #[prelude_import]
@ -705,12 +690,11 @@ mod clone {
} }
"#, "#,
); );
assert_eq!("S", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_derive_clone_in_core() { fn infer_derive_clone_in_core() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /lib.rs crate:core //- /lib.rs crate:core
#[prelude_import] #[prelude_import]
@ -726,16 +710,15 @@ pub struct S;
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
use core::S; use core::S;
fn test() { fn test() {
S.clone()<|>; S.clone();
} } //^ S
"#, "#,
); );
assert_eq!("S", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_derive_clone_with_params() { fn infer_derive_clone_with_params() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
#[derive(Clone)] #[derive(Clone)]
@ -744,7 +727,8 @@ struct S;
struct Wrapper<T>(T); struct Wrapper<T>(T);
struct NonClone; struct NonClone;
fn test() { fn test() {
(Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; (Wrapper(S).clone(), Wrapper(NonClone).clone());
//^ (Wrapper<S>, {unknown})
} }
//- /lib.rs crate:core //- /lib.rs crate:core
@ -757,13 +741,12 @@ mod clone {
} }
"#, "#,
); );
assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_custom_derive_simple() { fn infer_custom_derive_simple() {
// FIXME: this test current now do nothing // FIXME: this test current now do nothing
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main //- /main.rs crate:main
use foo::Foo; use foo::Foo;
@ -772,11 +755,10 @@ use foo::Foo;
struct S{} struct S{}
fn test() { fn test() {
S{}<|>; S{};
} } //^ S
"#, "#,
); );
assert_eq!("S", type_at_pos(&db, pos));
} }
#[test] #[test]

View file

@ -1,7 +1,6 @@
use super::{infer, type_at, type_at_pos};
use crate::test_db::TestDB;
use insta::assert_snapshot; use insta::assert_snapshot;
use ra_db::fixture::WithFixture;
use super::{check_types, infer};
#[test] #[test]
fn infer_slice_method() { fn infer_slice_method() {
@ -246,13 +245,13 @@ fn test() {
#[test] #[test]
fn cross_crate_associated_method_call() { fn cross_crate_associated_method_call() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:other_crate //- /main.rs crate:main deps:other_crate
fn test() { fn test() {
let x = other_crate::foo::S::thing(); let x = other_crate::foo::S::thing();
x<|>; x;
} } //^ i128
//- /lib.rs crate:other_crate //- /lib.rs crate:other_crate
mod foo { mod foo {
@ -263,7 +262,6 @@ mod foo {
} }
"#, "#,
); );
assert_eq!("i128", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -684,135 +682,127 @@ fn test() {
#[test] #[test]
fn method_resolution_unify_impl_self_type() { fn method_resolution_unify_impl_self_type() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct S<T>; struct S<T>;
impl S<u32> { fn foo(&self) -> u8 {} } impl S<u32> { fn foo(&self) -> u8 {} }
impl S<i32> { fn foo(&self) -> i8 {} } 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] #[test]
fn method_resolution_trait_before_autoref() { fn method_resolution_trait_before_autoref() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl S { fn foo(&self) -> i8 { 0 } } impl S { fn foo(&self) -> i8 { 0 } }
impl Trait for S { fn foo(self) -> u128 { 0 } } impl Trait for S { fn foo(self) -> u128 { 0 } }
fn test() { S.foo()<|>; } fn test() { S.foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn method_resolution_by_value_before_autoref() { fn method_resolution_by_value_before_autoref() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Clone { fn clone(&self) -> Self; } trait Clone { fn clone(&self) -> Self; }
struct S; struct S;
impl Clone for S {} impl Clone for 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] #[test]
fn method_resolution_trait_before_autoderef() { fn method_resolution_trait_before_autoderef() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl S { fn foo(self) -> i8 { 0 } } impl S { fn foo(self) -> i8 { 0 } }
impl Trait for &S { fn foo(self) -> u128 { 0 } } impl Trait for &S { fn foo(self) -> u128 { 0 } }
fn test() { (&S).foo()<|>; } fn test() { (&S).foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn method_resolution_impl_before_trait() { fn method_resolution_impl_before_trait() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl S { fn foo(self) -> i8 { 0 } } impl S { fn foo(self) -> i8 { 0 } }
impl Trait for S { fn foo(self) -> u128 { 0 } } impl Trait for S { fn foo(self) -> u128 { 0 } }
fn test() { S.foo()<|>; } fn test() { S.foo(); }
//^ i8
"#, "#,
); );
assert_eq!(t, "i8");
} }
#[test] #[test]
fn method_resolution_impl_ref_before_trait() { fn method_resolution_impl_ref_before_trait() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl S { fn foo(&self) -> i8 { 0 } } impl S { fn foo(&self) -> i8 { 0 } }
impl Trait for &S { fn foo(self) -> u128 { 0 } } impl Trait for &S { fn foo(self) -> u128 { 0 } }
fn test() { S.foo()<|>; } fn test() { S.foo(); }
//^ i8
"#, "#,
); );
assert_eq!(t, "i8");
} }
#[test] #[test]
fn method_resolution_trait_autoderef() { fn method_resolution_trait_autoderef() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl Trait for S { fn foo(self) -> u128 { 0 } } impl Trait for S { fn foo(self) -> u128 { 0 } }
fn test() { (&S).foo()<|>; } fn test() { (&S).foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn method_resolution_unsize_array() { fn method_resolution_unsize_array() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
#[lang = "slice"] #[lang = "slice"]
impl<T> [T] { impl<T> [T] {
fn len(&self) -> usize { loop {} } fn len(&self) -> usize { loop {} }
} }
fn test() { fn test() {
let a = [1, 2, 3]; let a = [1, 2, 3];
a.len()<|>; a.len();
} } //^ usize
"#, "#,
); );
assert_eq!(t, "usize");
} }
#[test] #[test]
fn method_resolution_trait_from_prelude() { fn method_resolution_trait_from_prelude() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:other_crate //- /main.rs crate:main deps:other_crate
struct S; struct S;
impl Clone for S {} impl Clone for S {}
fn test() { fn test() {
S.clone()<|>; S.clone();
//^ S
} }
//- /lib.rs crate:other_crate //- /lib.rs crate:other_crate
@ -825,115 +815,107 @@ mod foo {
} }
"#, "#,
); );
assert_eq!("S", type_at_pos(&db, pos));
} }
#[test] #[test]
fn method_resolution_where_clause_for_unknown_trait() { fn method_resolution_where_clause_for_unknown_trait() {
// The blanket impl currently applies because we ignore the unresolved where clause // The blanket impl currently applies because we ignore the unresolved where clause
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl<T> Trait for T where T: UnknownTrait {} impl<T> Trait for T where T: UnknownTrait {}
fn test() { (&S).foo()<|>; } fn test() { (&S).foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn method_resolution_where_clause_not_met() { fn method_resolution_where_clause_not_met() {
// The blanket impl shouldn't apply because we can't prove S: Clone // 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#" r#"
//- /main.rs
trait Clone {} trait Clone {}
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl<T> Trait for T where T: Clone {} 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] #[test]
fn method_resolution_where_clause_inline_not_met() { fn method_resolution_where_clause_inline_not_met() {
// The blanket impl shouldn't apply because we can't prove S: Clone // The blanket impl shouldn't apply because we can't prove S: Clone
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Clone {} trait Clone {}
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl<T: Clone> Trait for T {} impl<T: Clone> Trait for T {}
fn test() { (&S).foo()<|>; } fn test() { (&S).foo(); }
//^ {unknown}
"#, "#,
); );
assert_eq!(t, "{unknown}");
} }
#[test] #[test]
fn method_resolution_where_clause_1() { fn method_resolution_where_clause_1() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Clone {} trait Clone {}
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl Clone for S {} impl Clone for S {}
impl<T> Trait for T where T: Clone {} impl<T> Trait for T where T: Clone {}
fn test() { S.foo()<|>; } fn test() { S.foo(); }
//^ u128
"#, "#,
); );
assert_eq!(t, "u128");
} }
#[test] #[test]
fn method_resolution_where_clause_2() { fn method_resolution_where_clause_2() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Into<T> { fn into(self) -> T; } trait Into<T> { fn into(self) -> T; }
trait From<T> { fn from(other: T) -> Self; } trait From<T> { fn from(other: T) -> Self; }
struct S1; struct S1;
struct S2; struct S2;
impl From<S2> for S1 {} impl From<S2> for S1 {}
impl<T, U> Into<U> for T where U: From<T> {} 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] #[test]
fn method_resolution_where_clause_inline() { fn method_resolution_where_clause_inline() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Into<T> { fn into(self) -> T; } trait Into<T> { fn into(self) -> T; }
trait From<T> { fn from(other: T) -> Self; } trait From<T> { fn from(other: T) -> Self; }
struct S1; struct S1;
struct S2; struct S2;
impl From<S2> for S1 {} impl From<S2> for S1 {}
impl<T, U: From<T>> Into<U> for T {} impl<T, U: From<T>> Into<U> for T {}
fn test() { S2.into()<|>; } fn test() { S2.into(); }
//^ {unknown}
"#, "#,
); );
assert_eq!(t, "{unknown}");
} }
#[test] #[test]
fn method_resolution_overloaded_method() { fn method_resolution_overloaded_method() {
test_utils::mark::check!(impl_self_type_match_without_receiver); test_utils::mark::check!(impl_self_type_match_without_receiver);
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct Wrapper<T>(T); struct Wrapper<T>(T);
struct Foo<T>(T); struct Foo<T>(T);
struct Bar<T>(T); struct Bar<T>(T);
@ -953,30 +935,30 @@ impl<T> Wrapper<Bar<T>> {
fn main() { fn main() {
let a = Wrapper::<Foo<f32>>::new(1.0); let a = Wrapper::<Foo<f32>>::new(1.0);
let b = Wrapper::<Bar<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] #[test]
fn method_resolution_encountering_fn_type() { fn method_resolution_encountering_fn_type() {
type_at( check_types(
r#" r#"
//- /main.rs //- /main.rs
fn foo() {} fn foo() {}
trait FnOnce { fn call(self); } trait FnOnce { fn call(self); }
fn test() { foo.call()<|>; } fn test() { foo.call(); }
//^ {unknown}
"#, "#,
); );
} }
#[test] #[test]
fn method_resolution_non_parameter_type() { fn method_resolution_non_parameter_type() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
mod a { mod a {
pub trait Foo { pub trait Foo {
fn foo(&self); fn foo(&self);
@ -988,18 +970,16 @@ fn foo<T>(t: Wrapper<T>)
where where
Wrapper<T>: a::Foo, Wrapper<T>: a::Foo,
{ {
t.foo()<|>; t.foo();
} } //^ {unknown}
"#, "#,
); );
assert_eq!(t, "{unknown}");
} }
#[test] #[test]
fn method_resolution_3373() { fn method_resolution_3373() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct A<T>(T); struct A<T>(T);
impl A<i32> { impl A<i32> {
@ -1007,19 +987,17 @@ impl A<i32> {
} }
fn main() { fn main() {
A::from(3)<|>; A::from(3);
} } //^ A<i32>
"#, "#,
); );
assert_eq!(t, "A<i32>");
} }
#[test] #[test]
fn method_resolution_slow() { fn method_resolution_slow() {
// this can get quite slow if we set the solver size limit too high // this can get quite slow if we set the solver size limit too high
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait SendX {} trait SendX {}
struct S1; impl SendX for S1 {} 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 {} 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] #[test]

View file

@ -1,10 +1,7 @@
use insta::assert_snapshot; use insta::assert_snapshot;
use ra_db::fixture::WithFixture;
use test_utils::mark; use test_utils::mark;
use crate::test_db::TestDB; use super::{check_types, infer};
use super::infer;
#[test] #[test]
fn bug_484() { fn bug_484() {
@ -404,13 +401,13 @@ fn test() {
#[test] #[test]
fn issue_2683_chars_impl() { fn issue_2683_chars_impl() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:std //- /main.rs crate:main deps:std
fn test() { fn test() {
let chars: std::str::Chars<'_>; let chars: std::str::Chars<'_>;
(chars.next(), chars.nth(1))<|>; (chars.next(), chars.nth(1));
} } //^ (Option<char>, Option<char>)
//- /std.rs crate:std //- /std.rs crate:std
#[prelude_import] #[prelude_import]
@ -449,15 +446,12 @@ pub mod str {
} }
"#, "#,
); );
assert_eq!("(Option<char>, Option<char>)", super::type_at_pos(&db, pos));
} }
#[test] #[test]
fn issue_3642_bad_macro_stackover() { fn issue_3642_bad_macro_stackover() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs
#[macro_export] #[macro_export]
macro_rules! match_ast { macro_rules! match_ast {
(match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
@ -472,7 +466,8 @@ macro_rules! match_ast {
} }
fn main() { fn main() {
let anchor<|> = match_ast! { let anchor = match_ast! {
//^ ()
match parent { match parent {
as => {}, as => {},
_ => return None _ => return None
@ -480,8 +475,6 @@ fn main() {
}; };
}"#, }"#,
); );
assert_eq!("()", super::type_at_pos(&db, pos));
} }
#[test] #[test]

View file

@ -1,17 +1,13 @@
use insta::assert_snapshot; use insta::assert_snapshot;
use ra_db::fixture::WithFixture;
use test_utils::mark; use test_utils::mark;
use crate::test_db::TestDB; use super::{check_types, infer, infer_with_mismatches};
use super::{infer, infer_with_mismatches, type_at, type_at_pos};
#[test] #[test]
fn infer_await() { fn infer_await() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
struct IntFuture; struct IntFuture;
impl Future for IntFuture { impl Future for IntFuture {
@ -21,8 +17,8 @@ impl Future for IntFuture {
fn test() { fn test() {
let r = IntFuture; let r = IntFuture;
let v = r.await; let v = r.await;
v<|>; v;
} } //^ u64
//- /core.rs crate:core //- /core.rs crate:core
#[prelude_import] use future::*; #[prelude_import] use future::*;
@ -32,18 +28,15 @@ mod future {
type Output; type Output;
} }
} }
"#, "#,
); );
assert_eq!("u64", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_async() { fn infer_async() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
async fn foo() -> u64 { async fn foo() -> u64 {
128 128
} }
@ -51,8 +44,8 @@ async fn foo() -> u64 {
fn test() { fn test() {
let r = foo(); let r = foo();
let v = r.await; let v = r.await;
v<|>; v;
} } //^ u64
//- /core.rs crate:core //- /core.rs crate:core
#[prelude_import] use future::*; #[prelude_import] use future::*;
@ -62,26 +55,23 @@ mod future {
type Output; type Output;
} }
} }
"#, "#,
); );
assert_eq!("u64", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_desugar_async() { fn infer_desugar_async() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
async fn foo() -> u64 { async fn foo() -> u64 {
128 128
} }
fn test() { fn test() {
let r = foo(); let r = foo();
r<|>; r;
} } //^ impl Future<Output = u64>
//- /core.rs crate:core //- /core.rs crate:core
#[prelude_import] use future::*; #[prelude_import] use future::*;
@ -93,23 +83,20 @@ mod future {
"#, "#,
); );
assert_eq!("impl Future<Output = u64>", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_try() { fn infer_try() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
fn test() { fn test() {
let r: Result<i32, u64> = Result::Ok(1); let r: Result<i32, u64> = Result::Ok(1);
let v = r?; let v = r?;
v<|>; v;
} } //^ i32
//- /core.rs crate:core //- /core.rs crate:core
#[prelude_import] use ops::*; #[prelude_import] use ops::*;
mod ops { mod ops {
trait Try { trait Try {
@ -130,30 +117,26 @@ mod result {
type Error = E; type Error = E;
} }
} }
"#, "#,
); );
assert_eq!("i32", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_for_loop() { fn infer_for_loop() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:core,alloc //- /main.rs crate:main deps:core,alloc
use alloc::collections::Vec; use alloc::collections::Vec;
fn test() { fn test() {
let v = Vec::new(); let v = Vec::new();
v.push("foo"); v.push("foo");
for x in v { for x in v {
x<|>; x;
} } //^ &str
} }
//- /core.rs crate:core //- /core.rs crate:core
#[prelude_import] use iter::*; #[prelude_import] use iter::*;
mod iter { mod iter {
trait IntoIterator { trait IntoIterator {
@ -162,7 +145,6 @@ mod iter {
} }
//- /alloc.rs crate:alloc deps:core //- /alloc.rs crate:alloc deps:core
mod collections { mod collections {
struct Vec<T> {} struct Vec<T> {}
impl<T> Vec<T> { impl<T> Vec<T> {
@ -176,15 +158,13 @@ mod collections {
} }
"#, "#,
); );
assert_eq!("&str", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_ops_neg() { fn infer_ops_neg() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:std //- /main.rs crate:main deps:std
struct Bar; struct Bar;
struct Foo; struct Foo;
@ -195,11 +175,10 @@ impl std::ops::Neg for Bar {
fn test() { fn test() {
let a = Bar; let a = Bar;
let b = -a; let b = -a;
b<|>; b;
} } //^ Foo
//- /std.rs crate:std //- /std.rs crate:std
#[prelude_import] use ops::*; #[prelude_import] use ops::*;
mod ops { mod ops {
#[lang = "neg"] #[lang = "neg"]
@ -209,15 +188,13 @@ mod ops {
} }
"#, "#,
); );
assert_eq!("Foo", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_ops_not() { fn infer_ops_not() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:std //- /main.rs crate:main deps:std
struct Bar; struct Bar;
struct Foo; struct Foo;
@ -228,11 +205,10 @@ impl std::ops::Not for Bar {
fn test() { fn test() {
let a = Bar; let a = Bar;
let b = !a; let b = !a;
b<|>; b;
} } //^ Foo
//- /std.rs crate:std //- /std.rs crate:std
#[prelude_import] use ops::*; #[prelude_import] use ops::*;
mod ops { mod ops {
#[lang = "not"] #[lang = "not"]
@ -242,7 +218,6 @@ mod ops {
} }
"#, "#,
); );
assert_eq!("Foo", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -537,10 +512,9 @@ fn indexing_arrays() {
#[test] #[test]
fn infer_ops_index() { fn infer_ops_index() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:std //- /main.rs crate:main deps:std
struct Bar; struct Bar;
struct Foo; struct Foo;
@ -551,11 +525,10 @@ impl std::ops::Index<u32> for Bar {
fn test() { fn test() {
let a = Bar; let a = Bar;
let b = a[1u32]; let b = a[1u32];
b<|>; b;
} } //^ Foo
//- /std.rs crate:std //- /std.rs crate:std
#[prelude_import] use ops::*; #[prelude_import] use ops::*;
mod ops { mod ops {
#[lang = "index"] #[lang = "index"]
@ -565,19 +538,18 @@ mod ops {
} }
"#, "#,
); );
assert_eq!("Foo", type_at_pos(&db, pos));
} }
#[test] #[test]
fn infer_ops_index_autoderef() { fn infer_ops_index_autoderef() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:std //- /main.rs crate:main deps:std
fn test() { fn test() {
let a = &[1u32, 2, 3]; let a = &[1u32, 2, 3];
let b = a[1u32]; let b = a[1u32];
b<|>; b;
} } //^ u32
//- /std.rs crate:std //- /std.rs crate:std
impl<T> ops::Index<u32> for [T] { impl<T> ops::Index<u32> for [T] {
@ -593,14 +565,12 @@ mod ops {
} }
"#, "#,
); );
assert_eq!("u32", type_at_pos(&db, pos));
} }
#[test] #[test]
fn deref_trait() { fn deref_trait() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
#[lang = "deref"] #[lang = "deref"]
trait Deref { trait Deref {
type Target; type Target;
@ -618,16 +588,15 @@ impl S {
} }
fn test(s: Arc<S>) { fn test(s: Arc<S>) {
(*s, s.foo())<|>; (*s, s.foo());
} } //^ (S, u128)
"#, "#,
); );
assert_eq!(t, "(S, u128)");
} }
#[test] #[test]
fn deref_trait_with_inference_var() { fn deref_trait_with_inference_var() {
let t = type_at( check_types(
r#" r#"
//- /main.rs //- /main.rs
#[lang = "deref"] #[lang = "deref"]
@ -647,19 +616,18 @@ fn foo(a: Arc<S>) {}
fn test() { fn test() {
let a = new_arc(); let a = new_arc();
let b = (*a)<|>; let b = (*a);
//^ S
foo(a); foo(a);
} }
"#, "#,
); );
assert_eq!(t, "S");
} }
#[test] #[test]
fn deref_trait_infinite_recursion() { fn deref_trait_infinite_recursion() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
#[lang = "deref"] #[lang = "deref"]
trait Deref { trait Deref {
type Target; type Target;
@ -673,18 +641,16 @@ impl Deref for S {
} }
fn test(s: S) { fn test(s: S) {
s.foo()<|>; s.foo();
} } //^ {unknown}
"#, "#,
); );
assert_eq!(t, "{unknown}");
} }
#[test] #[test]
fn deref_trait_with_question_mark_size() { fn deref_trait_with_question_mark_size() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
#[lang = "deref"] #[lang = "deref"]
trait Deref { trait Deref {
type Target; type Target;
@ -702,18 +668,16 @@ impl S {
} }
fn test(s: Arc<S>) { fn test(s: Arc<S>) {
(*s, s.foo())<|>; (*s, s.foo());
} } //^ (S, u128)
"#, "#,
); );
assert_eq!(t, "(S, u128)");
} }
#[test] #[test]
fn obligation_from_function_clause() { fn obligation_from_function_clause() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct S; struct S;
trait Trait<T> {} trait Trait<T> {}
@ -722,16 +686,15 @@ impl Trait<u32> for S {}
fn foo<T: Trait<U>, U>(t: T) -> U {} fn foo<T: Trait<U>, U>(t: T) -> U {}
fn test(s: S) { fn test(s: S) {
foo(s)<|>; (foo(s));
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
fn obligation_from_method_clause() { fn obligation_from_method_clause() {
let t = type_at( check_types(
r#" r#"
//- /main.rs //- /main.rs
struct S; struct S;
@ -745,18 +708,16 @@ impl O {
} }
fn test() { fn test() {
O.foo(S)<|>; O.foo(S);
} } //^ isize
"#, "#,
); );
assert_eq!(t, "isize");
} }
#[test] #[test]
fn obligation_from_self_method_clause() { fn obligation_from_self_method_clause() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct S; struct S;
trait Trait<T> {} trait Trait<T> {}
@ -767,18 +728,16 @@ impl S {
} }
fn test() { fn test() {
S.foo()<|>; S.foo();
} } //^ i64
"#, "#,
); );
assert_eq!(t, "i64");
} }
#[test] #[test]
fn obligation_from_impl_clause() { fn obligation_from_impl_clause() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct S; struct S;
trait Trait<T> {} trait Trait<T> {}
@ -790,32 +749,30 @@ impl<U, T: Trait<U>> O<T> {
} }
fn test(o: O<S>) { fn test(o: O<S>) {
o.foo()<|>; o.foo();
} } //^ &str
"#, "#,
); );
assert_eq!(t, "&str");
} }
#[test] #[test]
fn generic_param_env_1() { fn generic_param_env_1() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Clone {} trait Clone {}
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl Clone for S {} impl Clone for S {}
impl<T> Trait for T where T: Clone {} 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] #[test]
fn generic_param_env_1_not_met() { fn generic_param_env_1_not_met() {
let t = type_at( check_types(
r#" r#"
//- /main.rs //- /main.rs
trait Clone {} trait Clone {}
@ -823,45 +780,42 @@ trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl Clone for S {} impl Clone for S {}
impl<T> Trait for T where T: Clone {} 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] #[test]
fn generic_param_env_2() { fn generic_param_env_2() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl Trait for 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] #[test]
fn generic_param_env_2_not_met() { fn generic_param_env_2_not_met() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { fn foo(self) -> u128; } trait Trait { fn foo(self) -> u128; }
struct S; struct S;
impl Trait for 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] #[test]
fn generic_param_env_deref() { fn generic_param_env_deref() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
#[lang = "deref"] #[lang = "deref"]
trait Deref { trait Deref {
type Target; type Target;
@ -870,17 +824,17 @@ trait Trait {}
impl<T> Deref for T where T: Trait { impl<T> Deref for T where T: Trait {
type Target = i128; type Target = i128;
} }
fn test<T: Trait>(t: T) { (*t)<|>; } fn test<T: Trait>(t: T) { (*t); }
//^ i128
"#, "#,
); );
assert_eq!(t, "i128");
} }
#[test] #[test]
fn associated_type_placeholder() { 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#" r#"
//- /main.rs
pub trait ApplyL { pub trait ApplyL {
type Out; type Out;
} }
@ -893,19 +847,16 @@ impl<T> ApplyL for RefMutL<T> {
fn test<T: ApplyL>() { fn test<T: ApplyL>() {
let y: <RefMutL<T> as ApplyL>::Out = no_matter; 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] #[test]
fn associated_type_placeholder_2() { fn associated_type_placeholder_2() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
pub trait ApplyL { pub trait ApplyL {
type Out; type Out;
} }
@ -913,11 +864,10 @@ fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
fn test<T: ApplyL>(t: T) { fn test<T: ApplyL>(t: T) {
let y = foo(t); let y = foo(t);
y<|>; y;
} } //^ ApplyL::Out<T>
"#, "#,
); );
assert_eq!(t, "ApplyL::Out<T>");
} }
#[test] #[test]
@ -1398,19 +1348,17 @@ fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl (
#[test] #[test]
#[ignore] #[ignore]
fn error_bound_chalk() { fn error_bound_chalk() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { trait Trait {
fn foo(&self) -> u32 {} fn foo(&self) -> u32 {}
} }
fn test(x: (impl Trait + UnknownTrait)) { fn test(x: (impl Trait + UnknownTrait)) {
x.foo()<|>; x.foo();
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
@ -1480,7 +1428,7 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
#[test] #[test]
fn impl_trait_assoc_binding_projection_bug() { fn impl_trait_assoc_binding_projection_bug() {
let (db, pos) = TestDB::with_position( check_types(
r#" r#"
//- /main.rs crate:main deps:std //- /main.rs crate:main deps:std
pub trait Language { pub trait Language {
@ -1499,8 +1447,8 @@ trait Clone {
fn api_walkthrough() { fn api_walkthrough() {
for node in foo() { for node in foo() {
node.clone()<|>; node.clone();
} } //^ {unknown}
} }
//- /std.rs crate:std //- /std.rs crate:std
@ -1518,7 +1466,6 @@ mod iter {
} }
"#, "#,
); );
assert_eq!("{unknown}", type_at_pos(&db, pos));
} }
#[test] #[test]
@ -1549,9 +1496,8 @@ fn test<T: Trait1<Type = u32>>(x: T) {
#[test] #[test]
fn where_clause_trait_in_scope_for_method_resolution() { fn where_clause_trait_in_scope_for_method_resolution() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
mod foo { mod foo {
trait Trait { trait Trait {
fn foo(&self) -> u32 {} fn foo(&self) -> u32 {}
@ -1559,11 +1505,10 @@ mod foo {
} }
fn test<T: foo::Trait>(x: T) { fn test<T: foo::Trait>(x: T) {
x.foo()<|>; x.foo();
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
@ -2012,7 +1957,7 @@ fn test() {
#[test] #[test]
fn unselected_projection_in_trait_env_1() { fn unselected_projection_in_trait_env_1() {
let t = type_at( check_types(
r#" r#"
//- /main.rs //- /main.rs
trait Trait { trait Trait {
@ -2025,18 +1970,16 @@ trait Trait2 {
fn test<T: Trait>() where T::Item: Trait2 { fn test<T: Trait>() where T::Item: Trait2 {
let x: T::Item = no_matter; let x: T::Item = no_matter;
x.foo()<|>; x.foo();
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
fn unselected_projection_in_trait_env_2() { fn unselected_projection_in_trait_env_2() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait<T> { trait Trait<T> {
type Item; type Item;
} }
@ -2047,11 +1990,10 @@ trait Trait2 {
fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
let x: T::Item = no_matter; let x: T::Item = no_matter;
x.foo()<|>; x.foo();
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
@ -2097,9 +2039,8 @@ impl Trait for S2 {
#[test] #[test]
fn unselected_projection_on_trait_self() { fn unselected_projection_on_trait_self() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { trait Trait {
type Item; type Item;
@ -2112,18 +2053,16 @@ impl Trait for S {
} }
fn test() { fn test() {
S.f()<|>; S.f();
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
fn unselected_projection_chalk_fold() { fn unselected_projection_chalk_fold() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Interner {} trait Interner {}
trait Fold<I: Interner, TI = I> { trait Fold<I: Interner, TI = I> {
type Result; type Result;
@ -2142,18 +2081,16 @@ where
} }
fn foo<I: Interner>(interner: &I, t: Ty<I>) { fn foo<I: Interner>(interner: &I, t: Ty<I>) {
fold(interner, t)<|>; fold(interner, t);
} } //^ Ty<I>
"#, "#,
); );
assert_eq!(t, "Ty<I>");
} }
#[test] #[test]
fn trait_impl_self_ty() { fn trait_impl_self_ty() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait<T> { trait Trait<T> {
fn foo(&self); fn foo(&self);
} }
@ -2163,18 +2100,16 @@ struct S;
impl Trait<Self> for S {} impl Trait<Self> for S {}
fn test() { fn test() {
S.foo()<|>; S.foo();
} } //^ ()
"#, "#,
); );
assert_eq!(t, "()");
} }
#[test] #[test]
fn trait_impl_self_ty_cycle() { fn trait_impl_self_ty_cycle() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Trait { trait Trait {
fn foo(&self); fn foo(&self);
} }
@ -2184,18 +2119,17 @@ struct S<T>;
impl Trait for S<Self> {} impl Trait for S<Self> {}
fn test() { fn test() {
S.foo()<|>; S.foo();
} } //^ {unknown}
"#, "#,
); );
assert_eq!(t, "{unknown}");
} }
#[test] #[test]
fn unselected_projection_in_trait_env_cycle_1() { fn unselected_projection_in_trait_env_cycle_1() {
let t = type_at( // this is a legitimate cycle
check_types(
r#" r#"
//- /main.rs
trait Trait { trait Trait {
type Item; type Item;
} }
@ -2203,17 +2137,16 @@ trait Trait {
trait Trait2<T> {} trait Trait2<T> {}
fn test<T: Trait>() where T: Trait2<T::Item> { 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] #[test]
fn unselected_projection_in_trait_env_cycle_2() { fn unselected_projection_in_trait_env_cycle_2() {
let t = type_at( // this is a legitimate cycle
check_types(
r#" r#"
//- /main.rs //- /main.rs
trait Trait<T> { trait Trait<T> {
@ -2221,19 +2154,16 @@ trait Trait<T> {
} }
fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { 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] #[test]
fn inline_assoc_type_bounds_1() { fn inline_assoc_type_bounds_1() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Iterator { trait Iterator {
type Item; type Item;
} }
@ -2249,29 +2179,26 @@ impl<T: Iterator> Iterator for S<T> {
fn test<I: Iterator<Item: OtherTrait<u32>>>() { fn test<I: Iterator<Item: OtherTrait<u32>>>() {
let x: <S<I> as Iterator>::Item; let x: <S<I> as Iterator>::Item;
x.foo()<|>; x.foo();
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
fn inline_assoc_type_bounds_2() { fn inline_assoc_type_bounds_2() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
trait Iterator { trait Iterator {
type Item; type Item;
} }
fn test<I: Iterator<Item: Iterator<Item = u32>>>() { fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
let x: <<I as Iterator>::Item as Iterator>::Item; let x: <<I as Iterator>::Item as Iterator>::Item;
x<|>; x;
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
@ -2445,9 +2372,8 @@ fn main() {
#[test] #[test]
fn associated_type_bound() { fn associated_type_bound() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
pub trait Trait { pub trait Trait {
type Item: OtherTrait<u32>; type Item: OtherTrait<u32>;
} }
@ -2463,18 +2389,16 @@ impl<T: Trait> Trait for S<T> {
fn test<T: Trait>() { fn test<T: Trait>() {
let y: <S<T> as Trait>::Item = no_matter; let y: <S<T> as Trait>::Item = no_matter;
y.foo()<|>; y.foo();
} } //^ u32
"#, "#,
); );
assert_eq!(t, "u32");
} }
#[test] #[test]
fn dyn_trait_through_chalk() { fn dyn_trait_through_chalk() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct Box<T> {} struct Box<T> {}
#[lang = "deref"] #[lang = "deref"]
trait Deref { trait Deref {
@ -2488,18 +2412,16 @@ trait Trait {
} }
fn test(x: Box<dyn Trait>) { fn test(x: Box<dyn Trait>) {
x.foo()<|>; x.foo();
} } //^ ()
"#, "#,
); );
assert_eq!(t, "()");
} }
#[test] #[test]
fn string_to_owned() { fn string_to_owned() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct String {} struct String {}
pub trait ToOwned { pub trait ToOwned {
type Owned; type Owned;
@ -2509,11 +2431,10 @@ impl ToOwned for str {
type Owned = String; type Owned = String;
} }
fn test() { fn test() {
"foo".to_owned()<|>; "foo".to_owned();
} } //^ String
"#, "#,
); );
assert_eq!(t, "String");
} }
#[test] #[test]
@ -2637,9 +2558,8 @@ fn main() {
#[test] #[test]
fn nested_assoc() { fn nested_assoc() {
let t = type_at( check_types(
r#" r#"
//- /main.rs
struct Bar; struct Bar;
struct Foo; struct Foo;
@ -2662,11 +2582,10 @@ impl<T:A> B for T {
} }
fn main() { fn main() {
Bar::foo()<|>; Bar::foo();
} } //^ Foo
"#, "#,
); );
assert_eq!(t, "Foo");
} }
#[test] #[test]
@ -2846,12 +2765,12 @@ fn test() {
#[test] #[test]
fn integer_range_iterate() { fn integer_range_iterate() {
let t = type_at( check_types(
r#" r#"
//- /main.rs crate:main deps:core //- /main.rs crate:main deps:core
fn test() { fn test() {
for x in 0..100 { x<|>; } for x in 0..100 { x; }
} } //^ i32
//- /core.rs crate:core //- /core.rs crate:core
pub mod ops { pub mod ops {
@ -2886,7 +2805,6 @@ impl<A: Step> iter::Iterator for ops::Range<A> {
} }
"#, "#,
); );
assert_eq!(t, "i32");
} }
#[test] #[test]

View file

@ -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) 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 /// Skip to next non `trivia` token
pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> { pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option<SyntaxToken> {
while token.kind().is_trivia() { while token.kind().is_trivia() {

View file

@ -161,7 +161,7 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
} }
/// Extracts `//^ some text` annotations /// Extracts `//^ some text` annotations
pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> { pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
let mut res = Vec::new(); let mut res = Vec::new();
let mut prev_line_start: Option<TextSize> = None; let mut prev_line_start: Option<TextSize> = None;
let mut line_start: TextSize = 0.into(); let mut line_start: TextSize = 0.into();
@ -169,7 +169,7 @@ pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> {
if let Some(idx) = line.find("//^") { if let Some(idx) = line.find("//^") {
let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]); let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]);
let data = line[idx + "//^".len()..].trim().to_string(); let data = line[idx + "//^".len()..].trim().to_string();
res.push((offset, data)) res.push((TextRange::at(offset, 1.into()), data))
} }
prev_line_start = Some(line_start); prev_line_start = Some(line_start);
line_start += TextSize::of(line); line_start += TextSize::of(line);
@ -179,18 +179,20 @@ pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> {
#[test] #[test]
fn test_extract_annotations() { fn test_extract_annotations() {
let res = extract_annotations(&trim_indent( let text = stdx::trim_indent(
r#" r#"
fn main() { fn main() {
let x = 92; let x = 92;
//^ def //^ def
z + 1
x + 1
} //^ i32 } //^ i32
"#, "#,
)); );
let res = extract_annotations(&text)
assert_eq!(res, vec![(20.into(), "def".into()), (47.into(), "i32".into())]); .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: // Comparison functionality borrowed from cargo: