aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_arena/src/lib.rs10
-rw-r--r--crates/ra_assists/src/assists/add_new.rs2
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs40
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs2
-rw-r--r--crates/ra_assists/src/assists/invert_if.rs102
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs17
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/test_db.rs1
-rw-r--r--crates/ra_batch/src/lib.rs9
-rw-r--r--crates/ra_cli/src/analysis_stats.rs13
-rw-r--r--crates/ra_db/src/fixture.rs19
-rw-r--r--crates/ra_db/src/input.rs138
-rw-r--r--crates/ra_db/src/lib.rs16
-rw-r--r--crates/ra_hir/src/code_model.rs426
-rw-r--r--crates/ra_hir/src/code_model/attrs.rs92
-rw-r--r--crates/ra_hir/src/code_model/docs.rs97
-rw-r--r--crates/ra_hir/src/code_model/src.rs138
-rw-r--r--crates/ra_hir/src/db.rs72
-rw-r--r--crates/ra_hir/src/debug.rs5
-rw-r--r--crates/ra_hir/src/diagnostics.rs3
-rw-r--r--crates/ra_hir/src/expr.rs6
-rw-r--r--crates/ra_hir/src/from_id.rs46
-rw-r--r--crates/ra_hir/src/from_source.rs33
-rw-r--r--crates/ra_hir/src/ids.rs45
-rw-r--r--crates/ra_hir/src/impl_block.rs52
-rw-r--r--crates/ra_hir/src/lang_item.rs160
-rw-r--r--crates/ra_hir/src/lib.rs22
-rw-r--r--crates/ra_hir/src/source_binder.rs27
-rw-r--r--crates/ra_hir/src/test_db.rs5
-rw-r--r--crates/ra_hir/src/ty.rs13
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs7
-rw-r--r--crates/ra_hir/src/ty/infer.rs29
-rw-r--r--crates/ra_hir/src/ty/infer/coerce.rs20
-rw-r--r--crates/ra_hir/src/ty/infer/expr.rs33
-rw-r--r--crates/ra_hir/src/ty/infer/pat.rs9
-rw-r--r--crates/ra_hir/src/ty/lower.rs58
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs55
-rw-r--r--crates/ra_hir/src/ty/tests.rs40
-rw-r--r--crates/ra_hir/src/ty/traits.rs11
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs29
-rw-r--r--crates/ra_hir/src/type_alias.rs31
-rw-r--r--crates/ra_hir_def/src/adt.rs169
-rw-r--r--crates/ra_hir_def/src/attr.rs156
-rw-r--r--crates/ra_hir_def/src/body.rs50
-rw-r--r--crates/ra_hir_def/src/body/lower.rs9
-rw-r--r--crates/ra_hir_def/src/body/scope.rs12
-rw-r--r--crates/ra_hir_def/src/data.rs216
-rw-r--r--crates/ra_hir_def/src/db.rs61
-rw-r--r--crates/ra_hir_def/src/docs.rs71
-rw-r--r--crates/ra_hir_def/src/generics.rs8
-rw-r--r--crates/ra_hir_def/src/impls.rs86
-rw-r--r--crates/ra_hir_def/src/lang_item.rs121
-rw-r--r--crates/ra_hir_def/src/lib.rs258
-rw-r--r--crates/ra_hir_def/src/nameres.rs130
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs141
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs17
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs76
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs6
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs2
-rw-r--r--crates/ra_hir_def/src/path.rs15
-rw-r--r--crates/ra_hir_def/src/per_ns.rs (renamed from crates/ra_hir_def/src/nameres/per_ns.rs)15
-rw-r--r--crates/ra_hir_def/src/resolver.rs101
-rw-r--r--crates/ra_hir_def/src/test_db.rs2
-rw-r--r--crates/ra_hir_def/src/trace.rs59
-rw-r--r--crates/ra_hir_def/src/traits.rs66
-rw-r--r--crates/ra_hir_def/src/type_ref.rs8
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs232
-rw-r--r--crates/ra_hir_expand/src/db.rs6
-rw-r--r--crates/ra_hir_expand/src/lib.rs7
-rw-r--r--crates/ra_hir_expand/src/name.rs3
-rw-r--r--crates/ra_hir_expand/src/test_db.rs50
-rw-r--r--crates/ra_ide_api/src/call_info.rs4
-rw-r--r--crates/ra_ide_api/src/change.rs4
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs3
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs10
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs29
-rw-r--r--crates/ra_ide_api/src/db.rs1
-rw-r--r--crates/ra_ide_api/src/display/function_signature.rs4
-rw-r--r--crates/ra_ide_api/src/expand_macro.rs60
-rw-r--r--crates/ra_ide_api/src/lib.rs4
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs12
-rw-r--r--crates/ra_ide_api/src/parent_module.rs11
-rw-r--r--crates/ra_ide_api/src/references/classify.rs10
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs12
-rw-r--r--crates/ra_project_model/src/lib.rs48
-rw-r--r--crates/ra_project_model/src/sysroot.rs10
-rw-r--r--crates/ra_syntax/src/ast/edit.rs12
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs2
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs4
-rw-r--r--crates/ra_syntax/src/ast/make.rs15
-rw-r--r--docs/user/README.md5
-rw-r--r--docs/user/assists.md19
-rw-r--r--xtask/tests/tidy-tests/docs.rs1
94 files changed, 2468 insertions, 1904 deletions
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index 3ec8d3b60..fc0f7c12f 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -37,7 +37,7 @@ impl fmt::Display for RawId {
37} 37}
38 38
39#[derive(Clone, PartialEq, Eq)] 39#[derive(Clone, PartialEq, Eq)]
40pub struct Arena<ID: ArenaId, T> { 40pub struct Arena<ID, T> {
41 data: Vec<T>, 41 data: Vec<T>,
42 _ty: PhantomData<ID>, 42 _ty: PhantomData<ID>,
43} 43}
@@ -67,6 +67,12 @@ pub trait ArenaId {
67 fn into_raw(self) -> RawId; 67 fn into_raw(self) -> RawId;
68} 68}
69 69
70impl<ID, T> Arena<ID, T> {
71 pub const fn new() -> Arena<ID, T> {
72 Arena { data: Vec::new(), _ty: PhantomData }
73 }
74}
75
70impl<ID: ArenaId, T> Arena<ID, T> { 76impl<ID: ArenaId, T> Arena<ID, T> {
71 pub fn len(&self) -> usize { 77 pub fn len(&self) -> usize {
72 self.data.len() 78 self.data.len()
@@ -79,7 +85,7 @@ impl<ID: ArenaId, T> Arena<ID, T> {
79 self.data.push(value); 85 self.data.push(value);
80 ID::from_raw(id) 86 ID::from_raw(id)
81 } 87 }
82 pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> + ExactSizeIterator { 88 pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> + ExactSizeIterator + DoubleEndedIterator {
83 self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value)) 89 self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value))
84 } 90 }
85} 91}
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs
index b5f8afb4e..ee8bff346 100644
--- a/crates/ra_assists/src/assists/add_new.rs
+++ b/crates/ra_assists/src/assists/add_new.rs
@@ -36,7 +36,7 @@ pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
36 36
37 // We want to only apply this to non-union structs with named fields 37 // We want to only apply this to non-union structs with named fields
38 let field_list = match (strukt.kind(), strukt.is_union()) { 38 let field_list = match (strukt.kind(), strukt.is_union()) {
39 (StructKind::Named(named), false) => named, 39 (StructKind::Record(named), false) => named,
40 _ => return None, 40 _ => return None,
41 }; 41 };
42 42
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs
index 068da1774..7c57c0560 100644
--- a/crates/ra_assists/src/assists/apply_demorgan.rs
+++ b/crates/ra_assists/src/assists/apply_demorgan.rs
@@ -1,6 +1,6 @@
1use super::invert_if::invert_boolean_expression;
1use hir::db::HirDatabase; 2use hir::db::HirDatabase;
2use ra_syntax::ast::{self, AstNode}; 3use ra_syntax::ast::{self, AstNode};
3use ra_syntax::SyntaxNode;
4 4
5use crate::{Assist, AssistCtx, AssistId}; 5use crate::{Assist, AssistCtx, AssistId};
6 6
@@ -32,18 +32,18 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
32 if !cursor_in_range { 32 if !cursor_in_range {
33 return None; 33 return None;
34 } 34 }
35 let lhs = expr.lhs()?.syntax().clone(); 35 let lhs = expr.lhs()?;
36 let lhs_range = lhs.text_range(); 36 let lhs_range = lhs.syntax().text_range();
37 let rhs = expr.rhs()?.syntax().clone(); 37 let rhs = expr.rhs()?;
38 let rhs_range = rhs.text_range(); 38 let rhs_range = rhs.syntax().text_range();
39 let not_lhs = undo_negation(lhs)?; 39 let not_lhs = invert_boolean_expression(&lhs)?;
40 let not_rhs = undo_negation(rhs)?; 40 let not_rhs = invert_boolean_expression(&rhs)?;
41 41
42 ctx.add_assist(AssistId("apply_demorgan"), "apply demorgan's law", |edit| { 42 ctx.add_assist(AssistId("apply_demorgan"), "apply demorgan's law", |edit| {
43 edit.target(op_range); 43 edit.target(op_range);
44 edit.replace(op_range, opposite_op); 44 edit.replace(op_range, opposite_op);
45 edit.replace(lhs_range, format!("!({}", not_lhs)); 45 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
46 edit.replace(rhs_range, format!("{})", not_rhs)); 46 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
47 }) 47 })
48} 48}
49 49
@@ -56,28 +56,6 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
56 } 56 }
57} 57}
58 58
59// This function tries to undo unary negation, or inequality
60fn undo_negation(node: SyntaxNode) -> Option<String> {
61 match ast::Expr::cast(node)? {
62 ast::Expr::BinExpr(bin) => match bin.op_kind()? {
63 ast::BinOp::NegatedEqualityTest => {
64 let lhs = bin.lhs()?.syntax().text();
65 let rhs = bin.rhs()?.syntax().text();
66 Some(format!("{} == {}", lhs, rhs))
67 }
68 _ => None,
69 },
70 ast::Expr::PrefixExpr(pe) => match pe.op_kind()? {
71 ast::PrefixOp::Not => {
72 let child = pe.expr()?.syntax().text();
73 Some(String::from(child))
74 }
75 _ => None,
76 },
77 _ => None,
78 }
79}
80
81#[cfg(test)] 59#[cfg(test)]
82mod tests { 60mod tests {
83 use super::*; 61 use super::*;
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs
index 9354466d9..8482897c5 100644
--- a/crates/ra_assists/src/assists/fill_match_arms.rs
+++ b/crates/ra_assists/src/assists/fill_match_arms.rs
@@ -101,7 +101,7 @@ fn build_pat(var: ast::EnumVariant) -> Option<ast::Pat> {
101 iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count()); 101 iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count());
102 make::tuple_struct_pat(path, pats).into() 102 make::tuple_struct_pat(path, pats).into()
103 } 103 }
104 ast::StructKind::Named(field_list) => { 104 ast::StructKind::Record(field_list) => {
105 let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); 105 let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into());
106 make::record_pat(path, pats).into() 106 make::record_pat(path, pats).into()
107 } 107 }
diff --git a/crates/ra_assists/src/assists/invert_if.rs b/crates/ra_assists/src/assists/invert_if.rs
new file mode 100644
index 000000000..bababa3e2
--- /dev/null
+++ b/crates/ra_assists/src/assists/invert_if.rs
@@ -0,0 +1,102 @@
1use hir::db::HirDatabase;
2use ra_syntax::ast::{self, AstNode};
3use ra_syntax::T;
4
5use crate::{Assist, AssistCtx, AssistId};
6
7// Assist: invert_if
8//
9// Apply invert_if
10// This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
11// This also works with `!=`. This assist can only be applied with the cursor
12// on `if`.
13//
14// ```
15// fn main() {
16// if<|> !y { A } else { B }
17// }
18// ```
19// ->
20// ```
21// fn main() {
22// if y { B } else { A }
23// }
24// ```
25
26pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 let if_keyword = ctx.find_token_at_offset(T![if])?;
28 let expr = ast::IfExpr::cast(if_keyword.parent())?;
29 let if_range = if_keyword.text_range();
30 let cursor_in_range = ctx.frange.range.is_subrange(&if_range);
31 if !cursor_in_range {
32 return None;
33 }
34
35 let cond = expr.condition()?.expr()?;
36 let then_node = expr.then_branch()?.syntax().clone();
37
38 if let ast::ElseBranch::Block(else_block) = expr.else_branch()? {
39 let flip_cond = invert_boolean_expression(&cond)?;
40 let cond_range = cond.syntax().text_range();
41 let else_node = else_block.syntax();
42 let else_range = else_node.text_range();
43 let then_range = then_node.text_range();
44 return ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| {
45 edit.target(if_range);
46 edit.replace(cond_range, flip_cond.syntax().text());
47 edit.replace(else_range, then_node.text());
48 edit.replace(then_range, else_node.text());
49 });
50 }
51
52 None
53}
54
55pub(crate) fn invert_boolean_expression(expr: &ast::Expr) -> Option<ast::Expr> {
56 match expr {
57 ast::Expr::BinExpr(bin) => match bin.op_kind()? {
58 ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
59 _ => None,
60 },
61 ast::Expr::PrefixExpr(pe) => match pe.op_kind()? {
62 ast::PrefixOp::Not => pe.expr(),
63 _ => None,
64 },
65 _ => None,
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 use crate::helpers::{check_assist, check_assist_not_applicable};
74
75 #[test]
76 fn invert_if_remove_inequality() {
77 check_assist(
78 invert_if,
79 "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }",
80 "fn f() { i<|>f x == 3 { 3 + 2 } else { 1 } }",
81 )
82 }
83
84 #[test]
85 fn invert_if_remove_not() {
86 check_assist(
87 invert_if,
88 "fn f() { <|>if !cond { 3 * 2 } else { 1 } }",
89 "fn f() { <|>if cond { 1 } else { 3 * 2 } }",
90 )
91 }
92
93 #[test]
94 fn invert_if_doesnt_apply_with_cursor_not_on_if() {
95 check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }")
96 }
97
98 #[test]
99 fn invert_if_doesnt_apply_without_negated() {
100 check_assist_not_applicable(invert_if, "fn f() { i<|>f cond { 3 * 2 } else { 1 } }")
101 }
102}
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 176761efb..3c716c2d1 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -342,6 +342,23 @@ fn main() {
342} 342}
343 343
344#[test] 344#[test]
345fn doctest_invert_if() {
346 check(
347 "invert_if",
348 r#####"
349fn main() {
350 if<|> !y { A } else { B }
351}
352"#####,
353 r#####"
354fn main() {
355 if y { B } else { A }
356}
357"#####,
358 )
359}
360
361#[test]
345fn doctest_make_raw_string() { 362fn doctest_make_raw_string() {
346 check( 363 check(
347 "make_raw_string", 364 "make_raw_string",
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index f2f0dacbf..a372bd8b9 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -97,6 +97,7 @@ mod assists {
97 mod add_impl; 97 mod add_impl;
98 mod add_new; 98 mod add_new;
99 mod apply_demorgan; 99 mod apply_demorgan;
100 mod invert_if;
100 mod flip_comma; 101 mod flip_comma;
101 mod flip_binexpr; 102 mod flip_binexpr;
102 mod flip_trait_bound; 103 mod flip_trait_bound;
@@ -122,6 +123,7 @@ mod assists {
122 add_impl::add_impl, 123 add_impl::add_impl,
123 add_new::add_new, 124 add_new::add_new,
124 apply_demorgan::apply_demorgan, 125 apply_demorgan::apply_demorgan,
126 invert_if::invert_if,
125 change_visibility::change_visibility, 127 change_visibility::change_visibility,
126 fill_match_arms::fill_match_arms, 128 fill_match_arms::fill_match_arms,
127 merge_match_arms::merge_match_arms, 129 merge_match_arms::merge_match_arms,
diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs
index 5be7383ed..5f96c974b 100644
--- a/crates/ra_assists/src/test_db.rs
+++ b/crates/ra_assists/src/test_db.rs
@@ -10,7 +10,6 @@ use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath
10 hir::db::InternDatabaseStorage, 10 hir::db::InternDatabaseStorage,
11 hir::db::AstDatabaseStorage, 11 hir::db::AstDatabaseStorage,
12 hir::db::DefDatabaseStorage, 12 hir::db::DefDatabaseStorage,
13 hir::db::DefDatabase2Storage,
14 hir::db::HirDatabaseStorage 13 hir::db::HirDatabaseStorage
15)] 14)]
16#[derive(Debug, Default)] 15#[derive(Debug, Default)]
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index df49eb13d..cb389eb26 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -117,9 +117,12 @@ pub fn load(
117 done = true; 117 done = true;
118 } 118 }
119 } 119 }
120 VfsChange::AddFile { .. } 120 VfsChange::AddFile { root, file, path, text } => {
121 | VfsChange::RemoveFile { .. } 121 let source_root_id = vfs_root_to_id(root);
122 | VfsChange::ChangeFile { .. } => { 122 let file_id = vfs_file_to_id(file);
123 analysis_change.add_file(source_root_id, file_id, path, text);
124 }
125 VfsChange::RemoveFile { .. } | VfsChange::ChangeFile { .. } => {
123 // We just need the first scan, so just ignore these 126 // We just need the first scan, so just ignore these
124 } 127 }
125 } 128 }
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 9cd21e4b6..c4eb28245 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -3,7 +3,7 @@
3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
4 4
5use ra_db::SourceDatabaseExt; 5use ra_db::SourceDatabaseExt;
6use ra_hir::{AssocItem, Crate, HasBodySource, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk}; 6use ra_hir::{AssocItem, Crate, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk};
7use ra_syntax::AstNode; 7use ra_syntax::AstNode;
8 8
9use crate::{Result, Verbosity}; 9use crate::{Result, Verbosity};
@@ -109,7 +109,7 @@ pub fn run(
109 } 109 }
110 let body = f.body(db); 110 let body = f.body(db);
111 let inference_result = f.infer(db); 111 let inference_result = f.infer(db);
112 for (expr_id, _) in body.exprs() { 112 for (expr_id, _) in body.exprs.iter() {
113 let ty = &inference_result[expr_id]; 113 let ty = &inference_result[expr_id];
114 num_exprs += 1; 114 num_exprs += 1;
115 if let Ty::Unknown = ty { 115 if let Ty::Unknown = ty {
@@ -128,15 +128,16 @@ pub fn run(
128 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 128 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
129 num_type_mismatches += 1; 129 num_type_mismatches += 1;
130 if verbosity.is_verbose() { 130 if verbosity.is_verbose() {
131 let src = f.expr_source(db, expr_id); 131 let src = f.body_source_map(db).expr_syntax(expr_id);
132 if let Some(src) = src { 132 if let Some(src) = src {
133 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly 133 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
134 let original_file = src.file_id.original_file(db); 134 let original_file = src.file_id.original_file(db);
135 let path = db.file_relative_path(original_file); 135 let path = db.file_relative_path(original_file);
136 let line_index = host.analysis().file_line_index(original_file).unwrap(); 136 let line_index = host.analysis().file_line_index(original_file).unwrap();
137 let text_range = src 137 let text_range = src.value.either(
138 .value 138 |it| it.syntax_node_ptr().range(),
139 .either(|it| it.syntax().text_range(), |it| it.syntax().text_range()); 139 |it| it.syntax_node_ptr().range(),
140 );
140 let (start, end) = ( 141 let (start, end) = (
141 line_index.line_col(text_range.start()), 142 line_index.line_col(text_range.start()),
142 line_index.line_col(text_range.end()), 143 line_index.line_col(text_range.end()),
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index ade187629..e8f335e33 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -8,7 +8,7 @@ use rustc_hash::FxHashMap;
8use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 8use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
9 9
10use crate::{ 10use crate::{
11 CrateGraph, CrateId, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, 11 CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt,
12 SourceRoot, SourceRootId, 12 SourceRoot, SourceRootId,
13}; 13};
14 14
@@ -53,7 +53,12 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId {
53 source_root.insert_file(rel_path.clone(), file_id); 53 source_root.insert_file(rel_path.clone(), file_id);
54 54
55 let mut crate_graph = CrateGraph::default(); 55 let mut crate_graph = CrateGraph::default();
56 crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); 56 crate_graph.add_crate_root(
57 file_id,
58 Edition::Edition2018,
59 CfgOptions::default(),
60 Env::default(),
61 );
57 62
58 db.set_file_text(file_id, Arc::new(text.to_string())); 63 db.set_file_text(file_id, Arc::new(text.to_string()));
59 db.set_file_relative_path(file_id, rel_path); 64 db.set_file_relative_path(file_id, rel_path);
@@ -93,7 +98,8 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
93 assert!(meta.path.starts_with(&source_root_prefix)); 98 assert!(meta.path.starts_with(&source_root_prefix));
94 99
95 if let Some(krate) = meta.krate { 100 if let Some(krate) = meta.krate {
96 let crate_id = crate_graph.add_crate_root(file_id, meta.edition, meta.cfg); 101 let crate_id =
102 crate_graph.add_crate_root(file_id, meta.edition, meta.cfg, Env::default());
97 let prev = crates.insert(krate.clone(), crate_id); 103 let prev = crates.insert(krate.clone(), crate_id);
98 assert!(prev.is_none()); 104 assert!(prev.is_none());
99 for dep in meta.deps { 105 for dep in meta.deps {
@@ -123,7 +129,12 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
123 129
124 if crates.is_empty() { 130 if crates.is_empty() {
125 let crate_root = default_crate_root.unwrap(); 131 let crate_root = default_crate_root.unwrap();
126 crate_graph.add_crate_root(crate_root, Edition::Edition2018, CfgOptions::default()); 132 crate_graph.add_crate_root(
133 crate_root,
134 Edition::Edition2018,
135 CfgOptions::default(),
136 Env::default(),
137 );
127 } else { 138 } else {
128 for (from, to) in crate_deps { 139 for (from, to) in crate_deps {
129 let from_id = crates[&from]; 140 let from_id = crates[&from];
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index c0d95a13f..b6d851776 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -6,14 +6,14 @@
6//! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how 6//! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how
7//! actual IO is done and lowered to input. 7//! actual IO is done and lowered to input.
8 8
9use rustc_hash::FxHashMap; 9use std::{fmt, str::FromStr};
10 10
11use ra_cfg::CfgOptions; 11use ra_cfg::CfgOptions;
12use ra_syntax::SmolStr; 12use ra_syntax::SmolStr;
13use rustc_hash::FxHashMap;
13use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
14 15
15use crate::{RelativePath, RelativePathBuf}; 16use crate::{RelativePath, RelativePathBuf};
16use std::str::FromStr;
17 17
18/// `FileId` is an integer which uniquely identifies a file. File paths are 18/// `FileId` is an integer which uniquely identifies a file. File paths are
19/// messy and system-dependent, so most of the code should work directly with 19/// messy and system-dependent, so most of the code should work directly with
@@ -80,56 +80,27 @@ pub struct CrateGraph {
80 arena: FxHashMap<CrateId, CrateData>, 80 arena: FxHashMap<CrateId, CrateData>,
81} 81}
82 82
83#[derive(Debug)]
84pub struct CyclicDependencies;
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 83#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
87pub struct CrateId(pub u32); 84pub struct CrateId(pub u32);
88 85
89impl CrateId {
90 pub fn shift(self, amount: u32) -> CrateId {
91 CrateId(self.0 + amount)
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
96pub enum Edition {
97 Edition2018,
98 Edition2015,
99}
100
101#[derive(Debug)]
102pub struct ParseEditionError {
103 pub msg: String,
104}
105
106impl FromStr for Edition {
107 type Err = ParseEditionError;
108 fn from_str(s: &str) -> Result<Self, Self::Err> {
109 match s {
110 "2015" => Ok(Edition::Edition2015),
111 "2018" => Ok(Edition::Edition2018),
112 _ => Err(ParseEditionError { msg: format!("unknown edition: {}", s) }),
113 }
114 }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq)] 86#[derive(Debug, Clone, PartialEq, Eq)]
118struct CrateData { 87struct CrateData {
119 file_id: FileId, 88 file_id: FileId,
120 edition: Edition, 89 edition: Edition,
121 dependencies: Vec<Dependency>,
122 cfg_options: CfgOptions, 90 cfg_options: CfgOptions,
91 env: Env,
92 dependencies: Vec<Dependency>,
123} 93}
124 94
125impl CrateData { 95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
126 fn new(file_id: FileId, edition: Edition, cfg_options: CfgOptions) -> CrateData { 96pub enum Edition {
127 CrateData { file_id, edition, dependencies: Vec::new(), cfg_options } 97 Edition2018,
128 } 98 Edition2015,
99}
129 100
130 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 101#[derive(Default, Debug, Clone, PartialEq, Eq)]
131 self.dependencies.push(Dependency { name, crate_id }) 102pub struct Env {
132 } 103 entries: FxHashMap<String, String>,
133} 104}
134 105
135#[derive(Debug, Clone, PartialEq, Eq)] 106#[derive(Debug, Clone, PartialEq, Eq)]
@@ -138,21 +109,17 @@ pub struct Dependency {
138 pub name: SmolStr, 109 pub name: SmolStr,
139} 110}
140 111
141impl Dependency {
142 pub fn crate_id(&self) -> CrateId {
143 self.crate_id
144 }
145}
146
147impl CrateGraph { 112impl CrateGraph {
148 pub fn add_crate_root( 113 pub fn add_crate_root(
149 &mut self, 114 &mut self,
150 file_id: FileId, 115 file_id: FileId,
151 edition: Edition, 116 edition: Edition,
152 cfg_options: CfgOptions, 117 cfg_options: CfgOptions,
118 env: Env,
153 ) -> CrateId { 119 ) -> CrateId {
120 let data = CrateData::new(file_id, edition, cfg_options, env);
154 let crate_id = CrateId(self.arena.len() as u32); 121 let crate_id = CrateId(self.arena.len() as u32);
155 let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition, cfg_options)); 122 let prev = self.arena.insert(crate_id, data);
156 assert!(prev.is_none()); 123 assert!(prev.is_none());
157 crate_id 124 crate_id
158 } 125 }
@@ -166,9 +133,9 @@ impl CrateGraph {
166 from: CrateId, 133 from: CrateId,
167 name: SmolStr, 134 name: SmolStr,
168 to: CrateId, 135 to: CrateId,
169 ) -> Result<(), CyclicDependencies> { 136 ) -> Result<(), CyclicDependenciesError> {
170 if self.dfs_find(from, to, &mut FxHashSet::default()) { 137 if self.dfs_find(from, to, &mut FxHashSet::default()) {
171 return Err(CyclicDependencies); 138 return Err(CyclicDependenciesError);
172 } 139 }
173 self.arena.get_mut(&from).unwrap().add_dep(name, to); 140 self.arena.get_mut(&from).unwrap().add_dep(name, to);
174 Ok(()) 141 Ok(())
@@ -239,16 +206,70 @@ impl CrateGraph {
239 } 206 }
240} 207}
241 208
209impl CrateId {
210 pub fn shift(self, amount: u32) -> CrateId {
211 CrateId(self.0 + amount)
212 }
213}
214
215impl CrateData {
216 fn new(file_id: FileId, edition: Edition, cfg_options: CfgOptions, env: Env) -> CrateData {
217 CrateData { file_id, edition, dependencies: Vec::new(), cfg_options, env }
218 }
219
220 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
221 self.dependencies.push(Dependency { name, crate_id })
222 }
223}
224
225impl FromStr for Edition {
226 type Err = ParseEditionError;
227
228 fn from_str(s: &str) -> Result<Self, Self::Err> {
229 let res = match s {
230 "2015" => Edition::Edition2015,
231 "2018" => Edition::Edition2018,
232 _ => Err(ParseEditionError { invalid_input: s.to_string() })?,
233 };
234 Ok(res)
235 }
236}
237
238impl Dependency {
239 pub fn crate_id(&self) -> CrateId {
240 self.crate_id
241 }
242}
243
244#[derive(Debug)]
245pub struct ParseEditionError {
246 invalid_input: String,
247}
248
249impl fmt::Display for ParseEditionError {
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 write!(f, "invalid edition: {:?}", self.invalid_input)
252 }
253}
254
255impl std::error::Error for ParseEditionError {}
256
257#[derive(Debug)]
258pub struct CyclicDependenciesError;
259
242#[cfg(test)] 260#[cfg(test)]
243mod tests { 261mod tests {
244 use super::{CfgOptions, CrateGraph, Edition::Edition2018, FileId, SmolStr}; 262 use super::{CfgOptions, CrateGraph, Edition::Edition2018, Env, FileId, SmolStr};
245 263
246 #[test] 264 #[test]
247 fn it_should_panic_because_of_cycle_dependencies() { 265 fn it_should_panic_because_of_cycle_dependencies() {
248 let mut graph = CrateGraph::default(); 266 let mut graph = CrateGraph::default();
249 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default()); 267 let crate1 =
250 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default()); 268 graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default());
251 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default()); 269 let crate2 =
270 graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default());
271 let crate3 =
272 graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default(), Env::default());
252 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 273 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
253 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 274 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
254 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err()); 275 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err());
@@ -257,9 +278,12 @@ mod tests {
257 #[test] 278 #[test]
258 fn it_works() { 279 fn it_works() {
259 let mut graph = CrateGraph::default(); 280 let mut graph = CrateGraph::default();
260 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default()); 281 let crate1 =
261 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default()); 282 graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default(), Env::default());
262 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default()); 283 let crate2 =
284 graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default(), Env::default());
285 let crate3 =
286 graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default(), Env::default());
263 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 287 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
264 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 288 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
265 } 289 }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index b6bfd531d..e8852531b 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -10,11 +10,25 @@ use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit};
10 10
11pub use crate::{ 11pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
13 input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId}, 13 input::{CrateGraph, CrateId, Dependency, Edition, Env, FileId, SourceRoot, SourceRootId},
14}; 14};
15pub use relative_path::{RelativePath, RelativePathBuf}; 15pub use relative_path::{RelativePath, RelativePathBuf};
16pub use salsa; 16pub use salsa;
17 17
18#[macro_export]
19macro_rules! impl_intern_key {
20 ($name:ident) => {
21 impl $crate::salsa::InternKey for $name {
22 fn from_intern_id(v: $crate::salsa::InternId) -> Self {
23 $name(v)
24 }
25 fn as_intern_id(&self) -> $crate::salsa::InternId {
26 self.0
27 }
28 }
29 };
30}
31
18pub trait CheckCanceled { 32pub trait CheckCanceled {
19 /// Aborts current query if there are pending changes. 33 /// Aborts current query if there are pending changes.
20 /// 34 ///
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 5690040a7..3f44a50c4 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,38 +1,33 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3pub(crate) mod src; 3pub(crate) mod src;
4pub(crate) mod docs;
5pub(crate) mod attrs;
6 4
7use std::sync::Arc; 5use std::sync::Arc;
8 6
9use hir_def::{ 7use hir_def::{
10 adt::VariantData, 8 adt::VariantData,
11 body::scope::ExprScopes,
12 builtin_type::BuiltinType, 9 builtin_type::BuiltinType,
13 nameres::per_ns::PerNs, 10 docs::Documentation,
11 per_ns::PerNs,
14 resolver::{HasResolver, TypeNs}, 12 resolver::{HasResolver, TypeNs},
15 traits::TraitData, 13 type_ref::TypeRef,
16 type_ref::{Mutability, TypeRef}, 14 AstItemDef, ConstId, ContainerId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId,
17 ContainerId, CrateModuleId, HasModule, ImplId, LocalEnumVariantId, LocalStructFieldId, Lookup, 15 LocalImportId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId,
18 ModuleId, UnionId, 16 TraitId, TypeAliasId, UnionId,
19}; 17};
20use hir_expand::{ 18use hir_expand::{
21 diagnostics::DiagnosticSink, 19 diagnostics::DiagnosticSink,
22 name::{self, AsName}, 20 name::{self, AsName},
21 AstId, MacroDefId,
23}; 22};
24use ra_db::{CrateId, Edition}; 23use ra_db::{CrateId, Edition, FileId, FilePosition};
25use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 24use ra_syntax::{ast, AstNode, SyntaxNode};
26 25
27use crate::{ 26use crate::{
28 db::{AstDatabase, DefDatabase, HirDatabase}, 27 db::{DefDatabase, HirDatabase},
29 expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, 28 expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId},
30 ids::{
31 AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId,
32 TypeAliasId,
33 },
34 ty::{InferenceResult, Namespace, TraitRef}, 29 ty::{InferenceResult, Namespace, TraitRef},
35 Either, HasSource, ImportId, Name, Source, Ty, 30 Either, Name, Source, Ty,
36}; 31};
37 32
38/// hir::Crate describes a single crate. It's the main interface with which 33/// hir::Crate describes a single crate. It's the main interface with which
@@ -66,7 +61,7 @@ impl Crate {
66 } 61 }
67 62
68 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> { 63 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> {
69 let module_id = db.crate_def_map(self.crate_id).root(); 64 let module_id = db.crate_def_map(self.crate_id).root;
70 Some(Module::new(self, module_id)) 65 Some(Module::new(self, module_id))
71 } 66 }
72 67
@@ -80,6 +75,64 @@ impl Crate {
80 } 75 }
81} 76}
82 77
78pub enum ModuleSource {
79 SourceFile(ast::SourceFile),
80 Module(ast::Module),
81}
82
83impl ModuleSource {
84 pub fn new(
85 db: &impl DefDatabase,
86 file_id: Option<FileId>,
87 decl_id: Option<AstId<ast::Module>>,
88 ) -> ModuleSource {
89 match (file_id, decl_id) {
90 (Some(file_id), _) => {
91 let source_file = db.parse(file_id).tree();
92 ModuleSource::SourceFile(source_file)
93 }
94 (None, Some(item_id)) => {
95 let module = item_id.to_node(db);
96 assert!(module.item_list().is_some(), "expected inline module");
97 ModuleSource::Module(module)
98 }
99 (None, None) => panic!(),
100 }
101 }
102
103 // FIXME: this methods do not belong here
104 pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource {
105 let parse = db.parse(position.file_id);
106 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
107 parse.tree().syntax(),
108 position.offset,
109 ) {
110 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
111 _ => {
112 let source_file = parse.tree();
113 ModuleSource::SourceFile(source_file)
114 }
115 }
116 }
117
118 pub fn from_child_node(db: &impl DefDatabase, child: Source<&SyntaxNode>) -> ModuleSource {
119 if let Some(m) =
120 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi())
121 {
122 ModuleSource::Module(m)
123 } else {
124 let file_id = child.file_id.original_file(db);
125 let source_file = db.parse(file_id).tree();
126 ModuleSource::SourceFile(source_file)
127 }
128 }
129
130 pub fn from_file_id(db: &impl DefDatabase, file_id: FileId) -> ModuleSource {
131 let source_file = db.parse(file_id).tree();
132 ModuleSource::SourceFile(source_file)
133 }
134}
135
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 136#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
84pub struct Module { 137pub struct Module {
85 pub(crate) id: ModuleId, 138 pub(crate) id: ModuleId,
@@ -111,10 +164,10 @@ impl_froms!(
111 BuiltinType 164 BuiltinType
112); 165);
113 166
114pub use hir_def::ModuleSource; 167pub use hir_def::attr::Attrs;
115 168
116impl Module { 169impl Module {
117 pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module { 170 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
118 Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } } 171 Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } }
119 } 172 }
120 173
@@ -131,17 +184,6 @@ impl Module {
131 }) 184 })
132 } 185 }
133 186
134 /// Returns the syntax of the last path segment corresponding to this import
135 pub fn import_source(
136 self,
137 db: &impl HirDatabase,
138 import: ImportId,
139 ) -> Either<ast::UseTree, ast::ExternCrateItem> {
140 let src = self.definition_source(db);
141 let (_, source_map) = db.raw_items_with_source_map(src.file_id);
142 source_map.get(&src.value, import)
143 }
144
145 /// Returns the crate this module is part of. 187 /// Returns the crate this module is part of.
146 pub fn krate(self) -> Crate { 188 pub fn krate(self) -> Crate {
147 Crate { crate_id: self.id.krate } 189 Crate { crate_id: self.id.krate }
@@ -152,7 +194,7 @@ impl Module {
152 /// in the module tree of any target in `Cargo.toml`. 194 /// in the module tree of any target in `Cargo.toml`.
153 pub fn crate_root(self, db: &impl DefDatabase) -> Module { 195 pub fn crate_root(self, db: &impl DefDatabase) -> Module {
154 let def_map = db.crate_def_map(self.id.krate); 196 let def_map = db.crate_def_map(self.id.krate);
155 self.with_module_id(def_map.root()) 197 self.with_module_id(def_map.root)
156 } 198 }
157 199
158 /// Finds a child module with the specified name. 200 /// Finds a child module with the specified name.
@@ -191,11 +233,13 @@ impl Module {
191 } 233 }
192 234
193 /// Returns a `ModuleScope`: a set of items, visible in this module. 235 /// Returns a `ModuleScope`: a set of items, visible in this module.
194 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<ImportId>)> { 236 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<Import>)> {
195 db.crate_def_map(self.id.krate)[self.id.module_id] 237 db.crate_def_map(self.id.krate)[self.id.module_id]
196 .scope 238 .scope
197 .entries() 239 .entries()
198 .map(|(name, res)| (name.clone(), res.def.into(), res.import)) 240 .map(|(name, res)| {
241 (name.clone(), res.def.into(), res.import.map(|id| Import { parent: self, id }))
242 })
199 .collect() 243 .collect()
200 } 244 }
201 245
@@ -233,11 +277,16 @@ impl Module {
233 def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect() 277 def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect()
234 } 278 }
235 279
236 fn with_module_id(self, module_id: CrateModuleId) -> Module { 280 fn with_module_id(self, module_id: LocalModuleId) -> Module {
237 Module::new(self.krate(), module_id) 281 Module::new(self.krate(), module_id)
238 } 282 }
239} 283}
240 284
285pub struct Import {
286 pub(crate) parent: Module,
287 pub(crate) id: LocalImportId,
288}
289
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 290#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
242pub struct StructField { 291pub struct StructField {
243 pub(crate) parent: VariantDef, 292 pub(crate) parent: VariantDef,
@@ -252,11 +301,11 @@ pub enum FieldSource {
252 301
253impl StructField { 302impl StructField {
254 pub fn name(&self, db: &impl HirDatabase) -> Name { 303 pub fn name(&self, db: &impl HirDatabase) -> Name {
255 self.parent.variant_data(db).fields().unwrap()[self.id].name.clone() 304 self.parent.variant_data(db).fields()[self.id].name.clone()
256 } 305 }
257 306
258 pub fn ty(&self, db: &impl HirDatabase) -> Ty { 307 pub fn ty(&self, db: &impl HirDatabase) -> Ty {
259 db.type_for_field(*self) 308 db.field_types(self.parent.into())[self.id].clone()
260 } 309 }
261 310
262 pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef { 311 pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
@@ -286,8 +335,7 @@ impl Struct {
286 db.struct_data(self.id.into()) 335 db.struct_data(self.id.into())
287 .variant_data 336 .variant_data
288 .fields() 337 .fields()
289 .into_iter() 338 .iter()
290 .flat_map(|it| it.iter())
291 .map(|(id, _)| StructField { parent: self.into(), id }) 339 .map(|(id, _)| StructField { parent: self.into(), id })
292 .collect() 340 .collect()
293 } 341 }
@@ -296,8 +344,7 @@ impl Struct {
296 db.struct_data(self.id.into()) 344 db.struct_data(self.id.into())
297 .variant_data 345 .variant_data
298 .fields() 346 .fields()
299 .into_iter() 347 .iter()
300 .flat_map(|it| it.iter())
301 .find(|(_id, data)| data.name == *name) 348 .find(|(_id, data)| data.name == *name)
302 .map(|(id, _)| StructField { parent: self.into(), id }) 349 .map(|(id, _)| StructField { parent: self.into(), id })
303 } 350 }
@@ -394,8 +441,7 @@ impl EnumVariant {
394 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { 441 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
395 self.variant_data(db) 442 self.variant_data(db)
396 .fields() 443 .fields()
397 .into_iter() 444 .iter()
398 .flat_map(|it| it.iter())
399 .map(|(id, _)| StructField { parent: self.into(), id }) 445 .map(|(id, _)| StructField { parent: self.into(), id })
400 .collect() 446 .collect()
401 } 447 }
@@ -403,8 +449,7 @@ impl EnumVariant {
403 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { 449 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
404 self.variant_data(db) 450 self.variant_data(db)
405 .fields() 451 .fields()
406 .into_iter() 452 .iter()
407 .flat_map(|it| it.iter())
408 .find(|(_id, data)| data.name == *name) 453 .find(|(_id, data)| data.name == *name)
409 .map(|(id, _)| StructField { parent: self.into(), id }) 454 .map(|(id, _)| StructField { parent: self.into(), id })
410 } 455 }
@@ -460,7 +505,7 @@ impl VariantDef {
460 } 505 }
461 } 506 }
462 507
463 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { 508 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
464 match self { 509 match self {
465 VariantDef::Struct(it) => it.field(db, name), 510 VariantDef::Struct(it) => it.field(db, name),
466 VariantDef::EnumVariant(it) => it.field(db, name), 511 VariantDef::EnumVariant(it) => it.field(db, name),
@@ -510,128 +555,11 @@ impl DefWithBody {
510 } 555 }
511} 556}
512 557
513pub trait HasBody: Copy {
514 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult>;
515 fn body(self, db: &impl HirDatabase) -> Arc<Body>;
516 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap>;
517 fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes>;
518}
519
520impl<T> HasBody for T
521where
522 T: Into<DefWithBody> + Copy + HasSource,
523{
524 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
525 db.infer(self.into())
526 }
527
528 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
529 self.into().body(db)
530 }
531
532 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
533 self.into().body_source_map(db)
534 }
535
536 fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes> {
537 self.into().expr_scopes(db)
538 }
539}
540
541impl HasBody for DefWithBody {
542 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
543 db.infer(self)
544 }
545
546 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
547 db.body(self.into())
548 }
549
550 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
551 db.body_with_source_map(self.into()).1
552 }
553
554 fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes> {
555 db.expr_scopes(self.into())
556 }
557}
558
559#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 558#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
560pub struct Function { 559pub struct Function {
561 pub(crate) id: FunctionId, 560 pub(crate) id: FunctionId,
562} 561}
563 562
564#[derive(Debug, Clone, PartialEq, Eq)]
565pub struct FnData {
566 pub(crate) name: Name,
567 pub(crate) params: Vec<TypeRef>,
568 pub(crate) ret_type: TypeRef,
569 /// True if the first param is `self`. This is relevant to decide whether this
570 /// can be called as a method.
571 pub(crate) has_self_param: bool,
572}
573
574impl FnData {
575 pub(crate) fn fn_data_query(
576 db: &(impl DefDatabase + AstDatabase),
577 func: Function,
578 ) -> Arc<FnData> {
579 let src = func.source(db);
580 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
581 let mut params = Vec::new();
582 let mut has_self_param = false;
583 if let Some(param_list) = src.value.param_list() {
584 if let Some(self_param) = param_list.self_param() {
585 let self_type = if let Some(type_ref) = self_param.ascribed_type() {
586 TypeRef::from_ast(type_ref)
587 } else {
588 let self_type = TypeRef::Path(name::SELF_TYPE.into());
589 match self_param.kind() {
590 ast::SelfParamKind::Owned => self_type,
591 ast::SelfParamKind::Ref => {
592 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
593 }
594 ast::SelfParamKind::MutRef => {
595 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
596 }
597 }
598 };
599 params.push(self_type);
600 has_self_param = true;
601 }
602 for param in param_list.params() {
603 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
604 params.push(type_ref);
605 }
606 }
607 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
608 TypeRef::from_ast(type_ref)
609 } else {
610 TypeRef::unit()
611 };
612
613 let sig = FnData { name, params, ret_type, has_self_param };
614 Arc::new(sig)
615 }
616 pub fn name(&self) -> &Name {
617 &self.name
618 }
619
620 pub fn params(&self) -> &[TypeRef] {
621 &self.params
622 }
623
624 pub fn ret_type(&self) -> &TypeRef {
625 &self.ret_type
626 }
627
628 /// True if the first arg is `self`. This is relevant to decide whether this
629 /// can be called as a method.
630 pub fn has_self_param(&self) -> bool {
631 self.has_self_param
632 }
633}
634
635impl Function { 563impl Function {
636 pub fn module(self, db: &impl DefDatabase) -> Module { 564 pub fn module(self, db: &impl DefDatabase) -> Module {
637 self.id.lookup(db).module(db).into() 565 self.id.lookup(db).module(db).into()
@@ -642,10 +570,18 @@ impl Function {
642 } 570 }
643 571
644 pub fn name(self, db: &impl HirDatabase) -> Name { 572 pub fn name(self, db: &impl HirDatabase) -> Name {
645 self.data(db).name.clone() 573 db.function_data(self.id).name.clone()
574 }
575
576 pub fn has_self_param(self, db: &impl HirDatabase) -> bool {
577 db.function_data(self.id).has_self_param
578 }
579
580 pub fn params(self, db: &impl HirDatabase) -> Vec<TypeRef> {
581 db.function_data(self.id).params.clone()
646 } 582 }
647 583
648 pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { 584 pub fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
649 db.body_with_source_map(self.id.into()).1 585 db.body_with_source_map(self.id.into()).1
650 } 586 }
651 587
@@ -657,10 +593,6 @@ impl Function {
657 db.type_for_def(self.into(), Namespace::Values) 593 db.type_for_def(self.into(), Namespace::Values)
658 } 594 }
659 595
660 pub fn data(self, db: &impl HirDatabase) -> Arc<FnData> {
661 db.fn_data(self)
662 }
663
664 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { 596 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
665 db.infer(self.into()) 597 db.infer(self.into())
666 } 598 }
@@ -711,12 +643,8 @@ impl Const {
711 Some(self.module(db).krate()) 643 Some(self.module(db).krate())
712 } 644 }
713 645
714 pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
715 db.const_data(self)
716 }
717
718 pub fn name(self, db: &impl HirDatabase) -> Option<Name> { 646 pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
719 self.data(db).name().cloned() 647 db.const_data(self.id).name.clone()
720 } 648 }
721 649
722 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { 650 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
@@ -748,45 +676,6 @@ impl Const {
748 } 676 }
749} 677}
750 678
751#[derive(Debug, Clone, PartialEq, Eq)]
752pub struct ConstData {
753 pub(crate) name: Option<Name>,
754 pub(crate) type_ref: TypeRef,
755}
756
757impl ConstData {
758 pub fn name(&self) -> Option<&Name> {
759 self.name.as_ref()
760 }
761
762 pub fn type_ref(&self) -> &TypeRef {
763 &self.type_ref
764 }
765
766 pub(crate) fn const_data_query(
767 db: &(impl DefDatabase + AstDatabase),
768 konst: Const,
769 ) -> Arc<ConstData> {
770 let node = konst.source(db).value;
771 const_data_for(&node)
772 }
773
774 pub(crate) fn static_data_query(
775 db: &(impl DefDatabase + AstDatabase),
776 konst: Static,
777 ) -> Arc<ConstData> {
778 let node = konst.source(db).value;
779 const_data_for(&node)
780 }
781}
782
783fn const_data_for<N: NameOwner + TypeAscriptionOwner>(node: &N) -> Arc<ConstData> {
784 let name = node.name().map(|n| n.as_name());
785 let type_ref = TypeRef::from_ast_opt(node.ascribed_type());
786 let sig = ConstData { name, type_ref };
787 Arc::new(sig)
788}
789
790#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 679#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
791pub struct Static { 680pub struct Static {
792 pub(crate) id: StaticId, 681 pub(crate) id: StaticId,
@@ -794,17 +683,13 @@ pub struct Static {
794 683
795impl Static { 684impl Static {
796 pub fn module(self, db: &impl DefDatabase) -> Module { 685 pub fn module(self, db: &impl DefDatabase) -> Module {
797 Module { id: self.id.module(db) } 686 Module { id: self.id.lookup(db).module(db) }
798 } 687 }
799 688
800 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 689 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
801 Some(self.module(db).krate()) 690 Some(self.module(db).krate())
802 } 691 }
803 692
804 pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
805 db.static_data(self)
806 }
807
808 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { 693 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
809 db.infer(self.into()) 694 db.infer(self.into())
810 } 695 }
@@ -821,11 +706,11 @@ impl Trait {
821 } 706 }
822 707
823 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 708 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
824 self.trait_data(db).name.clone() 709 db.trait_data(self.id).name.clone()
825 } 710 }
826 711
827 pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> { 712 pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> {
828 self.trait_data(db).items.iter().map(|it| (*it).into()).collect() 713 db.trait_data(self.id).items.iter().map(|it| (*it).into()).collect()
829 } 714 }
830 715
831 fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> { 716 fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
@@ -871,7 +756,7 @@ impl Trait {
871 } 756 }
872 757
873 pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> { 758 pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
874 let trait_data = self.trait_data(db); 759 let trait_data = db.trait_data(self.id);
875 let res = 760 let res =
876 trait_data.associated_types().map(TypeAlias::from).find(|t| &t.name(db) == name)?; 761 trait_data.associated_types().map(TypeAlias::from).find(|t| &t.name(db) == name)?;
877 Some(res) 762 Some(res)
@@ -885,16 +770,12 @@ impl Trait {
885 self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name)) 770 self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name))
886 } 771 }
887 772
888 pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
889 db.trait_data(self.id)
890 }
891
892 pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef { 773 pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef {
893 TraitRef::for_trait(db, self) 774 TraitRef::for_trait(db, self)
894 } 775 }
895 776
896 pub fn is_auto(self, db: &impl DefDatabase) -> bool { 777 pub fn is_auto(self, db: &impl DefDatabase) -> bool {
897 self.trait_data(db).auto 778 db.trait_data(self.id).auto
898 } 779 }
899} 780}
900 781
@@ -937,7 +818,7 @@ impl TypeAlias {
937 } 818 }
938 819
939 pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> { 820 pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> {
940 db.type_alias_data(self).type_ref.clone() 821 db.type_alias_data(self.id).type_ref.clone()
941 } 822 }
942 823
943 pub fn ty(self, db: &impl HirDatabase) -> Ty { 824 pub fn ty(self, db: &impl HirDatabase) -> Ty {
@@ -945,7 +826,7 @@ impl TypeAlias {
945 } 826 }
946 827
947 pub fn name(self, db: &impl DefDatabase) -> Name { 828 pub fn name(self, db: &impl DefDatabase) -> Name {
948 db.type_alias_data(self).name.clone() 829 db.type_alias_data(self.id).name.clone()
949 } 830 }
950} 831}
951 832
@@ -1034,7 +915,7 @@ pub struct Local {
1034 915
1035impl Local { 916impl Local {
1036 pub fn name(self, db: &impl HirDatabase) -> Option<Name> { 917 pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
1037 let body = self.parent.body(db); 918 let body = db.body(self.parent.into());
1038 match &body[self.pat_id] { 919 match &body[self.pat_id] {
1039 Pat::Bind { name, .. } => Some(name.clone()), 920 Pat::Bind { name, .. } => Some(name.clone()),
1040 _ => None, 921 _ => None,
@@ -1046,7 +927,7 @@ impl Local {
1046 } 927 }
1047 928
1048 pub fn is_mut(self, db: &impl HirDatabase) -> bool { 929 pub fn is_mut(self, db: &impl HirDatabase) -> bool {
1049 let body = self.parent.body(db); 930 let body = db.body(self.parent.into());
1050 match &body[self.pat_id] { 931 match &body[self.pat_id] {
1051 Pat::Bind { mode, .. } => match mode { 932 Pat::Bind { mode, .. } => match mode {
1052 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, 933 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
@@ -1070,7 +951,7 @@ impl Local {
1070 } 951 }
1071 952
1072 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> { 953 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> {
1073 let source_map = self.parent.body_source_map(db); 954 let (_body, source_map) = db.body_with_source_map(self.parent.into());
1074 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... 955 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
1075 let root = src.file_syntax(db); 956 let root = src.file_syntax(db);
1076 src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) 957 src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root)))
@@ -1088,6 +969,41 @@ pub struct ImplBlock {
1088 pub(crate) id: ImplId, 969 pub(crate) id: ImplId,
1089} 970}
1090 971
972impl ImplBlock {
973 pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> {
974 db.impl_data(self.id).target_trait.clone()
975 }
976
977 pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef {
978 db.impl_data(self.id).target_type.clone()
979 }
980
981 pub fn target_ty(&self, db: &impl HirDatabase) -> Ty {
982 Ty::from_hir(db, &self.id.resolver(db), &self.target_type(db))
983 }
984
985 pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> {
986 let target_ty = self.target_ty(db);
987 TraitRef::from_hir(db, &self.id.resolver(db), &self.target_trait(db)?, Some(target_ty))
988 }
989
990 pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> {
991 db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
992 }
993
994 pub fn is_negative(&self, db: &impl DefDatabase) -> bool {
995 db.impl_data(self.id).is_negative
996 }
997
998 pub fn module(&self, db: &impl DefDatabase) -> Module {
999 self.id.module(db).into()
1000 }
1001
1002 pub fn krate(&self, db: &impl DefDatabase) -> Crate {
1003 Crate { crate_id: self.module(db).id.krate }
1004 }
1005}
1006
1091/// For IDE only 1007/// For IDE only
1092pub enum ScopeDef { 1008pub enum ScopeDef {
1093 ModuleDef(ModuleDef), 1009 ModuleDef(ModuleDef),
@@ -1105,8 +1021,56 @@ impl From<PerNs> for ScopeDef {
1105 .or_else(|| def.take_values()) 1021 .or_else(|| def.take_values())
1106 .map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into())) 1022 .map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into()))
1107 .or_else(|| { 1023 .or_else(|| {
1108 def.get_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into())) 1024 def.take_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into()))
1109 }) 1025 })
1110 .unwrap_or(ScopeDef::Unknown) 1026 .unwrap_or(ScopeDef::Unknown)
1111 } 1027 }
1112} 1028}
1029
1030#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1031pub enum AttrDef {
1032 Module(Module),
1033 StructField(StructField),
1034 Adt(Adt),
1035 Function(Function),
1036 EnumVariant(EnumVariant),
1037 Static(Static),
1038 Const(Const),
1039 Trait(Trait),
1040 TypeAlias(TypeAlias),
1041 MacroDef(MacroDef),
1042}
1043
1044impl_froms!(
1045 AttrDef: Module,
1046 StructField,
1047 Adt(Struct, Enum, Union),
1048 EnumVariant,
1049 Static,
1050 Const,
1051 Function,
1052 Trait,
1053 TypeAlias,
1054 MacroDef
1055);
1056
1057pub trait HasAttrs {
1058 fn attrs(self, db: &impl DefDatabase) -> Attrs;
1059}
1060
1061impl<T: Into<AttrDef>> HasAttrs for T {
1062 fn attrs(self, db: &impl DefDatabase) -> Attrs {
1063 let def: AttrDef = self.into();
1064 db.attrs(def.into())
1065 }
1066}
1067
1068pub trait Docs {
1069 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation>;
1070}
1071impl<T: Into<AttrDef> + Copy> Docs for T {
1072 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
1073 let def: AttrDef = (*self).into();
1074 db.documentation(def.into())
1075 }
1076}
diff --git a/crates/ra_hir/src/code_model/attrs.rs b/crates/ra_hir/src/code_model/attrs.rs
deleted file mode 100644
index 9e304217c..000000000
--- a/crates/ra_hir/src/code_model/attrs.rs
+++ /dev/null
@@ -1,92 +0,0 @@
1//! FIXME: write short doc here
2
3use crate::{
4 db::{AstDatabase, DefDatabase, HirDatabase},
5 Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static,
6 Struct, StructField, Trait, TypeAlias, Union,
7};
8use hir_def::attr::Attr;
9use hir_expand::hygiene::Hygiene;
10use ra_syntax::ast;
11use std::sync::Arc;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum AttrDef {
15 Module(Module),
16 StructField(StructField),
17 Adt(Adt),
18 Function(Function),
19 EnumVariant(EnumVariant),
20 Static(Static),
21 Const(Const),
22 Trait(Trait),
23 TypeAlias(TypeAlias),
24 MacroDef(MacroDef),
25}
26
27impl_froms!(
28 AttrDef: Module,
29 StructField,
30 Adt(Struct, Enum, Union),
31 EnumVariant,
32 Static,
33 Const,
34 Function,
35 Trait,
36 TypeAlias,
37 MacroDef
38);
39
40pub trait Attrs {
41 fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>>;
42}
43
44pub(crate) fn attributes_query(
45 db: &(impl DefDatabase + AstDatabase),
46 def: AttrDef,
47) -> Option<Arc<[Attr]>> {
48 match def {
49 AttrDef::Module(it) => {
50 let src = it.declaration_source(db)?;
51 let hygiene = Hygiene::new(db, src.file_id);
52 Attr::from_attrs_owner(&src.value, &hygiene)
53 }
54 AttrDef::StructField(it) => match it.source(db).value {
55 FieldSource::Named(named) => {
56 let src = it.source(db);
57 let hygiene = Hygiene::new(db, src.file_id);
58 Attr::from_attrs_owner(&named, &hygiene)
59 }
60 FieldSource::Pos(..) => None,
61 },
62 AttrDef::Adt(it) => match it {
63 Adt::Struct(it) => attrs_from_ast(it, db),
64 Adt::Enum(it) => attrs_from_ast(it, db),
65 Adt::Union(it) => attrs_from_ast(it, db),
66 },
67 AttrDef::EnumVariant(it) => attrs_from_ast(it, db),
68 AttrDef::Static(it) => attrs_from_ast(it, db),
69 AttrDef::Const(it) => attrs_from_ast(it, db),
70 AttrDef::Function(it) => attrs_from_ast(it, db),
71 AttrDef::Trait(it) => attrs_from_ast(it, db),
72 AttrDef::TypeAlias(it) => attrs_from_ast(it, db),
73 AttrDef::MacroDef(it) => attrs_from_ast(it, db),
74 }
75}
76
77fn attrs_from_ast<T, D>(node: T, db: &D) -> Option<Arc<[Attr]>>
78where
79 T: HasSource,
80 T::Ast: ast::AttrsOwner,
81 D: DefDatabase + AstDatabase,
82{
83 let src = node.source(db);
84 let hygiene = Hygiene::new(db, src.file_id);
85 Attr::from_attrs_owner(&src.value, &hygiene)
86}
87
88impl<T: Into<AttrDef> + Copy> Attrs for T {
89 fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>> {
90 db.attrs((*self).into())
91 }
92}
diff --git a/crates/ra_hir/src/code_model/docs.rs b/crates/ra_hir/src/code_model/docs.rs
deleted file mode 100644
index e40efef34..000000000
--- a/crates/ra_hir/src/code_model/docs.rs
+++ /dev/null
@@ -1,97 +0,0 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use ra_syntax::ast;
6
7use crate::{
8 db::{AstDatabase, DefDatabase, HirDatabase},
9 Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static,
10 Struct, StructField, Trait, TypeAlias, Union,
11};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum DocDef {
15 Module(Module),
16 StructField(StructField),
17 Adt(Adt),
18 EnumVariant(EnumVariant),
19 Static(Static),
20 Const(Const),
21 Function(Function),
22 Trait(Trait),
23 TypeAlias(TypeAlias),
24 MacroDef(MacroDef),
25}
26
27impl_froms!(
28 DocDef: Module,
29 StructField,
30 Adt(Struct, Enum, Union),
31 EnumVariant,
32 Static,
33 Const,
34 Function,
35 Trait,
36 TypeAlias,
37 MacroDef
38);
39
40/// Holds documentation
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct Documentation(Arc<str>);
43
44impl Documentation {
45 fn new(s: &str) -> Documentation {
46 Documentation(s.into())
47 }
48
49 pub fn as_str(&self) -> &str {
50 &*self.0
51 }
52}
53
54impl Into<String> for Documentation {
55 fn into(self) -> String {
56 self.as_str().to_owned()
57 }
58}
59
60pub trait Docs {
61 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation>;
62}
63
64pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
65 node.doc_comment_text().map(|it| Documentation::new(&it))
66}
67
68pub(crate) fn documentation_query(
69 db: &(impl DefDatabase + AstDatabase),
70 def: DocDef,
71) -> Option<Documentation> {
72 match def {
73 DocDef::Module(it) => docs_from_ast(&it.declaration_source(db)?.value),
74 DocDef::StructField(it) => match it.source(db).value {
75 FieldSource::Named(named) => docs_from_ast(&named),
76 FieldSource::Pos(..) => None,
77 },
78 DocDef::Adt(it) => match it {
79 Adt::Struct(it) => docs_from_ast(&it.source(db).value),
80 Adt::Enum(it) => docs_from_ast(&it.source(db).value),
81 Adt::Union(it) => docs_from_ast(&it.source(db).value),
82 },
83 DocDef::EnumVariant(it) => docs_from_ast(&it.source(db).value),
84 DocDef::Static(it) => docs_from_ast(&it.source(db).value),
85 DocDef::Const(it) => docs_from_ast(&it.source(db).value),
86 DocDef::Function(it) => docs_from_ast(&it.source(db).value),
87 DocDef::Trait(it) => docs_from_ast(&it.source(db).value),
88 DocDef::TypeAlias(it) => docs_from_ast(&it.source(db).value),
89 DocDef::MacroDef(it) => docs_from_ast(&it.source(db).value),
90 }
91}
92
93impl<T: Into<DocDef> + Copy> Docs for T {
94 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
95 db.documentation((*self).into())
96 }
97}
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 4aa427de4..a4e317c20 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,172 +1,128 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{HasSource as _, Lookup}; 3use hir_def::{AstItemDef, HasChildSource, HasSource as _, Lookup, VariantId};
4use ra_syntax::ast::{self, AstNode}; 4use hir_expand::either::Either;
5use ra_syntax::ast;
5 6
6use crate::{ 7use crate::{
7 db::{AstDatabase, DefDatabase, HirDatabase}, 8 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, Import, MacroDef,
8 ids::AstItemDef, 9 Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
9 Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module,
10 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
11}; 10};
12 11
13pub use hir_expand::Source; 12pub use hir_expand::Source;
14 13
15pub trait HasSource { 14pub trait HasSource {
16 type Ast; 15 type Ast;
17 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; 16 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast>;
18} 17}
19 18
20/// NB: Module is !HasSource, because it has two source nodes at the same time: 19/// NB: Module is !HasSource, because it has two source nodes at the same time:
21/// definition and declaration. 20/// definition and declaration.
22impl Module { 21impl Module {
23 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 22 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
24 pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> { 23 pub fn definition_source(self, db: &impl DefDatabase) -> Source<ModuleSource> {
25 let def_map = db.crate_def_map(self.id.krate); 24 let def_map = db.crate_def_map(self.id.krate);
26 let decl_id = def_map[self.id.module_id].declaration; 25 let src = def_map[self.id.module_id].definition_source(db);
27 let file_id = def_map[self.id.module_id].definition; 26 src.map(|it| match it {
28 let value = ModuleSource::new(db, file_id, decl_id); 27 Either::A(it) => ModuleSource::SourceFile(it),
29 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id()); 28 Either::B(it) => ModuleSource::Module(it),
30 Source { file_id, value } 29 })
31 } 30 }
32 31
33 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 32 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
34 /// `None` for the crate root. 33 /// `None` for the crate root.
35 pub fn declaration_source( 34 pub fn declaration_source(self, db: &impl DefDatabase) -> Option<Source<ast::Module>> {
36 self,
37 db: &(impl DefDatabase + AstDatabase),
38 ) -> Option<Source<ast::Module>> {
39 let def_map = db.crate_def_map(self.id.krate); 35 let def_map = db.crate_def_map(self.id.krate);
40 let decl = def_map[self.id.module_id].declaration?; 36 def_map[self.id.module_id].declaration_source(db)
41 let value = decl.to_node(db);
42 Some(Source { file_id: decl.file_id(), value })
43 } 37 }
44} 38}
45 39
46impl HasSource for StructField { 40impl HasSource for StructField {
47 type Ast = FieldSource; 41 type Ast = FieldSource;
48 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<FieldSource> { 42 fn source(self, db: &impl DefDatabase) -> Source<FieldSource> {
49 let var_data = self.parent.variant_data(db); 43 let var = VariantId::from(self.parent);
50 let fields = var_data.fields().unwrap(); 44 let src = var.child_source(db);
51 let ss; 45 src.map(|it| match it[self.id].clone() {
52 let es; 46 Either::A(it) => FieldSource::Pos(it),
53 let (file_id, struct_kind) = match self.parent { 47 Either::B(it) => FieldSource::Named(it),
54 VariantDef::Struct(s) => { 48 })
55 ss = s.source(db);
56 (ss.file_id, ss.value.kind())
57 }
58 VariantDef::EnumVariant(e) => {
59 es = e.source(db);
60 (es.file_id, es.value.kind())
61 }
62 };
63
64 let field_sources = match struct_kind {
65 ast::StructKind::Tuple(fl) => fl.fields().map(|it| FieldSource::Pos(it)).collect(),
66 ast::StructKind::Named(fl) => fl.fields().map(|it| FieldSource::Named(it)).collect(),
67 ast::StructKind::Unit => Vec::new(),
68 };
69 let value = field_sources
70 .into_iter()
71 .zip(fields.iter())
72 .find(|(_syntax, (id, _))| *id == self.id)
73 .unwrap()
74 .0;
75 Source { file_id, value }
76 } 49 }
77} 50}
78impl HasSource for Struct { 51impl HasSource for Struct {
79 type Ast = ast::StructDef; 52 type Ast = ast::StructDef;
80 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 53 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
81 self.id.0.source(db) 54 self.id.0.source(db)
82 } 55 }
83} 56}
84impl HasSource for Union { 57impl HasSource for Union {
85 type Ast = ast::StructDef; 58 type Ast = ast::StructDef;
86 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 59 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
87 self.id.0.source(db) 60 self.id.0.source(db)
88 } 61 }
89} 62}
90impl HasSource for Enum { 63impl HasSource for Enum {
91 type Ast = ast::EnumDef; 64 type Ast = ast::EnumDef;
92 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumDef> { 65 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumDef> {
93 self.id.source(db) 66 self.id.source(db)
94 } 67 }
95} 68}
96impl HasSource for EnumVariant { 69impl HasSource for EnumVariant {
97 type Ast = ast::EnumVariant; 70 type Ast = ast::EnumVariant;
98 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumVariant> { 71 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumVariant> {
99 let enum_data = db.enum_data(self.parent.id); 72 self.parent.id.child_source(db).map(|map| map[self.id].clone())
100 let src = self.parent.id.source(db);
101 let value = src
102 .value
103 .variant_list()
104 .into_iter()
105 .flat_map(|it| it.variants())
106 .zip(enum_data.variants.iter())
107 .find(|(_syntax, (id, _))| *id == self.id)
108 .unwrap()
109 .0;
110 Source { file_id: src.file_id, value }
111 } 73 }
112} 74}
113impl HasSource for Function { 75impl HasSource for Function {
114 type Ast = ast::FnDef; 76 type Ast = ast::FnDef;
115 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::FnDef> { 77 fn source(self, db: &impl DefDatabase) -> Source<ast::FnDef> {
116 self.id.lookup(db).source(db) 78 self.id.lookup(db).source(db)
117 } 79 }
118} 80}
119impl HasSource for Const { 81impl HasSource for Const {
120 type Ast = ast::ConstDef; 82 type Ast = ast::ConstDef;
121 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ConstDef> { 83 fn source(self, db: &impl DefDatabase) -> Source<ast::ConstDef> {
122 self.id.lookup(db).source(db) 84 self.id.lookup(db).source(db)
123 } 85 }
124} 86}
125impl HasSource for Static { 87impl HasSource for Static {
126 type Ast = ast::StaticDef; 88 type Ast = ast::StaticDef;
127 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StaticDef> { 89 fn source(self, db: &impl DefDatabase) -> Source<ast::StaticDef> {
128 self.id.source(db) 90 self.id.lookup(db).source(db)
129 } 91 }
130} 92}
131impl HasSource for Trait { 93impl HasSource for Trait {
132 type Ast = ast::TraitDef; 94 type Ast = ast::TraitDef;
133 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::TraitDef> { 95 fn source(self, db: &impl DefDatabase) -> Source<ast::TraitDef> {
134 self.id.source(db) 96 self.id.source(db)
135 } 97 }
136} 98}
137impl HasSource for TypeAlias { 99impl HasSource for TypeAlias {
138 type Ast = ast::TypeAliasDef; 100 type Ast = ast::TypeAliasDef;
139 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::TypeAliasDef> { 101 fn source(self, db: &impl DefDatabase) -> Source<ast::TypeAliasDef> {
140 self.id.lookup(db).source(db) 102 self.id.lookup(db).source(db)
141 } 103 }
142} 104}
143impl HasSource for MacroDef { 105impl HasSource for MacroDef {
144 type Ast = ast::MacroCall; 106 type Ast = ast::MacroCall;
145 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> { 107 fn source(self, db: &impl DefDatabase) -> Source<ast::MacroCall> {
146 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) } 108 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) }
147 } 109 }
148} 110}
149 111impl HasSource for ImplBlock {
150pub trait HasBodySource: HasBody + HasSource 112 type Ast = ast::ImplBlock;
151where 113 fn source(self, db: &impl DefDatabase) -> Source<ast::ImplBlock> {
152 Self::Ast: AstNode, 114 self.id.source(db)
153{
154 fn expr_source(
155 self,
156 db: &impl HirDatabase,
157 expr_id: crate::expr::ExprId,
158 ) -> Option<Source<Either<ast::Expr, ast::RecordField>>> {
159 let source_map = self.body_source_map(db);
160 let source_ptr = source_map.expr_syntax(expr_id)?;
161 let root = source_ptr.file_syntax(db);
162 let source = source_ptr.map(|ast| ast.map(|it| it.to_node(&root), |it| it.to_node(&root)));
163 Some(source)
164 } 115 }
165} 116}
117impl HasSource for Import {
118 type Ast = Either<ast::UseTree, ast::ExternCrateItem>;
166 119
167impl<T> HasBodySource for T 120 /// Returns the syntax of the last path segment corresponding to this import
168where 121 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast> {
169 T: HasBody + HasSource, 122 let src = self.parent.definition_source(db);
170 T::Ast: AstNode, 123 let (_, source_map) = db.raw_items_with_source_map(src.file_id);
171{ 124 let root = db.parse_or_expand(src.file_id).unwrap();
125 let ptr = source_map.get(self.id);
126 src.with_value(ptr.map(|it| it.to_node(&root), |it| it.to_node(&root)))
127 }
172} 128}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index ed0d68001..5084bbacf 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -2,79 +2,46 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::attr::Attr; 5use ra_arena::map::ArenaMap;
6use ra_db::salsa; 6use ra_db::salsa;
7use ra_syntax::SmolStr;
8 7
9use crate::{ 8use crate::{
10 debug::HirDebugDatabase,
11 ids,
12 lang_item::{LangItemTarget, LangItems},
13 ty::{ 9 ty::{
14 method_resolution::CrateImplBlocks, 10 method_resolution::CrateImplBlocks,
15 traits::{AssocTyValue, Impl}, 11 traits::{AssocTyValue, Impl},
16 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef, 12 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
17 TypeCtor, 13 TypeCtor,
18 }, 14 },
19 type_alias::TypeAliasData, 15 Crate, DefWithBody, GenericDef, ImplBlock, Trait,
20 Const, ConstData, Crate, DefWithBody, FnData, Function, GenericDef, ImplBlock, Module, Static,
21 StructField, Trait, TypeAlias,
22}; 16};
23 17
24pub use hir_def::db::{ 18pub use hir_def::{
25 BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, 19 db::{
26 EnumDataQuery, ExprScopesQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, 20 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
27 InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, 21 DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
28 TraitDataQuery, 22 FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase,
23 InternDatabaseStorage, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery,
24 RawItemsWithSourceMapQuery, StaticDataQuery, StructDataQuery, TraitDataQuery,
25 TypeAliasDataQuery,
26 },
27 LocalStructFieldId, VariantId,
29}; 28};
30pub use hir_expand::db::{ 29pub use hir_expand::db::{
31 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 30 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
32 ParseMacroQuery, 31 ParseMacroQuery,
33}; 32};
34 33
35// This database uses `AstDatabase` internally,
36#[salsa::query_group(DefDatabaseStorage)]
37#[salsa::requires(AstDatabase)]
38pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
39 #[salsa::invoke(FnData::fn_data_query)]
40 fn fn_data(&self, func: Function) -> Arc<FnData>;
41
42 #[salsa::invoke(TypeAliasData::type_alias_data_query)]
43 fn type_alias_data(&self, typ: TypeAlias) -> Arc<TypeAliasData>;
44
45 #[salsa::invoke(ConstData::const_data_query)]
46 fn const_data(&self, konst: Const) -> Arc<ConstData>;
47
48 #[salsa::invoke(ConstData::static_data_query)]
49 fn static_data(&self, konst: Static) -> Arc<ConstData>;
50
51 #[salsa::invoke(LangItems::module_lang_items_query)]
52 fn module_lang_items(&self, module: Module) -> Option<Arc<LangItems>>;
53
54 #[salsa::invoke(LangItems::crate_lang_items_query)]
55 fn crate_lang_items(&self, krate: Crate) -> Arc<LangItems>;
56
57 #[salsa::invoke(LangItems::lang_item_query)]
58 fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>;
59
60 #[salsa::invoke(crate::code_model::docs::documentation_query)]
61 fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>;
62
63 #[salsa::invoke(crate::code_model::attrs::attributes_query)]
64 fn attrs(&self, def: crate::AttrDef) -> Option<Arc<[Attr]>>;
65}
66
67#[salsa::query_group(HirDatabaseStorage)] 34#[salsa::query_group(HirDatabaseStorage)]
68#[salsa::requires(salsa::Database)] 35#[salsa::requires(salsa::Database)]
69pub trait HirDatabase: DefDatabase + AstDatabase { 36pub trait HirDatabase: DefDatabase {
70 #[salsa::invoke(crate::ty::infer_query)] 37 #[salsa::invoke(crate::ty::infer_query)]
71 fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>; 38 fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>;
72 39
73 #[salsa::invoke(crate::ty::type_for_def)] 40 #[salsa::invoke(crate::ty::type_for_def)]
74 fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; 41 fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;
75 42
76 #[salsa::invoke(crate::ty::type_for_field)] 43 #[salsa::invoke(crate::ty::field_types_query)]
77 fn type_for_field(&self, field: StructField) -> Ty; 44 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>;
78 45
79 #[salsa::invoke(crate::ty::callable_item_sig)] 46 #[salsa::invoke(crate::ty::callable_item_sig)]
80 fn callable_item_signature(&self, def: CallableDef) -> FnSig; 47 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
@@ -108,11 +75,14 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
108 75
109 // Interned IDs for Chalk integration 76 // Interned IDs for Chalk integration
110 #[salsa::interned] 77 #[salsa::interned]
111 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; 78 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::ty::TypeCtorId;
112 #[salsa::interned] 79 #[salsa::interned]
113 fn intern_chalk_impl(&self, impl_: Impl) -> ids::GlobalImplId; 80 fn intern_chalk_impl(&self, impl_: Impl) -> crate::ty::traits::GlobalImplId;
114 #[salsa::interned] 81 #[salsa::interned]
115 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> ids::AssocTyValueId; 82 fn intern_assoc_ty_value(
83 &self,
84 assoc_ty_value: AssocTyValue,
85 ) -> crate::ty::traits::AssocTyValueId;
116 86
117 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] 87 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)]
118 fn associated_ty_data( 88 fn associated_ty_data(
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
index 4f3e922c3..7a2810f71 100644
--- a/crates/ra_hir/src/debug.rs
+++ b/crates/ra_hir/src/debug.rs
@@ -1,3 +1,5 @@
1//! XXX: This does not work at the moment.
2//!
1//! printf debugging infrastructure for rust-analyzer. 3//! printf debugging infrastructure for rust-analyzer.
2//! 4//!
3//! When you print a hir type, like a module, using `eprintln!("{:?}", module)`, 5//! When you print a hir type, like a module, using `eprintln!("{:?}", module)`,
@@ -20,9 +22,10 @@
20 22
21use std::fmt; 23use std::fmt;
22 24
25use hir_expand::HirFileId;
23use ra_db::{CrateId, FileId}; 26use ra_db::{CrateId, FileId};
24 27
25use crate::{db::HirDatabase, Crate, HirFileId, Module, Name}; 28use crate::{db::HirDatabase, Crate, Module, Name};
26 29
27impl Crate { 30impl Crate {
28 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ { 31 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index 7d1b64858..dafacba70 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -2,9 +2,10 @@
2 2
3use std::any::Any; 3use std::any::Any;
4 4
5use hir_expand::HirFileId;
5use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
6 7
7use crate::{db::AstDatabase, HirFileId, Name, Source}; 8use crate::{db::AstDatabase, Name, Source};
8 9
9pub use hir_def::diagnostics::UnresolvedModule; 10pub use hir_def::diagnostics::UnresolvedModule;
10pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 11pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 6b703d8b4..43fedde7a 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -44,15 +44,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
44 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { 44 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
45 let body = self.func.body(db); 45 let body = self.func.body(db);
46 46
47 for e in body.exprs() { 47 for e in body.exprs.iter() {
48 if let (id, Expr::RecordLit { path, fields, spread }) = e { 48 if let (id, Expr::RecordLit { path, fields, spread }) = e {
49 self.validate_record_literal(id, path, fields, *spread, db); 49 self.validate_record_literal(id, path, fields, *spread, db);
50 } 50 }
51 } 51 }
52 52
53 let body_expr = &body[body.body_expr()]; 53 let body_expr = &body[body.body_expr];
54 if let Expr::Block { statements: _, tail: Some(t) } = body_expr { 54 if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
55 self.validate_results_in_tail_expr(body.body_expr(), *t, db); 55 self.validate_results_in_tail_expr(body.body_expr, *t, db);
56 } 56 }
57 } 57 }
58 58
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
index e8ed04056..529ac8251 100644
--- a/crates/ra_hir/src/from_id.rs
+++ b/crates/ra_hir/src/from_id.rs
@@ -4,14 +4,14 @@
4//! are splitting the hir. 4//! are splitting the hir.
5 5
6use hir_def::{ 6use hir_def::{
7 AdtId, AssocItemId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, 7 AdtId, AssocItemId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
8 ModuleDefId, StaticId, StructId, TypeAliasId, UnionId, 8 GenericDefId, ModuleDefId, StaticId, StructFieldId, StructId, TypeAliasId, UnionId, VariantId,
9}; 9};
10 10
11use crate::{ 11use crate::{
12 ty::{CallableDef, TypableDef}, 12 ty::{CallableDef, TypableDef},
13 Adt, AssocItem, Const, Crate, DefWithBody, EnumVariant, Function, GenericDef, ModuleDef, 13 Adt, AssocItem, AttrDef, Const, Crate, DefWithBody, EnumVariant, Function, GenericDef,
14 Static, TypeAlias, 14 ModuleDef, Static, StructField, TypeAlias, VariantDef,
15}; 15};
16 16
17impl From<ra_db::CrateId> for Crate { 17impl From<ra_db::CrateId> for Crate {
@@ -70,6 +70,12 @@ impl From<EnumVariantId> for EnumVariant {
70 } 70 }
71} 71}
72 72
73impl From<EnumVariant> for EnumVariantId {
74 fn from(def: EnumVariant) -> Self {
75 EnumVariantId { parent: def.parent.id, local_id: def.id }
76 }
77}
78
73impl From<ModuleDefId> for ModuleDef { 79impl From<ModuleDefId> for ModuleDef {
74 fn from(id: ModuleDefId) -> Self { 80 fn from(id: ModuleDefId) -> Self {
75 match id { 81 match id {
@@ -219,3 +225,35 @@ impl From<CallableDef> for GenericDefId {
219 } 225 }
220 } 226 }
221} 227}
228
229impl From<VariantDef> for VariantId {
230 fn from(def: VariantDef) -> Self {
231 match def {
232 VariantDef::Struct(it) => VariantId::StructId(it.id),
233 VariantDef::EnumVariant(it) => VariantId::EnumVariantId(it.into()),
234 }
235 }
236}
237
238impl From<StructField> for StructFieldId {
239 fn from(def: StructField) -> Self {
240 StructFieldId { parent: def.parent.into(), local_id: def.id }
241 }
242}
243
244impl From<AttrDef> for AttrDefId {
245 fn from(def: AttrDef) -> Self {
246 match def {
247 AttrDef::Module(it) => AttrDefId::ModuleId(it.id),
248 AttrDef::StructField(it) => AttrDefId::StructFieldId(it.into()),
249 AttrDef::Adt(it) => AttrDefId::AdtId(it.into()),
250 AttrDef::Function(it) => AttrDefId::FunctionId(it.id),
251 AttrDef::EnumVariant(it) => AttrDefId::EnumVariantId(it.into()),
252 AttrDef::Static(it) => AttrDefId::StaticId(it.id),
253 AttrDef::Const(it) => AttrDefId::ConstId(it.id),
254 AttrDef::Trait(it) => AttrDefId::TraitId(it.id),
255 AttrDef::TypeAlias(it) => AttrDefId::TypeAliasId(it.id),
256 AttrDef::MacroDef(it) => AttrDefId::MacroDefId(it.id),
257 }
258 }
259}
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index b86307c58..1e7c22774 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; 3use hir_def::{AstItemDef, LocationCtx, ModuleId, StructId, StructOrUnionId, UnionId};
4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; 4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
5use ra_syntax::{ 5use ra_syntax::{
6 ast::{self, AstNode, NameOwner}, 6 ast::{self, AstNode, NameOwner},
@@ -9,10 +9,9 @@ use ra_syntax::{
9 9
10use crate::{ 10use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 ids::{AstItemDef, LocationCtx}, 12 AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock,
13 AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, 13 Local, MacroDef, Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait,
14 ImplBlock, Local, MacroDef, Module, ModuleDef, ModuleSource, Source, Static, Struct, 14 TypeAlias, Union, VariantDef,
15 StructField, Trait, TypeAlias, Union, VariantDef,
16}; 15};
17 16
18pub trait FromSource: Sized { 17pub trait FromSource: Sized {
@@ -105,10 +104,21 @@ impl FromSource for Const {
105impl FromSource for Static { 104impl FromSource for Static {
106 type Ast = ast::StaticDef; 105 type Ast = ast::StaticDef;
107 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 106 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
108 let id = from_source(db, src)?; 107 let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
109 Some(Static { id }) 108 Container::Module(it) => it,
109 Container::Trait(_) | Container::ImplBlock(_) => return None,
110 };
111 module
112 .declarations(db)
113 .into_iter()
114 .filter_map(|it| match it {
115 ModuleDef::Static(it) => Some(it),
116 _ => None,
117 })
118 .find(|it| same_source(&it.source(db), &src))
110 } 119 }
111} 120}
121
112impl FromSource for TypeAlias { 122impl FromSource for TypeAlias {
113 type Ast = ast::TypeAliasDef; 123 type Ast = ast::TypeAliasDef;
114 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 124 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
@@ -190,8 +200,7 @@ impl FromSource for StructField {
190 variant_def 200 variant_def
191 .variant_data(db) 201 .variant_data(db)
192 .fields() 202 .fields()
193 .into_iter() 203 .iter()
194 .flat_map(|it| it.iter())
195 .map(|(id, _)| StructField { parent: variant_def, id }) 204 .map(|(id, _)| StructField { parent: variant_def, id })
196 .find(|f| f.source(db) == src) 205 .find(|f| f.source(db) == src)
197 } 206 }
@@ -211,7 +220,7 @@ impl Local {
211 }; 220 };
212 Some(res) 221 Some(res)
213 })?; 222 })?;
214 let source_map = parent.body_source_map(db); 223 let (_body, source_map) = db.body_with_source_map(parent.into());
215 let src = src.map(ast::Pat::from); 224 let src = src.map(ast::Pat::from);
216 let pat_id = source_map.node_pat(src.as_ref())?; 225 let pat_id = source_map.node_pat(src.as_ref())?;
217 Some(Local { parent, pat_id }) 226 Some(Local { parent, pat_id })
@@ -272,7 +281,9 @@ where
272 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); 281 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
273 let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; 282 let module = Module::from_definition(db, Source::new(src.file_id, module_src))?;
274 let ctx = LocationCtx::new(db, module.id, src.file_id); 283 let ctx = LocationCtx::new(db, module.id, src.file_id);
275 Some(DEF::from_ast(ctx, &src.value)) 284 let items = db.ast_id_map(src.file_id);
285 let item_id = items.ast_id(&src.value);
286 Some(DEF::from_ast_id(ctx, item_id))
276} 287}
277 288
278enum Container { 289enum Container {
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
deleted file mode 100644
index 2b59365fb..000000000
--- a/crates/ra_hir/src/ids.rs
+++ /dev/null
@@ -1,45 +0,0 @@
1//! hir makes heavy use of ids: integer (u32) handlers to various things. You
2//! can think of id as a pointer (but without a lifetime) or a file descriptor
3//! (but for hir objects).
4//!
5//! This module defines a bunch of ids we are using. The most important ones are
6//! probably `HirFileId` and `DefId`.
7
8use ra_db::salsa;
9
10pub use hir_def::{
11 AstItemDef, ConstId, EnumId, FunctionId, ItemLoc, LocationCtx, StaticId, StructId, TraitId,
12 TypeAliasId,
13};
14pub use hir_expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind};
15
16macro_rules! impl_intern_key {
17 ($name:ident) => {
18 impl salsa::InternKey for $name {
19 fn from_intern_id(v: salsa::InternId) -> Self {
20 $name(v)
21 }
22 fn as_intern_id(&self) -> salsa::InternId {
23 self.0
24 }
25 }
26 };
27}
28
29/// This exists just for Chalk, because Chalk just has a single `StructId` where
30/// we have different kinds of ADTs, primitive types and special type
31/// constructors like tuples and function pointers.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub struct TypeCtorId(salsa::InternId);
34impl_intern_key!(TypeCtorId);
35
36/// This exists just for Chalk, because our ImplIds are only unique per module.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct GlobalImplId(salsa::InternId);
39impl_intern_key!(GlobalImplId);
40
41/// This exists just for Chalk, because it needs a unique ID for each associated
42/// type value in an impl (even synthetic ones).
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub struct AssocTyValueId(salsa::InternId);
45impl_intern_key!(AssocTyValueId);
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
deleted file mode 100644
index 774fa1d96..000000000
--- a/crates/ra_hir/src/impl_block.rs
+++ /dev/null
@@ -1,52 +0,0 @@
1//! FIXME: write short doc here
2
3use hir_def::{resolver::HasResolver, type_ref::TypeRef, AstItemDef};
4use ra_syntax::ast;
5
6use crate::{
7 db::{AstDatabase, DefDatabase, HirDatabase},
8 ty::Ty,
9 AssocItem, Crate, HasSource, ImplBlock, Module, Source, TraitRef,
10};
11
12impl HasSource for ImplBlock {
13 type Ast = ast::ImplBlock;
14 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ImplBlock> {
15 self.id.source(db)
16 }
17}
18
19impl ImplBlock {
20 pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> {
21 db.impl_data(self.id).target_trait().cloned()
22 }
23
24 pub fn target_type(&self, db: &impl DefDatabase) -> TypeRef {
25 db.impl_data(self.id).target_type().clone()
26 }
27
28 pub fn target_ty(&self, db: &impl HirDatabase) -> Ty {
29 Ty::from_hir(db, &self.id.resolver(db), &self.target_type(db))
30 }
31
32 pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> {
33 let target_ty = self.target_ty(db);
34 TraitRef::from_hir(db, &self.id.resolver(db), &self.target_trait(db)?, Some(target_ty))
35 }
36
37 pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> {
38 db.impl_data(self.id).items().iter().map(|it| (*it).into()).collect()
39 }
40
41 pub fn is_negative(&self, db: &impl DefDatabase) -> bool {
42 db.impl_data(self.id).is_negative()
43 }
44
45 pub fn module(&self, db: &impl DefDatabase) -> Module {
46 self.id.module(db).into()
47 }
48
49 pub fn krate(&self, db: &impl DefDatabase) -> Crate {
50 Crate { crate_id: self.module(db).id.krate }
51 }
52}
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs
deleted file mode 100644
index 89fd85f59..000000000
--- a/crates/ra_hir/src/lang_item.rs
+++ /dev/null
@@ -1,160 +0,0 @@
1//! FIXME: write short doc here
2
3use rustc_hash::FxHashMap;
4use std::sync::Arc;
5
6use ra_syntax::{ast::AttrsOwner, SmolStr};
7
8use crate::{
9 db::{AstDatabase, DefDatabase, HirDatabase},
10 Adt, Crate, Enum, Function, HasSource, ImplBlock, Module, ModuleDef, Static, Struct, Trait,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum LangItemTarget {
15 Enum(Enum),
16 Function(Function),
17 ImplBlock(ImplBlock),
18 Static(Static),
19 Struct(Struct),
20 Trait(Trait),
21}
22
23impl LangItemTarget {
24 pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
25 Some(match self {
26 LangItemTarget::Enum(e) => e.module(db).krate(),
27 LangItemTarget::Function(f) => f.module(db).krate(),
28 LangItemTarget::ImplBlock(i) => i.krate(db),
29 LangItemTarget::Static(s) => s.module(db).krate(),
30 LangItemTarget::Struct(s) => s.module(db).krate(),
31 LangItemTarget::Trait(t) => t.module(db).krate(),
32 })
33 }
34}
35
36#[derive(Default, Debug, Clone, PartialEq, Eq)]
37pub struct LangItems {
38 items: FxHashMap<SmolStr, LangItemTarget>,
39}
40
41impl LangItems {
42 pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
43 self.items.get(item)
44 }
45
46 /// Salsa query. This will look for lang items in a specific crate.
47 pub(crate) fn crate_lang_items_query(
48 db: &(impl DefDatabase + AstDatabase),
49 krate: Crate,
50 ) -> Arc<LangItems> {
51 let mut lang_items = LangItems::default();
52
53 if let Some(module) = krate.root_module(db) {
54 lang_items.collect_lang_items_recursive(db, module);
55 }
56
57 Arc::new(lang_items)
58 }
59
60 pub(crate) fn module_lang_items_query(
61 db: &(impl DefDatabase + AstDatabase),
62 module: Module,
63 ) -> Option<Arc<LangItems>> {
64 let mut lang_items = LangItems::default();
65 lang_items.collect_lang_items(db, module);
66 if lang_items.items.is_empty() {
67 None
68 } else {
69 Some(Arc::new(lang_items))
70 }
71 }
72
73 /// Salsa query. Look for a lang item, starting from the specified crate and recursively
74 /// traversing its dependencies.
75 pub(crate) fn lang_item_query(
76 db: &impl DefDatabase,
77 start_crate: Crate,
78 item: SmolStr,
79 ) -> Option<LangItemTarget> {
80 let lang_items = db.crate_lang_items(start_crate);
81 let start_crate_target = lang_items.items.get(&item);
82 if let Some(target) = start_crate_target {
83 Some(*target)
84 } else {
85 for dep in start_crate.dependencies(db) {
86 let dep_crate = dep.krate;
87 let dep_target = db.lang_item(dep_crate, item.clone());
88 if dep_target.is_some() {
89 return dep_target;
90 }
91 }
92 None
93 }
94 }
95
96 fn collect_lang_items(&mut self, db: &(impl DefDatabase + AstDatabase), module: Module) {
97 // Look for impl targets
98 for impl_block in module.impl_blocks(db) {
99 let src = impl_block.source(db);
100 if let Some(lang_item_name) = lang_item_name(&src.value) {
101 self.items
102 .entry(lang_item_name)
103 .or_insert_with(|| LangItemTarget::ImplBlock(impl_block));
104 }
105 }
106
107 for def in module.declarations(db) {
108 match def {
109 ModuleDef::Trait(trait_) => {
110 self.collect_lang_item(db, trait_, LangItemTarget::Trait)
111 }
112 ModuleDef::Adt(Adt::Enum(e)) => self.collect_lang_item(db, e, LangItemTarget::Enum),
113 ModuleDef::Adt(Adt::Struct(s)) => {
114 self.collect_lang_item(db, s, LangItemTarget::Struct)
115 }
116 ModuleDef::Function(f) => self.collect_lang_item(db, f, LangItemTarget::Function),
117 ModuleDef::Static(s) => self.collect_lang_item(db, s, LangItemTarget::Static),
118 _ => {}
119 }
120 }
121 }
122
123 fn collect_lang_items_recursive(
124 &mut self,
125 db: &(impl DefDatabase + AstDatabase),
126 module: Module,
127 ) {
128 if let Some(module_lang_items) = db.module_lang_items(module) {
129 self.items.extend(module_lang_items.items.iter().map(|(k, v)| (k.clone(), *v)))
130 }
131
132 // Look for lang items in the children
133 for child in module.children(db) {
134 self.collect_lang_items_recursive(db, child);
135 }
136 }
137
138 fn collect_lang_item<T, N>(
139 &mut self,
140 db: &(impl DefDatabase + AstDatabase),
141 item: T,
142 constructor: fn(T) -> LangItemTarget,
143 ) where
144 T: Copy + HasSource<Ast = N>,
145 N: AttrsOwner,
146 {
147 let node = item.source(db).value;
148 if let Some(lang_item_name) = lang_item_name(&node) {
149 self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
150 }
151 }
152}
153
154fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> {
155 node.attrs()
156 .filter_map(|a| a.as_simple_key_value())
157 .filter(|(key, _)| key == "lang")
158 .map(|(_, val)| val)
159 .nth(0)
160}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 8c6834392..843ce6a88 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -31,12 +31,8 @@ pub mod debug;
31pub mod db; 31pub mod db;
32pub mod source_binder; 32pub mod source_binder;
33 33
34mod ids;
35mod type_alias;
36mod ty; 34mod ty;
37mod impl_block;
38mod expr; 35mod expr;
39mod lang_item;
40pub mod diagnostics; 36pub mod diagnostics;
41mod util; 37mod util;
42 38
@@ -52,17 +48,13 @@ mod marks;
52 48
53pub use crate::{ 49pub use crate::{
54 code_model::{ 50 code_model::{
55 attrs::{AttrDef, Attrs}, 51 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency,
56 docs::{DocDef, Docs, Documentation}, 52 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam,
57 src::{HasBodySource, HasSource}, 53 HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef,
58 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, 54 Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
59 EnumVariant, FieldSource, FnData, Function, GenericDef, GenericParam, HasBody, ImplBlock,
60 Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, Static, Struct, StructField,
61 Trait, TypeAlias, Union, VariantDef,
62 }, 55 },
63 expr::ExprScopes, 56 expr::ExprScopes,
64 from_source::FromSource, 57 from_source::FromSource,
65 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile},
66 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 58 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
67 ty::{ 59 ty::{
68 display::HirDisplay, 60 display::HirDisplay,
@@ -73,8 +65,10 @@ pub use crate::{
73 65
74pub use hir_def::{ 66pub use hir_def::{
75 builtin_type::BuiltinType, 67 builtin_type::BuiltinType,
76 nameres::{per_ns::PerNs, raw::ImportId}, 68 docs::Documentation,
77 path::{Path, PathKind}, 69 path::{Path, PathKind},
78 type_ref::Mutability, 70 type_ref::Mutability,
79}; 71};
80pub use hir_expand::{either::Either, name::Name, Source}; 72pub use hir_expand::{
73 either::Either, name::Name, HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Source,
74};
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 797f90d50..31390bb7f 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -13,7 +13,9 @@ use hir_def::{
13 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs}, 13 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
14 DefWithBodyId, 14 DefWithBodyId,
15}; 15};
16use hir_expand::{name::AsName, AstId, MacroCallId, MacroCallLoc, MacroFileKind, Source}; 16use hir_expand::{
17 name::AsName, AstId, HirFileId, MacroCallId, MacroCallLoc, MacroFileKind, Source,
18};
17use ra_syntax::{ 19use ra_syntax::{
18 ast::{self, AstNode}, 20 ast::{self, AstNode},
19 match_ast, AstPtr, 21 match_ast, AstPtr,
@@ -24,11 +26,9 @@ use ra_syntax::{
24use crate::{ 26use crate::{
25 db::HirDatabase, 27 db::HirDatabase,
26 expr::{BodySourceMap, ExprScopes, ScopeId}, 28 expr::{BodySourceMap, ExprScopes, ScopeId},
27 ids::LocationCtx,
28 ty::method_resolution::{self, implements_trait}, 29 ty::method_resolution::{self, implements_trait},
29 Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function, 30 Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function,
30 GenericParam, HasBody, HirFileId, Local, MacroDef, Module, Name, Path, ScopeDef, Static, 31 GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Ty, TypeAlias,
31 Struct, Trait, Ty, TypeAlias,
32}; 32};
33 33
34fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> { 34fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> {
@@ -67,16 +67,12 @@ fn def_with_body_from_child_node(
67 db: &impl HirDatabase, 67 db: &impl HirDatabase,
68 child: Source<&SyntaxNode>, 68 child: Source<&SyntaxNode>,
69) -> Option<DefWithBody> { 69) -> Option<DefWithBody> {
70 let module_source = crate::ModuleSource::from_child_node(db, child);
71 let module = Module::from_definition(db, Source::new(child.file_id, module_source))?;
72 let ctx = LocationCtx::new(db, module.id, child.file_id);
73
74 child.value.ancestors().find_map(|node| { 70 child.value.ancestors().find_map(|node| {
75 match_ast! { 71 match_ast! {
76 match node { 72 match node {
77 ast::FnDef(def) => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 73 ast::FnDef(def) => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); },
78 ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 74 ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); },
79 ast::StaticDef(def) => { Some(Static { id: ctx.to_def(&def) }.into()) }, 75 ast::StaticDef(def) => { return Static::from_source(db, child.with_value(def)).map(DefWithBody::from); },
80 _ => { None }, 76 _ => { None },
81 } 77 }
82 } 78 }
@@ -158,8 +154,8 @@ impl SourceAnalyzer {
158 ) -> SourceAnalyzer { 154 ) -> SourceAnalyzer {
159 let def_with_body = def_with_body_from_child_node(db, node); 155 let def_with_body = def_with_body_from_child_node(db, node);
160 if let Some(def) = def_with_body { 156 if let Some(def) = def_with_body {
161 let source_map = def.body_source_map(db); 157 let (_body, source_map) = db.body_with_source_map(def.into());
162 let scopes = def.expr_scopes(db); 158 let scopes = db.expr_scopes(def.into());
163 let scope = match offset { 159 let scope = match offset {
164 None => scope_for(&scopes, &source_map, node), 160 None => scope_for(&scopes, &source_map, node),
165 Some(offset) => scope_for_offset(&scopes, &source_map, node.with_value(offset)), 161 Some(offset) => scope_for_offset(&scopes, &source_map, node.with_value(offset)),
@@ -169,7 +165,7 @@ impl SourceAnalyzer {
169 resolver, 165 resolver,
170 body_owner: Some(def), 166 body_owner: Some(def),
171 body_source_map: Some(source_map), 167 body_source_map: Some(source_map),
172 infer: Some(def.infer(db)), 168 infer: Some(db.infer(def)),
173 scopes: Some(scopes), 169 scopes: Some(scopes),
174 file_id: node.file_id, 170 file_id: node.file_id,
175 } 171 }
@@ -219,6 +215,11 @@ impl SourceAnalyzer {
219 self.infer.as_ref()?.field_resolution(expr_id) 215 self.infer.as_ref()?.field_resolution(expr_id)
220 } 216 }
221 217
218 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> {
219 let expr_id = self.expr_id(&field.expr()?)?;
220 self.infer.as_ref()?.record_field_resolution(expr_id)
221 }
222
222 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { 223 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
223 let expr_id = self.expr_id(&record_lit.clone().into())?; 224 let expr_id = self.expr_id(&record_lit.clone().into())?;
224 self.infer.as_ref()?.variant_resolution_for_expr(expr_id) 225 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
@@ -544,7 +545,7 @@ fn adjust(
544} 545}
545 546
546/// Given a `ast::MacroCall`, return what `MacroKindFile` it belongs to. 547/// Given a `ast::MacroCall`, return what `MacroKindFile` it belongs to.
547/// FIXME: Not completed 548/// FIXME: Not completed
548fn to_macro_file_kind(macro_call: &ast::MacroCall) -> MacroFileKind { 549fn to_macro_file_kind(macro_call: &ast::MacroCall) -> MacroFileKind {
549 let syn = macro_call.syntax(); 550 let syn = macro_call.syntax();
550 let parent = match syn.parent() { 551 let parent = match syn.parent() {
diff --git a/crates/ra_hir/src/test_db.rs b/crates/ra_hir/src/test_db.rs
index 1caa2e875..efee2f658 100644
--- a/crates/ra_hir/src/test_db.rs
+++ b/crates/ra_hir/src/test_db.rs
@@ -2,7 +2,7 @@
2 2
3use std::{panic, sync::Arc}; 3use std::{panic, sync::Arc};
4 4
5use hir_def::{db::DefDatabase2, ModuleId}; 5use hir_def::{db::DefDatabase, ModuleId};
6use hir_expand::diagnostics::DiagnosticSink; 6use hir_expand::diagnostics::DiagnosticSink;
7use parking_lot::Mutex; 7use parking_lot::Mutex;
8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase}; 8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase};
@@ -15,7 +15,6 @@ use crate::{db, debug::HirDebugHelper};
15 db::InternDatabaseStorage, 15 db::InternDatabaseStorage,
16 db::AstDatabaseStorage, 16 db::AstDatabaseStorage,
17 db::DefDatabaseStorage, 17 db::DefDatabaseStorage,
18 db::DefDatabase2Storage,
19 db::HirDatabaseStorage 18 db::HirDatabaseStorage
20)] 19)]
21#[derive(Debug, Default)] 20#[derive(Debug, Default)]
@@ -81,7 +80,7 @@ impl TestDB {
81 let crate_graph = self.crate_graph(); 80 let crate_graph = self.crate_graph();
82 for krate in crate_graph.iter().next() { 81 for krate in crate_graph.iter().next() {
83 let crate_def_map = self.crate_def_map(krate); 82 let crate_def_map = self.crate_def_map(krate);
84 for module_id in crate_def_map.modules() { 83 for (module_id, _) in crate_def_map.modules.iter() {
85 let module_id = ModuleId { krate, module_id }; 84 let module_id = ModuleId { krate, module_id };
86 let module = crate::Module::from(module_id); 85 let module = crate::Module::from(module_id);
87 module.diagnostics( 86 module.diagnostics(
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 95b8df181..f62316c1f 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -18,6 +18,7 @@ use std::sync::Arc;
18use std::{fmt, iter, mem}; 18use std::{fmt, iter, mem};
19 19
20use hir_def::{generics::GenericParams, AdtId}; 20use hir_def::{generics::GenericParams, AdtId};
21use ra_db::{impl_intern_key, salsa};
21 22
22use crate::{ 23use crate::{
23 db::HirDatabase, expr::ExprId, util::make_mut_slice, Adt, Crate, DefWithBody, FloatTy, 24 db::HirDatabase, expr::ExprId, util::make_mut_slice, Adt, Crate, DefWithBody, FloatTy,
@@ -29,8 +30,9 @@ pub(crate) use autoderef::autoderef;
29pub(crate) use infer::{infer_query, InferTy, InferenceResult}; 30pub(crate) use infer::{infer_query, InferTy, InferenceResult};
30pub use lower::CallableDef; 31pub use lower::CallableDef;
31pub(crate) use lower::{ 32pub(crate) use lower::{
32 callable_item_sig, generic_defaults_query, generic_predicates_for_param_query, 33 callable_item_sig, field_types_query, generic_defaults_query,
33 generic_predicates_query, type_for_def, type_for_field, Namespace, TypableDef, 34 generic_predicates_for_param_query, generic_predicates_query, type_for_def, Namespace,
35 TypableDef,
34}; 36};
35pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 37pub(crate) use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
36 38
@@ -114,6 +116,13 @@ pub enum TypeCtor {
114 Closure { def: DefWithBody, expr: ExprId }, 116 Closure { def: DefWithBody, expr: ExprId },
115} 117}
116 118
119/// This exists just for Chalk, because Chalk just has a single `StructId` where
120/// we have different kinds of ADTs, primitive types and special type
121/// constructors like tuples and function pointers.
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123pub struct TypeCtorId(salsa::InternId);
124impl_intern_key!(TypeCtorId);
125
117impl TypeCtor { 126impl TypeCtor {
118 pub fn num_ty_params(self, db: &impl HirDatabase) -> usize { 127 pub fn num_ty_params(self, db: &impl HirDatabase) -> usize {
119 match self { 128 match self {
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index b60e4bb31..41c99d227 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -5,12 +5,13 @@
5 5
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::resolver::Resolver; 8use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
9use hir_expand::name; 9use hir_expand::name;
10use log::{info, warn}; 10use log::{info, warn};
11 11
12use crate::{db::HirDatabase, Trait};
13
12use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; 14use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
13use crate::db::HirDatabase;
14 15
15const AUTODEREF_RECURSION_LIMIT: usize = 10; 16const AUTODEREF_RECURSION_LIMIT: usize = 10;
16 17
@@ -41,7 +42,7 @@ fn deref_by_trait(
41) -> Option<Canonical<Ty>> { 42) -> Option<Canonical<Ty>> {
42 let krate = resolver.krate()?; 43 let krate = resolver.krate()?;
43 let deref_trait = match db.lang_item(krate.into(), "deref".into())? { 44 let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
44 crate::lang_item::LangItemTarget::Trait(t) => t, 45 LangItemTarget::TraitId(t) => Trait::from(t),
45 _ => return None, 46 _ => return None,
46 }; 47 };
47 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; 48 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 69b13baef..ddc7d262a 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -22,6 +22,7 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
22use rustc_hash::FxHashMap; 22use rustc_hash::FxHashMap;
23 23
24use hir_def::{ 24use hir_def::{
25 data::{ConstData, FunctionData},
25 path::known, 26 path::known,
26 resolver::{HasResolver, Resolver, TypeNs}, 27 resolver::{HasResolver, Resolver, TypeNs},
27 type_ref::{Mutability, TypeRef}, 28 type_ref::{Mutability, TypeRef},
@@ -43,8 +44,7 @@ use crate::{
43 db::HirDatabase, 44 db::HirDatabase,
44 expr::{BindingAnnotation, Body, ExprId, PatId}, 45 expr::{BindingAnnotation, Body, ExprId, PatId},
45 ty::infer::diagnostics::InferenceDiagnostic, 46 ty::infer::diagnostics::InferenceDiagnostic,
46 Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, HasBody, IntTy, Path, 47 Adt, AssocItem, DefWithBody, FloatTy, Function, IntTy, Path, StructField, Trait, VariantDef,
47 StructField, Trait, VariantDef,
48}; 48};
49 49
50macro_rules! ty_app { 50macro_rules! ty_app {
@@ -68,10 +68,10 @@ pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResu
68 let resolver = DefWithBodyId::from(def).resolver(db); 68 let resolver = DefWithBodyId::from(def).resolver(db);
69 let mut ctx = InferenceContext::new(db, def, resolver); 69 let mut ctx = InferenceContext::new(db, def, resolver);
70 70
71 match def { 71 match &def {
72 DefWithBody::Const(ref c) => ctx.collect_const(&c.data(db)), 72 DefWithBody::Const(c) => ctx.collect_const(&db.const_data(c.id)),
73 DefWithBody::Function(ref f) => ctx.collect_fn(&f.data(db)), 73 DefWithBody::Function(f) => ctx.collect_fn(&db.function_data(f.id)),
74 DefWithBody::Static(ref s) => ctx.collect_const(&s.data(db)), 74 DefWithBody::Static(s) => ctx.collect_const(&db.static_data(s.id)),
75 } 75 }
76 76
77 ctx.infer_body(); 77 ctx.infer_body();
@@ -125,6 +125,8 @@ pub struct InferenceResult {
125 method_resolutions: FxHashMap<ExprId, Function>, 125 method_resolutions: FxHashMap<ExprId, Function>,
126 /// For each field access expr, records the field it resolves to. 126 /// For each field access expr, records the field it resolves to.
127 field_resolutions: FxHashMap<ExprId, StructField>, 127 field_resolutions: FxHashMap<ExprId, StructField>,
128 /// For each field in record literal, records the field it resolves to.
129 record_field_resolutions: FxHashMap<ExprId, StructField>,
128 /// For each struct literal, records the variant it resolves to. 130 /// For each struct literal, records the variant it resolves to.
129 variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>, 131 variant_resolutions: FxHashMap<ExprOrPatId, VariantDef>,
130 /// For each associated item record what it resolves to 132 /// For each associated item record what it resolves to
@@ -142,6 +144,9 @@ impl InferenceResult {
142 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { 144 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
143 self.field_resolutions.get(&expr).copied() 145 self.field_resolutions.get(&expr).copied()
144 } 146 }
147 pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructField> {
148 self.record_field_resolutions.get(&expr).copied()
149 }
145 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> { 150 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantDef> {
146 self.variant_resolutions.get(&id.into()).copied() 151 self.variant_resolutions.get(&id.into()).copied()
147 } 152 }
@@ -215,7 +220,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
215 coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), 220 coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver),
216 db, 221 db,
217 owner, 222 owner,
218 body: owner.body(db), 223 body: db.body(owner.into()),
219 resolver, 224 resolver,
220 } 225 }
221 } 226 }
@@ -559,21 +564,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
559 } 564 }
560 565
561 fn collect_const(&mut self, data: &ConstData) { 566 fn collect_const(&mut self, data: &ConstData) {
562 self.return_ty = self.make_ty(data.type_ref()); 567 self.return_ty = self.make_ty(&data.type_ref);
563 } 568 }
564 569
565 fn collect_fn(&mut self, data: &FnData) { 570 fn collect_fn(&mut self, data: &FunctionData) {
566 let body = Arc::clone(&self.body); // avoid borrow checker problem 571 let body = Arc::clone(&self.body); // avoid borrow checker problem
567 for (type_ref, pat) in data.params().iter().zip(body.params()) { 572 for (type_ref, pat) in data.params.iter().zip(body.params.iter()) {
568 let ty = self.make_ty(type_ref); 573 let ty = self.make_ty(type_ref);
569 574
570 self.infer_pat(*pat, &ty, BindingMode::default()); 575 self.infer_pat(*pat, &ty, BindingMode::default());
571 } 576 }
572 self.return_ty = self.make_ty(data.ret_type()); 577 self.return_ty = self.make_ty(&data.ret_type);
573 } 578 }
574 579
575 fn infer_body(&mut self) { 580 fn infer_body(&mut self) {
576 self.infer_expr(self.body.body_expr(), &Expectation::has_type(self.return_ty.clone())); 581 self.infer_expr(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
577 } 582 }
578 583
579 fn resolve_into_iter_item(&self) -> Option<TypeAlias> { 584 fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs
index 0772b9df5..54765da35 100644
--- a/crates/ra_hir/src/ty/infer/coerce.rs
+++ b/crates/ra_hir/src/ty/infer/coerce.rs
@@ -4,13 +4,12 @@
4//! 4//!
5//! See: https://doc.rust-lang.org/nomicon/coercions.html 5//! See: https://doc.rust-lang.org/nomicon/coercions.html
6 6
7use hir_def::resolver::Resolver; 7use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use test_utils::tested_by; 9use test_utils::tested_by;
10 10
11use crate::{ 11use crate::{
12 db::HirDatabase, 12 db::HirDatabase,
13 lang_item::LangItemTarget,
14 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk}, 13 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
15 Adt, Mutability, 14 Adt, Mutability,
16}; 15};
@@ -50,7 +49,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
50 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> { 49 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
51 let krate = resolver.krate().unwrap(); 50 let krate = resolver.krate().unwrap();
52 let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) { 51 let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) {
53 Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate.into(), trait_), 52 Some(LangItemTarget::TraitId(trait_)) => {
53 db.impls_for_trait(krate.into(), trait_.into())
54 }
54 _ => return FxHashMap::default(), 55 _ => return FxHashMap::default(),
55 }; 56 };
56 57
@@ -244,14 +245,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
244 ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1), 245 ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1),
245 ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2), 246 ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2),
246 ) if struct1 == struct2 => { 247 ) if struct1 == struct2 => {
247 let fields = struct1.fields(self.db); 248 let field_tys = self.db.field_types(struct1.id.into());
248 let (last_field, prev_fields) = fields.split_last()?; 249 let struct_data = self.db.struct_data(struct1.id.0);
250
251 let mut fields = struct_data.variant_data.fields().iter();
252 let (last_field_id, _data) = fields.next_back()?;
249 253
250 // Get the generic parameter involved in the last field. 254 // Get the generic parameter involved in the last field.
251 let unsize_generic_index = { 255 let unsize_generic_index = {
252 let mut index = None; 256 let mut index = None;
253 let mut multiple_param = false; 257 let mut multiple_param = false;
254 last_field.ty(self.db).walk(&mut |ty| match ty { 258 field_tys[last_field_id].walk(&mut |ty| match ty {
255 &Ty::Param { idx, .. } => { 259 &Ty::Param { idx, .. } => {
256 if index.is_none() { 260 if index.is_none() {
257 index = Some(idx); 261 index = Some(idx);
@@ -270,8 +274,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
270 274
271 // Check other fields do not involve it. 275 // Check other fields do not involve it.
272 let mut multiple_used = false; 276 let mut multiple_used = false;
273 prev_fields.iter().for_each(|field| { 277 fields.for_each(|(field_id, _data)| {
274 field.ty(self.db).walk(&mut |ty| match ty { 278 field_tys[field_id].walk(&mut |ty| match ty {
275 &Ty::Param { idx, .. } if idx == unsize_generic_index => { 279 &Ty::Param { idx, .. } if idx == unsize_generic_index => {
276 multiple_used = true 280 multiple_used = true
277 } 281 }
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs
index 20a7e9352..663ff9435 100644
--- a/crates/ra_hir/src/ty/infer/expr.rs
+++ b/crates/ra_hir/src/ty/infer/expr.rs
@@ -214,19 +214,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
214 self.unify(&ty, &expected.ty); 214 self.unify(&ty, &expected.ty);
215 215
216 let substs = ty.substs().unwrap_or_else(Substs::empty); 216 let substs = ty.substs().unwrap_or_else(Substs::empty);
217 let field_types =
218 def_id.map(|it| self.db.field_types(it.into())).unwrap_or_default();
217 for (field_idx, field) in fields.iter().enumerate() { 219 for (field_idx, field) in fields.iter().enumerate() {
218 let field_ty = def_id 220 let field_def = def_id.and_then(|it| match it.field(self.db, &field.name) {
219 .and_then(|it| match it.field(self.db, &field.name) { 221 Some(field) => Some(field),
220 Some(field) => Some(field), 222 None => {
221 None => { 223 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
222 self.push_diagnostic(InferenceDiagnostic::NoSuchField { 224 expr: tgt_expr,
223 expr: tgt_expr, 225 field: field_idx,
224 field: field_idx, 226 });
225 }); 227 None
226 None 228 }
227 } 229 });
228 }) 230 if let Some(field_def) = field_def {
229 .map_or(Ty::Unknown, |field| field.ty(self.db)) 231 self.result.record_field_resolutions.insert(field.expr, field_def);
232 }
233 let field_ty = field_def
234 .map_or(Ty::Unknown, |it| field_types[it.id].clone())
230 .subst(&substs); 235 .subst(&substs);
231 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); 236 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
232 } 237 }
@@ -250,7 +255,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
250 .and_then(|idx| a_ty.parameters.0.get(idx).cloned()), 255 .and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
251 TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| { 256 TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
252 self.write_field_resolution(tgt_expr, field); 257 self.write_field_resolution(tgt_expr, field);
253 field.ty(self.db).subst(&a_ty.parameters) 258 self.db.field_types(s.id.into())[field.id]
259 .clone()
260 .subst(&a_ty.parameters)
254 }), 261 }),
255 _ => None, 262 _ => None,
256 }, 263 },
diff --git a/crates/ra_hir/src/ty/infer/pat.rs b/crates/ra_hir/src/ty/infer/pat.rs
index c125ddfbc..641d61e87 100644
--- a/crates/ra_hir/src/ty/infer/pat.rs
+++ b/crates/ra_hir/src/ty/infer/pat.rs
@@ -27,10 +27,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
27 27
28 let substs = ty.substs().unwrap_or_else(Substs::empty); 28 let substs = ty.substs().unwrap_or_else(Substs::empty);
29 29
30 let field_tys = def.map(|it| self.db.field_types(it.into())).unwrap_or_default();
30 for (i, &subpat) in subpats.iter().enumerate() { 31 for (i, &subpat) in subpats.iter().enumerate() {
31 let expected_ty = def 32 let expected_ty = def
32 .and_then(|d| d.field(self.db, &Name::new_tuple_field(i))) 33 .and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
33 .map_or(Ty::Unknown, |field| field.ty(self.db)) 34 .map_or(Ty::Unknown, |field| field_tys[field.id].clone())
34 .subst(&substs); 35 .subst(&substs);
35 let expected_ty = self.normalize_associated_types_in(expected_ty); 36 let expected_ty = self.normalize_associated_types_in(expected_ty);
36 self.infer_pat(subpat, &expected_ty, default_bm); 37 self.infer_pat(subpat, &expected_ty, default_bm);
@@ -56,10 +57,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
56 57
57 let substs = ty.substs().unwrap_or_else(Substs::empty); 58 let substs = ty.substs().unwrap_or_else(Substs::empty);
58 59
60 let field_tys = def.map(|it| self.db.field_types(it.into())).unwrap_or_default();
59 for subpat in subpats { 61 for subpat in subpats {
60 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); 62 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
61 let expected_ty = 63 let expected_ty = matching_field
62 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); 64 .map_or(Ty::Unknown, |field| field_tys[field.id].clone())
65 .subst(&substs);
63 let expected_ty = self.normalize_associated_types_in(expected_ty); 66 let expected_ty = self.normalize_associated_types_in(expected_ty);
64 self.infer_pat(subpat.pat, &expected_ty, default_bm); 67 self.infer_pat(subpat.pat, &expected_ty, default_bm);
65 } 68 }
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 75c552569..a39beb2a0 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -14,8 +14,9 @@ use hir_def::{
14 path::{GenericArg, PathSegment}, 14 path::{GenericArg, PathSegment},
15 resolver::{HasResolver, Resolver, TypeNs}, 15 resolver::{HasResolver, Resolver, TypeNs},