diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-04-11 18:37:02 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-04-11 18:37:02 +0100 |
commit | 1a1c09ed3e3a34c0a8750f98ece9ad85595395d2 (patch) | |
tree | 44136a4ce738d388bb9b0ce9f5569cf68465cbe2 | |
parent | 11d400b63b07d3cffbe8d1363b802a2d52f5d786 (diff) | |
parent | 0aece75cdd40daa4d48484103cfcd36ba13ba076 (diff) |
Merge #3951
3951: Simplify records grammar r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/expr.rs | 55 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_unqualified_path.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_db/src/defs.rs | 2 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar/expressions.rs | 37 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 30 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast | 49 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs | 3 | ||||
-rw-r--r-- | crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast | 14 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/analysis_stats.rs | 12 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 2 |
17 files changed, 180 insertions, 121 deletions
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 226fb4534..58ae6ce41 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -139,7 +139,7 @@ impl SourceAnalyzer { | |||
139 | &self, | 139 | &self, |
140 | db: &dyn HirDatabase, | 140 | db: &dyn HirDatabase, |
141 | field: &ast::FieldExpr, | 141 | field: &ast::FieldExpr, |
142 | ) -> Option<crate::StructField> { | 142 | ) -> Option<StructField> { |
143 | let expr_id = self.expr_id(db, &field.clone().into())?; | 143 | let expr_id = self.expr_id(db, &field.clone().into())?; |
144 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) | 144 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) |
145 | } | 145 | } |
@@ -148,21 +148,19 @@ impl SourceAnalyzer { | |||
148 | &self, | 148 | &self, |
149 | db: &dyn HirDatabase, | 149 | db: &dyn HirDatabase, |
150 | field: &ast::RecordField, | 150 | field: &ast::RecordField, |
151 | ) -> Option<(crate::StructField, Option<Local>)> { | 151 | ) -> Option<(StructField, Option<Local>)> { |
152 | let (expr_id, local) = match field.expr() { | 152 | let expr = field.expr()?; |
153 | Some(it) => (self.expr_id(db, &it)?, None), | 153 | let expr_id = self.expr_id(db, &expr)?; |
154 | None => { | 154 | let local = if field.name_ref().is_some() { |
155 | let src = InFile { file_id: self.file_id, value: field }; | 155 | None |
156 | let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?; | 156 | } else { |
157 | let local_name = field.name_ref()?.as_name(); | 157 | let local_name = field.field_name()?.as_name(); |
158 | let path = ModPath::from_segments(PathKind::Plain, once(local_name)); | 158 | let path = ModPath::from_segments(PathKind::Plain, once(local_name)); |
159 | let local = match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { | 159 | match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { |
160 | Some(ValueNs::LocalBinding(pat_id)) => { | 160 | Some(ValueNs::LocalBinding(pat_id)) => { |
161 | Some(Local { pat_id, parent: self.resolver.body_owner()? }) | 161 | Some(Local { pat_id, parent: self.resolver.body_owner()? }) |
162 | } | 162 | } |
163 | _ => None, | 163 | _ => None, |
164 | }; | ||
165 | (expr_id, local) | ||
166 | } | 164 | } |
167 | }; | 165 | }; |
168 | let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; | 166 | let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; |
@@ -319,8 +317,7 @@ fn scope_for_offset( | |||
319 | if source.file_id != offset.file_id { | 317 | if source.file_id != offset.file_id { |
320 | return None; | 318 | return None; |
321 | } | 319 | } |
322 | let syntax_node_ptr = | 320 | let syntax_node_ptr = source.value.syntax_node_ptr(); |
323 | source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
324 | Some((syntax_node_ptr, scope)) | 321 | Some((syntax_node_ptr, scope)) |
325 | }) | 322 | }) |
326 | // find containing scope | 323 | // find containing scope |
@@ -399,8 +396,7 @@ fn adjust( | |||
399 | if source.file_id != file_id { | 396 | if source.file_id != file_id { |
400 | return None; | 397 | return None; |
401 | } | 398 | } |
402 | let syntax_node_ptr = | 399 | let syntax_node_ptr = source.value.syntax_node_ptr(); |
403 | source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
404 | Some((syntax_node_ptr, scope)) | 400 | Some((syntax_node_ptr, scope)) |
405 | }) | 401 | }) |
406 | .map(|(ptr, scope)| (ptr.range(), scope)) | 402 | .map(|(ptr, scope)| (ptr.range(), scope)) |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 7fac6ce66..eafaf48c1 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -9,6 +9,8 @@ use drop_bomb::DropBomb; | |||
9 | use either::Either; | 9 | use either::Either; |
10 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; | 10 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; |
11 | use ra_arena::{map::ArenaMap, Arena}; | 11 | use ra_arena::{map::ArenaMap, Arena}; |
12 | use ra_cfg::CfgOptions; | ||
13 | use ra_db::CrateId; | ||
12 | use ra_prof::profile; | 14 | use ra_prof::profile; |
13 | use ra_syntax::{ast, AstNode, AstPtr}; | 15 | use ra_syntax::{ast, AstNode, AstPtr}; |
14 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
@@ -24,8 +26,6 @@ use crate::{ | |||
24 | src::HasSource, | 26 | src::HasSource, |
25 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | 27 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, |
26 | }; | 28 | }; |
27 | use ra_cfg::CfgOptions; | ||
28 | use ra_db::CrateId; | ||
29 | 29 | ||
30 | /// A subser of Exander that only deals with cfg attributes. We only need it to | 30 | /// A subser of Exander that only deals with cfg attributes. We only need it to |
31 | /// avoid cyclic queries in crate def map during enum processing. | 31 | /// avoid cyclic queries in crate def map during enum processing. |
@@ -187,7 +187,7 @@ pub struct Body { | |||
187 | pub item_scope: ItemScope, | 187 | pub item_scope: ItemScope, |
188 | } | 188 | } |
189 | 189 | ||
190 | pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | 190 | pub type ExprPtr = AstPtr<ast::Expr>; |
191 | pub type ExprSource = InFile<ExprPtr>; | 191 | pub type ExprSource = InFile<ExprPtr>; |
192 | 192 | ||
193 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | 193 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; |
@@ -285,7 +285,7 @@ impl BodySourceMap { | |||
285 | } | 285 | } |
286 | 286 | ||
287 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { | 287 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { |
288 | let src = node.map(|it| Either::Left(AstPtr::new(it))); | 288 | let src = node.map(|it| AstPtr::new(it)); |
289 | self.expr_map.get(&src).cloned() | 289 | self.expr_map.get(&src).cloned() |
290 | } | 290 | } |
291 | 291 | ||
@@ -294,11 +294,6 @@ impl BodySourceMap { | |||
294 | self.expansions.get(&src).cloned() | 294 | self.expansions.get(&src).cloned() |
295 | } | 295 | } |
296 | 296 | ||
297 | pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> { | ||
298 | let src = node.map(|it| Either::Right(AstPtr::new(it))); | ||
299 | self.expr_map.get(&src).cloned() | ||
300 | } | ||
301 | |||
302 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { | 297 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { |
303 | self.pat_map_back[pat].clone() | 298 | self.pat_map_back[pat].clone() |
304 | } | 299 | } |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index c1d7eb826..cc2532e88 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -27,7 +27,6 @@ use crate::{ | |||
27 | }, | 27 | }, |
28 | item_scope::BuiltinShadowMode, | 28 | item_scope::BuiltinShadowMode, |
29 | path::GenericArgs, | 29 | path::GenericArgs, |
30 | path::Path, | ||
31 | type_ref::{Mutability, TypeRef}, | 30 | type_ref::{Mutability, TypeRef}, |
32 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | 31 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
33 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | 32 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
@@ -102,7 +101,6 @@ impl ExprCollector<'_> { | |||
102 | } | 101 | } |
103 | 102 | ||
104 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | 103 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { |
105 | let ptr = Either::Left(ptr); | ||
106 | let src = self.expander.to_source(ptr); | 104 | let src = self.expander.to_source(ptr); |
107 | let id = self.make_expr(expr, Ok(src.clone())); | 105 | let id = self.make_expr(expr, Ok(src.clone())); |
108 | self.source_map.expr_map.insert(src, id); | 106 | self.source_map.expr_map.insert(src, id); |
@@ -113,13 +111,6 @@ impl ExprCollector<'_> { | |||
113 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { | 111 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { |
114 | self.make_expr(expr, Err(SyntheticSyntax)) | 112 | self.make_expr(expr, Err(SyntheticSyntax)) |
115 | } | 113 | } |
116 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { | ||
117 | let ptr = Either::Right(ptr); | ||
118 | let src = self.expander.to_source(ptr); | ||
119 | let id = self.make_expr(expr, Ok(src.clone())); | ||
120 | self.source_map.expr_map.insert(src, id); | ||
121 | id | ||
122 | } | ||
123 | fn empty_block(&mut self) -> ExprId { | 114 | fn empty_block(&mut self) -> ExprId { |
124 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None }) | 115 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None }) |
125 | } | 116 | } |
@@ -289,7 +280,7 @@ impl ExprCollector<'_> { | |||
289 | ast::Expr::ParenExpr(e) => { | 280 | ast::Expr::ParenExpr(e) => { |
290 | let inner = self.collect_expr_opt(e.expr()); | 281 | let inner = self.collect_expr_opt(e.expr()); |
291 | // make the paren expr point to the inner expression as well | 282 | // make the paren expr point to the inner expression as well |
292 | let src = self.expander.to_source(Either::Left(syntax_ptr)); | 283 | let src = self.expander.to_source(syntax_ptr); |
293 | self.source_map.expr_map.insert(src, inner); | 284 | self.source_map.expr_map.insert(src, inner); |
294 | inner | 285 | inner |
295 | } | 286 | } |
@@ -309,22 +300,13 @@ impl ExprCollector<'_> { | |||
309 | if !self.expander.is_cfg_enabled(&attrs) { | 300 | if !self.expander.is_cfg_enabled(&attrs) { |
310 | return None; | 301 | return None; |
311 | } | 302 | } |
303 | let name = field.field_name()?.as_name(); | ||
312 | 304 | ||
313 | Some(RecordLitField { | 305 | Some(RecordLitField { |
314 | name: field | 306 | name, |
315 | .name_ref() | 307 | expr: match field.expr() { |
316 | .map(|nr| nr.as_name()) | 308 | Some(e) => self.collect_expr(e), |
317 | .unwrap_or_else(Name::missing), | 309 | None => self.missing_expr(), |
318 | expr: if let Some(e) = field.expr() { | ||
319 | self.collect_expr(e) | ||
320 | } else if let Some(nr) = field.name_ref() { | ||
321 | // field shorthand | ||
322 | self.alloc_expr_field_shorthand( | ||
323 | Expr::Path(Path::from_name_ref(&nr)), | ||
324 | AstPtr::new(&field), | ||
325 | ) | ||
326 | } else { | ||
327 | self.missing_expr() | ||
328 | }, | 310 | }, |
329 | }) | 311 | }) |
330 | }) | 312 | }) |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 904080341..91c7b3e09 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -134,11 +134,6 @@ impl Path { | |||
134 | lower::lower_path(path, hygiene) | 134 | lower::lower_path(path, hygiene) |
135 | } | 135 | } |
136 | 136 | ||
137 | /// Converts an `ast::NameRef` into a single-identifier `Path`. | ||
138 | pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { | ||
139 | Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } | ||
140 | } | ||
141 | |||
142 | /// Converts a known mod path to `Path`. | 137 | /// Converts a known mod path to `Path`. |
143 | pub(crate) fn from_known_path( | 138 | pub(crate) fn from_known_path( |
144 | path: ModPath, | 139 | path: ModPath, |
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index 827b687de..69b527f74 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -89,21 +89,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
89 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 89 | let (_, source_map) = db.body_with_source_map(self.func.into()); |
90 | 90 | ||
91 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 91 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
92 | if let Some(expr) = source_ptr.value.as_ref().left() { | 92 | let root = source_ptr.file_syntax(db.upcast()); |
93 | let root = source_ptr.file_syntax(db.upcast()); | 93 | if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) { |
94 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { | 94 | if let Some(field_list) = record_lit.record_field_list() { |
95 | if let Some(field_list) = record_lit.record_field_list() { | 95 | let variant_data = variant_data(db.upcast(), variant_def); |
96 | let variant_data = variant_data(db.upcast(), variant_def); | 96 | let missed_fields = missed_fields |
97 | let missed_fields = missed_fields | 97 | .into_iter() |
98 | .into_iter() | 98 | .map(|idx| variant_data.fields()[idx].name.clone()) |
99 | .map(|idx| variant_data.fields()[idx].name.clone()) | 99 | .collect(); |
100 | .collect(); | 100 | self.sink.push(MissingFields { |
101 | self.sink.push(MissingFields { | 101 | file: source_ptr.file_id, |
102 | file: source_ptr.file_id, | 102 | field_list: AstPtr::new(&field_list), |
103 | field_list: AstPtr::new(&field_list), | 103 | missed_fields, |
104 | missed_fields, | 104 | }) |
105 | }) | ||
106 | } | ||
107 | } | 105 | } |
108 | } | 106 | } |
109 | } | 107 | } |
@@ -205,18 +203,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
205 | } | 203 | } |
206 | 204 | ||
207 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 205 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
208 | if let Some(expr) = source_ptr.value.as_ref().left() { | 206 | let root = source_ptr.file_syntax(db.upcast()); |
209 | let root = source_ptr.file_syntax(db.upcast()); | 207 | if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) { |
210 | if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) { | 208 | if let (Some(match_expr), Some(arms)) = |
211 | if let (Some(match_expr), Some(arms)) = | 209 | (match_expr.expr(), match_expr.match_arm_list()) |
212 | (match_expr.expr(), match_expr.match_arm_list()) | 210 | { |
213 | { | 211 | self.sink.push(MissingMatchArms { |
214 | self.sink.push(MissingMatchArms { | 212 | file: source_ptr.file_id, |
215 | file: source_ptr.file_id, | 213 | match_expr: AstPtr::new(&match_expr), |
216 | match_expr: AstPtr::new(&match_expr), | 214 | arms: AstPtr::new(&arms), |
217 | arms: AstPtr::new(&arms), | 215 | }) |
218 | }) | ||
219 | } | ||
220 | } | 216 | } |
221 | } | 217 | } |
222 | } | 218 | } |
@@ -247,9 +243,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
247 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 243 | let (_, source_map) = db.body_with_source_map(self.func.into()); |
248 | 244 | ||
249 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 245 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
250 | if let Some(expr) = source_ptr.value.left() { | 246 | self.sink |
251 | self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); | 247 | .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value }); |
252 | } | ||
253 | } | 248 | } |
254 | } | 249 | } |
255 | } | 250 | } |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 54e31602f..81fc0f63a 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -82,9 +82,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
82 | 82 | ||
83 | for (expr, ty) in inference_result.type_of_expr.iter() { | 83 | for (expr, ty) in inference_result.type_of_expr.iter() { |
84 | let syntax_ptr = match body_source_map.expr_syntax(expr) { | 84 | let syntax_ptr = match body_source_map.expr_syntax(expr) { |
85 | Ok(sp) => { | 85 | Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()), |
86 | sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr())) | ||
87 | } | ||
88 | Err(SyntheticSyntax) => continue, | 86 | Err(SyntheticSyntax) => continue, |
89 | }; | 87 | }; |
90 | types.push((syntax_ptr.clone(), ty)); | 88 | types.push((syntax_ptr.clone(), ty)); |
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index efde9bf73..0b0da6ee4 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use crate::completion::{CompletionContext, Completions}; | 3 | use crate::completion::{CompletionContext, Completions}; |
4 | 4 | ||
5 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 5 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
6 | if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const) { | 6 | if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const && !ctx.record_lit_syntax.is_some()) { |
7 | return; | 7 | return; |
8 | } | 8 | } |
9 | 9 | ||
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 6637afaf7..14a4a14d7 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -227,7 +227,7 @@ impl<'a> CompletionContext<'a> { | |||
227 | self.name_ref_syntax = | 227 | self.name_ref_syntax = |
228 | find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); | 228 | find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); |
229 | let name_range = name_ref.syntax().text_range(); | 229 | let name_range = name_ref.syntax().text_range(); |
230 | if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { | 230 | if ast::RecordField::for_field_name(&name_ref).is_some() { |
231 | self.record_lit_syntax = | 231 | self.record_lit_syntax = |
232 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | 232 | self.sema.find_node_at_offset_with_macros(&original_file, offset); |
233 | } | 233 | } |
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index e9934844e..49a8c74fb 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -216,7 +216,7 @@ pub fn classify_name_ref( | |||
216 | } | 216 | } |
217 | } | 217 | } |
218 | 218 | ||
219 | if let Some(record_field) = ast::RecordField::cast(parent.clone()) { | 219 | if let Some(record_field) = ast::RecordField::for_field_name(name_ref) { |
220 | tested_by!(goto_def_for_record_fields; force); | 220 | tested_by!(goto_def_for_record_fields; force); |
221 | tested_by!(goto_def_for_field_init_shorthand; force); | 221 | tested_by!(goto_def_for_field_init_shorthand; force); |
222 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { | 222 | if let Some((field, local)) = sema.resolve_record_field(&record_field) { |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index a1bd53063..cb30b25a8 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -619,26 +619,39 @@ pub(crate) fn record_field_list(p: &mut Parser) { | |||
619 | let m = p.start(); | 619 | let m = p.start(); |
620 | p.bump(T!['{']); | 620 | p.bump(T!['{']); |
621 | while !p.at(EOF) && !p.at(T!['}']) { | 621 | while !p.at(EOF) && !p.at(T!['}']) { |
622 | let m = p.start(); | ||
623 | // test record_literal_field_with_attr | ||
624 | // fn main() { | ||
625 | // S { #[cfg(test)] field: 1 } | ||
626 | // } | ||
627 | attributes::outer_attributes(p); | ||
628 | |||
622 | match p.current() { | 629 | match p.current() { |
623 | // test record_literal_field_with_attr | 630 | IDENT | INT_NUMBER => { |
624 | // fn main() { | 631 | // test_err record_literal_before_ellipsis_recovery |
625 | // S { #[cfg(test)] field: 1 } | 632 | // fn main() { |
626 | // } | 633 | // S { field ..S::default() } |
627 | IDENT | INT_NUMBER | T![#] => { | 634 | // } |
628 | let m = p.start(); | 635 | if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) { |
629 | attributes::outer_attributes(p); | 636 | name_ref_or_index(p); |
630 | name_ref_or_index(p); | 637 | p.expect(T![:]); |
631 | if p.eat(T![:]) { | ||
632 | expr(p); | ||
633 | } | 638 | } |
639 | expr(p); | ||
634 | m.complete(p, RECORD_FIELD); | 640 | m.complete(p, RECORD_FIELD); |
635 | } | 641 | } |
636 | T![.] if p.at(T![..]) => { | 642 | T![.] if p.at(T![..]) => { |
643 | m.abandon(p); | ||
637 | p.bump(T![..]); | 644 | p.bump(T![..]); |
638 | expr(p); | 645 | expr(p); |
639 | } | 646 | } |
640 | T!['{'] => error_block(p, "expected a field"), | 647 | T!['{'] => { |
641 | _ => p.err_and_bump("expected identifier"), | 648 | error_block(p, "expected a field"); |
649 | m.abandon(p); | ||
650 | } | ||
651 | _ => { | ||
652 | p.err_and_bump("expected identifier"); | ||
653 | m.abandon(p); | ||
654 | } | ||
642 | } | 655 | } |
643 | if !p.at(T!['}']) { | 656 | if !p.at(T!['}']) { |
644 | p.expect(T![,]); | 657 | p.expect(T![,]); |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index 76b7655e6..63e272fbf 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -187,6 +187,36 @@ impl ast::StructDef { | |||
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
190 | impl ast::RecordField { | ||
191 | pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordField> { | ||
192 | let candidate = | ||
193 | field_name.syntax().parent().and_then(ast::RecordField::cast).or_else(|| { | ||
194 | field_name.syntax().ancestors().nth(4).and_then(ast::RecordField::cast) | ||
195 | })?; | ||
196 | if candidate.field_name().as_ref() == Some(field_name) { | ||
197 | Some(candidate) | ||
198 | } else { | ||
199 | None | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /// Deals with field init shorthand | ||
204 | pub fn field_name(&self) -> Option<ast::NameRef> { | ||
205 | if let Some(name_ref) = self.name_ref() { | ||
206 | return Some(name_ref); | ||
207 | } | ||
208 | if let Some(ast::Expr::PathExpr(expr)) = self.expr() { | ||
209 | let path = expr.path()?; | ||
210 | let segment = path.segment()?; | ||
211 | let name_ref = segment.name_ref()?; | ||
212 | if path.qualifier().is_none() { | ||
213 | return Some(name_ref); | ||
214 | } | ||
215 | } | ||
216 | None | ||
217 | } | ||
218 | } | ||
219 | |||
190 | impl ast::EnumVariant { | 220 | impl ast::EnumVariant { |
191 | pub fn parent_enum(&self) -> ast::EnumDef { | 221 | pub fn parent_enum(&self) -> ast::EnumDef { |
192 | self.syntax() | 222 | self.syntax() |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index f0e16dc2b..a796e78b1 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -19,6 +19,11 @@ | |||
19 | //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256> | 19 | //! [RFC]: <https://github.com/rust-lang/rfcs/pull/2256> |
20 | //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> | 20 | //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> |
21 | 21 | ||
22 | #[allow(unused)] | ||
23 | macro_rules! eprintln { | ||
24 | ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; | ||
25 | } | ||
26 | |||
22 | mod syntax_node; | 27 | mod syntax_node; |
23 | mod syntax_error; | 28 | mod syntax_error; |
24 | mod parsing; | 29 | mod parsing; |
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast new file mode 100644 index 000000000..75043c9c0 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast | |||
@@ -0,0 +1,49 @@ | |||
1 | SOURCE_FILE@[0; 45) | ||
2 | FN_DEF@[0; 44) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 7) | ||
6 | IDENT@[3; 7) "main" | ||
7 | PARAM_LIST@[7; 9) | ||
8 | L_PAREN@[7; 8) "(" | ||
9 | R_PAREN@[8; 9) ")" | ||
10 | WHITESPACE@[9; 10) " " | ||
11 | BLOCK_EXPR@[10; 44) | ||
12 | BLOCK@[10; 44) | ||
13 | L_CURLY@[10; 11) "{" | ||
14 | WHITESPACE@[11; 16) "\n " | ||
15 | RECORD_LIT@[16; 42) | ||
16 | PATH@[16; 17) | ||
17 | PATH_SEGMENT@[16; 17) | ||
18 | NAME_REF@[16; 17) | ||
19 | IDENT@[16; 17) "S" | ||
20 | WHITESPACE@[17; 18) " " | ||
21 | RECORD_FIELD_LIST@[18; 42) | ||
22 | L_CURLY@[18; 19) "{" | ||
23 | WHITESPACE@[19; 20) " " | ||
24 | RECORD_FIELD@[20; 40) | ||
25 | NAME_REF@[20; 25) | ||
26 | IDENT@[20; 25) "field" | ||
27 | WHITESPACE@[25; 26) " " | ||
28 | RANGE_EXPR@[26; 40) | ||
29 | DOT2@[26; 28) ".." | ||
30 | CALL_EXPR@[28; 40) | ||
31 | PATH_EXPR@[28; 38) | ||
32 | PATH@[28; 38) | ||
33 | PATH@[28; 29) | ||
34 | PATH_SEGMENT@[28; 29) | ||
35 | NAME_REF@[28; 29) | ||
36 | IDENT@[28; 29) "S" | ||
37 | COLON2@[29; 31) "::" | ||
38 | PATH_SEGMENT@[31; 38) | ||
39 | NAME_REF@[31; 38) | ||
40 | IDENT@[31; 38) "default" | ||
41 | ARG_LIST@[38; 40) | ||
42 | L_PAREN@[38; 39) "(" | ||
43 | R_PAREN@[39; 40) ")" | ||
44 | WHITESPACE@[40; 41) " " | ||
45 | R_CURLY@[41; 42) "}" | ||
46 | WHITESPACE@[42; 43) "\n" | ||
47 | R_CURLY@[43; 44) "}" | ||
48 | WHITESPACE@[44; 45) "\n" | ||
49 | error [25; 25): expected COLON | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs new file mode 100644 index 000000000..a4e5b2f69 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | fn main() { | ||
2 | S { field ..S::default() } | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast b/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast index f4206858b..89a611799 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast +++ b/crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast | |||
@@ -35,8 +35,11 @@ SOURCE_FILE@[0; 112) | |||
35 | L_CURLY@[27; 28) "{" | 35 | L_CURLY@[27; 28) "{" |
36 | WHITESPACE@[28; 29) " " | 36 | WHITESPACE@[28; 29) " " |
37 | RECORD_FIELD@[29; 30) | 37 | RECORD_FIELD@[29; 30) |
38 | NAME_REF@[29; 30) | 38 | PATH_EXPR@[29; 30) |
39 | IDENT@[29; 30) "x" | 39 | PATH@[29; 30) |
40 | PATH_SEGMENT@[29; 30) | ||
41 | NAME_REF@[29; 30) | ||
42 | IDENT@[29; 30) "x" | ||
40 | COMMA@[30; 31) "," | 43 | COMMA@[30; 31) "," |
41 | WHITESPACE@[31; 32) " " | 44 | WHITESPACE@[31; 32) " " |
42 | RECORD_FIELD@[32; 37) | 45 | RECORD_FIELD@[32; 37) |
@@ -62,8 +65,11 @@ SOURCE_FILE@[0; 112) | |||
62 | L_CURLY@[48; 49) "{" | 65 | L_CURLY@[48; 49) "{" |
63 | WHITESPACE@[49; 50) " " | 66 | WHITESPACE@[49; 50) " " |
64 | RECORD_FIELD@[50; 51) | 67 | RECORD_FIELD@[50; 51) |
65 | NAME_REF@[50; 51) | 68 | PATH_EXPR@[50; 51) |
66 | IDENT@[50; 51) "x" | 69 | PATH@[50; 51) |
70 | PATH_SEGMENT@[50; 51) | ||
71 | NAME_REF@[50; 51) | ||
72 | IDENT@[50; 51) "x" | ||
67 | COMMA@[51; 52) "," | 73 | COMMA@[51; 52) "," |
68 | WHITESPACE@[52; 53) " " | 74 | WHITESPACE@[52; 53) " " |
69 | RECORD_FIELD@[53; 58) | 75 | RECORD_FIELD@[53; 58) |
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 75cf2dae5..e9ee0b888 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -163,10 +163,7 @@ pub fn analysis_stats( | |||
163 | if let Ok(src) = src { | 163 | if let Ok(src) = src { |
164 | let original_file = src.file_id.original_file(db); | 164 | let original_file = src.file_id.original_file(db); |
165 | let line_index = host.analysis().file_line_index(original_file).unwrap(); | 165 | let line_index = host.analysis().file_line_index(original_file).unwrap(); |
166 | let text_range = src.value.either( | 166 | let text_range = src.value.syntax_node_ptr().range(); |
167 | |it| it.syntax_node_ptr().range(), | ||
168 | |it| it.syntax_node_ptr().range(), | ||
169 | ); | ||
170 | let (start, end) = ( | 167 | let (start, end) = ( |
171 | line_index.line_col(text_range.start()), | 168 | line_index.line_col(text_range.start()), |
172 | line_index.line_col(text_range.end()), | 169 | line_index.line_col(text_range.end()), |
@@ -192,12 +189,7 @@ pub fn analysis_stats( | |||
192 | // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly | 189 | // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly |
193 | // But also, we should just turn the type mismatches into diagnostics and provide these | 190 | // But also, we should just turn the type mismatches into diagnostics and provide these |
194 | let root = db.parse_or_expand(src.file_id).unwrap(); | 191 | let root = db.parse_or_expand(src.file_id).unwrap(); |
195 | let node = src.map(|e| { | 192 | let node = src.map(|e| e.to_node(&root).syntax().clone()); |
196 | e.either( | ||
197 | |p| p.to_node(&root).syntax().clone(), | ||
198 | |p| p.to_node(&root).syntax().clone(), | ||
199 | ) | ||
200 | }); | ||
201 | let original_range = original_range(db, node.as_ref()); | 193 | let original_range = original_range(db, node.as_ref()); |
202 | let path = db.file_relative_path(original_range.file_id); | 194 | let path = db.file_relative_path(original_range.file_id); |
203 | let line_index = | 195 | let line_index = |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 3b60c55f3..4164bfd5e 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -395,7 +395,7 @@ pub fn skip_slow_tests() -> bool { | |||
395 | should_skip | 395 | should_skip |
396 | } | 396 | } |
397 | 397 | ||
398 | const REWRITE: bool = true; | 398 | const REWRITE: bool = false; |
399 | 399 | ||
400 | /// Asserts that `expected` and `actual` strings are equal. If they differ only | 400 | /// Asserts that `expected` and `actual` strings are equal. If they differ only |
401 | /// in trailing or leading whitespace the test won't fail and | 401 | /// in trailing or leading whitespace the test won't fail and |