aboutsummaryrefslogtreecommitdiff
path: root/crates
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
parent0525778a3ad590492b51cc11085d815f9bb8f92b (diff)
parentbbb022d3999b3038549ec6c309efb065231c896a (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assists/early_return.rs128
-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
-rw-r--r--crates/ra_hir_def/src/body.rs136
-rw-r--r--crates/ra_hir_def/src/body/lower.rs90
-rw-r--r--crates/ra_hir_def/src/body/scope.rs165
-rw-r--r--crates/ra_hir_def/src/db.rs12
-rw-r--r--crates/ra_hir_def/src/lib.rs10
-rw-r--r--crates/ra_hir_expand/src/lib.rs5
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs34
-rw-r--r--crates/ra_parser/src/token_set.rs4
-rw-r--r--crates/ra_prof/Cargo.toml36
-rw-r--r--crates/ra_prof/src/lib.rs2
-rw-r--r--crates/ra_prof/src/memory_usage.rs4
-rw-r--r--crates/ra_syntax/src/ast/edit.rs2
-rw-r--r--crates/ra_syntax/src/ast/make.rs71
30 files changed, 835 insertions, 712 deletions
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
index 570a07a20..264412526 100644
--- a/crates/ra_assists/src/assists/early_return.rs
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -1,4 +1,4 @@
1use std::ops::RangeInclusive; 1use std::{iter::once, ops::RangeInclusive};
2 2
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4use ra_syntax::{ 4use ra_syntax::{
@@ -38,27 +38,30 @@ use crate::{
38// ``` 38// ```
39pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 39pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
40 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; 40 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
41 if if_expr.else_branch().is_some() {
42 return None;
43 }
44
41 let cond = if_expr.condition()?; 45 let cond = if_expr.condition()?;
42 let mut if_let_ident: Option<String> = None;
43 46
44 // Check if there is an IfLet that we can handle. 47 // Check if there is an IfLet that we can handle.
45 match cond.pat() { 48 let if_let_pat = match cond.pat() {
46 None => {} // No IfLet, supported. 49 None => None, // No IfLet, supported.
47 Some(TupleStructPat(ref pat)) if pat.args().count() == 1usize => match &pat.path() { 50 Some(TupleStructPat(pat)) if pat.args().count() == 1 => {
48 Some(p) => match p.qualifier() { 51 let path = pat.path()?;
49 None => if_let_ident = Some(p.syntax().text().to_string()), 52 match path.qualifier() {
50 _ => return None, 53 None => {
51 }, 54 let bound_ident = pat.args().next().unwrap();
52 _ => return None, 55 Some((path, bound_ident))
53 }, 56 }
54 _ => return None, // Unsupported IfLet. 57 Some(_) => return None,
58 }
59 }
60 Some(_) => return None, // Unsupported IfLet.
55 }; 61 };
56 62
57 let expr = cond.expr()?; 63 let cond_expr = cond.expr()?;
58 let then_block = if_expr.then_branch()?.block()?; 64 let then_block = if_expr.then_branch()?.block()?;
59 if if_expr.else_branch().is_some() {
60 return None;
61 }
62 65
63 let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; 66 let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?;
64 67
@@ -79,11 +82,11 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
79 82
80 let parent_container = parent_block.syntax().parent()?.parent()?; 83 let parent_container = parent_block.syntax().parent()?.parent()?;
81 84
82 let early_expression = match parent_container.kind() { 85 let early_expression: ast::Expr = match parent_container.kind() {
83 WHILE_EXPR | LOOP_EXPR => Some("continue"), 86 WHILE_EXPR | LOOP_EXPR => make::expr_continue().into(),
84 FN_DEF => Some("return"), 87 FN_DEF => make::expr_return().into(),
85 _ => None, 88 _ => return None,
86 }?; 89 };
87 90
88 if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() { 91 if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() {
89 return None; 92 return None;
@@ -94,22 +97,43 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
94 97
95 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { 98 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
96 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 99 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
97 let new_block = match if_let_ident { 100 let new_block = match if_let_pat {
98 None => { 101 None => {
99 // If. 102 // If.
100 let early_expression = &(early_expression.to_owned() + ";"); 103 let early_expression = &(early_expression.syntax().to_string() + ";");
101 let new_expr = 104 let new_expr = if_indent_level
102 if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); 105 .increase_indent(make::if_expression(&cond_expr, early_expression));
103 replace(new_expr, &then_block, &parent_block, &if_expr) 106 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
104 } 107 }
105 Some(if_let_ident) => { 108 Some((path, bound_ident)) => {
106 // If-let. 109 // If-let.
107 let new_expr = if_indent_level.increase_indent(make::let_match_early( 110 let match_expr = {
108 expr, 111 let happy_arm = make::match_arm(
109 &if_let_ident, 112 once(
110 early_expression, 113 make::tuple_struct_pat(
111 )); 114 path,
112 replace(new_expr, &then_block, &parent_block, &if_expr) 115 once(make::bind_pat(make::name("it")).into()),
116 )
117 .into(),
118 ),
119 make::expr_path(make::path_from_name_ref(make::name_ref("it"))).into(),
120 );
121
122 let sad_arm = make::match_arm(
123 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
124 once(make::placeholder_pat().into()),
125 early_expression.into(),
126 );
127
128 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
129 };
130
131 let let_stmt = make::let_stmt(
132 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
133 Some(match_expr.into()),
134 );
135 let let_stmt = if_indent_level.increase_indent(let_stmt);
136 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
113 } 137 }
114 }; 138 };
115 edit.target(if_expr.syntax().text_range()); 139 edit.target(if_expr.syntax().text_range());
@@ -117,7 +141,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
117 edit.set_cursor(cursor_position); 141 edit.set_cursor(cursor_position);
118 142
119 fn replace( 143 fn replace(
120 new_expr: impl AstNode, 144 new_expr: &SyntaxNode,
121 then_block: &Block, 145 then_block: &Block,
122 parent_block: &Block, 146 parent_block: &Block,
123 if_expr: &ast::IfExpr, 147 if_expr: &ast::IfExpr,
@@ -130,7 +154,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
130 } else { 154 } else {
131 end_of_then 155 end_of_then
132 }; 156 };
133 let mut then_statements = new_expr.syntax().children_with_tokens().chain( 157 let mut then_statements = new_expr.children_with_tokens().chain(
134 then_block_items 158 then_block_items
135 .syntax() 159 .syntax()
136 .children_with_tokens() 160 .children_with_tokens()
@@ -151,9 +175,10 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
151 175
152#[cfg(test)] 176#[cfg(test)]
153mod tests { 177mod tests {
154 use super::*;
155 use crate::helpers::{check_assist, check_assist_not_applicable}; 178 use crate::helpers::{check_assist, check_assist_not_applicable};
156 179
180 use super::*;
181
157 #[test] 182 #[test]
158 fn convert_inside_fn() { 183 fn convert_inside_fn() {
159 check_assist( 184 check_assist(
@@ -204,7 +229,7 @@ mod tests {
204 bar(); 229 bar();
205 le<|>t n = match n { 230 le<|>t n = match n {
206 Some(it) => it, 231 Some(it) => it,
207 None => return, 232 _ => return,
208 }; 233 };
209 foo(n); 234 foo(n);
210 235
@@ -216,6 +241,29 @@ mod tests {
216 } 241 }
217 242
218 #[test] 243 #[test]
244 fn convert_if_let_result() {
245 check_assist(
246 convert_to_guarded_return,
247 r#"
248 fn main() {
249 if<|> let Ok(x) = Err(92) {
250 foo(x);
251 }
252 }
253 "#,
254 r#"
255 fn main() {
256 le<|>t x = match Err(92) {
257 Ok(it) => it,
258 _ => return,
259 };
260 foo(x);
261 }
262 "#,
263 );
264 }
265
266 #[test]
219 fn convert_let_ok_inside_fn() { 267 fn convert_let_ok_inside_fn() {
220 check_assist( 268 check_assist(
221 convert_to_guarded_return, 269 convert_to_guarded_return,
@@ -235,7 +283,7 @@ mod tests {
235 bar(); 283 bar();
236 le<|>t n = match n { 284 le<|>t n = match n {
237 Ok(it) => it, 285 Ok(it) => it,
238 None => return, 286 _ => return,
239 }; 287 };
240 foo(n); 288 foo(n);
241 289
@@ -293,7 +341,7 @@ mod tests {
293 while true { 341 while true {
294 le<|>t n = match n { 342 le<|>t n = match n {
295 Some(it) => it, 343 Some(it) => it,
296 None => continue, 344 _ => continue,
297 }; 345 };
298 foo(n); 346 foo(n);
299 bar(); 347 bar();
@@ -350,7 +398,7 @@ mod tests {
350 loop { 398 loop {
351 le<|>t n = match n { 399 le<|>t n = match n {
352 Some(it) => it, 400 Some(it) => it,
353 None => continue, 401 _ => continue,
354 }; 402 };
355 foo(n); 403 foo(n);
356 bar(); 404 bar();
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);
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index ac8f8261b..85dc4feb0 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -1,11 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2mod lower; 2mod lower;
3pub mod scope;
3 4
4use std::{ops::Index, sync::Arc}; 5use std::{ops::Index, sync::Arc};
5 6
6use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; 7use hir_expand::{
8 either::Either, hygiene::Hygiene, AstId, HirFileId, MacroCallLoc, MacroDefId, MacroFileKind,
9 Source,
10};
7use ra_arena::{map::ArenaMap, Arena}; 11use ra_arena::{map::ArenaMap, Arena};
8use ra_syntax::{ast, AstPtr}; 12use ra_syntax::{ast, AstNode, AstPtr};
9use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
10 14
11use crate::{ 15use crate::{
@@ -13,28 +17,87 @@ use crate::{
13 expr::{Expr, ExprId, Pat, PatId}, 17 expr::{Expr, ExprId, Pat, PatId},
14 nameres::CrateDefMap, 18 nameres::CrateDefMap,
15 path::Path, 19 path::Path,
16 ModuleId, 20 AstItemDef, DefWithBodyId, ModuleId,
17}; 21};
18 22
19pub struct MacroResolver { 23pub struct Expander {
20 crate_def_map: Arc<CrateDefMap>, 24 crate_def_map: Arc<CrateDefMap>,
25 current_file_id: HirFileId,
26 hygiene: Hygiene,
21 module: ModuleId, 27 module: ModuleId,
22} 28}
23 29
24impl MacroResolver { 30impl Expander {
25 pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver { 31 pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander {
26 MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } 32 let crate_def_map = db.crate_def_map(module.krate);
33 let hygiene = Hygiene::new(db, current_file_id);
34 Expander { crate_def_map, current_file_id, hygiene, module }
27 } 35 }
28 36
29 pub(crate) fn resolve_path_as_macro( 37 fn enter_expand(
30 &self, 38 &mut self,
31 db: &impl DefDatabase2, 39 db: &impl DefDatabase2,
32 path: &Path, 40 macro_call: ast::MacroCall,
33 ) -> Option<MacroDefId> { 41 ) -> Option<(Mark, ast::Expr)> {
42 let ast_id = AstId::new(
43 self.current_file_id,
44 db.ast_id_map(self.current_file_id).ast_id(&macro_call),
45 );
46
47 if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) {
48 if let Some(def) = self.resolve_path_as_macro(db, &path) {
49 let call_id = db.intern_macro(MacroCallLoc { def, ast_id });
50 let file_id = call_id.as_file(MacroFileKind::Expr);
51 if let Some(node) = db.parse_or_expand(file_id) {
52 if let Some(expr) = ast::Expr::cast(node) {
53 log::debug!("macro expansion {:#?}", expr.syntax());
54
55 let mark = Mark { file_id: self.current_file_id };
56 self.hygiene = Hygiene::new(db, file_id);
57 self.current_file_id = file_id;
58
59 return Some((mark, expr));
60 }
61 }
62 }
63 }
64
65 // FIXME: Instead of just dropping the error from expansion
66 // report it
67 None
68 }
69
70 fn exit(&mut self, db: &impl DefDatabase2, mark: Mark) {
71 self.hygiene = Hygiene::new(db, mark.file_id);
72 self.current_file_id = mark.file_id;
73 std::mem::forget(mark);
74 }
75
76 fn to_source<T>(&self, ast: T) -> Source<T> {
77 Source { file_id: self.current_file_id, ast }
78 }
79
80 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
81 Path::from_src(path, &self.hygiene)
82 }
83
84 fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option<MacroDefId> {
34 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() 85 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros()
35 } 86 }
36} 87}
37 88
89struct Mark {
90 file_id: HirFileId,
91}
92
93impl Drop for Mark {
94 fn drop(&mut self) {
95 if !std::thread::panicking() {
96 panic!("dropped mark")
97 }
98 }
99}
100
38/// The body of an item (function, const etc.). 101/// The body of an item (function, const etc.).
39#[derive(Debug, Eq, PartialEq)] 102#[derive(Debug, Eq, PartialEq)]
40pub struct Body { 103pub struct Body {
@@ -70,22 +133,51 @@ pub type PatSource = Source<PatPtr>;
70/// this properly for macros. 133/// this properly for macros.
71#[derive(Default, Debug, Eq, PartialEq)] 134#[derive(Default, Debug, Eq, PartialEq)]
72pub struct BodySourceMap { 135pub struct BodySourceMap {
73 expr_map: FxHashMap<ExprPtr, ExprId>, 136 expr_map: FxHashMap<ExprSource, ExprId>,
74 expr_map_back: ArenaMap<ExprId, ExprSource>, 137 expr_map_back: ArenaMap<ExprId, ExprSource>,
75 pat_map: FxHashMap<PatPtr, PatId>, 138 pat_map: FxHashMap<PatSource, PatId>,
76 pat_map_back: ArenaMap<PatId, PatSource>, 139 pat_map_back: ArenaMap<PatId, PatSource>,
77 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 140 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
78} 141}
79 142
80impl Body { 143impl Body {
81 pub fn new( 144 pub(crate) fn body_with_source_map_query(
145 db: &impl DefDatabase2,
146 def: DefWithBodyId,
147 ) -> (Arc<Body>, Arc<BodySourceMap>) {
148 let mut params = None;
149
150 let (file_id, module, body) = match def {
151 DefWithBodyId::FunctionId(f) => {
152 let src = f.source(db);
153 params = src.ast.param_list();
154 (src.file_id, f.module(db), src.ast.body().map(ast::Expr::from))
155 }
156 DefWithBodyId::ConstId(c) => {
157 let src = c.source(db);
158 (src.file_id, c.module(db), src.ast.body())
159 }
160 DefWithBodyId::StaticId(s) => {
161 let src = s.source(db);
162 (src.file_id, s.module(db), src.ast.body())
163 }
164 };
165 let expander = Expander::new(db, file_id, module);
166 let (body, source_map) = Body::new(db, expander, params, body);
167 (Arc::new(body), Arc::new(source_map))
168 }
169
170 pub(crate) fn body_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc<Body> {
171 db.body_with_source_map(def).0
172 }
173
174 fn new(
82 db: &impl DefDatabase2, 175 db: &impl DefDatabase2,
83 resolver: MacroResolver, 176 expander: Expander,
84 file_id: HirFileId,
85 params: Option<ast::ParamList>, 177 params: Option<ast::ParamList>,
86 body: Option<ast::Expr>, 178 body: Option<ast::Expr>,
87 ) -> (Body, BodySourceMap) { 179 ) -> (Body, BodySourceMap) {
88 lower::lower(db, resolver, file_id, params, body) 180 lower::lower(db, expander, params, body)
89 } 181 }
90 182
91 pub fn params(&self) -> &[PatId] { 183 pub fn params(&self) -> &[PatId] {
@@ -126,16 +218,18 @@ impl BodySourceMap {
126 self.expr_map_back.get(expr).copied() 218 self.expr_map_back.get(expr).copied()
127 } 219 }
128 220
129 pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { 221 pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option<ExprId> {
130 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() 222 let src = node.map(|it| Either::A(AstPtr::new(it)));
223 self.expr_map.get(&src).cloned()
131 } 224 }
132 225
133 pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> { 226 pub fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
134 self.pat_map_back.get(pat).copied() 227 self.pat_map_back.get(pat).copied()
135 } 228 }
136 229
137 pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { 230 pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option<PatId> {
138 self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() 231 let src = node.map(|it| Either::A(AstPtr::new(it)));
232 self.pat_map.get(&src).cloned()
139 } 233 }
140 234
141 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { 235 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> {
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 2aa863c9e..a5bb60e85 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -2,9 +2,7 @@
2 2
3use hir_expand::{ 3use hir_expand::{
4 either::Either, 4 either::Either,
5 hygiene::Hygiene,
6 name::{self, AsName, Name}, 5 name::{self, AsName, Name},
7 AstId, HirFileId, MacroCallLoc, MacroFileKind, Source,
8}; 6};
9use ra_arena::Arena; 7use ra_arena::Arena;
10use ra_syntax::{ 8use ra_syntax::{
@@ -16,7 +14,7 @@ use ra_syntax::{
16}; 14};
17 15
18use crate::{ 16use crate::{
19 body::{Body, BodySourceMap, MacroResolver, PatPtr}, 17 body::{Body, BodySourceMap, Expander, PatPtr},
20 builtin_type::{BuiltinFloat, BuiltinInt}, 18 builtin_type::{BuiltinFloat, BuiltinInt},
21 db::DefDatabase2, 19 db::DefDatabase2,
22 expr::{ 20 expr::{
@@ -30,16 +28,13 @@ use crate::{
30 28
31pub(super) fn lower( 29pub(super) fn lower(
32 db: &impl DefDatabase2, 30 db: &impl DefDatabase2,
33 resolver: MacroResolver, 31 expander: Expander,
34 file_id: HirFileId,
35 params: Option<ast::ParamList>, 32 params: Option<ast::ParamList>,
36 body: Option<ast::Expr>, 33 body: Option<ast::Expr>,
37) -> (Body, BodySourceMap) { 34) -> (Body, BodySourceMap) {
38 ExprCollector { 35 ExprCollector {
39 resolver, 36 expander,
40 db, 37 db,
41 original_file_id: file_id,
42 current_file_id: file_id,
43 source_map: BodySourceMap::default(), 38 source_map: BodySourceMap::default(),
44 body: Body { 39 body: Body {
45 exprs: Arena::default(), 40 exprs: Arena::default(),
@@ -53,9 +48,7 @@ pub(super) fn lower(
53 48
54struct ExprCollector<DB> { 49struct ExprCollector<DB> {
55 db: DB, 50 db: DB,
56 resolver: MacroResolver, 51 expander: Expander,
57 original_file_id: HirFileId,
58 current_file_id: HirFileId,
59 52
60 body: Body, 53 body: Body,
61 source_map: BodySourceMap, 54 source_map: BodySourceMap,
@@ -101,12 +94,9 @@ where
101 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { 94 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
102 let ptr = Either::A(ptr); 95 let ptr = Either::A(ptr);
103 let id = self.body.exprs.alloc(expr); 96 let id = self.body.exprs.alloc(expr);
104 if self.current_file_id == self.original_file_id { 97 let src = self.expander.to_source(ptr);
105 self.source_map.expr_map.insert(ptr, id); 98 self.source_map.expr_map.insert(src, id);
106 } 99 self.source_map.expr_map_back.insert(id, src);
107 self.source_map
108 .expr_map_back
109 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
110 id 100 id
111 } 101 }
112 // desugared exprs don't have ptr, that's wrong and should be fixed 102 // desugared exprs don't have ptr, that's wrong and should be fixed
@@ -117,20 +107,16 @@ where
117 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { 107 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
118 let ptr = Either::B(ptr); 108 let ptr = Either::B(ptr);
119 let id = self.body.exprs.alloc(expr); 109 let id = self.body.exprs.alloc(expr);
120 if self.current_file_id == self.original_file_id { 110 let src = self.expander.to_source(ptr);
121 self.source_map.expr_map.insert(ptr, id); 111 self.source_map.expr_map.insert(src, id);
122 } 112 self.source_map.expr_map_back.insert(id, src);
123 self.source_map
124 .expr_map_back
125 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
126 id 113 id
127 } 114 }
128 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { 115 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
129 let id = self.body.pats.alloc(pat); 116 let id = self.body.pats.alloc(pat);
130 if self.current_file_id == self.original_file_id { 117 let src = self.expander.to_source(ptr);
131 self.source_map.pat_map.insert(ptr, id); 118 self.source_map.pat_map.insert(src, id);
132 } 119 self.source_map.pat_map_back.insert(id, src);
133 self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr });
134 id 120 id
135 } 121 }
136 122
@@ -272,7 +258,7 @@ where
272 ast::Expr::PathExpr(e) => { 258 ast::Expr::PathExpr(e) => {
273 let path = e 259 let path = e
274 .path() 260 .path()
275 .and_then(|path| self.parse_path(path)) 261 .and_then(|path| self.expander.parse_path(path))
276 .map(Expr::Path) 262 .map(Expr::Path)
277 .unwrap_or(Expr::Missing); 263 .unwrap_or(Expr::Missing);
278 self.alloc_expr(path, syntax_ptr) 264 self.alloc_expr(path, syntax_ptr)
@@ -288,7 +274,8 @@ where
288 ast::Expr::ParenExpr(e) => { 274 ast::Expr::ParenExpr(e) => {
289 let inner = self.collect_expr_opt(e.expr()); 275 let inner = self.collect_expr_opt(e.expr());
290 // make the paren expr point to the inner expression as well 276 // make the paren expr point to the inner expression as well
291 self.source_map.expr_map.insert(Either::A(syntax_ptr), inner); 277 let src = self.expander.to_source(Either::A(syntax_ptr));
278 self.source_map.expr_map.insert(src, inner);
292 inner 279 inner
293 } 280 }
294 ast::Expr::ReturnExpr(e) => { 281 ast::Expr::ReturnExpr(e) => {
@@ -296,7 +283,7 @@ where
296 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 283 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
297 } 284 }
298 ast::Expr::RecordLit(e) => { 285 ast::Expr::RecordLit(e) => {
299 let path = e.path().and_then(|path| self.parse_path(path)); 286 let path = e.path().and_then(|path| self.expander.parse_path(path));
300 let mut field_ptrs = Vec::new(); 287 let mut field_ptrs = Vec::new();
301 let record_lit = if let Some(nfl) = e.record_field_list() { 288 let record_lit = if let Some(nfl) = e.record_field_list() {
302 let fields = nfl 289 let fields = nfl
@@ -443,32 +430,14 @@ where
443 // FIXME implement HIR for these: 430 // FIXME implement HIR for these:
444 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 431 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
445 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 432 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
446 ast::Expr::MacroCall(e) => { 433 ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) {
447 let ast_id = AstId::new( 434 Some((mark, expansion)) => {
448 self.current_file_id, 435 let id = self.collect_expr(expansion);
449 self.db.ast_id_map(self.current_file_id).ast_id(&e), 436 self.expander.exit(self.db, mark);
450 ); 437 id
451
452 if let Some(path) = e.path().and_then(|path| self.parse_path(path)) {
453 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
454 let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id });
455 let file_id = call_id.as_file(MacroFileKind::Expr);
456 if let Some(node) = self.db.parse_or_expand(file_id) {
457 if let Some(expr) = ast::Expr::cast(node) {
458 log::debug!("macro expansion {:#?}", expr.syntax());
459 let old_file_id =
460 std::mem::replace(&mut self.current_file_id, file_id);
461 let id = self.collect_expr(expr);
462 self.current_file_id = old_file_id;
463 return id;
464 }
465 }
466 }
467 } 438 }
468 // FIXME: Instead of just dropping the error from expansion 439 None => self.alloc_expr(Expr::Missing, syntax_ptr),
469 // report it 440 },
470 self.alloc_expr(Expr::Missing, syntax_ptr)
471 }
472 } 441 }
473 } 442 }
474 443
@@ -519,7 +488,7 @@ where
519 Pat::Bind { name, mode: annotation, subpat } 488 Pat::Bind { name, mode: annotation, subpat }
520 } 489 }
521 ast::Pat::TupleStructPat(p) => { 490 ast::Pat::TupleStructPat(p) => {
522 let path = p.path().and_then(|path| self.parse_path(path)); 491 let path = p.path().and_then(|path| self.expander.parse_path(path));
523 let args = p.args().map(|p| self.collect_pat(p)).collect(); 492 let args = p.args().map(|p| self.collect_pat(p)).collect();
524 Pat::TupleStruct { path, args } 493 Pat::TupleStruct { path, args }
525 } 494 }
@@ -529,7 +498,7 @@ where
529 Pat::Ref { pat, mutability } 498 Pat::Ref { pat, mutability }
530 } 499 }
531 ast::Pat::PathPat(p) => { 500 ast::Pat::PathPat(p) => {
532 let path = p.path().and_then(|path| self.parse_path(path)); 501 let path = p.path().and_then(|path| self.expander.parse_path(path));
533 path.map(Pat::Path).unwrap_or(Pat::Missing) 502 path.map(Pat::Path).unwrap_or(Pat::Missing)
534 } 503 }
535 ast::Pat::TuplePat(p) => { 504 ast::Pat::TuplePat(p) => {
@@ -538,7 +507,7 @@ where
538 } 507 }
539 ast::Pat::PlaceholderPat(_) => Pat::Wild, 508 ast::Pat::PlaceholderPat(_) => Pat::Wild,
540 ast::Pat::RecordPat(p) => { 509 ast::Pat::RecordPat(p) => {
541 let path = p.path().and_then(|path| self.parse_path(path)); 510 let path = p.path().and_then(|path| self.expander.parse_path(path));
542 let record_field_pat_list = 511 let record_field_pat_list =
543 p.record_field_pat_list().expect("every struct should have a field list"); 512 p.record_field_pat_list().expect("every struct should have a field list");
544 let mut fields: Vec<_> = record_field_pat_list 513 let mut fields: Vec<_> = record_field_pat_list
@@ -579,11 +548,6 @@ where
579 self.missing_pat() 548 self.missing_pat()
580 } 549 }
581 } 550 }
582
583 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
584 let hygiene = Hygiene::new(self.db, self.current_file_id);
585 Path::from_src(path, &hygiene)
586 }
587} 551}
588 552
589impl From<ast::BinOp> for BinaryOp { 553impl From<ast::BinOp> for BinaryOp {
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
new file mode 100644
index 000000000..09a39e721
--- /dev/null
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -0,0 +1,165 @@
1//! FIXME: write short doc here
2use std::sync::Arc;
3
4use hir_expand::name::Name;
5use ra_arena::{impl_arena_id, Arena, RawId};
6use rustc_hash::FxHashMap;
7
8use crate::{
9 body::Body,
10 db::DefDatabase2,
11 expr::{Expr, ExprId, Pat, PatId, Statement},
12 DefWithBodyId,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub struct ScopeId(RawId);
17impl_arena_id!(ScopeId);
18
19#[derive(Debug, PartialEq, Eq)]
20pub struct ExprScopes {
21 scopes: Arena<ScopeId, ScopeData>,
22 scope_by_expr: FxHashMap<ExprId, ScopeId>,
23}
24
25#[derive(Debug, PartialEq, Eq)]
26pub struct ScopeEntry {
27 name: Name,
28 pat: PatId,
29}
30
31impl ScopeEntry {
32 pub fn name(&self) -> &Name {
33 &self.name
34 }
35
36 pub fn pat(&self) -> PatId {
37 self.pat
38 }
39}
40
41#[derive(Debug, PartialEq, Eq)]
42pub struct ScopeData {
43 parent: Option<ScopeId>,
44 entries: Vec<ScopeEntry>,
45}
46
47impl ExprScopes {
48 pub(crate) fn expr_scopes_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc<ExprScopes> {
49 let body = db.body(def);
50 Arc::new(ExprScopes::new(&*body))
51 }
52
53 fn new(body: &Body) -> ExprScopes {
54 let mut scopes =
55 ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
56 let root = scopes.root_scope();
57 scopes.add_params_bindings(body, root, body.params());
58 compute_expr_scopes(body.body_expr(), body, &mut scopes, root);
59 scopes
60 }
61
62 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
63 &self.scopes[scope].entries
64 }
65
66 pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ {
67 std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
68 }
69
70 pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
71 self.scope_by_expr.get(&expr).copied()
72 }
73
74 pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> {
75 &self.scope_by_expr
76 }
77
78 fn root_scope(&mut self) -> ScopeId {
79 self.scopes.alloc(ScopeData { parent: None, entries: vec![] })
80 }
81
82 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
83 self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] })
84 }
85
86 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
87 match &body[pat] {
88 Pat::Bind { name, .. } => {
89 // bind can have a sub pattern, but it's actually not allowed
90 // to bind to things in there
91 let entry = ScopeEntry { name: name.clone(), pat };
92 self.scopes[scope].entries.push(entry)
93 }
94 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
95 }
96 }
97
98 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) {
99 params.iter().for_each(|pat| self.add_bindings(body, scope, *pat));
100 }
101
102 fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
103 self.scope_by_expr.insert(node, scope);
104 }
105}
106
107fn compute_block_scopes(
108 statements: &[Statement],
109 tail: Option<ExprId>,
110 body: &Body,
111 scopes: &mut ExprScopes,
112 mut scope: ScopeId,
113) {
114 for stmt in statements {
115 match stmt {
116 Statement::Let { pat, initializer, .. } => {
117 if let Some(expr) = initializer {
118 scopes.set_scope(*expr, scope);
119 compute_expr_scopes(*expr, body, scopes, scope);
120 }
121 scope = scopes.new_scope(scope);
122 scopes.add_bindings(body, scope, *pat);
123 }
124 Statement::Expr(expr) => {
125 scopes.set_scope(*expr, scope);
126 compute_expr_scopes(*expr, body, scopes, scope);
127 }
128 }
129 }
130 if let Some(expr) = tail {
131 compute_expr_scopes(expr, body, scopes, scope);
132 }
133}
134
135fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) {
136 scopes.set_scope(expr, scope);
137 match &body[expr] {
138 Expr::Block { statements, tail } => {
139 compute_block_scopes(&statements, *tail, body, scopes, scope);
140 }
141 Expr::For { iterable, pat, body: body_expr } => {
142 compute_expr_scopes(*iterable, body, scopes, scope);
143 let scope = scopes.new_scope(scope);
144 scopes.add_bindings(body, scope, *pat);
145 compute_expr_scopes(*body_expr, body, scopes, scope);
146 }
147 Expr::Lambda { args, body: body_expr, .. } => {
148 let scope = scopes.new_scope(scope);
149 scopes.add_params_bindings(body, scope, &args);
150 compute_expr_scopes(*body_expr, body, scopes, scope);
151 }
152 Expr::Match { expr, arms } => {
153 compute_expr_scopes(*expr, body, scopes, scope);
154 for arm in arms {
155 let scope = scopes.new_scope(scope);
156 for pat in &arm.pats {
157 scopes.add_bindings(body, scope, *pat);
158 }
159 scopes.set_scope(arm.expr, scope);
160 compute_expr_scopes(arm.expr, body, scopes, scope);
161 }
162 }
163 e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
164 };
165}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 29cf71a59..40b5920d9 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -7,11 +7,12 @@ use ra_syntax::ast;
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
10 body::{scope::ExprScopes, Body, BodySourceMap},
10 nameres::{ 11 nameres::{
11 raw::{ImportSourceMap, RawItems}, 12 raw::{ImportSourceMap, RawItems},
12 CrateDefMap, 13 CrateDefMap,
13 }, 14 },
14 EnumId, StructOrUnionId, 15 DefWithBodyId, EnumId, StructOrUnionId,
15}; 16};
16 17
17#[salsa::query_group(InternDatabaseStorage)] 18#[salsa::query_group(InternDatabaseStorage)]
@@ -52,4 +53,13 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
52 53
53 #[salsa::invoke(EnumData::enum_data_query)] 54 #[salsa::invoke(EnumData::enum_data_query)]
54 fn enum_data(&self, e: EnumId) -> Arc<EnumData>; 55 fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
56
57 #[salsa::invoke(Body::body_with_source_map_query)]
58 fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>);
59
60 #[salsa::invoke(Body::body_query)]
61 fn body(&self, def: DefWithBodyId) -> Arc<Body>;
62
63 #[salsa::invoke(ExprScopes::expr_scopes_query)]
64 fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
55} 65}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 4a758bb83..3fab7965c 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -374,3 +374,13 @@ impl_froms!(
374 TypeAliasId, 374 TypeAliasId,
375 BuiltinType 375 BuiltinType
376); 376);
377
378/// The defs which have a body.
379#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
380pub enum DefWithBodyId {
381 FunctionId(FunctionId),
382 StaticId(StaticId),
383 ConstId(ConstId),
384}
385
386impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId);
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index c6ffa2c6f..930789b0f 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -223,7 +223,7 @@ impl<N: AstNode> AstId<N> {
223 } 223 }
224} 224}
225 225
226#[derive(Debug, PartialEq, Eq, Clone, Copy)] 226#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
227pub struct Source<T> { 227pub struct Source<T> {
228 pub file_id: HirFileId, 228 pub file_id: HirFileId,
229 pub ast: T, 229 pub ast: T,
@@ -233,6 +233,9 @@ impl<T> Source<T> {
233 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { 233 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
234 Source { file_id: self.file_id, ast: f(self.ast) } 234 Source { file_id: self.file_id, ast: f(self.ast) }
235 } 235 }
236 pub fn as_ref(&self) -> Source<&T> {
237 Source { file_id: self.file_id, ast: &self.ast }
238 }
236 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { 239 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
237 db.parse_or_expand(self.file_id).expect("source created from invalid file") 240 db.parse_or_expand(self.file_id).expect("source created from invalid file")
238 } 241 }
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 4952bd189..f06191963 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -40,24 +40,24 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
40// E.g. for after the break in `if break {}`, this should not match 40// E.g. for after the break in `if break {}`, this should not match
41pub(super) const ATOM_EXPR_FIRST: TokenSet = 41pub(super) const ATOM_EXPR_FIRST: TokenSet =
42 LITERAL_FIRST.union(paths::PATH_FIRST).union(token_set![ 42 LITERAL_FIRST.union(paths::PATH_FIRST).union(token_set![
43 L_PAREN, 43 T!['('],
44 L_CURLY, 44 T!['{'],
45 L_BRACK, 45 T!['['],
46 PIPE, 46 T![|],
47 MOVE_KW, 47 T![move],
48 BOX_KW, 48 T![box],
49 IF_KW, 49 T![if],
50 WHILE_KW, 50 T![while],
51 MATCH_KW, 51 T![match],
52 UNSAFE_KW, 52 T![unsafe],
53 RETURN_KW, 53 T![return],
54 BREAK_KW, 54 T![break],
55 CONTINUE_KW, 55 T![continue],
56 T![async],
57 T![try],
58 T![loop],
59 T![for],
56 LIFETIME, 60 LIFETIME,
57 ASYNC_KW,
58 TRY_KW,
59 LOOP_KW,
60 FOR_KW,
61 ]); 61 ]);
62 62
63const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; 63const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW];
diff --git a/crates/ra_parser/src/token_set.rs b/crates/ra_parser/src/token_set.rs
index 6dc061889..2a6952c01 100644
--- a/crates/ra_parser/src/token_set.rs
+++ b/crates/ra_parser/src/token_set.rs
@@ -30,8 +30,8 @@ const fn mask(kind: SyntaxKind) -> u128 {
30 30
31#[macro_export] 31#[macro_export]
32macro_rules! token_set { 32macro_rules! token_set {
33 ($($t:ident),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* }; 33 ($($t:expr),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* };
34 ($($t:ident),* ,) => { token_set!($($t),*) }; 34 ($($t:expr),* ,) => { token_set!($($t),*) };
35} 35}
36 36
37#[test] 37#[test]
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml
index 7db4498c3..bb241258c 100644
--- a/crates/ra_prof/Cargo.toml
+++ b/crates/ra_prof/Cargo.toml
@@ -1,17 +1,19 @@
1[package] 1[package]
2edition = "2018" 2edition = "2018"
3name = "ra_prof" 3name = "ra_prof"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
9once_cell = "1.0.1" 9once_cell = "1.0.1"
10itertools = "0.8.0" 10itertools = "0.8.0"
11backtrace = "0.3.28" 11backtrace = "0.3.28"
12jemallocator = { version = "0.3.2", optional = true } 12
13jemalloc-ctl = { version = "0.3.2", optional = true } 13[target.'cfg(not(target_env = "msvc"))'.dependencies]
14 14jemallocator = { version = "0.3.2", optional = true }
15[features] 15jemalloc-ctl = { version = "0.3.2", optional = true }
16jemalloc = [ "jemallocator", "jemalloc-ctl" ] 16
17cpu_profiler = [] 17[features]
18jemalloc = [ "jemallocator", "jemalloc-ctl" ]
19cpu_profiler = []
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index e5385f51b..845b2221c 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -24,7 +24,7 @@ pub use crate::memory_usage::{Bytes, MemoryUsage};
24 24
25// We use jemalloc mainly to get heap usage statistics, actual performance 25// We use jemalloc mainly to get heap usage statistics, actual performance
26// difference is not measures. 26// difference is not measures.
27#[cfg(feature = "jemalloc")] 27#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
28#[global_allocator] 28#[global_allocator]
29static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 29static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
30 30
diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs
index ad005ea14..9768f656c 100644
--- a/crates/ra_prof/src/memory_usage.rs
+++ b/crates/ra_prof/src/memory_usage.rs
@@ -8,7 +8,7 @@ pub struct MemoryUsage {
8} 8}
9 9
10impl MemoryUsage { 10impl MemoryUsage {
11 #[cfg(feature = "jemalloc")] 11 #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))]
12 pub fn current() -> MemoryUsage { 12 pub fn current() -> MemoryUsage {
13 jemalloc_ctl::epoch::advance().unwrap(); 13 jemalloc_ctl::epoch::advance().unwrap();
14 MemoryUsage { 14 MemoryUsage {
@@ -17,7 +17,7 @@ impl MemoryUsage {
17 } 17 }
18 } 18 }
19 19
20 #[cfg(not(feature = "jemalloc"))] 20 #[cfg(any(not(feature = "jemalloc"), target_env = "msvc"))]
21 pub fn current() -> MemoryUsage { 21 pub fn current() -> MemoryUsage {
22 MemoryUsage { allocated: Bytes(0), resident: Bytes(0) } 22 MemoryUsage { allocated: Bytes(0), resident: Bytes(0) }
23 } 23 }
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 47bdbb81a..6f005a2d8 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -358,7 +358,7 @@ fn replace_children<N: AstNode>(
358fn test_increase_indent() { 358fn test_increase_indent() {
359 let arm_list = { 359 let arm_list = {
360 let arm = make::match_arm(iter::once(make::placeholder_pat().into()), make::expr_unit()); 360 let arm = make::match_arm(iter::once(make::placeholder_pat().into()), make::expr_unit());
361 make::match_arm_list(vec![arm.clone(), arm].into_iter()) 361 make::match_arm_list(vec![arm.clone(), arm])
362 }; 362 };
363 assert_eq!( 363 assert_eq!(
364 arm_list.syntax().to_string(), 364 arm_list.syntax().to_string(),
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 95062ef6c..9749327fa 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -4,6 +4,10 @@ use itertools::Itertools;
4 4
5use crate::{ast, AstNode, SourceFile}; 5use crate::{ast, AstNode, SourceFile};
6 6
7pub fn name(text: &str) -> ast::Name {
8 ast_from_text(&format!("mod {};", text))
9}
10
7pub fn name_ref(text: &str) -> ast::NameRef { 11pub fn name_ref(text: &str) -> ast::NameRef {
8 ast_from_text(&format!("fn f() {{ {}; }}", text)) 12 ast_from_text(&format!("fn f() {{ {}; }}", text))
9} 13}
@@ -43,6 +47,21 @@ pub fn expr_unit() -> ast::Expr {
43pub fn expr_unimplemented() -> ast::Expr { 47pub fn expr_unimplemented() -> ast::Expr {
44 expr_from_text("unimplemented!()") 48 expr_from_text("unimplemented!()")
45} 49}
50pub fn expr_path(path: ast::Path) -> ast::Expr {
51 expr_from_text(&path.syntax().to_string())
52}
53pub fn expr_continue() -> ast::Expr {
54 expr_from_text("continue")
55}
56pub fn expr_break() -> ast::Expr {
57 expr_from_text("break")
58}
59pub fn expr_return() -> ast::Expr {
60 expr_from_text("return")
61}
62pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
63 expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
64}
46fn expr_from_text(text: &str) -> ast::Expr { 65fn expr_from_text(text: &str) -> ast::Expr {
47 ast_from_text(&format!("const C: () = {};", text)) 66 ast_from_text(&format!("const C: () = {};", text))
48} 67}
@@ -65,9 +84,9 @@ pub fn placeholder_pat() -> ast::PlaceholderPat {
65 84
66pub fn tuple_struct_pat( 85pub fn tuple_struct_pat(
67 path: ast::Path, 86 path: ast::Path,
68 pats: impl Iterator<Item = ast::Pat>, 87 pats: impl IntoIterator<Item = ast::Pat>,
69) -> ast::TupleStructPat { 88) -> ast::TupleStructPat {
70 let pats_str = pats.map(|p| p.syntax().to_string()).join(", "); 89 let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
71 return from_text(&format!("{}({})", path.syntax(), pats_str)); 90 return from_text(&format!("{}({})", path.syntax(), pats_str));
72 91
73 fn from_text(text: &str) -> ast::TupleStructPat { 92 fn from_text(text: &str) -> ast::TupleStructPat {
@@ -75,8 +94,8 @@ pub fn tuple_struct_pat(
75 } 94 }
76} 95}
77 96
78pub fn record_pat(path: ast::Path, pats: impl Iterator<Item = ast::Pat>) -> ast::RecordPat { 97pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
79 let pats_str = pats.map(|p| p.syntax().to_string()).join(", "); 98 let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", ");
80 return from_text(&format!("{} {{ {} }}", path.syntax(), pats_str)); 99 return from_text(&format!("{} {{ {} }}", path.syntax(), pats_str));
81 100
82 fn from_text(text: &str) -> ast::RecordPat { 101 fn from_text(text: &str) -> ast::RecordPat {
@@ -92,8 +111,8 @@ pub fn path_pat(path: ast::Path) -> ast::PathPat {
92 } 111 }
93} 112}
94 113
95pub fn match_arm(pats: impl Iterator<Item = ast::Pat>, expr: ast::Expr) -> ast::MatchArm { 114pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> ast::MatchArm {
96 let pats_str = pats.map(|p| p.syntax().to_string()).join(" | "); 115 let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(" | ");
97 return from_text(&format!("{} => {}", pats_str, expr.syntax())); 116 return from_text(&format!("{} => {}", pats_str, expr.syntax()));
98 117
99 fn from_text(text: &str) -> ast::MatchArm { 118 fn from_text(text: &str) -> ast::MatchArm {
@@ -101,8 +120,8 @@ pub fn match_arm(pats: impl Iterator<Item = ast::Pat>, expr: ast::Expr) -> ast::
101 } 120 }
102} 121}
103 122
104pub fn match_arm_list(arms: impl Iterator<Item = ast::MatchArm>) -> ast::MatchArmList { 123pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
105 let arms_str = arms.map(|arm| format!("\n {}", arm.syntax())).join(","); 124 let arms_str = arms.into_iter().map(|arm| format!("\n {}", arm.syntax())).join(",");
106 return from_text(&format!("{},\n", arms_str)); 125 return from_text(&format!("{},\n", arms_str));
107 126
108 fn from_text(text: &str) -> ast::MatchArmList { 127 fn from_text(text: &str) -> ast::MatchArmList {
@@ -110,25 +129,11 @@ pub fn match_arm_list(arms: impl Iterator<Item = ast::MatchArm>) -> ast::MatchAr
110 } 129 }
111} 130}
112 131
113pub fn let_match_early(expr: ast::Expr, path: &str, early_expression: &str) -> ast::LetStmt { 132pub fn where_pred(
114 return from_text(&format!( 133 path: ast::Path,
115 r#"let {} = match {} {{ 134 bounds: impl IntoIterator<Item = ast::TypeBound>,
116 {}(it) => it, 135) -> ast::WherePred {
117 None => {}, 136 let bounds = bounds.into_iter().map(|b| b.syntax().to_string()).join(" + ");
118}};"#,
119 expr.syntax().text(),
120 expr.syntax().text(),
121 path,
122 early_expression
123 ));
124
125 fn from_text(text: &str) -> ast::LetStmt {
126 ast_from_text(&format!("fn f() {{ {} }}", text))
127 }
128}
129
130pub fn where_pred(path: ast::Path, bounds: impl Iterator<Item = ast::TypeBound>) -> ast::WherePred {
131 let bounds = bounds.map(|b| b.syntax().to_string()).join(" + ");
132 return from_text(&format!("{}: {}", path.syntax(), bounds)); 137 return from_text(&format!("{}: {}", path.syntax(), bounds));
133 138
134 fn from_text(text: &str) -> ast::WherePred { 139 fn from_text(text: &str) -> ast::WherePred {
@@ -136,8 +141,8 @@ pub fn where_pred(path: ast::Path, bounds: impl Iterator<Item = ast::TypeBound>)
136 } 141 }
137} 142}
138 143
139pub fn where_clause(preds: impl Iterator<Item = ast::WherePred>) -> ast::WhereClause { 144pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::WhereClause {
140 let preds = preds.map(|p| p.syntax().to_string()).join(", "); 145 let preds = preds.into_iter().map(|p| p.syntax().to_string()).join(", ");
141 return from_text(preds.as_str()); 146 return from_text(preds.as_str());
142 147
143 fn from_text(text: &str) -> ast::WhereClause { 148 fn from_text(text: &str) -> ast::WhereClause {
@@ -153,6 +158,14 @@ pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr {
153 )) 158 ))
154} 159}
155 160
161pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
162 let text = match initializer {
163 Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()),
164 None => format!("let {};", pattern.syntax()),
165 };
166 ast_from_text(&format!("fn f() {{ {} }}", text))
167}
168
156fn ast_from_text<N: AstNode>(text: &str) -> N { 169fn ast_from_text<N: AstNode>(text: &str) -> N {
157 let parse = SourceFile::parse(text); 170 let parse = SourceFile::parse(text);
158 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 171 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap();