diff options
author | Seivan Heidari <[email protected]> | 2019-11-14 22:20:27 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-14 22:20:27 +0000 |
commit | c622413bc72ea56d5f62a16788d897cb61eca948 (patch) | |
tree | 9de3dbe8b5c935ed168efac4e70770e54fbe0714 /crates | |
parent | 0525778a3ad590492b51cc11085d815f9bb8f92b (diff) | |
parent | bbb022d3999b3038549ec6c309efb065231c896a (diff) |
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates')
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 @@ | |||
1 | use std::ops::RangeInclusive; | 1 | use std::{iter::once, ops::RangeInclusive}; |
2 | 2 | ||
3 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
@@ -38,27 +38,30 @@ use crate::{ | |||
38 | // ``` | 38 | // ``` |
39 | pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 39 | pub(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)] |
153 | mod tests { | 177 | mod 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 | ||
9 | use hir_def::{ | 9 | use 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 | ||
544 | impl<T> HasBody for T | 546 | impl<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 | ||
1080 | impl Local { | 1090 | impl 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 | ||
9 | use crate::{ | 9 | use 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 | ||
26 | pub use hir_def::db::{ | 25 | pub 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 | }; |
30 | pub use hir_expand::db::{ | 30 | pub 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)] |
87 | pub trait HirDatabase: DefDatabase + AstDatabase { | 87 | pub 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 | ||
3 | pub(crate) mod scope; | ||
4 | pub(crate) mod validation; | 3 | pub(crate) mod validation; |
5 | 4 | ||
6 | use std::sync::Arc; | 5 | use std::sync::Arc; |
7 | 6 | ||
8 | use ra_syntax::{ast, AstPtr}; | 7 | use ra_syntax::AstPtr; |
9 | 8 | ||
10 | use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver}; | 9 | use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; |
11 | |||
12 | pub use self::scope::ExprScopes; | ||
13 | 10 | ||
14 | pub use hir_def::{ | 11 | pub 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 | ||
22 | pub(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 | |||
48 | pub(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? |
53 | pub(crate) fn resolver_for_expr( | 23 | pub(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 | ||
62 | pub(crate) fn resolver_for_scope( | 32 | pub(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)] | ||
47 | mod 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 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use ra_arena::{impl_arena_id, Arena, RawId}; | ||
6 | use rustc_hash::FxHashMap; | ||
7 | |||
8 | use 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)] | ||
15 | pub struct ScopeId(RawId); | ||
16 | impl_arena_id!(ScopeId); | ||
17 | |||
18 | #[derive(Debug, PartialEq, Eq)] | ||
19 | pub 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)] | ||
26 | pub(crate) struct ScopeEntry { | ||
27 | name: Name, | ||
28 | pat: PatId, | ||
29 | } | ||
30 | |||
31 | impl 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)] | ||
42 | pub(crate) struct ScopeData { | ||
43 | parent: Option<ScopeId>, | ||
44 | entries: Vec<ScopeEntry>, | ||
45 | } | ||
46 | |||
47 | impl 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 | |||
112 | fn 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 | |||
140 | fn 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)] | ||
173 | mod 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 | ||
6 | use hir_def::{AdtId, EnumVariantId, ModuleDefId}; | 6 | use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; |
7 | 7 | ||
8 | use crate::{Adt, EnumVariant, ModuleDef}; | 8 | use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; |
9 | 9 | ||
10 | macro_rules! from_id { | 10 | macro_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 | |||
65 | impl 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::{ | |||
10 | use crate::{ | 10 | use 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; | |||
13 | use crate::{ | 13 | use 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". |
8 | use std::sync::Arc; | 8 | use std::sync::Arc; |
9 | 9 | ||
10 | use hir_def::path::known; | 10 | use hir_def::{ |
11 | use hir_expand::name::AsName; | 11 | expr::{ExprId, PatId}, |
12 | path::known, | ||
13 | }; | ||
14 | use hir_expand::{name::AsName, Source}; | ||
12 | use ra_db::FileId; | 15 | use ra_db::FileId; |
13 | use ra_syntax::{ | 16 | use ra_syntax::{ |
14 | ast::{self, AstNode}, | 17 | ast::{self, AstNode}, |
@@ -20,11 +23,7 @@ use rustc_hash::FxHashSet; | |||
20 | 23 | ||
21 | use crate::{ | 24 | use 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)] |
95 | pub struct SourceAnalyzer { | 94 | pub 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 { | |||
418 | fn scope_for( | 431 | fn 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 | }; |
26 | use display::{HirDisplay, HirFormatter}; | 26 | use 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; | |||
31 | use test_utils::tested_by; | 31 | use test_utils::tested_by; |
32 | 32 | ||
33 | use super::{ | 33 | use 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 | }; |
39 | use crate::{ | 39 | use 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 | ||
49 | macro_rules! ty_app { | 50 | macro_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 @@ | |||
3 | use std::iter::{repeat, repeat_with}; | 3 | use std::iter::{repeat, repeat_with}; |
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::path::{GenericArg, GenericArgs}; | 6 | use hir_def::{ |
7 | builtin_type::Signedness, | ||
8 | path::{GenericArg, GenericArgs}, | ||
9 | }; | ||
7 | use hir_expand::name; | 10 | use hir_expand::name; |
8 | 11 | ||
9 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; | 12 | use 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 | ||
677 | impl From<Option<BuiltinInt>> for UncertainIntTy { | 677 | impl 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 | ||
686 | impl From<Option<BuiltinFloat>> for UncertainFloatTy { | 686 | impl 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; | |||
8 | use hir_def::CrateModuleId; | 8 | use hir_def::CrateModuleId; |
9 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
10 | 10 | ||
11 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | ||
12 | use crate::{ | 11 | use 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 | ||
20 | use 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)] |
23 | pub enum TyFingerprint { | 24 | pub 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 | ||
5 | pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; | 5 | pub 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)] |
8 | pub enum UncertainIntTy { | 8 | pub enum Uncertain<T> { |
9 | Unknown, | 9 | Unknown, |
10 | Known(IntTy), | 10 | Known(T), |
11 | } | 11 | } |
12 | 12 | ||
13 | impl From<IntTy> for UncertainIntTy { | 13 | impl 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 | ||
19 | impl fmt::Display for UncertainIntTy { | 19 | impl 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)] | 28 | impl From<FloatTy> for Uncertain<FloatTy> { |
29 | pub enum UncertainFloatTy { | ||
30 | Unknown, | ||
31 | Known(FloatTy), | ||
32 | } | ||
33 | |||
34 | impl 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 | ||
40 | impl fmt::Display for UncertainFloatTy { | 34 | impl 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 |
2 | mod lower; | 2 | mod lower; |
3 | pub mod scope; | ||
3 | 4 | ||
4 | use std::{ops::Index, sync::Arc}; | 5 | use std::{ops::Index, sync::Arc}; |
5 | 6 | ||
6 | use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; | 7 | use hir_expand::{ |
8 | either::Either, hygiene::Hygiene, AstId, HirFileId, MacroCallLoc, MacroDefId, MacroFileKind, | ||
9 | Source, | ||
10 | }; | ||
7 | use ra_arena::{map::ArenaMap, Arena}; | 11 | use ra_arena::{map::ArenaMap, Arena}; |
8 | use ra_syntax::{ast, AstPtr}; | 12 | use ra_syntax::{ast, AstNode, AstPtr}; |
9 | use rustc_hash::FxHashMap; | 13 | use rustc_hash::FxHashMap; |
10 | 14 | ||
11 | use crate::{ | 15 | use 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 | ||
19 | pub struct MacroResolver { | 23 | pub 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 | ||
24 | impl MacroResolver { | 30 | impl 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(¯o_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 | ||
89 | struct Mark { | ||
90 | file_id: HirFileId, | ||
91 | } | ||
92 | |||
93 | impl 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)] |
40 | pub struct Body { | 103 | pub 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)] |
72 | pub struct BodySourceMap { | 135 | pub 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 | ||
80 | impl Body { | 143 | impl 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 | ||
3 | use hir_expand::{ | 3 | use 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 | }; |
9 | use ra_arena::Arena; | 7 | use ra_arena::Arena; |
10 | use ra_syntax::{ | 8 | use ra_syntax::{ |
@@ -16,7 +14,7 @@ use ra_syntax::{ | |||
16 | }; | 14 | }; |
17 | 15 | ||
18 | use crate::{ | 16 | use 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 | ||
31 | pub(super) fn lower( | 29 | pub(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 | ||
54 | struct ExprCollector<DB> { | 49 | struct 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 | ||
589 | impl From<ast::BinOp> for BinaryOp { | 553 | impl 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 | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use hir_expand::name::Name; | ||
5 | use ra_arena::{impl_arena_id, Arena, RawId}; | ||
6 | use rustc_hash::FxHashMap; | ||
7 | |||
8 | use 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)] | ||
16 | pub struct ScopeId(RawId); | ||
17 | impl_arena_id!(ScopeId); | ||
18 | |||
19 | #[derive(Debug, PartialEq, Eq)] | ||
20 | pub struct ExprScopes { | ||
21 | scopes: Arena<ScopeId, ScopeData>, | ||
22 | scope_by_expr: FxHashMap<ExprId, ScopeId>, | ||
23 | } | ||
24 | |||
25 | #[derive(Debug, PartialEq, Eq)] | ||
26 | pub struct ScopeEntry { | ||
27 | name: Name, | ||
28 | pat: PatId, | ||
29 | } | ||
30 | |||
31 | impl 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)] | ||
42 | pub struct ScopeData { | ||
43 | parent: Option<ScopeId>, | ||
44 | entries: Vec<ScopeEntry>, | ||
45 | } | ||
46 | |||
47 | impl 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 | |||
107 | fn 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 | |||
135 | fn 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 | ||
8 | use crate::{ | 8 | use 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)] | ||
380 | pub enum DefWithBodyId { | ||
381 | FunctionId(FunctionId), | ||
382 | StaticId(StaticId), | ||
383 | ConstId(ConstId), | ||
384 | } | ||
385 | |||
386 | impl_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)] |
227 | pub struct Source<T> { | 227 | pub 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 |
41 | pub(super) const ATOM_EXPR_FIRST: TokenSet = | 41 | pub(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 | ||
63 | const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; | 63 | const 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] |
32 | macro_rules! token_set { | 32 | macro_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] |
2 | edition = "2018" | 2 | edition = "2018" |
3 | name = "ra_prof" | 3 | name = "ra_prof" |
4 | version = "0.1.0" | 4 | version = "0.1.0" |
5 | authors = ["rust-analyzer developers"] | 5 | authors = ["rust-analyzer developers"] |
6 | publish = false | 6 | publish = false |
7 | 7 | ||
8 | [dependencies] | 8 | [dependencies] |
9 | once_cell = "1.0.1" | 9 | once_cell = "1.0.1" |
10 | itertools = "0.8.0" | 10 | itertools = "0.8.0" |
11 | backtrace = "0.3.28" | 11 | backtrace = "0.3.28" |
12 | jemallocator = { version = "0.3.2", optional = true } | 12 | |
13 | jemalloc-ctl = { version = "0.3.2", optional = true } | 13 | [target.'cfg(not(target_env = "msvc"))'.dependencies] |
14 | 14 | jemallocator = { version = "0.3.2", optional = true } | |
15 | [features] | 15 | jemalloc-ctl = { version = "0.3.2", optional = true } |
16 | jemalloc = [ "jemallocator", "jemalloc-ctl" ] | 16 | |
17 | cpu_profiler = [] | 17 | [features] |
18 | jemalloc = [ "jemallocator", "jemalloc-ctl" ] | ||
19 | cpu_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] |
29 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; | 29 | static 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 | ||
10 | impl MemoryUsage { | 10 | impl 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>( | |||
358 | fn test_increase_indent() { | 358 | fn 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 | ||
5 | use crate::{ast, AstNode, SourceFile}; | 5 | use crate::{ast, AstNode, SourceFile}; |
6 | 6 | ||
7 | pub fn name(text: &str) -> ast::Name { | ||
8 | ast_from_text(&format!("mod {};", text)) | ||
9 | } | ||
10 | |||
7 | pub fn name_ref(text: &str) -> ast::NameRef { | 11 | pub 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 { | |||
43 | pub fn expr_unimplemented() -> ast::Expr { | 47 | pub fn expr_unimplemented() -> ast::Expr { |
44 | expr_from_text("unimplemented!()") | 48 | expr_from_text("unimplemented!()") |
45 | } | 49 | } |
50 | pub fn expr_path(path: ast::Path) -> ast::Expr { | ||
51 | expr_from_text(&path.syntax().to_string()) | ||
52 | } | ||
53 | pub fn expr_continue() -> ast::Expr { | ||
54 | expr_from_text("continue") | ||
55 | } | ||
56 | pub fn expr_break() -> ast::Expr { | ||
57 | expr_from_text("break") | ||
58 | } | ||
59 | pub fn expr_return() -> ast::Expr { | ||
60 | expr_from_text("return") | ||
61 | } | ||
62 | pub 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 | } | ||
46 | fn expr_from_text(text: &str) -> ast::Expr { | 65 | fn 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 | ||
66 | pub fn tuple_struct_pat( | 85 | pub 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 | ||
78 | pub fn record_pat(path: ast::Path, pats: impl Iterator<Item = ast::Pat>) -> ast::RecordPat { | 97 | pub 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 | ||
95 | pub fn match_arm(pats: impl Iterator<Item = ast::Pat>, expr: ast::Expr) -> ast::MatchArm { | 114 | pub 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 | ||
104 | pub fn match_arm_list(arms: impl Iterator<Item = ast::MatchArm>) -> ast::MatchArmList { | 123 | pub 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 | ||
113 | pub fn let_match_early(expr: ast::Expr, path: &str, early_expression: &str) -> ast::LetStmt { | 132 | pub 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 | |||
130 | pub 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 | ||
139 | pub fn where_clause(preds: impl Iterator<Item = ast::WherePred>) -> ast::WhereClause { | 144 | pub 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 | ||
161 | pub 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 | |||
156 | fn ast_from_text<N: AstNode>(text: &str) -> N { | 169 | fn 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(); |