diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model_impl/module.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/module_tree.rs | 99 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/lower.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/query_definitions.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 37 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 49 |
15 files changed, 242 insertions, 115 deletions
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index 480ec27bf..418d59c91 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs | |||
@@ -25,9 +25,10 @@ impl Module { | |||
25 | 25 | ||
26 | pub(crate) fn definition_source_impl(&self, db: &impl HirDatabase) -> (FileId, ModuleSource) { | 26 | pub(crate) fn definition_source_impl(&self, db: &impl HirDatabase) -> (FileId, ModuleSource) { |
27 | let module_tree = db.module_tree(self.krate); | 27 | let module_tree = db.module_tree(self.krate); |
28 | let source = self.module_id.source(&module_tree); | 28 | let file_id = self.module_id.file_id(&module_tree); |
29 | let module_source = ModuleSource::from_source_item_id(db, source); | 29 | let decl_id = self.module_id.decl_id(&module_tree); |
30 | let file_id = source.file_id.as_original_file(); | 30 | let module_source = ModuleSource::new(db, file_id, decl_id); |
31 | let file_id = file_id.as_original_file(); | ||
31 | (file_id, module_source) | 32 | (file_id, module_source) |
32 | } | 33 | } |
33 | 34 | ||
@@ -39,8 +40,7 @@ impl Module { | |||
39 | let link = self.module_id.parent_link(&module_tree)?; | 40 | let link = self.module_id.parent_link(&module_tree)?; |
40 | let file_id = link | 41 | let file_id = link |
41 | .owner(&module_tree) | 42 | .owner(&module_tree) |
42 | .source(&module_tree) | 43 | .file_id(&module_tree) |
43 | .file_id | ||
44 | .as_original_file(); | 44 | .as_original_file(); |
45 | let src = link.source(&module_tree, db); | 45 | let src = link.source(&module_tree, db); |
46 | Some((file_id, src)) | 46 | Some((file_id, src)) |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 5df4bd4a1..3f76b769d 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -16,6 +16,7 @@ use crate::{ | |||
16 | adt::{StructData, EnumData}, | 16 | adt::{StructData, EnumData}, |
17 | impl_block::ModuleImplBlocks, | 17 | impl_block::ModuleImplBlocks, |
18 | generics::{GenericParams, GenericDef}, | 18 | generics::{GenericParams, GenericDef}, |
19 | ids::SourceFileItemId, | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | #[salsa::query_group(HirDatabaseStorage)] | 22 | #[salsa::query_group(HirDatabaseStorage)] |
@@ -51,7 +52,11 @@ pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> { | |||
51 | fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; | 52 | fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; |
52 | 53 | ||
53 | #[salsa::invoke(crate::module_tree::Submodule::submodules_query)] | 54 | #[salsa::invoke(crate::module_tree::Submodule::submodules_query)] |
54 | fn submodules(&self, source: SourceItemId) -> Arc<Vec<crate::module_tree::Submodule>>; | 55 | fn submodules( |
56 | &self, | ||
57 | file_id: HirFileId, | ||
58 | delc_id: Option<SourceFileItemId>, | ||
59 | ) -> Arc<Vec<crate::module_tree::Submodule>>; | ||
55 | 60 | ||
56 | #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] | 61 | #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] |
57 | fn lower_module(&self, module: Module) -> (Arc<LoweredModule>, Arc<ImportSourceMap>); | 62 | fn lower_module(&self, module: Module) -> (Arc<LoweredModule>, Arc<ImportSourceMap>); |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 29469af2c..60d997bbe 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -498,7 +498,13 @@ impl ExprCollector { | |||
498 | let then_branch = self.collect_block_opt(e.then_branch()); | 498 | let then_branch = self.collect_block_opt(e.then_branch()); |
499 | let else_branch = e | 499 | let else_branch = e |
500 | .else_branch() | 500 | .else_branch() |
501 | .map(|e| self.collect_block(e)) | 501 | .map(|b| match b { |
502 | ast::ElseBranchFlavor::Block(it) => self.collect_block(it), | ||
503 | ast::ElseBranchFlavor::IfExpr(elif) => { | ||
504 | let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); | ||
505 | self.collect_expr(expr) | ||
506 | } | ||
507 | }) | ||
502 | .unwrap_or_else(|| self.empty_block()); | 508 | .unwrap_or_else(|| self.empty_block()); |
503 | let placeholder_pat = self.pats.alloc(Pat::Missing); | 509 | let placeholder_pat = self.pats.alloc(Pat::Missing); |
504 | let arms = vec![ | 510 | let arms = vec![ |
@@ -521,7 +527,13 @@ impl ExprCollector { | |||
521 | } else { | 527 | } else { |
522 | let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); | 528 | let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); |
523 | let then_branch = self.collect_block_opt(e.then_branch()); | 529 | let then_branch = self.collect_block_opt(e.then_branch()); |
524 | let else_branch = e.else_branch().map(|e| self.collect_block(e)); | 530 | let else_branch = e.else_branch().map(|b| match b { |
531 | ast::ElseBranchFlavor::Block(it) => self.collect_block(it), | ||
532 | ast::ElseBranchFlavor::IfExpr(elif) => { | ||
533 | let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); | ||
534 | self.collect_expr(expr) | ||
535 | } | ||
536 | }); | ||
525 | self.alloc_expr( | 537 | self.alloc_expr( |
526 | Expr::If { | 538 | Expr::If { |
527 | condition, | 539 | condition, |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 7dd4b540e..0e4dc6261 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -4,7 +4,7 @@ use std::{ | |||
4 | }; | 4 | }; |
5 | 5 | ||
6 | use ra_db::{LocationIntener, FileId}; | 6 | use ra_db::{LocationIntener, FileId}; |
7 | use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast}; | 7 | use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; |
8 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; | 8 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
@@ -203,7 +203,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { | |||
203 | let items = ctx.db.file_items(ctx.file_id); | 203 | let items = ctx.db.file_items(ctx.file_id); |
204 | let raw = SourceItemId { | 204 | let raw = SourceItemId { |
205 | file_id: ctx.file_id, | 205 | file_id: ctx.file_id, |
206 | item_id: Some(items.id_of(ctx.file_id, ast.syntax())), | 206 | item_id: items.id_of(ctx.file_id, ast.syntax()), |
207 | }; | 207 | }; |
208 | let loc = ItemLoc { | 208 | let loc = ItemLoc { |
209 | module: ctx.module, | 209 | module: ctx.module, |
@@ -301,15 +301,14 @@ impl_arena_id!(SourceFileItemId); | |||
301 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 301 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
302 | pub struct SourceItemId { | 302 | pub struct SourceItemId { |
303 | pub(crate) file_id: HirFileId, | 303 | pub(crate) file_id: HirFileId, |
304 | /// None for the whole file. | 304 | pub(crate) item_id: SourceFileItemId, |
305 | pub(crate) item_id: Option<SourceFileItemId>, | ||
306 | } | 305 | } |
307 | 306 | ||
308 | /// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. | 307 | /// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. |
309 | #[derive(Debug, PartialEq, Eq)] | 308 | #[derive(Debug, PartialEq, Eq)] |
310 | pub struct SourceFileItems { | 309 | pub struct SourceFileItems { |
311 | file_id: HirFileId, | 310 | file_id: HirFileId, |
312 | arena: Arena<SourceFileItemId, TreeArc<SyntaxNode>>, | 311 | arena: Arena<SourceFileItemId, SyntaxNodePtr>, |
313 | } | 312 | } |
314 | 313 | ||
315 | impl SourceFileItems { | 314 | impl SourceFileItems { |
@@ -329,15 +328,15 @@ impl SourceFileItems { | |||
329 | // trait does not chage ids of top-level items, which helps caching. | 328 | // trait does not chage ids of top-level items, which helps caching. |
330 | bfs(source_file.syntax(), |it| { | 329 | bfs(source_file.syntax(), |it| { |
331 | if let Some(module_item) = ast::ModuleItem::cast(it) { | 330 | if let Some(module_item) = ast::ModuleItem::cast(it) { |
332 | self.alloc(module_item.syntax().to_owned()); | 331 | self.alloc(module_item.syntax()); |
333 | } else if let Some(macro_call) = ast::MacroCall::cast(it) { | 332 | } else if let Some(macro_call) = ast::MacroCall::cast(it) { |
334 | self.alloc(macro_call.syntax().to_owned()); | 333 | self.alloc(macro_call.syntax()); |
335 | } | 334 | } |
336 | }) | 335 | }) |
337 | } | 336 | } |
338 | 337 | ||
339 | fn alloc(&mut self, item: TreeArc<SyntaxNode>) -> SourceFileItemId { | 338 | fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { |
340 | self.arena.alloc(item) | 339 | self.arena.alloc(SyntaxNodePtr::new(item)) |
341 | } | 340 | } |
342 | pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { | 341 | pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { |
343 | assert_eq!( | 342 | assert_eq!( |
@@ -348,17 +347,8 @@ impl SourceFileItems { | |||
348 | self.id_of_unchecked(item) | 347 | self.id_of_unchecked(item) |
349 | } | 348 | } |
350 | pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { | 349 | pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { |
351 | if let Some((id, _)) = self.arena.iter().find(|(_id, i)| *i == item) { | 350 | let ptr = SyntaxNodePtr::new(item); |
352 | return id; | 351 | if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) { |
353 | } | ||
354 | // This should not happen. Let's try to give a sensible diagnostics. | ||
355 | if let Some((id, i)) = self.arena.iter().find(|(_id, i)| i.range() == item.range()) { | ||
356 | // FIXME(#288): whyyy are we getting here? | ||
357 | log::error!( | ||
358 | "unequal syntax nodes with the same range:\n{:?}\n{:?}", | ||
359 | item, | ||
360 | i | ||
361 | ); | ||
362 | return id; | 352 | return id; |
363 | } | 353 | } |
364 | panic!( | 354 | panic!( |
@@ -367,15 +357,11 @@ impl SourceFileItems { | |||
367 | self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), | 357 | self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(), |
368 | ); | 358 | ); |
369 | } | 359 | } |
370 | pub fn id_of_parse(&self) -> SourceFileItemId { | ||
371 | let (id, _syntax) = self.arena.iter().next().unwrap(); | ||
372 | id | ||
373 | } | ||
374 | } | 360 | } |
375 | 361 | ||
376 | impl std::ops::Index<SourceFileItemId> for SourceFileItems { | 362 | impl std::ops::Index<SourceFileItemId> for SourceFileItems { |
377 | type Output = SyntaxNode; | 363 | type Output = SyntaxNodePtr; |
378 | fn index(&self, idx: SourceFileItemId) -> &SyntaxNode { | 364 | fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { |
379 | &self.arena[idx] | 365 | &self.arena[idx] |
380 | } | 366 | } |
381 | } | 367 | } |
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 338ed0516..d704c3adb 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -1,4 +1,6 @@ | |||
1 | test_utils::marks!( | 1 | test_utils::marks!( |
2 | name_res_works_for_broken_modules | 2 | name_res_works_for_broken_modules |
3 | item_map_enum_importing | 3 | item_map_enum_importing |
4 | type_var_cycles_resolve_completely | ||
5 | type_var_cycles_resolve_as_possible | ||
4 | ); | 6 | ); |
diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs index d5ad9decb..d1dc3fa4b 100644 --- a/crates/ra_hir/src/module_tree.rs +++ b/crates/ra_hir/src/module_tree.rs | |||
@@ -11,21 +11,28 @@ use ra_syntax::{ | |||
11 | use ra_arena::{Arena, RawId, impl_arena_id}; | 11 | use ra_arena::{Arena, RawId, impl_arena_id}; |
12 | use test_utils::tested_by; | 12 | use test_utils::tested_by; |
13 | 13 | ||
14 | use crate::{Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource}; | 14 | use crate::{ |
15 | Name, AsName, HirDatabase, SourceItemId, HirFileId, Problem, SourceFileItems, ModuleSource, | ||
16 | ids::SourceFileItemId, | ||
17 | }; | ||
15 | 18 | ||
16 | impl ModuleSource { | 19 | impl ModuleSource { |
17 | pub(crate) fn from_source_item_id( | 20 | pub(crate) fn new( |
18 | db: &impl HirDatabase, | 21 | db: &impl HirDatabase, |
19 | source_item_id: SourceItemId, | 22 | file_id: HirFileId, |
23 | decl_id: Option<SourceFileItemId>, | ||
20 | ) -> ModuleSource { | 24 | ) -> ModuleSource { |
21 | let module_syntax = db.file_item(source_item_id); | 25 | match decl_id { |
22 | if let Some(source_file) = ast::SourceFile::cast(&module_syntax) { | 26 | Some(item_id) => { |
23 | ModuleSource::SourceFile(source_file.to_owned()) | 27 | let module = db.file_item(SourceItemId { file_id, item_id }); |
24 | } else if let Some(module) = ast::Module::cast(&module_syntax) { | 28 | let module = ast::Module::cast(&*module).unwrap(); |
25 | assert!(module.item_list().is_some(), "expected inline module"); | 29 | assert!(module.item_list().is_some(), "expected inline module"); |
26 | ModuleSource::Module(module.to_owned()) | 30 | ModuleSource::Module(module.to_owned()) |
27 | } else { | 31 | } |
28 | panic!("expected file or inline module") | 32 | None => { |
33 | let source_file = db.hir_parse(file_id); | ||
34 | ModuleSource::SourceFile(source_file) | ||
35 | } | ||
29 | } | 36 | } |
30 | } | 37 | } |
31 | } | 38 | } |
@@ -34,18 +41,18 @@ impl ModuleSource { | |||
34 | pub struct Submodule { | 41 | pub struct Submodule { |
35 | name: Name, | 42 | name: Name, |
36 | is_declaration: bool, | 43 | is_declaration: bool, |
37 | source: SourceItemId, | 44 | decl_id: SourceFileItemId, |
38 | } | 45 | } |
39 | 46 | ||
40 | impl Submodule { | 47 | impl Submodule { |
41 | pub(crate) fn submodules_query( | 48 | pub(crate) fn submodules_query( |
42 | db: &impl HirDatabase, | 49 | db: &impl HirDatabase, |
43 | source: SourceItemId, | 50 | file_id: HirFileId, |
51 | decl_id: Option<SourceFileItemId>, | ||
44 | ) -> Arc<Vec<Submodule>> { | 52 | ) -> Arc<Vec<Submodule>> { |
45 | db.check_canceled(); | 53 | db.check_canceled(); |
46 | let file_id = source.file_id; | ||
47 | let file_items = db.file_items(file_id); | 54 | let file_items = db.file_items(file_id); |
48 | let module_source = ModuleSource::from_source_item_id(db, source); | 55 | let module_source = ModuleSource::new(db, file_id, decl_id); |
49 | let submodules = match module_source { | 56 | let submodules = match module_source { |
50 | ModuleSource::SourceFile(source_file) => { | 57 | ModuleSource::SourceFile(source_file) => { |
51 | collect_submodules(file_id, &file_items, &*source_file) | 58 | collect_submodules(file_id, &file_items, &*source_file) |
@@ -54,6 +61,7 @@ impl Submodule { | |||
54 | collect_submodules(file_id, &file_items, module.item_list().unwrap()) | 61 | collect_submodules(file_id, &file_items, module.item_list().unwrap()) |
55 | } | 62 | } |
56 | }; | 63 | }; |
64 | |||
57 | return Arc::new(submodules); | 65 | return Arc::new(submodules); |
58 | 66 | ||
59 | fn collect_submodules( | 67 | fn collect_submodules( |
@@ -75,10 +83,7 @@ impl Submodule { | |||
75 | let sub = Submodule { | 83 | let sub = Submodule { |
76 | name, | 84 | name, |
77 | is_declaration: module.has_semi(), | 85 | is_declaration: module.has_semi(), |
78 | source: SourceItemId { | 86 | decl_id: file_items.id_of(file_id, module.syntax()), |
79 | file_id, | ||
80 | item_id: Some(file_items.id_of(file_id, module.syntax())), | ||
81 | }, | ||
82 | }; | 87 | }; |
83 | Some(sub) | 88 | Some(sub) |
84 | }) | 89 | }) |
@@ -110,7 +115,9 @@ pub struct ModuleTree { | |||
110 | 115 | ||
111 | #[derive(Debug, PartialEq, Eq, Hash)] | 116 | #[derive(Debug, PartialEq, Eq, Hash)] |
112 | pub struct ModuleData { | 117 | pub struct ModuleData { |
113 | source: SourceItemId, | 118 | file_id: HirFileId, |
119 | /// Points to `ast::Module`, `None` for the whole file. | ||
120 | decl_id: Option<SourceFileItemId>, | ||
114 | parent: Option<LinkId>, | 121 | parent: Option<LinkId>, |
115 | children: Vec<LinkId>, | 122 | children: Vec<LinkId>, |
116 | } | 123 | } |
@@ -136,8 +143,15 @@ impl ModuleTree { | |||
136 | self.mods.iter().map(|(id, _)| id) | 143 | self.mods.iter().map(|(id, _)| id) |
137 | } | 144 | } |
138 | 145 | ||
139 | pub(crate) fn find_module_by_source(&self, source: SourceItemId) -> Option<ModuleId> { | 146 | pub(crate) fn find_module_by_source( |
140 | let (res, _) = self.mods.iter().find(|(_, m)| m.source == source)?; | 147 | &self, |
148 | file_id: HirFileId, | ||
149 | decl_id: Option<SourceFileItemId>, | ||
150 | ) -> Option<ModuleId> { | ||
151 | let (res, _) = self | ||
152 | .mods | ||
153 | .iter() | ||
154 | .find(|(_, m)| (m.file_id, m.decl_id) == (file_id, decl_id))?; | ||
141 | Some(res) | 155 | Some(res) |
142 | } | 156 | } |
143 | 157 | ||
@@ -147,11 +161,7 @@ impl ModuleTree { | |||
147 | let source_root_id = db.file_source_root(file_id); | 161 | let source_root_id = db.file_source_root(file_id); |
148 | 162 | ||
149 | let source_root = db.source_root(source_root_id); | 163 | let source_root = db.source_root(source_root_id); |
150 | let source = SourceItemId { | 164 | self.init_subtree(db, &source_root, None, file_id.into(), None); |
151 | file_id: file_id.into(), | ||
152 | item_id: None, | ||
153 | }; | ||
154 | self.init_subtree(db, &source_root, None, source); | ||
155 | } | 165 | } |
156 | 166 | ||
157 | fn init_subtree( | 167 | fn init_subtree( |
@@ -159,16 +169,21 @@ impl ModuleTree { | |||
159 | db: &impl HirDatabase, | 169 | db: &impl HirDatabase, |
160 | source_root: &SourceRoot, | 170 | source_root: &SourceRoot, |
161 | parent: Option<LinkId>, | 171 | parent: Option<LinkId>, |
162 | source: SourceItemId, | 172 | file_id: HirFileId, |
173 | decl_id: Option<SourceFileItemId>, | ||
163 | ) -> ModuleId { | 174 | ) -> ModuleId { |
164 | let id = self.alloc_mod(ModuleData { | 175 | let id = self.alloc_mod(ModuleData { |
165 | source, | 176 | file_id, |
177 | decl_id, | ||
166 | parent, | 178 | parent, |
167 | children: Vec::new(), | 179 | children: Vec::new(), |
168 | }); | 180 | }); |
169 | for sub in db.submodules(source).iter() { | 181 | for sub in db.submodules(file_id, decl_id).iter() { |
170 | let link = self.alloc_link(LinkData { | 182 | let link = self.alloc_link(LinkData { |
171 | source: sub.source, | 183 | source: SourceItemId { |
184 | file_id, | ||
185 | item_id: sub.decl_id, | ||
186 | }, | ||
172 | name: sub.name.clone(), | 187 | name: sub.name.clone(), |
173 | owner: id, | 188 | owner: id, |
174 | points_to: Vec::new(), | 189 | points_to: Vec::new(), |
@@ -176,24 +191,17 @@ impl ModuleTree { | |||
176 | }); | 191 | }); |
177 | 192 | ||
178 | let (points_to, problem) = if sub.is_declaration { | 193 | let (points_to, problem) = if sub.is_declaration { |
179 | let (points_to, problem) = resolve_submodule(db, source.file_id, &sub.name); | 194 | let (points_to, problem) = resolve_submodule(db, file_id, &sub.name); |
180 | let points_to = points_to | 195 | let points_to = points_to |
181 | .into_iter() | 196 | .into_iter() |
182 | .map(|file_id| { | 197 | .map(|file_id| { |
183 | self.init_subtree( | 198 | self.init_subtree(db, source_root, Some(link), file_id.into(), None) |
184 | db, | ||
185 | source_root, | ||
186 | Some(link), | ||
187 | SourceItemId { | ||
188 | file_id: file_id.into(), | ||
189 | item_id: None, | ||
190 | }, | ||
191 | ) | ||
192 | }) | 199 | }) |
193 | .collect::<Vec<_>>(); | 200 | .collect::<Vec<_>>(); |
194 | (points_to, problem) | 201 | (points_to, problem) |
195 | } else { | 202 | } else { |
196 | let points_to = self.init_subtree(db, source_root, Some(link), sub.source); | 203 | let points_to = |
204 | self.init_subtree(db, source_root, Some(link), file_id, Some(sub.decl_id)); | ||
197 | (vec![points_to], None) | 205 | (vec![points_to], None) |
198 | }; | 206 | }; |
199 | 207 | ||
@@ -216,8 +224,11 @@ impl ModuleTree { | |||
216 | } | 224 | } |
217 | 225 | ||
218 | impl ModuleId { | 226 | impl ModuleId { |
219 | pub(crate) fn source(self, tree: &ModuleTree) -> SourceItemId { | 227 | pub(crate) fn file_id(self, tree: &ModuleTree) -> HirFileId { |
220 | tree.mods[self].source | 228 | tree.mods[self].file_id |
229 | } | ||
230 | pub(crate) fn decl_id(self, tree: &ModuleTree) -> Option<SourceFileItemId> { | ||
231 | tree.mods[self].decl_id | ||
221 | } | 232 | } |
222 | pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { | 233 | pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { |
223 | tree.mods[self].parent | 234 | tree.mods[self].parent |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 5193900e0..97ce6c946 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -215,7 +215,7 @@ where | |||
215 | // Populate extern crates prelude | 215 | // Populate extern crates prelude |
216 | { | 216 | { |
217 | let root_id = module_id.crate_root(&self.module_tree); | 217 | let root_id = module_id.crate_root(&self.module_tree); |
218 | let file_id = root_id.source(&self.module_tree).file_id; | 218 | let file_id = root_id.file_id(&self.module_tree); |
219 | let crate_graph = self.db.crate_graph(); | 219 | let crate_graph = self.db.crate_graph(); |
220 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) | 220 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file()) |
221 | { | 221 | { |
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index 1d77548f3..8df11a5f4 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs | |||
@@ -121,10 +121,7 @@ impl LoweredModule { | |||
121 | let item_id = file_items.id_of_unchecked(macro_call.syntax()); | 121 | let item_id = file_items.id_of_unchecked(macro_call.syntax()); |
122 | let loc = MacroCallLoc { | 122 | let loc = MacroCallLoc { |
123 | module, | 123 | module, |
124 | source_item_id: SourceItemId { | 124 | source_item_id: SourceItemId { file_id, item_id }, |
125 | file_id, | ||
126 | item_id: Some(item_id), | ||
127 | }, | ||
128 | }; | 125 | }; |
129 | let id = loc.id(db); | 126 | let id = loc.id(db); |
130 | let file_id = HirFileId::from(id); | 127 | let file_id = HirFileId::from(id); |
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index 61c93a964..bf9ac0dfb 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs | |||
@@ -4,9 +4,7 @@ use std::{ | |||
4 | }; | 4 | }; |
5 | 5 | ||
6 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{SyntaxNode, TreeArc}; |
8 | AstNode, SyntaxNode, TreeArc, | ||
9 | }; | ||
10 | use ra_db::{CrateId}; | 8 | use ra_db::{CrateId}; |
11 | 9 | ||
12 | use crate::{ | 10 | use crate::{ |
@@ -32,10 +30,10 @@ pub(super) fn file_item( | |||
32 | db: &impl HirDatabase, | 30 | db: &impl HirDatabase, |
33 | source_item_id: SourceItemId, | 31 | source_item_id: SourceItemId, |
34 | ) -> TreeArc<SyntaxNode> { | 32 | ) -> TreeArc<SyntaxNode> { |
35 | match source_item_id.item_id { | 33 | let source_file = db.hir_parse(source_item_id.file_id); |
36 | Some(id) => db.file_items(source_item_id.file_id)[id].to_owned(), | 34 | db.file_items(source_item_id.file_id)[source_item_id.item_id] |
37 | None => db.hir_parse(source_item_id.file_id).syntax().to_owned(), | 35 | .to_node(&source_file) |
38 | } | 36 | .to_owned() |
39 | } | 37 | } |
40 | 38 | ||
41 | pub(super) fn item_map(db: &impl HirDatabase, crate_id: CrateId) -> Arc<ItemMap> { | 39 | pub(super) fn item_map(db: &impl HirDatabase, crate_id: CrateId) -> Arc<ItemMap> { |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index c0b3f1cd4..f523f0647 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -13,18 +13,14 @@ use ra_syntax::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | HirDatabase, Function, SourceItemId, ModuleDef, | 16 | HirDatabase, Function, ModuleDef, |
17 | AsName, Module, | 17 | AsName, Module, HirFileId, |
18 | ids::LocationCtx, | 18 | ids::{LocationCtx, SourceFileItemId}, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | /// Locates the module by `FileId`. Picks topmost module in the file. | 21 | /// Locates the module by `FileId`. Picks topmost module in the file. |
22 | pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> { | 22 | pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> { |
23 | let module_source = SourceItemId { | 23 | module_from_source(db, file_id.into(), None) |
24 | file_id: file_id.into(), | ||
25 | item_id: None, | ||
26 | }; | ||
27 | module_from_source(db, module_source) | ||
28 | } | 24 | } |
29 | 25 | ||
30 | /// Locates the child module by `mod child;` declaration. | 26 | /// Locates the child module by `mod child;` declaration. |
@@ -59,11 +55,7 @@ fn module_from_inline( | |||
59 | let file_id = file_id.into(); | 55 | let file_id = file_id.into(); |
60 | let file_items = db.file_items(file_id); | 56 | let file_items = db.file_items(file_id); |
61 | let item_id = file_items.id_of(file_id, module.syntax()); | 57 | let item_id = file_items.id_of(file_id, module.syntax()); |
62 | let source = SourceItemId { | 58 | module_from_source(db, file_id, Some(item_id)) |
63 | file_id, | ||
64 | item_id: Some(item_id), | ||
65 | }; | ||
66 | module_from_source(db, source) | ||
67 | } | 59 | } |
68 | 60 | ||
69 | /// Locates the module by child syntax element within the module | 61 | /// Locates the module by child syntax element within the module |
@@ -83,13 +75,17 @@ pub fn module_from_child_node( | |||
83 | } | 75 | } |
84 | } | 76 | } |
85 | 77 | ||
86 | fn module_from_source(db: &impl HirDatabase, source: SourceItemId) -> Option<Module> { | 78 | fn module_from_source( |
87 | let source_root_id = db.file_source_root(source.file_id.as_original_file()); | 79 | db: &impl HirDatabase, |
80 | file_id: HirFileId, | ||
81 | decl_id: Option<SourceFileItemId>, | ||
82 | ) -> Option<Module> { | ||
83 | let source_root_id = db.file_source_root(file_id.as_original_file()); | ||
88 | db.source_root_crates(source_root_id) | 84 | db.source_root_crates(source_root_id) |
89 | .iter() | 85 | .iter() |
90 | .find_map(|&krate| { | 86 | .find_map(|&krate| { |
91 | let module_tree = db.module_tree(krate); | 87 | let module_tree = db.module_tree(krate); |
92 | let module_id = module_tree.find_module_by_source(source)?; | 88 | let module_id = module_tree.find_module_by_source(file_id, decl_id)?; |
93 | Some(Module { krate, module_id }) | 89 | Some(Module { krate, module_id }) |
94 | }) | 90 | }) |
95 | } | 91 | } |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 179ebddee..31ea45706 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -29,6 +29,8 @@ use ra_arena::map::ArenaMap; | |||
29 | use join_to_string::join; | 29 | use join_to_string::join; |
30 | use rustc_hash::FxHashMap; | 30 | use rustc_hash::FxHashMap; |
31 | 31 | ||
32 | use test_utils::tested_by; | ||
33 | |||
32 | use crate::{ | 34 | use crate::{ |
33 | Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock, | 35 | Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock, |
34 | FnSignature, FnScopes, ModuleDef, AdtDef, | 36 | FnSignature, FnScopes, ModuleDef, AdtDef, |
@@ -862,14 +864,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
862 | } | 864 | } |
863 | 865 | ||
864 | fn resolve_all(mut self) -> InferenceResult { | 866 | fn resolve_all(mut self) -> InferenceResult { |
867 | let mut tv_stack = Vec::new(); | ||
865 | let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default()); | 868 | let mut expr_types = mem::replace(&mut self.type_of_expr, ArenaMap::default()); |
866 | for ty in expr_types.values_mut() { | 869 | for ty in expr_types.values_mut() { |
867 | let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); | 870 | let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); |
868 | *ty = resolved; | 871 | *ty = resolved; |
869 | } | 872 | } |
870 | let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default()); | 873 | let mut pat_types = mem::replace(&mut self.type_of_pat, ArenaMap::default()); |
871 | for ty in pat_types.values_mut() { | 874 | for ty in pat_types.values_mut() { |
872 | let resolved = self.resolve_ty_completely(mem::replace(ty, Ty::Unknown)); | 875 | let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); |
873 | *ty = resolved; | 876 | *ty = resolved; |
874 | } | 877 | } |
875 | InferenceResult { | 878 | InferenceResult { |
@@ -1014,13 +1017,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1014 | /// by their known types. All types returned by the infer_* functions should | 1017 | /// by their known types. All types returned by the infer_* functions should |
1015 | /// be resolved as far as possible, i.e. contain no type variables with | 1018 | /// be resolved as far as possible, i.e. contain no type variables with |
1016 | /// known type. | 1019 | /// known type. |
1017 | fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { | 1020 | fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { |
1018 | ty.fold(&mut |ty| match ty { | 1021 | ty.fold(&mut |ty| match ty { |
1019 | Ty::Infer(tv) => { | 1022 | Ty::Infer(tv) => { |
1020 | let inner = tv.to_inner(); | 1023 | let inner = tv.to_inner(); |
1024 | if tv_stack.contains(&inner) { | ||
1025 | tested_by!(type_var_cycles_resolve_as_possible); | ||
1026 | // recursive type | ||
1027 | return tv.fallback_value(); | ||
1028 | } | ||
1021 | if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { | 1029 | if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { |
1022 | // known_ty may contain other variables that are known by now | 1030 | // known_ty may contain other variables that are known by now |
1023 | self.resolve_ty_as_possible(known_ty.clone()) | 1031 | tv_stack.push(inner); |
1032 | let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone()); | ||
1033 | tv_stack.pop(); | ||
1034 | result | ||
1024 | } else { | 1035 | } else { |
1025 | ty | 1036 | ty |
1026 | } | 1037 | } |
@@ -1049,13 +1060,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1049 | 1060 | ||
1050 | /// Resolves the type completely; type variables without known type are | 1061 | /// Resolves the type completely; type variables without known type are |
1051 | /// replaced by Ty::Unknown. | 1062 | /// replaced by Ty::Unknown. |
1052 | fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { | 1063 | fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { |
1053 | ty.fold(&mut |ty| match ty { | 1064 | ty.fold(&mut |ty| match ty { |
1054 | Ty::Infer(tv) => { | 1065 | Ty::Infer(tv) => { |
1055 | let inner = tv.to_inner(); | 1066 | let inner = tv.to_inner(); |
1067 | if tv_stack.contains(&inner) { | ||
1068 | tested_by!(type_var_cycles_resolve_completely); | ||
1069 | // recursive type | ||
1070 | return tv.fallback_value(); | ||
1071 | } | ||
1056 | if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { | 1072 | if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { |
1057 | // known_ty may contain other variables that are known by now | 1073 | // known_ty may contain other variables that are known by now |
1058 | self.resolve_ty_completely(known_ty.clone()) | 1074 | tv_stack.push(inner); |
1075 | let result = self.resolve_ty_completely(tv_stack, known_ty.clone()); | ||
1076 | tv_stack.pop(); | ||
1077 | result | ||
1059 | } else { | 1078 | } else { |
1060 | tv.fallback_value() | 1079 | tv.fallback_value() |
1061 | } | 1080 | } |
@@ -1070,7 +1089,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1070 | let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); | 1089 | let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); |
1071 | if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { | 1090 | if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { |
1072 | let ty = self.type_of_pat.get(scope_entry.pat())?; | 1091 | let ty = self.type_of_pat.get(scope_entry.pat())?; |
1073 | let ty = self.resolve_ty_as_possible(ty.clone()); | 1092 | let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone()); |
1074 | return Some(ty); | 1093 | return Some(ty); |
1075 | }; | 1094 | }; |
1076 | }; | 1095 | }; |
@@ -1239,7 +1258,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1239 | // use a new type variable if we got Ty::Unknown here | 1258 | // use a new type variable if we got Ty::Unknown here |
1240 | let ty = self.insert_type_vars_shallow(ty); | 1259 | let ty = self.insert_type_vars_shallow(ty); |
1241 | self.unify(&ty, expected); | 1260 | self.unify(&ty, expected); |
1242 | let ty = self.resolve_ty_as_possible(ty); | 1261 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); |
1243 | self.write_pat_ty(pat, ty.clone()); | 1262 | self.write_pat_ty(pat, ty.clone()); |
1244 | ty | 1263 | ty |
1245 | } | 1264 | } |
@@ -1538,7 +1557,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1538 | // use a new type variable if we got Ty::Unknown here | 1557 | // use a new type variable if we got Ty::Unknown here |
1539 | let ty = self.insert_type_vars_shallow(ty); | 1558 | let ty = self.insert_type_vars_shallow(ty); |
1540 | self.unify(&ty, &expected.ty); | 1559 | self.unify(&ty, &expected.ty); |
1541 | let ty = self.resolve_ty_as_possible(ty); | 1560 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); |
1542 | self.write_expr_ty(tgt_expr, ty.clone()); | 1561 | self.write_expr_ty(tgt_expr, ty.clone()); |
1543 | ty | 1562 | ty |
1544 | } | 1563 | } |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap new file mode 100644 index 000000000..6a435e5cf --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_in_elseif.snap | |||
@@ -0,0 +1,17 @@ | |||
1 | --- | ||
2 | created: "2019-01-26T21:36:52.714121185+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: crates/ra_hir/src/ty/tests.rs | ||
6 | --- | ||
7 | [35; 38) 'foo': Foo | ||
8 | [45; 109) '{ ... } }': () | ||
9 | [51; 107) 'if tru... }': () | ||
10 | [54; 58) 'true': bool | ||
11 | [59; 67) '{ }': () | ||
12 | [73; 107) 'if fal... }': i32 | ||
13 | [76; 81) 'false': bool | ||
14 | [82; 107) '{ ... }': i32 | ||
15 | [92; 95) 'foo': Foo | ||
16 | [92; 101) 'foo.field': i32 | ||
17 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap new file mode 100644 index 000000000..c3227ff7e --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars.snap | |||
@@ -0,0 +1,14 @@ | |||
1 | --- | ||
2 | created: "2019-01-26T22:42:22.329980185+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: crates/ra_hir/src/ty/tests.rs | ||
6 | --- | ||
7 | [11; 48) '{ ...&y]; }': () | ||
8 | [21; 22) 'y': &[unknown] | ||
9 | [25; 32) 'unknown': &[unknown] | ||
10 | [38; 45) '[y, &y]': [&&[unknown]] | ||
11 | [39; 40) 'y': &[unknown] | ||
12 | [42; 44) '&y': &&[unknown] | ||
13 | [43; 44) 'y': &[unknown] | ||
14 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap new file mode 100644 index 000000000..de124da5b --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__recursive_vars_2.snap | |||
@@ -0,0 +1,21 @@ | |||
1 | --- | ||
2 | created: "2019-01-26T22:42:22.331805845+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: "&result" | ||
5 | source: crates/ra_hir/src/ty/tests.rs | ||
6 | --- | ||
7 | [11; 80) '{ ...x)]; }': () | ||
8 | [21; 22) 'x': &&[unknown] | ||
9 | [25; 32) 'unknown': &&[unknown] | ||
10 | [42; 43) 'y': &&[unknown] | ||
11 | [46; 53) 'unknown': &&[unknown] | ||
12 | [59; 77) '[(x, y..., &x)]': [(&&[unknown], &&[unknown])] | ||
13 | [60; 66) '(x, y)': (&&[unknown], &&[unknown]) | ||
14 | [61; 62) 'x': &&[unknown] | ||
15 | [64; 65) 'y': &&[unknown] | ||
16 | [68; 76) '(&y, &x)': (&&&[unknown], &&&[unknown]) | ||
17 | [69; 71) '&y': &&&[unknown] | ||
18 | [70; 71) 'y': &&[unknown] | ||
19 | [73; 75) '&x': &&&[unknown] | ||
20 | [74; 75) 'x': &&[unknown] | ||
21 | |||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index e0b0689f8..f74d6f5ea 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3,6 +3,7 @@ use std::fmt::Write; | |||
3 | 3 | ||
4 | use ra_db::{SourceDatabase, salsa::Database}; | 4 | use ra_db::{SourceDatabase, salsa::Database}; |
5 | use ra_syntax::ast::{self, AstNode}; | 5 | use ra_syntax::ast::{self, AstNode}; |
6 | use test_utils::covers; | ||
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{ |
8 | source_binder, | 9 | source_binder, |
@@ -285,6 +286,23 @@ fn test() { | |||
285 | } | 286 | } |
286 | 287 | ||
287 | #[test] | 288 | #[test] |
289 | fn infer_in_elseif() { | ||
290 | check_inference( | ||
291 | "infer_in_elseif", | ||
292 | r#" | ||
293 | struct Foo { field: i32 } | ||
294 | fn main(foo: Foo) { | ||
295 | if true { | ||
296 | |||
297 | } else if false { | ||
298 | foo.field | ||
299 | } | ||
300 | } | ||
301 | "#, | ||
302 | ) | ||
303 | } | ||
304 | |||
305 | #[test] | ||
288 | fn infer_inherent_method() { | 306 | fn infer_inherent_method() { |
289 | check_inference( | 307 | check_inference( |
290 | "infer_inherent_method", | 308 | "infer_inherent_method", |
@@ -545,6 +563,37 @@ fn quux() { | |||
545 | ); | 563 | ); |
546 | } | 564 | } |
547 | 565 | ||
566 | #[test] | ||
567 | fn recursive_vars() { | ||
568 | covers!(type_var_cycles_resolve_completely); | ||
569 | covers!(type_var_cycles_resolve_as_possible); | ||
570 | check_inference( | ||
571 | "recursive_vars", | ||
572 | r#" | ||
573 | fn test() { | ||
574 | let y = unknown; | ||
575 | [y, &y]; | ||
576 | } | ||
577 | "#, | ||
578 | ); | ||
579 | } | ||
580 | |||
581 | #[test] | ||
582 | fn recursive_vars_2() { | ||
583 | covers!(type_var_cycles_resolve_completely); | ||
584 | covers!(type_var_cycles_resolve_as_possible); | ||
585 | check_inference( | ||
586 | "recursive_vars_2", | ||
587 | r#" | ||
588 | fn test() { | ||
589 | let x = unknown; | ||
590 | let y = unknown; | ||
591 | [(x, y), (&y, &x)]; | ||
592 | } | ||
593 | "#, | ||
594 | ); | ||
595 | } | ||
596 | |||
548 | fn infer(content: &str) -> String { | 597 | fn infer(content: &str) -> String { |
549 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 598 | let (db, _, file_id) = MockDatabase::with_single_file(content); |
550 | let source_file = db.parse(file_id); | 599 | let source_file = db.parse(file_id); |