diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-25 11:38:46 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-25 11:38:46 +0000 |
commit | c4ead49361e4b8c0586b810399c8e96a468b891c (patch) | |
tree | 0b1ba767e34e3baef938f6b7672f95ce4572ec07 /crates/ra_hir/src/expr.rs | |
parent | 8aedf9603df1bc68eafcd8dcf3c14e5a6a2c8638 (diff) | |
parent | 309716cffe93d065bcad0344b0f332425576c1e5 (diff) |
Merge #1034
1034: HIR diagnostics API r=matklad a=matklad
This PR introduces diagnostics API for HIR, so we can now start issuing errors and warnings! Here are requirements that this solution aims to fulfill:
* structured diagnostics: rather than immediately rendering error to string, we provide a well-typed blob of data with error-description. These data is used by IDE to provide fixes
* open set diagnostics: there's no single enum with all possible diagnostics, which hopefully should result in better modularity
The `Diagnostic` trait describes "a diagnostic", which can be downcast to a specific diagnostic kind. Diagnostics are expressed in terms of macro-expanded syntax tree: they store pointers to syntax nodes. Diagnostics are self-contained: you don't need any context, besides `db`, to fully understand the meaning of a diagnostic.
Because diagnostics are tied to the source, we can't store them in salsa. So subsystems like type-checking produce subsystem-local diagnostic (which is a closed `enum`), which is expressed in therms of subsystem IR. A separate step converts these proto-diagnostics into `Diagnostic`, by merging them with source-maps.
Note that this PR stresses type-system quite a bit: we now type-check every function in open files to compute errors!
Discussion on Zulip: https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Diagnostics.20API
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/expr.rs')
-rw-r--r-- | crates/ra_hir/src/expr.rs | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index c37fd0454..a85422955 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -5,7 +5,7 @@ use rustc_hash::FxHashMap; | |||
5 | 5 | ||
6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; |
7 | use ra_syntax::{ | 7 | use ra_syntax::{ |
8 | SyntaxNodePtr, AstNode, | 8 | SyntaxNodePtr, AstPtr, AstNode, |
9 | ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor, TypeAscriptionOwner} | 9 | ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor, TypeAscriptionOwner} |
10 | }; | 10 | }; |
11 | 11 | ||
@@ -54,6 +54,7 @@ pub struct BodySourceMap { | |||
54 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, | 54 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, |
55 | pat_map: FxHashMap<SyntaxNodePtr, PatId>, | 55 | pat_map: FxHashMap<SyntaxNodePtr, PatId>, |
56 | pat_map_back: ArenaMap<PatId, SyntaxNodePtr>, | 56 | pat_map_back: ArenaMap<PatId, SyntaxNodePtr>, |
57 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::NamedField>>, | ||
57 | } | 58 | } |
58 | 59 | ||
59 | impl Body { | 60 | impl Body { |
@@ -138,6 +139,10 @@ impl BodySourceMap { | |||
138 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | 139 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { |
139 | self.pat_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() | 140 | self.pat_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() |
140 | } | 141 | } |
142 | |||
143 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { | ||
144 | self.field_map[&(expr, field)].clone() | ||
145 | } | ||
141 | } | 146 | } |
142 | 147 | ||
143 | #[derive(Debug, Clone, Eq, PartialEq)] | 148 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -629,8 +634,10 @@ impl ExprCollector { | |||
629 | } | 634 | } |
630 | ast::ExprKind::StructLit(e) => { | 635 | ast::ExprKind::StructLit(e) => { |
631 | let path = e.path().and_then(Path::from_ast); | 636 | let path = e.path().and_then(Path::from_ast); |
637 | let mut field_ptrs = Vec::new(); | ||
632 | let fields = if let Some(nfl) = e.named_field_list() { | 638 | let fields = if let Some(nfl) = e.named_field_list() { |
633 | nfl.fields() | 639 | nfl.fields() |
640 | .inspect(|field| field_ptrs.push(AstPtr::new(*field))) | ||
634 | .map(|field| StructLitField { | 641 | .map(|field| StructLitField { |
635 | name: field | 642 | name: field |
636 | .name_ref() | 643 | .name_ref() |
@@ -657,7 +664,11 @@ impl ExprCollector { | |||
657 | Vec::new() | 664 | Vec::new() |
658 | }; | 665 | }; |
659 | let spread = e.spread().map(|s| self.collect_expr(s)); | 666 | let spread = e.spread().map(|s| self.collect_expr(s)); |
660 | self.alloc_expr(Expr::StructLit { path, fields, spread }, syntax_ptr) | 667 | let res = self.alloc_expr(Expr::StructLit { path, fields, spread }, syntax_ptr); |
668 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | ||
669 | self.source_map.field_map.insert((res, i), ptr); | ||
670 | } | ||
671 | res | ||
661 | } | 672 | } |
662 | ast::ExprKind::FieldExpr(e) => { | 673 | ast::ExprKind::FieldExpr(e) => { |
663 | let expr = self.collect_expr_opt(e.expr()); | 674 | let expr = self.collect_expr_opt(e.expr()); |