aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-14 22:20:27 +0000
committerSeivan Heidari <[email protected]>2019-11-14 22:20:27 +0000
commitc622413bc72ea56d5f62a16788d897cb61eca948 (patch)
tree9de3dbe8b5c935ed168efac4e70770e54fbe0714 /crates/ra_hir
parent0525778a3ad590492b51cc11085d815f9bb8f92b (diff)
parentbbb022d3999b3038549ec6c309efb065231c896a (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/code_model.rs28
-rw-r--r--crates/ra_hir/src/db.rs19
-rw-r--r--crates/ra_hir/src/expr.rs237
-rw-r--r--crates/ra_hir/src/expr/scope.rs354
-rw-r--r--crates/ra_hir/src/from_id.rs14
-rw-r--r--crates/ra_hir/src/from_source.rs7
-rw-r--r--crates/ra_hir/src/lib.rs4
-rw-r--r--crates/ra_hir/src/resolve.rs5
-rw-r--r--crates/ra_hir/src/source_binder.rs52
-rw-r--r--crates/ra_hir/src/ty.rs6
-rw-r--r--crates/ra_hir/src/ty/infer.rs31
-rw-r--r--crates/ra_hir/src/ty/infer/expr.rs30
-rw-r--r--crates/ra_hir/src/ty/lower.rs14
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs11
-rw-r--r--crates/ra_hir/src/ty/primitive.rs32
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs4
16 files changed, 331 insertions, 517 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 2fd4ccb10..962d5a8c1 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -8,6 +8,7 @@ use std::sync::Arc;
8 8
9use hir_def::{ 9use hir_def::{
10 adt::VariantData, 10 adt::VariantData,
11 body::scope::ExprScopes,
11 builtin_type::BuiltinType, 12 builtin_type::BuiltinType,
12 type_ref::{Mutability, TypeRef}, 13 type_ref::{Mutability, TypeRef},
13 CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, 14 CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId,
@@ -539,6 +540,7 @@ pub trait HasBody: Copy {
539 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult>; 540 fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult>;
540 fn body(self, db: &impl HirDatabase) -> Arc<Body>; 541 fn body(self, db: &impl HirDatabase) -> Arc<Body>;
541 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap>; 542 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap>;
543 fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes>;
542} 544}
543 545
544impl<T> HasBody for T 546impl<T> HasBody for T
@@ -550,11 +552,15 @@ where
550 } 552 }
551 553
552 fn body(self, db: &impl HirDatabase) -> Arc<Body> { 554 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
553 db.body(self.into()) 555 self.into().body(db)
554 } 556 }
555 557
556 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { 558 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
557 db.body_with_source_map(self.into()).1 559 self.into().body_source_map(db)
560 }
561
562 fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes> {
563 self.into().expr_scopes(db)
558 } 564 }
559} 565}
560 566
@@ -564,11 +570,15 @@ impl HasBody for DefWithBody {
564 } 570 }
565 571
566 fn body(self, db: &impl HirDatabase) -> Arc<Body> { 572 fn body(self, db: &impl HirDatabase) -> Arc<Body> {
567 db.body(self) 573 db.body(self.into())
568 } 574 }
569 575
570 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { 576 fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
571 db.body_with_source_map(self).1 577 db.body_with_source_map(self.into()).1
578 }
579
580 fn expr_scopes(self, db: &impl HirDatabase) -> Arc<ExprScopes> {
581 db.expr_scopes(self.into())
572 } 582 }
573} 583}
574 584
@@ -662,11 +672,11 @@ impl Function {
662 } 672 }
663 673
664 pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { 674 pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
665 db.body_with_source_map(self.into()).1 675 db.body_with_source_map(self.id.into()).1
666 } 676 }
667 677
668 pub fn body(self, db: &impl HirDatabase) -> Arc<Body> { 678 pub fn body(self, db: &impl HirDatabase) -> Arc<Body> {
669 db.body(self.into()) 679 db.body(self.id.into())
670 } 680 }
671 681
672 pub fn ty(self, db: &impl HirDatabase) -> Ty { 682 pub fn ty(self, db: &impl HirDatabase) -> Ty {
@@ -1079,7 +1089,7 @@ pub struct Local {
1079 1089
1080impl Local { 1090impl Local {
1081 pub fn name(self, db: &impl HirDatabase) -> Option<Name> { 1091 pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
1082 let body = db.body(self.parent); 1092 let body = self.parent.body(db);
1083 match &body[self.pat_id] { 1093 match &body[self.pat_id] {
1084 Pat::Bind { name, .. } => Some(name.clone()), 1094 Pat::Bind { name, .. } => Some(name.clone()),
1085 _ => None, 1095 _ => None,
@@ -1091,7 +1101,7 @@ impl Local {
1091 } 1101 }
1092 1102
1093 pub fn is_mut(self, db: &impl HirDatabase) -> bool { 1103 pub fn is_mut(self, db: &impl HirDatabase) -> bool {
1094 let body = db.body(self.parent); 1104 let body = self.parent.body(db);
1095 match &body[self.pat_id] { 1105 match &body[self.pat_id] {
1096 Pat::Bind { mode, .. } => match mode { 1106 Pat::Bind { mode, .. } => match mode {
1097 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, 1107 BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
@@ -1115,7 +1125,7 @@ impl Local {
1115 } 1125 }
1116 1126
1117 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> { 1127 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> {
1118 let (_body, source_map) = db.body_with_source_map(self.parent); 1128 let source_map = self.parent.body_source_map(db);
1119 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... 1129 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
1120 let root = src.file_syntax(db); 1130 let root = src.file_syntax(db);
1121 src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) 1131 src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root)))
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 9ac811232..c60029c01 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -8,7 +8,6 @@ use ra_syntax::SmolStr;
8 8
9use crate::{ 9use crate::{
10 debug::HirDebugDatabase, 10 debug::HirDebugDatabase,
11 expr::{Body, BodySourceMap},
12 generics::{GenericDef, GenericParams}, 11 generics::{GenericDef, GenericParams},
13 ids, 12 ids,
14 impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, 13 impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks},
@@ -19,13 +18,14 @@ use crate::{
19 InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, 18 InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor,
20 }, 19 },
21 type_alias::TypeAliasData, 20 type_alias::TypeAliasData,
22 Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, 21 Const, ConstData, Crate, DefWithBody, FnData, Function, Module, Static, StructField, Trait,
23 StructField, Trait, TypeAlias, 22 TypeAlias,
24}; 23};
25 24
26pub use hir_def::db::{ 25pub use hir_def::db::{
27 CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, 26 BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage,
28 InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, 27 EnumDataQuery, ExprScopesQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery,
28 RawItemsWithSourceMapQuery, StructDataQuery,
29}; 29};
30pub use hir_expand::db::{ 30pub use hir_expand::db::{
31 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 31 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@@ -85,9 +85,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
85#[salsa::query_group(HirDatabaseStorage)] 85#[salsa::query_group(HirDatabaseStorage)]
86#[salsa::requires(salsa::Database)] 86#[salsa::requires(salsa::Database)]
87pub trait HirDatabase: DefDatabase + AstDatabase { 87pub trait HirDatabase: DefDatabase + AstDatabase {
88 #[salsa::invoke(ExprScopes::expr_scopes_query)]
89 fn expr_scopes(&self, def: DefWithBody) -> Arc<ExprScopes>;
90
91 #[salsa::invoke(crate::ty::infer_query)] 88 #[salsa::invoke(crate::ty::infer_query)]
92 fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>; 89 fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>;
93 90
@@ -113,12 +110,6 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
113 #[salsa::invoke(crate::ty::generic_defaults_query)] 110 #[salsa::invoke(crate::ty::generic_defaults_query)]
114 fn generic_defaults(&self, def: GenericDef) -> Substs; 111 fn generic_defaults(&self, def: GenericDef) -> Substs;
115 112
116 #[salsa::invoke(crate::expr::body_with_source_map_query)]
117 fn body_with_source_map(&self, def: DefWithBody) -> (Arc<Body>, Arc<BodySourceMap>);
118
119 #[salsa::invoke(crate::expr::body_query)]
120 fn body(&self, def: DefWithBody) -> Arc<Body>;
121
122 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] 113 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
123 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; 114 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;
124 115
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 82955fa55..9262325f2 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -1,74 +1,233 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3pub(crate) mod scope;
4pub(crate) mod validation; 3pub(crate) mod validation;
5 4
6use std::sync::Arc; 5use std::sync::Arc;
7 6
8use ra_syntax::{ast, AstPtr}; 7use ra_syntax::AstPtr;
9 8
10use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver}; 9use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver};
11
12pub use self::scope::ExprScopes;
13 10
14pub use hir_def::{ 11pub use hir_def::{
15 body::{Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource}, 12 body::{
13 scope::{ExprScopes, ScopeEntry, ScopeId},
14 Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource,
15 },
16 expr::{ 16 expr::{
17 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, 17 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
18 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, 18 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp,
19 }, 19 },
20}; 20};
21 21
22pub(crate) fn body_with_source_map_query(
23 db: &impl HirDatabase,
24 def: DefWithBody,
25) -> (Arc<Body>, Arc<BodySourceMap>) {
26 let mut params = None;
27
28 let (file_id, body) = match def {
29 DefWithBody::Function(f) => {
30 let src = f.source(db);
31 params = src.ast.param_list();
32 (src.file_id, src.ast.body().map(ast::Expr::from))
33 }
34 DefWithBody::Const(c) => {
35 let src = c.source(db);
36 (src.file_id, src.ast.body())
37 }
38 DefWithBody::Static(s) => {
39 let src = s.source(db);
40 (src.file_id, src.ast.body())
41 }
42 };
43 let resolver = hir_def::body::MacroResolver::new(db, def.module(db).id);
44 let (body, source_map) = Body::new(db, resolver, file_id, params, body);
45 (Arc::new(body), Arc::new(source_map))
46}
47
48pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
49 db.body_with_source_map(def).0
50}
51
52// needs arbitrary_self_types to be a method... or maybe move to the def? 22// needs arbitrary_self_types to be a method... or maybe move to the def?
53pub(crate) fn resolver_for_expr( 23pub(crate) fn resolver_for_expr(
54 db: &impl HirDatabase, 24 db: &impl HirDatabase,
55 owner: DefWithBody, 25 owner: DefWithBody,
56 expr_id: ExprId, 26 expr_id: ExprId,
57) -> Resolver { 27) -> Resolver {
58 let scopes = db.expr_scopes(owner); 28 let scopes = owner.expr_scopes(db);
59 resolver_for_scope(db, owner, scopes.scope_for(expr_id)) 29 resolver_for_scope(db, owner, scopes.scope_for(expr_id))
60} 30}
61 31
62pub(crate) fn resolver_for_scope( 32pub(crate) fn resolver_for_scope(
63 db: &impl HirDatabase, 33 db: &impl HirDatabase,
64 owner: DefWithBody, 34 owner: DefWithBody,
65 scope_id: Option<scope::ScopeId>, 35 scope_id: Option<ScopeId>,
66) -> Resolver { 36) -> Resolver {
67 let mut r = owner.resolver(db); 37 let mut r = owner.resolver(db);
68 let scopes = db.expr_scopes(owner); 38 let scopes = owner.expr_scopes(db);
69 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); 39 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
70 for scope in scope_chain.into_iter().rev() { 40 for scope in scope_chain.into_iter().rev() {
71 r = r.push_expr_scope(Arc::clone(&scopes), scope); 41 r = r.push_expr_scope(Arc::clone(&scopes), scope);
72 } 42 }
73 r 43 r
74} 44}
45
46#[cfg(test)]
47mod tests {
48 use hir_expand::Source;
49 use ra_db::{fixture::WithFixture, SourceDatabase};
50 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
51 use test_utils::{assert_eq_text, extract_offset};
52
53 use crate::{source_binder::SourceAnalyzer, test_db::TestDB};
54
55 fn do_check(code: &str, expected: &[&str]) {
56 let (off, code) = extract_offset(code);
57 let code = {
58 let mut buf = String::new();
59 let off = u32::from(off) as usize;
60 buf.push_str(&code[..off]);
61 buf.push_str("marker");
62 buf.push_str(&code[off..]);
63 buf
64 };
65
66 let (db, file_id) = TestDB::with_single_file(&code);
67
68 let file = db.parse(file_id).ok().unwrap();
69 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
70 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None);
71
72 let scopes = analyzer.scopes();
73 let expr_id = analyzer
74 .body_source_map()
75 .node_expr(Source { file_id: file_id.into(), ast: &marker.into() })
76 .unwrap();
77 let scope = scopes.scope_for(expr_id);
78
79 let actual = scopes
80 .scope_chain(scope)
81 .flat_map(|scope| scopes.entries(scope))
82 .map(|it| it.name().to_string())
83 .collect::<Vec<_>>()
84 .join("\n");
85 let expected = expected.join("\n");
86 assert_eq_text!(&expected, &actual);
87 }
88
89 #[test]
90 fn test_lambda_scope() {
91 do_check(
92 r"
93 fn quux(foo: i32) {
94 let f = |bar, baz: i32| {
95 <|>
96 };
97 }",
98 &["bar", "baz", "foo"],
99 );
100 }
101
102 #[test]
103 fn test_call_scope() {
104 do_check(
105 r"
106 fn quux() {
107 f(|x| <|> );
108 }",
109 &["x"],
110 );
111 }
112
113 #[test]
114 fn test_method_call_scope() {
115 do_check(
116 r"
117 fn quux() {
118 z.f(|x| <|> );
119 }",
120 &["x"],
121 );
122 }
123
124 #[test]
125 fn test_loop_scope() {
126 do_check(
127 r"
128 fn quux() {
129 loop {
130 let x = ();
131 <|>
132 };
133 }",
134 &["x"],
135 );
136 }
137
138 #[test]
139 fn test_match() {
140 do_check(
141 r"
142 fn quux() {
143 match () {
144 Some(x) => {
145 <|>
146 }
147 };
148 }",
149 &["x"],
150 );
151 }
152
153 #[test]
154 fn test_shadow_variable() {
155 do_check(
156 r"
157 fn foo(x: String) {
158 let x : &str = &x<|>;
159 }",
160 &["x"],
161 );
162 }
163
164 fn do_check_local_name(code: &str, expected_offset: u32) {
165 let (off, code) = extract_offset(code);
166
167 let (db, file_id) = TestDB::with_single_file(&code);
168 let file = db.parse(file_id).ok().unwrap();
169 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
170 .expect("failed to find a name at the target offset");
171 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
172 let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None);
173
174 let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap();
175 let local_name =
176 local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
177 assert_eq!(local_name.range(), expected_name.syntax().text_range());
178 }
179
180 #[test]
181 fn test_resolve_local_name() {
182 do_check_local_name(
183 r#"
184 fn foo(x: i32, y: u32) {
185 {
186 let z = x * 2;
187 }
188 {
189 let t = x<|> * 3;
190 }
191 }"#,
192 21,
193 );
194 }
195
196 #[test]
197 fn test_resolve_local_name_declaration() {
198 do_check_local_name(
199 r#"
200 fn foo(x: String) {
201 let x : &str = &x<|>;
202 }"#,
203 21,
204 );
205 }
206
207 #[test]
208 fn test_resolve_local_name_shadow() {
209 do_check_local_name(
210 r"
211 fn foo(x: String) {
212 let x : &str = &x;
213 x<|>
214 }
215 ",
216 53,
217 );
218 }
219
220 #[test]
221 fn ref_patterns_contribute_bindings() {
222 do_check_local_name(
223 r"
224 fn foo() {
225 if let Some(&from) = bar() {
226 from<|>;
227 }
228 }
229 ",
230 53,
231 );
232 }
233}
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
deleted file mode 100644
index 0e49a28d6..000000000
--- a/crates/ra_hir/src/expr/scope.rs
+++ /dev/null
@@ -1,354 +0,0 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use ra_arena::{impl_arena_id, Arena, RawId};
6use rustc_hash::FxHashMap;
7
8use crate::{
9 db::HirDatabase,
10 expr::{Body, Expr, ExprId, Pat, PatId, Statement},
11 DefWithBody, Name,
12};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct ScopeId(RawId);
16impl_arena_id!(ScopeId);
17
18#[derive(Debug, PartialEq, Eq)]
19pub struct ExprScopes {
20 pub(crate) body: Arc<Body>,
21 scopes: Arena<ScopeId, ScopeData>,
22 scope_by_expr: FxHashMap<ExprId, ScopeId>,
23}
24
25#[derive(Debug, PartialEq, Eq)]
26pub(crate) struct ScopeEntry {
27 name: Name,
28 pat: PatId,
29}
30
31impl ScopeEntry {
32 pub(crate) fn name(&self) -> &Name {
33 &self.name
34 }
35
36 pub(crate) fn pat(&self) -> PatId {
37 self.pat
38 }
39}
40
41#[derive(Debug, PartialEq, Eq)]
42pub(crate) struct ScopeData {
43 parent: Option<ScopeId>,
44 entries: Vec<ScopeEntry>,
45}
46
47impl ExprScopes {
48 pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> {
49 let body = db.body(def);
50 let res = ExprScopes::new(body);
51 Arc::new(res)
52 }
53
54 fn new(body: Arc<Body>) -> ExprScopes {
55 let mut scopes = ExprScopes {
56 body: body.clone(),
57 scopes: Arena::default(),
58 scope_by_expr: FxHashMap::default(),
59 };
60 let root = scopes.root_scope();
61 scopes.add_params_bindings(root, body.params());
62 compute_expr_scopes(body.body_expr(), &body, &mut scopes, root);
63 scopes
64 }
65
66 pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
67 &self.scopes[scope].entries
68 }
69
70 pub(crate) fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
71 std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
72 }
73
74 pub(crate) fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
75 self.scope_by_expr.get(&expr).copied()
76 }
77
78 pub(crate) fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> {
79 &self.scope_by_expr
80 }
81
82 fn root_scope(&mut self) -> ScopeId {
83 self.scopes.alloc(ScopeData { parent: None, entries: vec![] })
84 }
85
86 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
87 self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] })
88 }
89
90 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
91 match &body[pat] {
92 Pat::Bind { name, .. } => {
93 // bind can have a sub pattern, but it's actually not allowed
94 // to bind to things in there
95 let entry = ScopeEntry { name: name.clone(), pat };
96 self.scopes[scope].entries.push(entry)
97 }
98 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
99 }
100 }
101
102 fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) {
103 let body = Arc::clone(&self.body);
104 params.iter().for_each(|pat| self.add_bindings(&body, scope, *pat));
105 }
106
107 fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
108 self.scope_by_expr.insert(node, scope);
109 }
110}
111
112fn compute_block_scopes(
113 statements: &[Statement],
114 tail: Option<ExprId>,
115 body: &Body,
116 scopes: &mut ExprScopes,
117 mut scope: ScopeId,
118) {
119 for stmt in statements {
120 match stmt {
121 Statement::Let { pat, initializer, .. } => {
122 if let Some(expr) = initializer {
123 scopes.set_scope(*expr, scope);
124 compute_expr_scopes(*expr, body, scopes, scope);
125 }
126 scope = scopes.new_scope(scope);
127 scopes.add_bindings(body, scope, *pat);
128 }
129 Statement::Expr(expr) => {
130 scopes.set_scope(*expr, scope);
131 compute_expr_scopes(*expr, body, scopes, scope);
132 }
133 }
134 }
135 if let Some(expr) = tail {
136 compute_expr_scopes(expr, body, scopes, scope);
137 }
138}
139
140fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) {
141 scopes.set_scope(expr, scope);
142 match &body[expr] {
143 Expr::Block { statements, tail } => {
144 compute_block_scopes(&statements, *tail, body, scopes, scope);
145 }
146 Expr::For { iterable, pat, body: body_expr } => {
147 compute_expr_scopes(*iterable, body, scopes, scope);
148 let scope = scopes.new_scope(scope);
149 scopes.add_bindings(body, scope, *pat);
150 compute_expr_scopes(*body_expr, body, scopes, scope);
151 }
152 Expr::Lambda { args, body: body_expr, .. } => {
153 let scope = scopes.new_scope(scope);
154 scopes.add_params_bindings(scope, &args);
155 compute_expr_scopes(*body_expr, body, scopes, scope);
156 }
157 Expr::Match { expr, arms } => {
158 compute_expr_scopes(*expr, body, scopes, scope);
159 for arm in arms {
160 let scope = scopes.new_scope(scope);
161 for pat in &arm.pats {
162 scopes.add_bindings(body, scope, *pat);
163 }
164 scopes.set_scope(arm.expr, scope);
165 compute_expr_scopes(arm.expr, body, scopes, scope);
166 }
167 }
168 e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
169 };
170}
171
172#[cfg(test)]
173mod tests {
174 use ra_db::{fixture::WithFixture, SourceDatabase};
175 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
176 use test_utils::{assert_eq_text, extract_offset};
177
178 use crate::{source_binder::SourceAnalyzer, test_db::TestDB};
179
180 fn do_check(code: &str, expected: &[&str]) {
181 let (off, code) = extract_offset(code);
182 let code = {
183 let mut buf = String::new();
184 let off = u32::from(off) as usize;
185 buf.push_str(&code[..off]);
186 buf.push_str("marker");
187 buf.push_str(&code[off..]);
188 buf
189 };
190
191 let (db, file_id) = TestDB::with_single_file(&code);
192 let file = db.parse(file_id).ok().unwrap();
193 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
194 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None);
195
196 let scopes = analyzer.scopes();
197 let expr_id = analyzer.body_source_map().node_expr(&marker.into()).unwrap();
198 let scope = scopes.scope_for(expr_id);
199
200 let actual = scopes
201 .scope_chain(scope)
202 .flat_map(|scope| scopes.entries(scope))
203 .map(|it| it.name().to_string())
204 .collect::<Vec<_>>()
205 .join("\n");
206 let expected = expected.join("\n");
207 assert_eq_text!(&expected, &actual);
208 }
209
210 #[test]
211 fn test_lambda_scope() {
212 do_check(
213 r"
214 fn quux(foo: i32) {
215 let f = |bar, baz: i32| {
216 <|>
217 };
218 }",
219 &["bar", "baz", "foo"],
220 );
221 }
222
223 #[test]
224 fn test_call_scope() {
225 do_check(
226 r"
227 fn quux() {
228 f(|x| <|> );
229 }",
230 &["x"],
231 );
232 }
233
234 #[test]
235 fn test_method_call_scope() {
236 do_check(
237 r"
238 fn quux() {
239 z.f(|x| <|> );
240 }",
241 &["x"],
242 );
243 }
244
245 #[test]
246 fn test_loop_scope() {
247 do_check(
248 r"
249 fn quux() {
250 loop {
251 let x = ();
252 <|>
253 };
254 }",
255 &["x"],
256 );
257 }
258
259 #[test]
260 fn test_match() {
261 do_check(
262 r"
263 fn quux() {
264 match () {
265 Some(x) => {
266 <|>
267 }
268 };
269 }",
270 &["x"],
271 );
272 }
273
274 #[test]
275 fn test_shadow_variable() {
276 do_check(
277 r"
278 fn foo(x: String) {
279 let x : &str = &x<|>;
280 }",
281 &["x"],
282 );
283 }
284
285 fn do_check_local_name(code: &str, expected_offset: u32) {
286 let (off, code) = extract_offset(code);
287
288 let (db, file_id) = TestDB::with_single_file(&code);
289 let file = db.parse(file_id).ok().unwrap();
290 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
291 .expect("failed to find a name at the target offset");
292 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
293 let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None);
294
295 let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap();
296 let local_name =
297 local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
298 assert_eq!(local_name.range(), expected_name.syntax().text_range());
299 }
300
301 #[test]
302 fn test_resolve_local_name() {
303 do_check_local_name(
304 r#"
305 fn foo(x: i32, y: u32) {
306 {
307 let z = x * 2;
308 }
309 {
310 let t = x<|> * 3;
311 }
312 }"#,
313 21,
314 );
315 }
316
317 #[test]
318 fn test_resolve_local_name_declaration() {
319 do_check_local_name(
320 r#"
321 fn foo(x: String) {
322 let x : &str = &x<|>;
323 }"#,
324 21,
325 );
326 }
327
328 #[test]
329 fn test_resolve_local_name_shadow() {
330 do_check_local_name(
331 r"
332 fn foo(x: String) {
333 let x : &str = &x;
334 x<|>
335 }
336 ",
337 53,
338 );
339 }
340
341 #[test]
342 fn ref_patterns_contribute_bindings() {
343 do_check_local_name(
344 r"
345 fn foo() {
346 if let Some(&from) = bar() {
347 from<|>;
348 }
349 }
350 ",
351 53,
352 );
353 }
354}
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
index 089dbc908..9633ef586 100644
--- a/crates/ra_hir/src/from_id.rs
+++ b/crates/ra_hir/src/from_id.rs
@@ -3,9 +3,9 @@
3//! It's unclear if we need this long-term, but it's definitelly useful while we 3//! It's unclear if we need this long-term, but it's definitelly useful while we
4//! are splitting the hir. 4//! are splitting the hir.
5 5
6use hir_def::{AdtId, EnumVariantId, ModuleDefId}; 6use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId};
7 7
8use crate::{Adt, EnumVariant, ModuleDef}; 8use crate::{Adt, DefWithBody, EnumVariant, ModuleDef};
9 9
10macro_rules! from_id { 10macro_rules! from_id {
11 ($(($id:path, $ty:path)),*) => {$( 11 ($(($id:path, $ty:path)),*) => {$(
@@ -61,3 +61,13 @@ impl From<ModuleDefId> for ModuleDef {
61 } 61 }
62 } 62 }
63} 63}
64
65impl From<DefWithBody> for DefWithBodyId {
66 fn from(def: DefWithBody) -> Self {
67 match def {
68 DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
69 DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
70 DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
71 }
72 }
73}
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 2c441b0f4..9793af858 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -10,7 +10,7 @@ use ra_syntax::{
10use crate::{ 10use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 ids::{AstItemDef, LocationCtx}, 12 ids::{AstItemDef, LocationCtx},
13 AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, 13 AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource,
14 ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, 14 ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias,
15 Union, VariantDef, 15 Union, VariantDef,
16}; 16};
@@ -144,8 +144,9 @@ impl Local {
144 }; 144 };
145 Some(res) 145 Some(res)
146 })?; 146 })?;
147 let (_body, source_map) = db.body_with_source_map(parent); 147 let source_map = parent.body_source_map(db);
148 let pat_id = source_map.node_pat(&src.ast.into())?; 148 let src = src.map(ast::Pat::from);
149 let pat_id = source_map.node_pat(src.as_ref())?;
149 Some(Local { parent, pat_id }) 150 Some(Local { parent, pat_id })
150 } 151 }
151} 152}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 92d71b9e8..5ba847d35 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -77,9 +77,7 @@ pub use crate::{
77 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 77 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
78 ty::{ 78 ty::{
79 display::HirDisplay, 79 display::HirDisplay,
80 primitive::{ 80 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
81 FloatBitness, FloatTy, IntBitness, IntTy, Signedness, UncertainFloatTy, UncertainIntTy,
82 },
83 ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 81 ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
84 }, 82 },
85}; 83};
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index b932b0c8c..2f3e12eb8 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -13,10 +13,7 @@ use rustc_hash::FxHashSet;
13use crate::{ 13use crate::{
14 code_model::Crate, 14 code_model::Crate,
15 db::{DefDatabase, HirDatabase}, 15 db::{DefDatabase, HirDatabase},
16 expr::{ 16 expr::{ExprScopes, PatId, ScopeId},
17 scope::{ExprScopes, ScopeId},
18 PatId,
19 },
20 generics::GenericParams, 17 generics::GenericParams,
21 impl_block::ImplBlock, 18 impl_block::ImplBlock,
22 Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, 19 Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait,
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index f28e9c931..ca40e3b54 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,8 +7,11 @@
7//! purely for "IDE needs". 7//! purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use hir_def::path::known; 10use hir_def::{
11use hir_expand::name::AsName; 11 expr::{ExprId, PatId},
12 path::known,
13};
14use hir_expand::{name::AsName, Source};
12use ra_db::FileId; 15use ra_db::FileId;
13use ra_syntax::{ 16use ra_syntax::{
14 ast::{self, AstNode}, 17 ast::{self, AstNode},
@@ -20,11 +23,7 @@ use rustc_hash::FxHashSet;
20 23
21use crate::{ 24use crate::{
22 db::HirDatabase, 25 db::HirDatabase,
23 expr::{ 26 expr::{self, BodySourceMap, ExprScopes, ScopeId},
24 self,
25 scope::{ExprScopes, ScopeId},
26 BodySourceMap,
27 },
28 ids::LocationCtx, 27 ids::LocationCtx,
29 resolve::{ScopeDef, TypeNs, ValueNs}, 28 resolve::{ScopeDef, TypeNs, ValueNs},
30 ty::method_resolution::{self, implements_trait}, 29 ty::method_resolution::{self, implements_trait},
@@ -93,6 +92,8 @@ fn def_with_body_from_child_node(
93/// original source files. It should not be used inside the HIR itself. 92/// original source files. It should not be used inside the HIR itself.
94#[derive(Debug)] 93#[derive(Debug)]
95pub struct SourceAnalyzer { 94pub struct SourceAnalyzer {
95 // FIXME: this doesn't handle macros at all
96 file_id: FileId,
96 resolver: Resolver, 97 resolver: Resolver,
97 body_owner: Option<DefWithBody>, 98 body_owner: Option<DefWithBody>,
98 body_source_map: Option<Arc<BodySourceMap>>, 99 body_source_map: Option<Arc<BodySourceMap>>,
@@ -145,9 +146,9 @@ impl SourceAnalyzer {
145 let def_with_body = def_with_body_from_child_node(db, file_id, node); 146 let def_with_body = def_with_body_from_child_node(db, file_id, node);
146 if let Some(def) = def_with_body { 147 if let Some(def) = def_with_body {
147 let source_map = def.body_source_map(db); 148 let source_map = def.body_source_map(db);
148 let scopes = db.expr_scopes(def); 149 let scopes = def.expr_scopes(db);
149 let scope = match offset { 150 let scope = match offset {
150 None => scope_for(&scopes, &source_map, &node), 151 None => scope_for(&scopes, &source_map, file_id.into(), &node),
151 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), 152 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset),
152 }; 153 };
153 let resolver = expr::resolver_for_scope(db, def, scope); 154 let resolver = expr::resolver_for_scope(db, def, scope);
@@ -157,6 +158,7 @@ impl SourceAnalyzer {
157 body_source_map: Some(source_map), 158 body_source_map: Some(source_map),
158 infer: Some(def.infer(db)), 159 infer: Some(def.infer(db)),
159 scopes: Some(scopes), 160 scopes: Some(scopes),
161 file_id,
160 } 162 }
161 } else { 163 } else {
162 SourceAnalyzer { 164 SourceAnalyzer {
@@ -168,17 +170,28 @@ impl SourceAnalyzer {
168 body_source_map: None, 170 body_source_map: None,
169 infer: None, 171 infer: None,
170 scopes: None, 172 scopes: None,
173 file_id,
171 } 174 }
172 } 175 }
173 } 176 }
174 177
178 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
179 let src = Source { file_id: self.file_id.into(), ast: expr };
180 self.body_source_map.as_ref()?.node_expr(src)
181 }
182
183 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
184 let src = Source { file_id: self.file_id.into(), ast: pat };
185 self.body_source_map.as_ref()?.node_pat(src)
186 }
187
175 pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { 188 pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> {
176 let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; 189 let expr_id = self.expr_id(expr)?;
177 Some(self.infer.as_ref()?[expr_id].clone()) 190 Some(self.infer.as_ref()?[expr_id].clone())
178 } 191 }
179 192
180 pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { 193 pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> {
181 let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; 194 let pat_id = self.pat_id(pat)?;
182 Some(self.infer.as_ref()?[pat_id].clone()) 195 Some(self.infer.as_ref()?[pat_id].clone())
183 } 196 }
184 197
@@ -191,22 +204,22 @@ impl SourceAnalyzer {
191 } 204 }
192 205
193 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 206 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
194 let expr_id = self.body_source_map.as_ref()?.node_expr(&call.clone().into())?; 207 let expr_id = self.expr_id(&call.clone().into())?;
195 self.infer.as_ref()?.method_resolution(expr_id) 208 self.infer.as_ref()?.method_resolution(expr_id)
196 } 209 }
197 210
198 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { 211 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> {
199 let expr_id = self.body_source_map.as_ref()?.node_expr(&field.clone().into())?; 212 let expr_id = self.expr_id(&field.clone().into())?;
200 self.infer.as_ref()?.field_resolution(expr_id) 213 self.infer.as_ref()?.field_resolution(expr_id)
201 } 214 }
202 215
203 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { 216 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> {
204 let expr_id = self.body_source_map.as_ref()?.node_expr(&record_lit.clone().into())?; 217 let expr_id = self.expr_id(&record_lit.clone().into())?;
205 self.infer.as_ref()?.variant_resolution_for_expr(expr_id) 218 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
206 } 219 }
207 220
208 pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { 221 pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> {
209 let pat_id = self.body_source_map.as_ref()?.node_pat(&record_pat.clone().into())?; 222 let pat_id = self.pat_id(&record_pat.clone().into())?;
210 self.infer.as_ref()?.variant_resolution_for_pat(pat_id) 223 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
211 } 224 }
212 225
@@ -264,13 +277,13 @@ impl SourceAnalyzer {
264 277
265 pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { 278 pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
266 if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { 279 if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) {
267 let expr_id = self.body_source_map.as_ref()?.node_expr(&path_expr.into())?; 280 let expr_id = self.expr_id(&path_expr.into())?;
268 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { 281 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
269 return Some(PathResolution::AssocItem(assoc)); 282 return Some(PathResolution::AssocItem(assoc));
270 } 283 }
271 } 284 }
272 if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { 285 if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
273 let pat_id = self.body_source_map.as_ref()?.node_pat(&path_pat.into())?; 286 let pat_id = self.pat_id(&path_pat.into())?;
274 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { 287 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
275 return Some(PathResolution::AssocItem(assoc)); 288 return Some(PathResolution::AssocItem(assoc));
276 } 289 }
@@ -285,7 +298,7 @@ impl SourceAnalyzer {
285 let name = name_ref.as_name(); 298 let name = name_ref.as_name();
286 let source_map = self.body_source_map.as_ref()?; 299 let source_map = self.body_source_map.as_ref()?;
287 let scopes = self.scopes.as_ref()?; 300 let scopes = self.scopes.as_ref()?;
288 let scope = scope_for(scopes, source_map, name_ref.syntax()); 301 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax());
289 let ret = scopes 302 let ret = scopes
290 .scope_chain(scope) 303 .scope_chain(scope)
291 .flat_map(|scope| scopes.entries(scope).iter()) 304 .flat_map(|scope| scopes.entries(scope).iter())
@@ -418,11 +431,12 @@ impl SourceAnalyzer {
418fn scope_for( 431fn scope_for(
419 scopes: &ExprScopes, 432 scopes: &ExprScopes,
420 source_map: &BodySourceMap, 433 source_map: &BodySourceMap,
434 file_id: HirFileId,
421 node: &SyntaxNode, 435 node: &SyntaxNode,
422) -> Option<ScopeId> { 436) -> Option<ScopeId> {
423 node.ancestors() 437 node.ancestors()
424 .filter_map(ast::Expr::cast) 438 .filter_map(ast::Expr::cast)
425 .filter_map(|it| source_map.node_expr(&it)) 439 .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it }))
426 .find_map(|it| scopes.scope_for(it)) 440 .find_map(|it| scopes.scope_for(it))
427} 441}
428 442
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 6f24cfad6..ff6030ac4 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -21,7 +21,7 @@ use crate::{
21 expr::ExprId, 21 expr::ExprId,
22 generics::{GenericParams, HasGenericParams}, 22 generics::{GenericParams, HasGenericParams},
23 util::make_mut_slice, 23 util::make_mut_slice,
24 Adt, Crate, DefWithBody, Mutability, Name, Trait, TypeAlias, 24 Adt, Crate, DefWithBody, FloatTy, IntTy, Mutability, Name, Trait, TypeAlias, Uncertain,
25}; 25};
26use display::{HirDisplay, HirFormatter}; 26use display::{HirDisplay, HirFormatter};
27 27
@@ -47,10 +47,10 @@ pub enum TypeCtor {
47 Char, 47 Char,
48 48
49 /// A primitive integer type. For example, `i32`. 49 /// A primitive integer type. For example, `i32`.
50 Int(primitive::UncertainIntTy), 50 Int(Uncertain<IntTy>),
51 51
52 /// A primitive floating-point type. For example, `f64`. 52 /// A primitive floating-point type. For example, `f64`.
53 Float(primitive::UncertainFloatTy), 53 Float(Uncertain<FloatTy>),
54 54
55 /// Structures, enumerations and unions. 55 /// Structures, enumerations and unions.
56 Adt(Adt), 56 Adt(Adt),
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index f17c6c614..c35378cc4 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -31,10 +31,10 @@ use ra_prof::profile;
31use test_utils::tested_by; 31use test_utils::tested_by;
32 32
33use super::{ 33use super::{
34 lower, primitive, 34 lower,
35 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 35 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
36 ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, 36 ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef,
37 TypeCtor, TypeWalk, 37 TypeCtor, TypeWalk, Uncertain,
38}; 38};
39use crate::{ 39use crate::{
40 adt::VariantDef, 40 adt::VariantDef,
@@ -43,7 +43,8 @@ use crate::{
43 expr::{BindingAnnotation, Body, ExprId, PatId}, 43 expr::{BindingAnnotation, Body, ExprId, PatId},
44 resolve::{Resolver, TypeNs}, 44 resolve::{Resolver, TypeNs},
45 ty::infer::diagnostics::InferenceDiagnostic, 45 ty::infer::diagnostics::InferenceDiagnostic,
46 Adt, AssocItem, ConstData, DefWithBody, FnData, Function, Path, StructField, 46 Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, HasBody, IntTy, Path,
47 StructField,
47}; 48};
48 49
49macro_rules! ty_app { 50macro_rules! ty_app {
@@ -214,7 +215,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
214 coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), 215 coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver),
215 db, 216 db,
216 owner, 217 owner,
217 body: db.body(owner), 218 body: owner.body(db),
218 resolver, 219 resolver,
219 } 220 }
220 } 221 }
@@ -358,14 +359,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
358 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 359 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
359 match ty { 360 match ty {
360 Ty::Unknown => self.new_type_var(), 361 Ty::Unknown => self.new_type_var(),
361 Ty::Apply(ApplicationTy { 362 Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => {
362 ctor: TypeCtor::Int(primitive::UncertainIntTy::Unknown), 363 self.new_integer_var()
363 .. 364 }
364 }) => self.new_integer_var(), 365 Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => {
365 Ty::Apply(ApplicationTy { 366 self.new_float_var()
366 ctor: TypeCtor::Float(primitive::UncertainFloatTy::Unknown), 367 }
367 ..
368 }) => self.new_float_var(),
369 _ => ty, 368 _ => ty,
370 } 369 }
371 } 370 }
@@ -684,12 +683,8 @@ impl InferTy {
684 fn fallback_value(self) -> Ty { 683 fn fallback_value(self) -> Ty {
685 match self { 684 match self {
686 InferTy::TypeVar(..) => Ty::Unknown, 685 InferTy::TypeVar(..) => Ty::Unknown,
687 InferTy::IntVar(..) => { 686 InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::i32()))),
688 Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known(primitive::IntTy::i32()))) 687 InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(Uncertain::Known(FloatTy::f64()))),
689 }
690 InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(
691 primitive::UncertainFloatTy::Known(primitive::FloatTy::f64()),
692 )),
693 InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), 688 InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never),
694 } 689 }
695 } 690 }
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs
index c6802487a..5e68a1678 100644
--- a/crates/ra_hir/src/ty/infer/expr.rs
+++ b/crates/ra_hir/src/ty/infer/expr.rs
@@ -3,7 +3,10 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use hir_def::path::{GenericArg, GenericArgs}; 6use hir_def::{
7 builtin_type::Signedness,
8 path::{GenericArg, GenericArgs},
9};
7use hir_expand::name; 10use hir_expand::name;
8 11
9use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 12use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
@@ -12,8 +15,9 @@ use crate::{
12 expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 15 expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
13 generics::{GenericParams, HasGenericParams}, 16 generics::{GenericParams, HasGenericParams},
14 ty::{ 17 ty::{
15 autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Namespace, 18 autoderef, method_resolution, op, CallableDef, InferTy, IntTy, Mutability, Namespace,
16 Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 19 Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
20 Uncertain,
17 }, 21 },
18 Adt, Name, 22 Adt, Name,
19}; 23};
@@ -337,13 +341,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
337 UnaryOp::Neg => { 341 UnaryOp::Neg => {
338 match &inner_ty { 342 match &inner_ty {
339 Ty::Apply(a_ty) => match a_ty.ctor { 343 Ty::Apply(a_ty) => match a_ty.ctor {
340 TypeCtor::Int(primitive::UncertainIntTy::Unknown) 344 TypeCtor::Int(Uncertain::Unknown)
341 | TypeCtor::Int(primitive::UncertainIntTy::Known( 345 | TypeCtor::Int(Uncertain::Known(IntTy {
342 primitive::IntTy { 346 signedness: Signedness::Signed,
343 signedness: primitive::Signedness::Signed, 347 ..
344 .. 348 }))
345 },
346 ))
347 | TypeCtor::Float(..) => inner_ty, 349 | TypeCtor::Float(..) => inner_ty,
348 _ => Ty::Unknown, 350 _ => Ty::Unknown,
349 }, 351 },
@@ -428,9 +430,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
428 ); 430 );
429 self.infer_expr( 431 self.infer_expr(
430 *repeat, 432 *repeat,
431 &Expectation::has_type(Ty::simple(TypeCtor::Int( 433 &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known(
432 primitive::UncertainIntTy::Known(primitive::IntTy::usize()), 434 IntTy::usize(),
433 ))), 435 )))),
434 ); 436 );
435 } 437 }
436 } 438 }
@@ -443,9 +445,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
443 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) 445 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str))
444 } 446 }
445 Literal::ByteString(..) => { 447 Literal::ByteString(..) => {
446 let byte_type = Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known( 448 let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8())));
447 primitive::IntTy::u8(),
448 )));
449 let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); 449 let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type);
450 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) 450 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type)
451 } 451 }
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 1832fcf50..de3c56097 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -25,7 +25,7 @@ use crate::{
25 generics::{GenericDef, WherePredicate}, 25 generics::{GenericDef, WherePredicate},
26 resolve::{Resolver, TypeNs}, 26 resolve::{Resolver, TypeNs},
27 ty::{ 27 ty::{
28 primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, 28 primitive::{FloatTy, IntTy, Uncertain},
29 Adt, 29 Adt,
30 }, 30 },
31 util::make_mut_slice, 31 util::make_mut_slice,
@@ -674,20 +674,20 @@ impl From<BuiltinFloat> for FloatTy {
674 } 674 }
675} 675}
676 676
677impl From<Option<BuiltinInt>> for UncertainIntTy { 677impl From<Option<BuiltinInt>> for Uncertain<IntTy> {
678 fn from(t: Option<BuiltinInt>) -> Self { 678 fn from(t: Option<BuiltinInt>) -> Self {
679 match t { 679 match t {
680 None => UncertainIntTy::Unknown, 680 None => Uncertain::Unknown,
681 Some(t) => UncertainIntTy::Known(t.into()), 681 Some(t) => Uncertain::Known(t.into()),
682 } 682 }
683 } 683 }
684} 684}
685 685
686impl From<Option<BuiltinFloat>> for UncertainFloatTy { 686impl From<Option<BuiltinFloat>> for Uncertain<FloatTy> {
687 fn from(t: Option<BuiltinFloat>) -> Self { 687 fn from(t: Option<BuiltinFloat>) -> Self {
688 match t { 688 match t {
689 None => UncertainFloatTy::Unknown, 689 None => Uncertain::Unknown,
690 Some(t) => UncertainFloatTy::Known(t.into()), 690 Some(t) => Uncertain::Known(t.into()),
691 } 691 }
692 } 692 }
693} 693}
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 8c3d32d09..eb5ca6769 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -8,16 +8,17 @@ use arrayvec::ArrayVec;
8use hir_def::CrateModuleId; 8use hir_def::CrateModuleId;
9use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
10 10
11use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
12use crate::{ 11use crate::{
13 db::HirDatabase, 12 db::HirDatabase,
14 impl_block::{ImplBlock, ImplId}, 13 impl_block::{ImplBlock, ImplId},
15 resolve::Resolver, 14 resolve::Resolver,
16 ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, 15 ty::primitive::{FloatBitness, Uncertain},
17 ty::{Ty, TypeCtor}, 16 ty::{Ty, TypeCtor},
18 AssocItem, Crate, Function, Module, Mutability, Name, Trait, 17 AssocItem, Crate, Function, Module, Mutability, Name, Trait,
19}; 18};
20 19
20use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
21
21/// This is used as a key for indexing impls. 22/// This is used as a key for indexing impls.
22#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 23#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
23pub enum TyFingerprint { 24pub enum TyFingerprint {
@@ -140,14 +141,12 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV
140 TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), 141 TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()),
141 TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), 142 TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"),
142 TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), 143 TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"),
143 TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness { 144 TypeCtor::Float(Uncertain::Known(f)) => match f.bitness {
144 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) 145 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
145 FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), 146 FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"),
146 FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), 147 FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"),
147 }, 148 },
148 TypeCtor::Int(UncertainIntTy::Known(i)) => { 149 TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(db, cur_crate, i.ty_to_string()),
149 lang_item_crate!(db, cur_crate, i.ty_to_string())
150 }
151 TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), 150 TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"),
152 TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), 151 TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"),
153 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), 152 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"),
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 7362de4c3..47789db87 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -4,44 +4,38 @@ use std::fmt;
4 4
5pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; 5pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness};
6 6
7#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 7#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
8pub enum UncertainIntTy { 8pub enum Uncertain<T> {
9 Unknown, 9 Unknown,
10 Known(IntTy), 10 Known(T),
11} 11}
12 12
13impl From<IntTy> for UncertainIntTy { 13impl From<IntTy> for Uncertain<IntTy> {
14 fn from(ty: IntTy) -> Self { 14 fn from(ty: IntTy) -> Self {
15 UncertainIntTy::Known(ty) 15 Uncertain::Known(ty)
16 } 16 }
17} 17}
18 18
19impl fmt::Display for UncertainIntTy { 19impl fmt::Display for Uncertain<IntTy> {
20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 20 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
21 match *self { 21 match *self {
22 UncertainIntTy::Unknown => write!(f, "{{integer}}"), 22 Uncertain::Unknown => write!(f, "{{integer}}"),
23 UncertainIntTy::Known(ty) => write!(f, "{}", ty), 23 Uncertain::Known(ty) => write!(f, "{}", ty),
24 } 24 }
25 } 25 }
26} 26}
27 27
28#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 28impl From<FloatTy> for Uncertain<FloatTy> {
29pub enum UncertainFloatTy {
30 Unknown,
31 Known(FloatTy),
32}
33
34impl From<FloatTy> for UncertainFloatTy {
35 fn from(ty: FloatTy) -> Self { 29 fn from(ty: FloatTy) -> Self {
36 UncertainFloatTy::Known(ty) 30 Uncertain::Known(ty)
37 } 31 }
38} 32}
39 33
40impl fmt::Display for UncertainFloatTy { 34impl fmt::Display for Uncertain<FloatTy> {
41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42 match *self { 36 match *self {
43 UncertainFloatTy::Unknown => write!(f, "{{float}}"), 37 Uncertain::Unknown => write!(f, "{{float}}"),
44 UncertainFloatTy::Known(ty) => write!(f, "{}", ty), 38 Uncertain::Known(ty) => write!(f, "{}", ty),
45 } 39 }
46 } 40 }
47} 41}
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index de322dd52..75351c17d 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -22,7 +22,7 @@ use crate::{
22 ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 22 ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
23 TypeWalk, 23 TypeWalk,
24 }, 24 },
25 AssocItem, Crate, ImplBlock, Trait, TypeAlias, 25 AssocItem, Crate, HasBody, ImplBlock, Trait, TypeAlias,
26}; 26};
27 27
28/// This represents a trait whose name we could not resolve. 28/// This represents a trait whose name we could not resolve.
@@ -714,7 +714,7 @@ fn closure_fn_trait_impl_datum(
714 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; 714 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
715 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait 715 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
716 716
717 let num_args: u16 = match &db.body(data.def)[data.expr] { 717 let num_args: u16 = match &data.def.body(db)[data.expr] {
718 crate::expr::Expr::Lambda { args, .. } => args.len() as u16, 718 crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
719 _ => { 719 _ => {
720 log::warn!("closure for closure type {:?} not found", data); 720 log::warn!("closure for closure type {:?} not found", data);