aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/code_model.rs6
-rw-r--r--crates/ra_hir/src/code_model/src.rs2
-rw-r--r--crates/ra_hir/src/diagnostics.rs81
-rw-r--r--crates/ra_hir/src/expr/validation.rs3
-rw-r--r--crates/ra_hir/src/lib.rs4
-rw-r--r--crates/ra_hir/src/mock.rs3
-rw-r--r--crates/ra_hir/src/nameres.rs5
-rw-r--r--crates/ra_hir/src/ty/infer.rs12
-rw-r--r--crates/ra_hir_def/src/lib.rs17
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs85
-rw-r--r--crates/ra_hir_expand/src/lib.rs21
11 files changed, 130 insertions, 109 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index c97ea18a2..5b78bdfef 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -11,14 +11,16 @@ use hir_def::{
11 type_ref::{Mutability, TypeRef}, 11 type_ref::{Mutability, TypeRef},
12 CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, 12 CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId,
13}; 13};
14use hir_expand::name::{self, AsName}; 14use hir_expand::{
15 diagnostics::DiagnosticSink,
16 name::{self, AsName},
17};
15use ra_db::{CrateId, Edition}; 18use ra_db::{CrateId, Edition};
16use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 19use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
17 20
18use crate::{ 21use crate::{
19 adt::VariantDef, 22 adt::VariantDef,
20 db::{AstDatabase, DefDatabase, HirDatabase}, 23 db::{AstDatabase, DefDatabase, HirDatabase},
21 diagnostics::DiagnosticSink,
22 expr::{validation::ExprValidator, Body, BodySourceMap}, 24 expr::{validation::ExprValidator, Body, BodySourceMap},
23 generics::HasGenericParams, 25 generics::HasGenericParams,
24 ids::{ 26 ids::{
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 0f4c78df7..bd0c3c226 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -10,7 +10,7 @@ use crate::{
10 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, 10 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
11}; 11};
12 12
13pub use hir_def::Source; 13pub use hir_expand::Source;
14 14
15pub trait HasSource { 15pub trait HasSource {
16 type Ast; 16 type Ast;
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index 9acdaf8ed..a33af8f46 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -1,82 +1,13 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{any::Any, fmt}; 3use std::any::Any;
4 4
5use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; 5use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
6use relative_path::RelativePathBuf; 6use relative_path::RelativePathBuf;
7 7
8use crate::{db::HirDatabase, HirFileId, Name, Source}; 8use crate::{db::AstDatabase, HirFileId, Name, Source};
9
10/// Diagnostic defines hir API for errors and warnings.
11///
12/// It is used as a `dyn` object, which you can downcast to a concrete
13/// diagnostic. DiagnosticSink are structured, meaning that they include rich
14/// information which can be used by IDE to create fixes. DiagnosticSink are
15/// expressed in terms of macro-expanded syntax tree nodes (so, it's a bad idea
16/// to diagnostic in a salsa value).
17///
18/// Internally, various subsystems of hir produce diagnostics specific to a
19/// subsystem (typically, an `enum`), which are safe to store in salsa but do not
20/// include source locations. Such internal diagnostic are transformed into an
21/// instance of `Diagnostic` on demand.
22pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
23 fn message(&self) -> String;
24 fn source(&self) -> Source<SyntaxNodePtr>;
25 fn highlight_range(&self) -> TextRange {
26 self.source().ast.range()
27 }
28 fn as_any(&self) -> &(dyn Any + Send + 'static);
29}
30
31pub trait AstDiagnostic {
32 type AST;
33 fn ast(&self, db: &impl HirDatabase) -> Self::AST;
34}
35
36impl dyn Diagnostic {
37 pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode {
38 let node = db.parse_or_expand(self.source().file_id).unwrap();
39 self.source().ast.to_node(&node)
40 }
41
42 pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> {
43 self.as_any().downcast_ref()
44 }
45}
46 9
47pub struct DiagnosticSink<'a> { 10pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
48 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
49 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
50}
51
52impl<'a> DiagnosticSink<'a> {
53 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> {
54 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) }
55 }
56
57 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> {
58 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
59 Some(d) => {
60 cb(d);
61 Ok(())
62 }
63 None => Err(()),
64 };
65 self.callbacks.push(Box::new(cb));
66 self
67 }
68
69 pub(crate) fn push(&mut self, d: impl Diagnostic) {
70 let d: &dyn Diagnostic = &d;
71 for cb in self.callbacks.iter_mut() {
72 match cb(d) {
73 Ok(()) => return,
74 Err(()) => (),
75 }
76 }
77 (self.default_callback)(d)
78 }
79}
80 11
81#[derive(Debug)] 12#[derive(Debug)]
82pub struct NoSuchField { 13pub struct NoSuchField {
@@ -139,7 +70,7 @@ impl Diagnostic for MissingFields {
139impl AstDiagnostic for MissingFields { 70impl AstDiagnostic for MissingFields {
140 type AST = ast::RecordFieldList; 71 type AST = ast::RecordFieldList;
141 72
142 fn ast(&self, db: &impl HirDatabase) -> Self::AST { 73 fn ast(&self, db: &impl AstDatabase) -> Self::AST {
143 let root = db.parse_or_expand(self.source().file_id).unwrap(); 74 let root = db.parse_or_expand(self.source().file_id).unwrap();
144 let node = self.source().ast.to_node(&root); 75 let node = self.source().ast.to_node(&root);
145 ast::RecordFieldList::cast(node).unwrap() 76 ast::RecordFieldList::cast(node).unwrap()
@@ -167,7 +98,7 @@ impl Diagnostic for MissingOkInTailExpr {
167impl AstDiagnostic for MissingOkInTailExpr { 98impl AstDiagnostic for MissingOkInTailExpr {
168 type AST = ast::Expr; 99 type AST = ast::Expr;
169 100
170 fn ast(&self, db: &impl HirDatabase) -> Self::AST { 101 fn ast(&self, db: &impl AstDatabase) -> Self::AST {
171 let root = db.parse_or_expand(self.file).unwrap(); 102 let root = db.parse_or_expand(self.file).unwrap();
172 let node = self.source().ast.to_node(&root); 103 let node = self.source().ast.to_node(&root);
173 ast::Expr::cast(node).unwrap() 104 ast::Expr::cast(node).unwrap()
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index c685edda1..3054f1dce 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -3,12 +3,13 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::path::known; 5use hir_def::path::known;
6use hir_expand::diagnostics::DiagnosticSink;
6use ra_syntax::ast; 7use ra_syntax::ast;
7use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
8 9
9use crate::{ 10use crate::{
10 db::HirDatabase, 11 db::HirDatabase,
11 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, 12 diagnostics::{MissingFields, MissingOkInTailExpr},
12 expr::AstPtr, 13 expr::AstPtr,
13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, 14 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
14 Adt, Function, Name, Path, 15 Adt, Function, Name, Path,
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 40f5562b4..0ba17e571 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -62,7 +62,7 @@ pub use crate::{
62 adt::VariantDef, 62 adt::VariantDef,
63 code_model::{ 63 code_model::{
64 docs::{DocDef, Docs, Documentation}, 64 docs::{DocDef, Docs, Documentation},
65 src::{HasBodySource, HasSource, Source}, 65 src::{HasBodySource, HasSource},
66 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, 66 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
67 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, 67 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef,
68 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, 68 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
@@ -85,4 +85,4 @@ pub use hir_def::{
85 path::{Path, PathKind}, 85 path::{Path, PathKind},
86 type_ref::Mutability, 86 type_ref::Mutability,
87}; 87};
88pub use hir_expand::{either::Either, name::Name}; 88pub use hir_expand::{either::Either, name::Name, Source};
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 35dfaf3ba..4c89c8d38 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -2,6 +2,7 @@
2 2
3use std::{panic, sync::Arc}; 3use std::{panic, sync::Arc};
4 4
5use hir_expand::diagnostics::DiagnosticSink;
5use parking_lot::Mutex; 6use parking_lot::Mutex;
6use ra_cfg::CfgOptions; 7use ra_cfg::CfgOptions;
7use ra_db::{ 8use ra_db::{
@@ -12,7 +13,7 @@ use relative_path::{RelativePath, RelativePathBuf};
12use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
13use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 14use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
14 15
15use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink}; 16use crate::{db, debug::HirDebugHelper};
16 17
17pub const WORKSPACE: SourceRootId = SourceRootId(0); 18pub const WORKSPACE: SourceRootId = SourceRootId(0);
18 19
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 7ba031827..32a6ab474 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -55,6 +55,7 @@ mod tests;
55use std::sync::Arc; 55use std::sync::Arc;
56 56
57use hir_def::{builtin_type::BuiltinType, CrateModuleId}; 57use hir_def::{builtin_type::BuiltinType, CrateModuleId};
58use hir_expand::diagnostics::DiagnosticSink;
58use once_cell::sync::Lazy; 59use once_cell::sync::Lazy;
59use ra_arena::Arena; 60use ra_arena::Arena;
60use ra_db::{Edition, FileId}; 61use ra_db::{Edition, FileId};
@@ -65,7 +66,6 @@ use test_utils::tested_by;
65 66
66use crate::{ 67use crate::{
67 db::{AstDatabase, DefDatabase}, 68 db::{AstDatabase, DefDatabase},
68 diagnostics::DiagnosticSink,
69 ids::MacroDefId, 69 ids::MacroDefId,
70 nameres::diagnostics::DefDiagnostic, 70 nameres::diagnostics::DefDiagnostic,
71 Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, 71 Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait,
@@ -513,12 +513,13 @@ impl CrateDefMap {
513} 513}
514 514
515mod diagnostics { 515mod diagnostics {
516 use hir_expand::diagnostics::DiagnosticSink;
516 use ra_syntax::{ast, AstPtr}; 517 use ra_syntax::{ast, AstPtr};
517 use relative_path::RelativePathBuf; 518 use relative_path::RelativePathBuf;
518 519
519 use crate::{ 520 use crate::{
520 db::{AstDatabase, DefDatabase}, 521 db::{AstDatabase, DefDatabase},
521 diagnostics::{DiagnosticSink, UnresolvedModule}, 522 diagnostics::UnresolvedModule,
522 nameres::CrateModuleId, 523 nameres::CrateModuleId,
523 AstId, 524 AstId,
524 }; 525 };
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 6694467a3..2370e8d4f 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -25,7 +25,7 @@ use hir_def::{
25 path::known, 25 path::known,
26 type_ref::{Mutability, TypeRef}, 26 type_ref::{Mutability, TypeRef},
27}; 27};
28use hir_expand::name; 28use hir_expand::{diagnostics::DiagnosticSink, name};
29use ra_arena::map::ArenaMap; 29use ra_arena::map::ArenaMap;
30use ra_prof::profile; 30use ra_prof::profile;
31use test_utils::tested_by; 31use test_utils::tested_by;
@@ -40,7 +40,6 @@ use crate::{
40 adt::VariantDef, 40 adt::VariantDef,
41 code_model::TypeAlias, 41 code_model::TypeAlias,
42 db::HirDatabase, 42 db::HirDatabase,
43 diagnostics::DiagnosticSink,
44 expr::{BindingAnnotation, Body, ExprId, PatId}, 43 expr::{BindingAnnotation, Body, ExprId, PatId},
45 resolve::{Resolver, TypeNs}, 44 resolve::{Resolver, TypeNs},
46 ty::infer::diagnostics::InferenceDiagnostic, 45 ty::infer::diagnostics::InferenceDiagnostic,
@@ -719,12 +718,9 @@ impl Expectation {
719} 718}
720 719
721mod diagnostics { 720mod diagnostics {
722 use crate::{ 721 use hir_expand::diagnostics::DiagnosticSink;
723 db::HirDatabase, 722
724 diagnostics::{DiagnosticSink, NoSuchField}, 723 use crate::{db::HirDatabase, diagnostics::NoSuchField, expr::ExprId, Function, HasSource};
725 expr::ExprId,
726 Function, HasSource,
727 };
728 724
729 #[derive(Debug, PartialEq, Eq, Clone)] 725 #[derive(Debug, PartialEq, Eq, Clone)]
730 pub(super) enum InferenceDiagnostic { 726 pub(super) enum InferenceDiagnostic {
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 76d5f1852..6d66f481d 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -19,19 +19,13 @@ pub mod nameres;
19 19
20use std::hash::{Hash, Hasher}; 20use std::hash::{Hash, Hasher};
21 21
22use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; 22use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, Source};
23use ra_arena::{impl_arena_id, RawId}; 23use ra_arena::{impl_arena_id, RawId};
24use ra_db::{salsa, CrateId, FileId}; 24use ra_db::{salsa, CrateId, FileId};
25use ra_syntax::{ast, AstNode, SyntaxNode}; 25use ra_syntax::{ast, AstNode, SyntaxNode};
26 26
27use crate::{builtin_type::BuiltinType, db::InternDatabase}; 27use crate::{builtin_type::BuiltinType, db::InternDatabase};
28 28
29#[derive(Debug, PartialEq, Eq, Clone, Copy)]
30pub struct Source<T> {
31 pub file_id: HirFileId,
32 pub ast: T,
33}
34
35pub enum ModuleSource { 29pub enum ModuleSource {
36 SourceFile(ast::SourceFile), 30 SourceFile(ast::SourceFile),
37 Module(ast::Module), 31 Module(ast::Module),
@@ -94,15 +88,6 @@ impl ModuleSource {
94 } 88 }
95} 89}
96 90
97impl<T> Source<T> {
98 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
99 Source { file_id: self.file_id, ast: f(self.ast) }
100 }
101 pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
102 db.parse_or_expand(self.file_id).expect("source created from invalid file")
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 91#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
107pub struct ModuleId { 92pub struct ModuleId {
108 pub krate: CrateId, 93 pub krate: CrateId,
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
new file mode 100644
index 000000000..201884b95
--- /dev/null
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -0,0 +1,85 @@
1//! Semantic errors and warnings.
2//!
3//! The `Diagnostic` trait defines a trait object which can represent any
4//! diagnostic.
5//!
6//! `DiagnosticSink` struct is used as an emitter for diagnostic. When creating
7//! a `DiagnosticSink`, you supply a callback which can react to a `dyn
8//! Diagnostic` or to any concrete diagnostic (downcasting is sued internally).
9//!
10//! Because diagnostics store file offsets, it's a bad idea to store them
11//! directly in salsa. For this reason, every hir subsytem defines it's own
12//! strongly-typed closed set of diagnostics which use hir ids internally, are
13//! stored in salsa and do *not* implement the `Diagnostic` trait. Instead, a
14//! subsystem provides a separate, non-query-based API which can walk all stored
15//! values and transform them into instances of `Diagnostic`.
16
17use std::{any::Any, fmt};
18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange};
20
21use crate::{db::AstDatabase, Source};
22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String;
25 fn source(&self) -> Source<SyntaxNodePtr>;
26 fn highlight_range(&self) -> TextRange {
27 self.source().ast.range()
28 }
29 fn as_any(&self) -> &(dyn Any + Send + 'static);
30}
31
32pub trait AstDiagnostic {
33 type AST;
34 fn ast(&self, db: &impl AstDatabase) -> Self::AST;
35}
36
37impl dyn Diagnostic {
38 pub fn syntax_node(&self, db: &impl AstDatabase) -> SyntaxNode {
39 let node = db.parse_or_expand(self.source().file_id).unwrap();
40 self.source().ast.to_node(&node)
41 }
42
43 pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> {
44 self.as_any().downcast_ref()
45 }
46}
47
48pub struct DiagnosticSink<'a> {
49 callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>,
50 default_callback: Box<dyn FnMut(&dyn Diagnostic) + 'a>,
51}
52
53impl<'a> DiagnosticSink<'a> {
54 /// FIXME: split `new` and `on` into a separate builder type
55 pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> {
56 DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) }
57 }
58
59 pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> DiagnosticSink<'a> {
60 let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() {
61 Some(d) => {
62 cb(d);
63 Ok(())
64 }
65 None => Err(()),
66 };
67 self.callbacks.push(Box::new(cb));
68 self
69 }
70
71 pub fn push(&mut self, d: impl Diagnostic) {
72 let d: &dyn Diagnostic = &d;
73 self._push(d);
74 }
75
76 fn _push(&mut self, d: &dyn Diagnostic) {
77 for cb in self.callbacks.iter_mut() {
78 match cb(d) {
79 Ok(()) => return,
80 Err(()) => (),
81 }
82 }
83 (self.default_callback)(d)
84 }
85}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 5a0e5a19c..dd07a16b4 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -9,11 +9,15 @@ pub mod ast_id_map;
9pub mod either; 9pub mod either;
10pub mod name; 10pub mod name;
11pub mod hygiene; 11pub mod hygiene;
12pub mod diagnostics;
12 13
13use std::hash::{Hash, Hasher}; 14use std::hash::{Hash, Hasher};
14 15
15use ra_db::{salsa, CrateId, FileId}; 16use ra_db::{salsa, CrateId, FileId};
16use ra_syntax::ast::{self, AstNode}; 17use ra_syntax::{
18 ast::{self, AstNode},
19 SyntaxNode,
20};
17 21
18use crate::ast_id_map::FileAstId; 22use crate::ast_id_map::FileAstId;
19 23
@@ -151,3 +155,18 @@ impl<N: AstNode> AstId<N> {
151 db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) 155 db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
152 } 156 }
153} 157}
158
159#[derive(Debug, PartialEq, Eq, Clone, Copy)]
160pub struct Source<T> {
161 pub file_id: HirFileId,
162 pub ast: T,
163}
164
165impl<T> Source<T> {
166 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
167 Source { file_id: self.file_id, ast: f(self.ast) }
168 }
169 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
170 db.parse_or_expand(self.file_id).expect("source created from invalid file")
171 }
172}