diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 49 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/coercion.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/macros.rs | 51 |
4 files changed, 133 insertions, 24 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 1e78f6efd..b8df27706 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -201,7 +201,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
201 | } | 201 | } |
202 | Expr::Return { expr } => { | 202 | Expr::Return { expr } => { |
203 | if let Some(expr) = expr { | 203 | if let Some(expr) = expr { |
204 | self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone())); | 204 | self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); |
205 | } | 205 | } |
206 | Ty::simple(TypeCtor::Never) | 206 | Ty::simple(TypeCtor::Never) |
207 | } | 207 | } |
@@ -245,7 +245,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
245 | ty | 245 | ty |
246 | } | 246 | } |
247 | Expr::Field { expr, name } => { | 247 | Expr::Field { expr, name } => { |
248 | let receiver_ty = self.infer_expr(*expr, &Expectation::none()); | 248 | let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
249 | let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); | 249 | let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); |
250 | let ty = autoderef::autoderef( | 250 | let ty = autoderef::autoderef( |
251 | self.db, | 251 | self.db, |
@@ -280,7 +280,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
280 | self.normalize_associated_types_in(ty) | 280 | self.normalize_associated_types_in(ty) |
281 | } | 281 | } |
282 | Expr::Await { expr } => { | 282 | Expr::Await { expr } => { |
283 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 283 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
284 | let ty = match self.resolve_future_future_output() { | 284 | let ty = match self.resolve_future_future_output() { |
285 | Some(future_future_output_alias) => { | 285 | Some(future_future_output_alias) => { |
286 | let ty = self.table.new_type_var(); | 286 | let ty = self.table.new_type_var(); |
@@ -299,7 +299,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
299 | ty | 299 | ty |
300 | } | 300 | } |
301 | Expr::Try { expr } => { | 301 | Expr::Try { expr } => { |
302 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 302 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
303 | let ty = match self.resolve_ops_try_ok() { | 303 | let ty = match self.resolve_ops_try_ok() { |
304 | Some(ops_try_ok_alias) => { | 304 | Some(ops_try_ok_alias) => { |
305 | let ty = self.table.new_type_var(); | 305 | let ty = self.table.new_type_var(); |
@@ -318,7 +318,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
318 | ty | 318 | ty |
319 | } | 319 | } |
320 | Expr::Cast { expr, type_ref } => { | 320 | Expr::Cast { expr, type_ref } => { |
321 | let _inner_ty = self.infer_expr(*expr, &Expectation::none()); | 321 | let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
322 | let cast_ty = self.make_ty(type_ref); | 322 | let cast_ty = self.make_ty(type_ref); |
323 | // FIXME check the cast... | 323 | // FIXME check the cast... |
324 | cast_ty | 324 | cast_ty |
@@ -334,12 +334,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
334 | } else { | 334 | } else { |
335 | Expectation::none() | 335 | Expectation::none() |
336 | }; | 336 | }; |
337 | // FIXME reference coercions etc. | 337 | let inner_ty = self.infer_expr_inner(*expr, &expectation); |
338 | let inner_ty = self.infer_expr(*expr, &expectation); | ||
339 | Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) | 338 | Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) |
340 | } | 339 | } |
341 | Expr::Box { expr } => { | 340 | Expr::Box { expr } => { |
342 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 341 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
343 | if let Some(box_) = self.resolve_boxed_box() { | 342 | if let Some(box_) = self.resolve_boxed_box() { |
344 | Ty::apply_one(TypeCtor::Adt(box_), inner_ty) | 343 | Ty::apply_one(TypeCtor::Adt(box_), inner_ty) |
345 | } else { | 344 | } else { |
@@ -347,7 +346,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
347 | } | 346 | } |
348 | } | 347 | } |
349 | Expr::UnaryOp { expr, op } => { | 348 | Expr::UnaryOp { expr, op } => { |
350 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 349 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
351 | match op { | 350 | match op { |
352 | UnaryOp::Deref => match self.resolver.krate() { | 351 | UnaryOp::Deref => match self.resolver.krate() { |
353 | Some(krate) => { | 352 | Some(krate) => { |
@@ -417,7 +416,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
417 | _ => Ty::Unknown, | 416 | _ => Ty::Unknown, |
418 | }, | 417 | }, |
419 | Expr::Range { lhs, rhs, range_type } => { | 418 | Expr::Range { lhs, rhs, range_type } => { |
420 | let lhs_ty = lhs.map(|e| self.infer_expr(e, &Expectation::none())); | 419 | let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none())); |
421 | let rhs_expect = lhs_ty | 420 | let rhs_expect = lhs_ty |
422 | .as_ref() | 421 | .as_ref() |
423 | .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); | 422 | .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone())); |
@@ -455,7 +454,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
455 | } | 454 | } |
456 | } | 455 | } |
457 | Expr::Index { base, index } => { | 456 | Expr::Index { base, index } => { |
458 | let _base_ty = self.infer_expr(*base, &Expectation::none()); | 457 | let _base_ty = self.infer_expr_inner(*base, &Expectation::none()); |
459 | let _index_ty = self.infer_expr(*index, &Expectation::none()); | 458 | let _index_ty = self.infer_expr(*index, &Expectation::none()); |
460 | // FIXME: use `std::ops::Index::Output` to figure out the real return type | 459 | // FIXME: use `std::ops::Index::Output` to figure out the real return type |
461 | Ty::Unknown | 460 | Ty::Unknown |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index c520bb375..f1b67555f 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -11,8 +11,8 @@ use std::fmt::Write; | |||
11 | use std::sync::Arc; | 11 | use std::sync::Arc; |
12 | 12 | ||
13 | use hir_def::{ | 13 | use hir_def::{ |
14 | body::BodySourceMap, db::DefDatabase, nameres::CrateDefMap, AssocItemId, DefWithBodyId, | 14 | body::BodySourceMap, child_from_source::ChildFromSource, db::DefDatabase, nameres::CrateDefMap, |
15 | LocalModuleId, Lookup, ModuleDefId, | 15 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, |
16 | }; | 16 | }; |
17 | use hir_expand::InFile; | 17 | use hir_expand::InFile; |
18 | use insta::assert_snapshot; | 18 | use insta::assert_snapshot; |
@@ -31,18 +31,15 @@ use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResu | |||
31 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { | 31 | fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { |
32 | let file = db.parse(pos.file_id).ok().unwrap(); | 32 | let file = db.parse(pos.file_id).ok().unwrap(); |
33 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 33 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
34 | 34 | let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | |
35 | let module = db.module_for_file(pos.file_id); | 35 | let module = db.module_for_file(pos.file_id); |
36 | let crate_def_map = db.crate_def_map(module.krate); | 36 | let func = module.child_from_source(db, InFile::new(pos.file_id.into(), fn_def)).unwrap(); |
37 | for decl in crate_def_map[module.local_id].scope.declarations() { | 37 | |
38 | if let ModuleDefId::FunctionId(func) = decl { | 38 | let (_body, source_map) = db.body_with_source_map(func.into()); |
39 | let (_body, source_map) = db.body_with_source_map(func.into()); | 39 | if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { |
40 | if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { | 40 | let infer = db.infer(func.into()); |
41 | let infer = db.infer(func.into()); | 41 | let ty = &infer[expr_id]; |
42 | let ty = &infer[expr_id]; | 42 | return ty.display(db).to_string(); |
43 | return ty.display(db).to_string(); | ||
44 | } | ||
45 | } | ||
46 | } | 43 | } |
47 | panic!("Can't find expression") | 44 | panic!("Can't find expression") |
48 | } | 45 | } |
@@ -53,6 +50,10 @@ fn type_at(content: &str) -> String { | |||
53 | } | 50 | } |
54 | 51 | ||
55 | fn infer(content: &str) -> String { | 52 | fn infer(content: &str) -> String { |
53 | infer_with_mismatches(content, false) | ||
54 | } | ||
55 | |||
56 | fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | ||
56 | let (db, file_id) = TestDB::with_single_file(content); | 57 | let (db, file_id) = TestDB::with_single_file(content); |
57 | 58 | ||
58 | let mut acc = String::new(); | 59 | let mut acc = String::new(); |
@@ -60,6 +61,7 @@ fn infer(content: &str) -> String { | |||
60 | let mut infer_def = |inference_result: Arc<InferenceResult>, | 61 | let mut infer_def = |inference_result: Arc<InferenceResult>, |
61 | body_source_map: Arc<BodySourceMap>| { | 62 | body_source_map: Arc<BodySourceMap>| { |
62 | let mut types = Vec::new(); | 63 | let mut types = Vec::new(); |
64 | let mut mismatches = Vec::new(); | ||
63 | 65 | ||
64 | for (pat, ty) in inference_result.type_of_pat.iter() { | 66 | for (pat, ty) in inference_result.type_of_pat.iter() { |
65 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | 67 | let syntax_ptr = match body_source_map.pat_syntax(pat) { |
@@ -79,6 +81,9 @@ fn infer(content: &str) -> String { | |||
79 | None => continue, | 81 | None => continue, |
80 | }; | 82 | }; |
81 | types.push((syntax_ptr, ty)); | 83 | types.push((syntax_ptr, ty)); |
84 | if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { | ||
85 | mismatches.push((syntax_ptr, mismatch)); | ||
86 | } | ||
82 | } | 87 | } |
83 | 88 | ||
84 | // sort ranges for consistency | 89 | // sort ranges for consistency |
@@ -104,6 +109,24 @@ fn infer(content: &str) -> String { | |||
104 | ) | 109 | ) |
105 | .unwrap(); | 110 | .unwrap(); |
106 | } | 111 | } |
112 | if include_mismatches { | ||
113 | mismatches.sort_by_key(|(src_ptr, _)| { | ||
114 | (src_ptr.value.range().start(), src_ptr.value.range().end()) | ||
115 | }); | ||
116 | for (src_ptr, mismatch) in &mismatches { | ||
117 | let range = src_ptr.value.range(); | ||
118 | let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; | ||
119 | write!( | ||
120 | acc, | ||
121 | "{}{}: expected {}, got {}\n", | ||
122 | macro_prefix, | ||
123 | range, | ||
124 | mismatch.expected.display(&db), | ||
125 | mismatch.actual.display(&db), | ||
126 | ) | ||
127 | .unwrap(); | ||
128 | } | ||
129 | } | ||
107 | }; | 130 | }; |
108 | 131 | ||
109 | let module = db.module_for_file(file_id); | 132 | let module = db.module_for_file(file_id); |
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 1530fcc63..58b22396f 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use super::infer_with_mismatches; | ||
1 | use insta::assert_snapshot; | 2 | use insta::assert_snapshot; |
2 | use test_utils::covers; | 3 | use test_utils::covers; |
3 | 4 | ||
@@ -367,3 +368,38 @@ fn test() { | |||
367 | "### | 368 | "### |
368 | ); | 369 | ); |
369 | } | 370 | } |
371 | |||
372 | #[test] | ||
373 | fn coerce_autoderef() { | ||
374 | assert_snapshot!( | ||
375 | infer_with_mismatches(r#" | ||
376 | struct Foo; | ||
377 | fn takes_ref_foo(x: &Foo) {} | ||
378 | fn test() { | ||
379 | takes_ref_foo(&Foo); | ||
380 | takes_ref_foo(&&Foo); | ||
381 | takes_ref_foo(&&&Foo); | ||
382 | } | ||
383 | "#, true), | ||
384 | @r###" | ||
385 | [30; 31) 'x': &Foo | ||
386 | [39; 41) '{}': () | ||
387 | [52; 133) '{ ...oo); }': () | ||
388 | [58; 71) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> () | ||
389 | [58; 77) 'takes_...(&Foo)': () | ||
390 | [72; 76) '&Foo': &Foo | ||
391 | [73; 76) 'Foo': Foo | ||
392 | [83; 96) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> () | ||
393 | [83; 103) 'takes_...&&Foo)': () | ||
394 | [97; 102) '&&Foo': &&Foo | ||
395 | [98; 102) '&Foo': &Foo | ||
396 | [99; 102) 'Foo': Foo | ||
397 | [109; 122) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> () | ||
398 | [109; 130) 'takes_...&&Foo)': () | ||
399 | [123; 129) '&&&Foo': &&&Foo | ||
400 | [124; 129) '&&Foo': &&Foo | ||
401 | [125; 129) '&Foo': &Foo | ||
402 | [126; 129) 'Foo': Foo | ||
403 | "### | ||
404 | ); | ||
405 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 0d9a35ce0..9c29a054e 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -266,3 +266,54 @@ fn main() { | |||
266 | "### | 266 | "### |
267 | ); | 267 | ); |
268 | } | 268 | } |
269 | |||
270 | #[test] | ||
271 | fn infer_derive_clone_simple() { | ||
272 | let (db, pos) = TestDB::with_position( | ||
273 | r#" | ||
274 | //- /main.rs crate:main deps:std | ||
275 | #[derive(Clone)] | ||
276 | struct S; | ||
277 | fn test() { | ||
278 | S.clone()<|>; | ||
279 | } | ||
280 | |||
281 | //- /lib.rs crate:std | ||
282 | #[prelude_import] | ||
283 | use clone::*; | ||
284 | mod clone { | ||
285 | trait Clone { | ||
286 | fn clone(&self) -> Self; | ||
287 | } | ||
288 | } | ||
289 | "#, | ||
290 | ); | ||
291 | assert_eq!("S", type_at_pos(&db, pos)); | ||
292 | } | ||
293 | |||
294 | #[test] | ||
295 | fn infer_derive_clone_with_params() { | ||
296 | let (db, pos) = TestDB::with_position( | ||
297 | r#" | ||
298 | //- /main.rs crate:main deps:std | ||
299 | #[derive(Clone)] | ||
300 | struct S; | ||
301 | #[derive(Clone)] | ||
302 | struct Wrapper<T>(T); | ||
303 | struct NonClone; | ||
304 | fn test() { | ||
305 | (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; | ||
306 | } | ||
307 | |||
308 | //- /lib.rs crate:std | ||
309 | #[prelude_import] | ||
310 | use clone::*; | ||
311 | mod clone { | ||
312 | trait Clone { | ||
313 | fn clone(&self) -> Self; | ||
314 | } | ||
315 | } | ||
316 | "#, | ||
317 | ); | ||
318 | assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos)); | ||
319 | } | ||