diff options
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/hir/src/source_analyzer.rs | 24 | ||||
| -rw-r--r-- | crates/hir_def/src/body.rs | 19 | ||||
| -rw-r--r-- | crates/hir_def/src/body/lower.rs | 24 | ||||
| -rw-r--r-- | crates/hir_ty/src/infer.rs | 6 | ||||
| -rw-r--r-- | crates/hir_ty/src/infer/expr.rs | 5 |
5 files changed, 33 insertions, 45 deletions
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 055a3e5d0..4d59293e9 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
| @@ -24,7 +24,7 @@ use hir_ty::{ | |||
| 24 | }; | 24 | }; |
| 25 | use syntax::{ | 25 | use syntax::{ |
| 26 | ast::{self, AstNode}, | 26 | ast::{self, AstNode}, |
| 27 | AstPtr, SyntaxNode, TextRange, TextSize, | 27 | SyntaxNode, TextRange, TextSize, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | use crate::{ | 30 | use crate::{ |
| @@ -161,26 +161,8 @@ impl SourceAnalyzer { | |||
| 161 | db: &dyn HirDatabase, | 161 | db: &dyn HirDatabase, |
| 162 | field: &ast::RecordExprField, | 162 | field: &ast::RecordExprField, |
| 163 | ) -> Option<(Field, Option<Local>)> { | 163 | ) -> Option<(Field, Option<Local>)> { |
| 164 | let expr_id = { | 164 | let expr_id = |
| 165 | let record_lit = field.parent_record_lit(); | 165 | self.body_source_map.as_ref()?.node_field(InFile::new(self.file_id, field))?; |
| 166 | let record_lit_expr = self.expr_id(db, &ast::Expr::from(record_lit))?; | ||
| 167 | let body = self.body.as_ref()?; | ||
| 168 | let body_source_map = self.body_source_map.as_ref()?; | ||
| 169 | match &body[record_lit_expr] { | ||
| 170 | hir_def::expr::Expr::RecordLit { fields, .. } => { | ||
| 171 | let field_ptr = InFile::new(self.file_id, AstPtr::new(field)); | ||
| 172 | fields.iter().enumerate().find_map(|(i, f)| { | ||
| 173 | let ptr = body_source_map.field_syntax(record_lit_expr, i); | ||
| 174 | if ptr == field_ptr { | ||
| 175 | Some(f.expr) | ||
| 176 | } else { | ||
| 177 | None | ||
| 178 | } | ||
| 179 | })? | ||
| 180 | } | ||
| 181 | _ => return None, | ||
| 182 | } | ||
| 183 | }; | ||
| 184 | 166 | ||
| 185 | let local = if field.name_ref().is_some() { | 167 | let local = if field.name_ref().is_some() { |
| 186 | None | 168 | None |
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 19c4eb521..8bcc350ce 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
| @@ -253,11 +253,18 @@ pub type LabelSource = InFile<LabelPtr>; | |||
| 253 | pub struct BodySourceMap { | 253 | pub struct BodySourceMap { |
| 254 | expr_map: FxHashMap<ExprSource, ExprId>, | 254 | expr_map: FxHashMap<ExprSource, ExprId>, |
| 255 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, | 255 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, |
| 256 | |||
| 256 | pat_map: FxHashMap<PatSource, PatId>, | 257 | pat_map: FxHashMap<PatSource, PatId>, |
| 257 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, | 258 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, |
| 259 | |||
| 258 | label_map: FxHashMap<LabelSource, LabelId>, | 260 | label_map: FxHashMap<LabelSource, LabelId>, |
| 259 | label_map_back: ArenaMap<LabelId, LabelSource>, | 261 | label_map_back: ArenaMap<LabelId, LabelSource>, |
| 260 | field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordExprField>>>, | 262 | |
| 263 | /// We don't create explicit nodes for record fields (`S { record_field: 92 }`). | ||
| 264 | /// Instead, we use id of expression (`92`) to identify the field. | ||
| 265 | field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>, | ||
| 266 | field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>, | ||
| 267 | |||
| 261 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, | 268 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, |
| 262 | 269 | ||
| 263 | /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in | 270 | /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in |
| @@ -337,6 +344,8 @@ impl Index<LabelId> for Body { | |||
| 337 | } | 344 | } |
| 338 | } | 345 | } |
| 339 | 346 | ||
| 347 | // FIXME: Change `node_` prefix to something more reasonable. | ||
| 348 | // Perhaps `expr_syntax` and `expr_id`? | ||
| 340 | impl BodySourceMap { | 349 | impl BodySourceMap { |
| 341 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { | 350 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { |
| 342 | self.expr_map_back[expr].clone() | 351 | self.expr_map_back[expr].clone() |
| @@ -375,8 +384,12 @@ impl BodySourceMap { | |||
| 375 | self.label_map.get(&src).cloned() | 384 | self.label_map.get(&src).cloned() |
| 376 | } | 385 | } |
| 377 | 386 | ||
| 378 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordExprField>> { | 387 | pub fn field_syntax(&self, expr: ExprId) -> InFile<AstPtr<ast::RecordExprField>> { |
| 379 | self.field_map[&(expr, field)].clone() | 388 | self.field_map_back[&expr].clone() |
| 389 | } | ||
| 390 | pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> { | ||
| 391 | let src = node.map(|it| AstPtr::new(it)); | ||
| 392 | self.field_map.get(&src).cloned() | ||
| 380 | } | 393 | } |
| 381 | 394 | ||
| 382 | pub(crate) fn add_diagnostics(&self, _db: &dyn DefDatabase, sink: &mut DiagnosticSink<'_>) { | 395 | pub(crate) fn add_diagnostics(&self, _db: &dyn DefDatabase, sink: &mut DiagnosticSink<'_>) { |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 8c8eb8007..8934ae6c9 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
| @@ -379,23 +379,22 @@ impl ExprCollector<'_> { | |||
| 379 | } | 379 | } |
| 380 | ast::Expr::RecordExpr(e) => { | 380 | ast::Expr::RecordExpr(e) => { |
| 381 | let path = e.path().and_then(|path| self.expander.parse_path(path)); | 381 | let path = e.path().and_then(|path| self.expander.parse_path(path)); |
| 382 | let mut field_ptrs = Vec::new(); | ||
| 383 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { | 382 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { |
| 384 | let fields = nfl | 383 | let fields = nfl |
| 385 | .fields() | 384 | .fields() |
| 386 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) | ||
| 387 | .filter_map(|field| { | 385 | .filter_map(|field| { |
| 388 | self.check_cfg(&field)?; | 386 | self.check_cfg(&field)?; |
| 389 | 387 | ||
| 390 | let name = field.field_name()?.as_name(); | 388 | let name = field.field_name()?.as_name(); |
| 391 | 389 | ||
| 392 | Some(RecordLitField { | 390 | let expr = match field.expr() { |
| 393 | name, | 391 | Some(e) => self.collect_expr(e), |
| 394 | expr: match field.expr() { | 392 | None => self.missing_expr(), |
| 395 | Some(e) => self.collect_expr(e), | 393 | }; |
| 396 | None => self.missing_expr(), | 394 | let src = self.expander.to_source(AstPtr::new(&field)); |
| 397 | }, | 395 | self.source_map.field_map.insert(src.clone(), expr); |
| 398 | }) | 396 | self.source_map.field_map_back.insert(expr, src); |
| 397 | Some(RecordLitField { name, expr }) | ||
| 399 | }) | 398 | }) |
| 400 | .collect(); | 399 | .collect(); |
| 401 | let spread = nfl.spread().map(|s| self.collect_expr(s)); | 400 | let spread = nfl.spread().map(|s| self.collect_expr(s)); |
| @@ -404,12 +403,7 @@ impl ExprCollector<'_> { | |||
| 404 | Expr::RecordLit { path, fields: Vec::new(), spread: None } | 403 | Expr::RecordLit { path, fields: Vec::new(), spread: None } |
| 405 | }; | 404 | }; |
| 406 | 405 | ||
| 407 | let res = self.alloc_expr(record_lit, syntax_ptr); | 406 | self.alloc_expr(record_lit, syntax_ptr) |
| 408 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | ||
| 409 | let src = self.expander.to_source(ptr); | ||
| 410 | self.source_map.field_map.insert((res, i), src); | ||
| 411 | } | ||
| 412 | res | ||
| 413 | } | 407 | } |
| 414 | ast::Expr::FieldExpr(e) => { | 408 | ast::Expr::FieldExpr(e) => { |
| 415 | let expr = self.collect_expr_opt(e.expr()); | 409 | let expr = self.collect_expr_opt(e.expr()); |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index fbfedb4e6..9f29098ee 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
| @@ -784,7 +784,7 @@ mod diagnostics { | |||
| 784 | 784 | ||
| 785 | #[derive(Debug, PartialEq, Eq, Clone)] | 785 | #[derive(Debug, PartialEq, Eq, Clone)] |
| 786 | pub(super) enum InferenceDiagnostic { | 786 | pub(super) enum InferenceDiagnostic { |
| 787 | NoSuchField { expr: ExprId, field: usize }, | 787 | NoSuchField { expr: ExprId }, |
| 788 | BreakOutsideOfLoop { expr: ExprId }, | 788 | BreakOutsideOfLoop { expr: ExprId }, |
| 789 | } | 789 | } |
| 790 | 790 | ||
| @@ -796,9 +796,9 @@ mod diagnostics { | |||
| 796 | sink: &mut DiagnosticSink, | 796 | sink: &mut DiagnosticSink, |
| 797 | ) { | 797 | ) { |
| 798 | match self { | 798 | match self { |
| 799 | InferenceDiagnostic::NoSuchField { expr, field } => { | 799 | InferenceDiagnostic::NoSuchField { expr } => { |
| 800 | let (_, source_map) = db.body_with_source_map(owner); | 800 | let (_, source_map) = db.body_with_source_map(owner); |
| 801 | let field = source_map.field_syntax(*expr, *field); | 801 | let field = source_map.field_syntax(*expr); |
| 802 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | 802 | sink.push(NoSuchField { file: field.file_id, field: field.value }) |
| 803 | } | 803 | } |
| 804 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | 804 | InferenceDiagnostic::BreakOutsideOfLoop { expr } => { |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 55163c963..1a11b146a 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
| @@ -405,14 +405,13 @@ impl<'a> InferenceContext<'a> { | |||
| 405 | let substs = ty.substs().cloned().unwrap_or_else(Substs::empty); | 405 | let substs = ty.substs().cloned().unwrap_or_else(Substs::empty); |
| 406 | let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); | 406 | let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); |
| 407 | let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it)); | 407 | let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it)); |
| 408 | for (field_idx, field) in fields.iter().enumerate() { | 408 | for field in fields.iter() { |
| 409 | let field_def = | 409 | let field_def = |
| 410 | variant_data.as_ref().and_then(|it| match it.field(&field.name) { | 410 | variant_data.as_ref().and_then(|it| match it.field(&field.name) { |
| 411 | Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }), | 411 | Some(local_id) => Some(FieldId { parent: def_id.unwrap(), local_id }), |
| 412 | None => { | 412 | None => { |
| 413 | self.push_diagnostic(InferenceDiagnostic::NoSuchField { | 413 | self.push_diagnostic(InferenceDiagnostic::NoSuchField { |
| 414 | expr: tgt_expr, | 414 | expr: field.expr, |
| 415 | field: field_idx, | ||
| 416 | }); | 415 | }); |
| 417 | None | 416 | None |
| 418 | } | 417 | } |
