diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_analysis/src/db.rs | 1 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/function.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/module.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/query_definitions.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 195 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0003_paths.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/data/0003_paths.txt | 9 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 6 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 2 |
16 files changed, 214 insertions, 87 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index f26c49887..780a84291 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -94,6 +94,7 @@ salsa::database_storage! { | |||
94 | fn fn_syntax() for hir::db::FnSyntaxQuery; | 94 | fn fn_syntax() for hir::db::FnSyntaxQuery; |
95 | fn submodules() for hir::db::SubmodulesQuery; | 95 | fn submodules() for hir::db::SubmodulesQuery; |
96 | fn infer() for hir::db::InferQuery; | 96 | fn infer() for hir::db::InferQuery; |
97 | fn type_for_def() for hir::db::TypeForDefQuery; | ||
97 | } | 98 | } |
98 | } | 99 | } |
99 | } | 100 | } |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index f2912d235..40996bfd7 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -524,7 +524,7 @@ impl AnalysisImpl { | |||
524 | let function = ctry!(source_binder::function_from_source( | 524 | let function = ctry!(source_binder::function_from_source( |
525 | &*self.db, file_id, parent_fn | 525 | &*self.db, file_id, parent_fn |
526 | )?); | 526 | )?); |
527 | let infer = function.infer(&*self.db); | 527 | let infer = function.infer(&*self.db)?; |
528 | Ok(infer.type_of_node(node).map(|t| t.to_string())) | 528 | Ok(infer.type_of_node(node).map(|t| t.to_string())) |
529 | } | 529 | } |
530 | 530 | ||
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 61650cee9..594176337 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -16,3 +16,6 @@ ra_syntax = { path = "../ra_syntax" } | |||
16 | ra_editor = { path = "../ra_editor" } | 16 | ra_editor = { path = "../ra_editor" } |
17 | ra_db = { path = "../ra_db" } | 17 | ra_db = { path = "../ra_db" } |
18 | test_utils = { path = "../test_utils" } | 18 | test_utils = { path = "../test_utils" } |
19 | |||
20 | [dev-dependencies] | ||
21 | flexi_logger = "0.10.0" | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index f0bff3c02..d94f75857 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | function::FnId, | 14 | function::FnId, |
15 | module::{ModuleId, ModuleTree, ModuleSource, | 15 | module::{ModuleId, ModuleTree, ModuleSource, |
16 | nameres::{ItemMap, InputModuleItems}}, | 16 | nameres::{ItemMap, InputModuleItems}}, |
17 | ty::InferenceResult, | 17 | ty::{InferenceResult, Ty}, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | salsa::query_group! { | 20 | salsa::query_group! { |
@@ -31,11 +31,16 @@ pub trait HirDatabase: SyntaxDatabase | |||
31 | use fn query_definitions::fn_syntax; | 31 | use fn query_definitions::fn_syntax; |
32 | } | 32 | } |
33 | 33 | ||
34 | fn infer(fn_id: FnId) -> Arc<InferenceResult> { | 34 | fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> { |
35 | type InferQuery; | 35 | type InferQuery; |
36 | use fn query_definitions::infer; | 36 | use fn query_definitions::infer; |
37 | } | 37 | } |
38 | 38 | ||
39 | fn type_for_def(def_id: DefId) -> Cancelable<Ty> { | ||
40 | type TypeForDefQuery; | ||
41 | use fn query_definitions::type_for_def; | ||
42 | } | ||
43 | |||
39 | fn file_items(file_id: FileId) -> Arc<SourceFileItems> { | 44 | fn file_items(file_id: FileId) -> Arc<SourceFileItems> { |
40 | type SourceFileItemsQuery; | 45 | type SourceFileItemsQuery; |
41 | use fn query_definitions::file_items; | 46 | use fn query_definitions::file_items; |
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs index 360e9e9a0..d36477b48 100644 --- a/crates/ra_hir/src/function.rs +++ b/crates/ra_hir/src/function.rs | |||
@@ -5,12 +5,13 @@ use std::{ | |||
5 | sync::Arc, | 5 | sync::Arc, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_db::Cancelable; | ||
8 | use ra_syntax::{ | 9 | use ra_syntax::{ |
9 | TextRange, TextUnit, | 10 | TextRange, TextUnit, |
10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 11 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
11 | }; | 12 | }; |
12 | 13 | ||
13 | use crate::{ DefId, HirDatabase, ty::InferenceResult }; | 14 | use crate::{ DefId, HirDatabase, ty::InferenceResult, Module }; |
14 | 15 | ||
15 | pub use self::scope::FnScopes; | 16 | pub use self::scope::FnScopes; |
16 | 17 | ||
@@ -18,7 +19,7 @@ pub use self::scope::FnScopes; | |||
18 | pub struct FnId(pub(crate) DefId); | 19 | pub struct FnId(pub(crate) DefId); |
19 | 20 | ||
20 | pub struct Function { | 21 | pub struct Function { |
21 | fn_id: FnId, | 22 | pub(crate) fn_id: FnId, |
22 | } | 23 | } |
23 | 24 | ||
24 | impl Function { | 25 | impl Function { |
@@ -27,6 +28,10 @@ impl Function { | |||
27 | Function { fn_id } | 28 | Function { fn_id } |
28 | } | 29 | } |
29 | 30 | ||
31 | pub fn syntax(&self, db: &impl HirDatabase) -> ast::FnDefNode { | ||
32 | db.fn_syntax(self.fn_id) | ||
33 | } | ||
34 | |||
30 | pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> { | 35 | pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> { |
31 | db.fn_scopes(self.fn_id) | 36 | db.fn_scopes(self.fn_id) |
32 | } | 37 | } |
@@ -36,9 +41,14 @@ impl Function { | |||
36 | FnSignatureInfo::new(syntax.borrowed()) | 41 | FnSignatureInfo::new(syntax.borrowed()) |
37 | } | 42 | } |
38 | 43 | ||
39 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 44 | pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> { |
40 | db.infer(self.fn_id) | 45 | db.infer(self.fn_id) |
41 | } | 46 | } |
47 | |||
48 | pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { | ||
49 | let loc = self.fn_id.0.loc(db); | ||
50 | Module::new(db, loc.source_root_id, loc.module_id) | ||
51 | } | ||
42 | } | 52 | } |
43 | 53 | ||
44 | #[derive(Debug, Clone)] | 54 | #[derive(Debug, Clone)] |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index e84f44675..a0d99a84d 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -29,7 +29,7 @@ mod ty; | |||
29 | 29 | ||
30 | use std::ops::Index; | 30 | use std::ops::Index; |
31 | 31 | ||
32 | use ra_syntax::{SyntaxNodeRef, SyntaxNode}; | 32 | use ra_syntax::{SyntaxNodeRef, SyntaxNode, SyntaxKind}; |
33 | use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable}; | 33 | use ra_db::{LocationIntener, SourceRootId, FileId, Cancelable}; |
34 | 34 | ||
35 | use crate::{ | 35 | use crate::{ |
@@ -67,6 +67,23 @@ pub struct DefLoc { | |||
67 | source_item_id: SourceItemId, | 67 | source_item_id: SourceItemId, |
68 | } | 68 | } |
69 | 69 | ||
70 | impl DefKind { | ||
71 | pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> { | ||
72 | match kind { | ||
73 | SyntaxKind::FN_DEF => Some(DefKind::Function), | ||
74 | SyntaxKind::MODULE => Some(DefKind::Module), | ||
75 | // These define items, but don't have their own DefKinds yet: | ||
76 | SyntaxKind::STRUCT_DEF => Some(DefKind::Item), | ||
77 | SyntaxKind::ENUM_DEF => Some(DefKind::Item), | ||
78 | SyntaxKind::TRAIT_DEF => Some(DefKind::Item), | ||
79 | SyntaxKind::TYPE_DEF => Some(DefKind::Item), | ||
80 | SyntaxKind::CONST_DEF => Some(DefKind::Item), | ||
81 | SyntaxKind::STATIC_DEF => Some(DefKind::Item), | ||
82 | _ => None, | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
70 | impl DefId { | 87 | impl DefId { |
71 | pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc { | 88 | pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc { |
72 | db.as_ref().id2loc(self) | 89 | db.as_ref().id2loc(self) |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 3020ee793..b5a997170 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -192,6 +192,7 @@ salsa::database_storage! { | |||
192 | fn fn_syntax() for db::FnSyntaxQuery; | 192 | fn fn_syntax() for db::FnSyntaxQuery; |
193 | fn submodules() for db::SubmodulesQuery; | 193 | fn submodules() for db::SubmodulesQuery; |
194 | fn infer() for db::InferQuery; | 194 | fn infer() for db::InferQuery; |
195 | fn type_for_def() for db::TypeForDefQuery; | ||
195 | } | 196 | } |
196 | } | 197 | } |
197 | } | 198 | } |
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index cd31e8cfe..891119953 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs | |||
@@ -2,6 +2,7 @@ pub(super) mod imp; | |||
2 | pub(super) mod nameres; | 2 | pub(super) mod nameres; |
3 | 3 | ||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | use log; | ||
5 | 6 | ||
6 | use ra_syntax::{ | 7 | use ra_syntax::{ |
7 | algo::generate, | 8 | algo::generate, |
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 39e891cda..0b152a406 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -272,13 +272,13 @@ where | |||
272 | } | 272 | } |
273 | } | 273 | } |
274 | } | 274 | } |
275 | // Populate explicitelly declared items, except modules | 275 | // Populate explicitly declared items, except modules |
276 | for item in input.items.iter() { | 276 | for item in input.items.iter() { |
277 | if item.kind == MODULE { | 277 | if item.kind == MODULE { |
278 | continue; | 278 | continue; |
279 | } | 279 | } |
280 | let def_loc = DefLoc { | 280 | let def_loc = DefLoc { |
281 | kind: DefKind::Item, | 281 | kind: DefKind::for_syntax_kind(item.kind).unwrap_or(DefKind::Item), |
282 | source_root_id: self.source_root, | 282 | source_root_id: self.source_root, |
283 | module_id, | 283 | module_id, |
284 | source_item_id: SourceItemId { | 284 | source_item_id: SourceItemId { |
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index ccbfdf028..b654af920 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | use ra_db::{SourceRootId, FileId, Cancelable,}; | 11 | use ra_db::{SourceRootId, FileId, Cancelable,}; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | SourceFileItems, SourceItemId, DefKind, | 14 | SourceFileItems, SourceItemId, DefKind, Function, DefId, |
15 | db::HirDatabase, | 15 | db::HirDatabase, |
16 | function::{FnScopes, FnId}, | 16 | function::{FnScopes, FnId}, |
17 | module::{ | 17 | module::{ |
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | imp::Submodule, | 19 | imp::Submodule, |
20 | nameres::{InputModuleItems, ItemMap, Resolver}, | 20 | nameres::{InputModuleItems, ItemMap, Resolver}, |
21 | }, | 21 | }, |
22 | ty::{self, InferenceResult} | 22 | ty::{self, InferenceResult, Ty} |
23 | }; | 23 | }; |
24 | 24 | ||
25 | /// Resolve `FnId` to the corresponding `SyntaxNode` | 25 | /// Resolve `FnId` to the corresponding `SyntaxNode` |
@@ -36,11 +36,13 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> { | |||
36 | Arc::new(res) | 36 | Arc::new(res) |
37 | } | 37 | } |
38 | 38 | ||
39 | pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Arc<InferenceResult> { | 39 | pub(super) fn infer(db: &impl HirDatabase, fn_id: FnId) -> Cancelable<Arc<InferenceResult>> { |
40 | let syntax = db.fn_syntax(fn_id); | 40 | let function = Function { fn_id }; |
41 | let scopes = db.fn_scopes(fn_id); | 41 | ty::infer(db, function).map(Arc::new) |
42 | let res = ty::infer(db, syntax.borrowed(), scopes); | 42 | } |
43 | Arc::new(res) | 43 | |
44 | pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { | ||
45 | ty::type_for_def(db, def_id) | ||
44 | } | 46 | } |
45 | 47 | ||
46 | pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { | 48 | pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 615a1caed..13ee6cb27 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -5,21 +5,17 @@ mod tests; | |||
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | use std::fmt; | 6 | use std::fmt; |
7 | 7 | ||
8 | use log; | ||
8 | use rustc_hash::{FxHashMap}; | 9 | use rustc_hash::{FxHashMap}; |
9 | 10 | ||
10 | use ra_db::LocalSyntaxPtr; | 11 | use ra_db::{LocalSyntaxPtr, Cancelable}; |
11 | use ra_syntax::{ | 12 | use ra_syntax::{ |
12 | SmolStr, | 13 | SmolStr, |
13 | ast::{self, AstNode, LoopBodyOwner, ArgListOwner}, | 14 | ast::{self, AstNode, LoopBodyOwner, ArgListOwner}, |
14 | SyntaxNodeRef | 15 | SyntaxNodeRef |
15 | }; | 16 | }; |
16 | 17 | ||
17 | use crate::{ | 18 | use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase}; |
18 | FnScopes, | ||
19 | db::HirDatabase, | ||
20 | }; | ||
21 | |||
22 | // pub(crate) type TypeId = Id<Ty>; | ||
23 | 19 | ||
24 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | 20 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
25 | pub enum Ty { | 21 | pub enum Ty { |
@@ -65,18 +61,6 @@ pub enum Ty { | |||
65 | /// `&'a mut T` or `&'a T`. | 61 | /// `&'a mut T` or `&'a T`. |
66 | // Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), | 62 | // Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability), |
67 | 63 | ||
68 | /// The anonymous type of a function declaration/definition. Each | ||
69 | /// function has a unique type, which is output (for a function | ||
70 | /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`. | ||
71 | /// | ||
72 | /// For example the type of `bar` here: | ||
73 | /// | ||
74 | /// ```rust | ||
75 | /// fn foo() -> i32 { 1 } | ||
76 | /// let bar = foo; // bar: fn() -> i32 {foo} | ||
77 | /// ``` | ||
78 | // FnDef(DefId, &'tcx Substs<'tcx>), | ||
79 | |||
80 | /// A pointer to a function. Written as `fn() -> i32`. | 64 | /// A pointer to a function. Written as `fn() -> i32`. |
81 | /// | 65 | /// |
82 | /// For example the type of `bar` here: | 66 | /// For example the type of `bar` here: |
@@ -85,7 +69,7 @@ pub enum Ty { | |||
85 | /// fn foo() -> i32 { 1 } | 69 | /// fn foo() -> i32 { 1 } |
86 | /// let bar: fn() -> i32 = foo; | 70 | /// let bar: fn() -> i32 = foo; |
87 | /// ``` | 71 | /// ``` |
88 | // FnPtr(PolyFnSig<'tcx>), | 72 | FnPtr(Arc<FnSig>), |
89 | 73 | ||
90 | /// A trait, defined with `trait`. | 74 | /// A trait, defined with `trait`. |
91 | // Dynamic(Binder<&'tcx List<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>), | 75 | // Dynamic(Binder<&'tcx List<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>), |
@@ -139,6 +123,12 @@ pub enum Ty { | |||
139 | 123 | ||
140 | type TyRef = Arc<Ty>; | 124 | type TyRef = Arc<Ty>; |
141 | 125 | ||
126 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||
127 | pub struct FnSig { | ||
128 | input: Vec<Ty>, | ||
129 | output: Ty, | ||
130 | } | ||
131 | |||
142 | impl Ty { | 132 | impl Ty { |
143 | pub fn new(node: ast::TypeRef) -> Self { | 133 | pub fn new(node: ast::TypeRef) -> Self { |
144 | use ra_syntax::ast::TypeRef::*; | 134 | use ra_syntax::ast::TypeRef::*; |
@@ -208,11 +198,55 @@ impl fmt::Display for Ty { | |||
208 | } | 198 | } |
209 | write!(f, ")") | 199 | write!(f, ")") |
210 | } | 200 | } |
201 | Ty::FnPtr(sig) => { | ||
202 | write!(f, "fn(")?; | ||
203 | for t in &sig.input { | ||
204 | write!(f, "{},", t)?; | ||
205 | } | ||
206 | write!(f, ") -> {}", sig.output) | ||
207 | } | ||
211 | Ty::Unknown => write!(f, "[unknown]"), | 208 | Ty::Unknown => write!(f, "[unknown]"), |
212 | } | 209 | } |
213 | } | 210 | } |
214 | } | 211 | } |
215 | 212 | ||
213 | pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { | ||
214 | eprintln!("type_for_fn {:?}", f.fn_id); | ||
215 | let syntax = f.syntax(db); | ||
216 | let node = syntax.borrowed(); | ||
217 | // TODO we ignore type parameters for now | ||
218 | let input = node | ||
219 | .param_list() | ||
220 | .map(|pl| { | ||
221 | pl.params() | ||
222 | .map(|p| p.type_ref().map(|t| Ty::new(t)).unwrap_or(Ty::Unknown)) | ||
223 | .collect() | ||
224 | }) | ||
225 | .unwrap_or_else(Vec::new); | ||
226 | let output = node | ||
227 | .ret_type() | ||
228 | .and_then(|rt| rt.type_ref()) | ||
229 | .map(|t| Ty::new(t)) | ||
230 | .unwrap_or(Ty::Unknown); | ||
231 | let sig = FnSig { input, output }; | ||
232 | Ok(Ty::FnPtr(Arc::new(sig))) | ||
233 | } | ||
234 | |||
235 | pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { | ||
236 | let def = def_id.resolve(db)?; | ||
237 | match def { | ||
238 | Def::Module(..) => { | ||
239 | log::debug!("trying to get type for module {:?}", def_id); | ||
240 | Ok(Ty::Unknown) | ||
241 | } | ||
242 | Def::Function(f) => type_for_fn(db, f), | ||
243 | Def::Item => { | ||
244 | log::debug!("trying to get type for item of unknown type {:?}", def_id); | ||
245 | Ok(Ty::Unknown) | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
216 | #[derive(Clone, PartialEq, Eq, Debug)] | 250 | #[derive(Clone, PartialEq, Eq, Debug)] |
217 | pub struct InferenceResult { | 251 | pub struct InferenceResult { |
218 | type_for: FxHashMap<LocalSyntaxPtr, Ty>, | 252 | type_for: FxHashMap<LocalSyntaxPtr, Ty>, |
@@ -224,18 +258,22 @@ impl InferenceResult { | |||
224 | } | 258 | } |
225 | } | 259 | } |
226 | 260 | ||
227 | #[derive(Clone, PartialEq, Eq, Debug)] | 261 | #[derive(Clone, Debug)] |
228 | pub struct InferenceContext { | 262 | pub struct InferenceContext<'a, D: HirDatabase> { |
263 | db: &'a D, | ||
229 | scopes: Arc<FnScopes>, | 264 | scopes: Arc<FnScopes>, |
265 | module: Module, | ||
230 | // TODO unification tables... | 266 | // TODO unification tables... |
231 | type_for: FxHashMap<LocalSyntaxPtr, Ty>, | 267 | type_for: FxHashMap<LocalSyntaxPtr, Ty>, |
232 | } | 268 | } |
233 | 269 | ||
234 | impl InferenceContext { | 270 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
235 | fn new(scopes: Arc<FnScopes>) -> Self { | 271 | fn new(db: &'a D, scopes: Arc<FnScopes>, module: Module) -> Self { |
236 | InferenceContext { | 272 | InferenceContext { |
237 | type_for: FxHashMap::default(), | 273 | type_for: FxHashMap::default(), |
274 | db, | ||
238 | scopes, | 275 | scopes, |
276 | module, | ||
239 | } | 277 | } |
240 | } | 278 | } |
241 | 279 | ||
@@ -262,36 +300,42 @@ impl InferenceContext { | |||
262 | self.unify(ty1, ty2) | 300 | self.unify(ty1, ty2) |
263 | } | 301 | } |
264 | 302 | ||
265 | fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Option<Ty> { | 303 | fn infer_path_expr(&mut self, expr: ast::PathExpr) -> Cancelable<Option<Ty>> { |
266 | let p = expr.path()?; | 304 | let ast_path = ctry!(expr.path()); |
267 | if p.qualifier().is_none() { | 305 | let path = ctry!(Path::from_ast(ast_path)); |
268 | let name = p.segment().and_then(|s| s.name_ref())?; | 306 | if path.is_ident() { |
269 | let scope_entry = self.scopes.resolve_local_name(name)?; | 307 | // resolve locally |
270 | let ty = self.type_for.get(&scope_entry.ptr())?; | 308 | let name = ctry!(ast_path.segment().and_then(|s| s.name_ref())); |
271 | Some(ty.clone()) | 309 | if let Some(scope_entry) = self.scopes.resolve_local_name(name) { |
272 | } else { | 310 | let ty = ctry!(self.type_for.get(&scope_entry.ptr())); |
273 | // TODO resolve path | 311 | return Ok(Some(ty.clone())); |
274 | Some(Ty::Unknown) | 312 | }; |
275 | } | 313 | }; |
314 | |||
315 | // resolve in module | ||
316 | let resolved = ctry!(self.module.resolve_path(self.db, path)?); | ||
317 | let ty = self.db.type_for_def(resolved)?; | ||
318 | // TODO we will need to add type variables for type parameters etc. here | ||
319 | Ok(Some(ty)) | ||
276 | } | 320 | } |
277 | 321 | ||
278 | fn infer_expr(&mut self, expr: ast::Expr) -> Ty { | 322 | fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> { |
279 | let ty = match expr { | 323 | let ty = match expr { |
280 | ast::Expr::IfExpr(e) => { | 324 | ast::Expr::IfExpr(e) => { |
281 | if let Some(condition) = e.condition() { | 325 | if let Some(condition) = e.condition() { |
282 | if let Some(e) = condition.expr() { | 326 | if let Some(e) = condition.expr() { |
283 | // TODO if no pat, this should be bool | 327 | // TODO if no pat, this should be bool |
284 | self.infer_expr(e); | 328 | self.infer_expr(e)?; |
285 | } | 329 | } |
286 | // TODO write type for pat | 330 | // TODO write type for pat |
287 | }; | 331 | }; |
288 | let if_ty = if let Some(block) = e.then_branch() { | 332 | let if_ty = if let Some(block) = e.then_branch() { |
289 | self.infer_block(block) | 333 | self.infer_block(block)? |
290 | } else { | 334 | } else { |
291 | Ty::Unknown | 335 | Ty::Unknown |
292 | }; | 336 | }; |
293 | let else_ty = if let Some(block) = e.else_branch() { | 337 | let else_ty = if let Some(block) = e.else_branch() { |
294 | self.infer_block(block) | 338 | self.infer_block(block)? |
295 | } else { | 339 | } else { |
296 | Ty::Unknown | 340 | Ty::Unknown |
297 | }; | 341 | }; |
@@ -304,14 +348,14 @@ impl InferenceContext { | |||
304 | } | 348 | } |
305 | ast::Expr::BlockExpr(e) => { | 349 | ast::Expr::BlockExpr(e) => { |
306 | if let Some(block) = e.block() { | 350 | if let Some(block) = e.block() { |
307 | self.infer_block(block) | 351 | self.infer_block(block)? |
308 | } else { | 352 | } else { |
309 | Ty::Unknown | 353 | Ty::Unknown |
310 | } | 354 | } |
311 | } | 355 | } |
312 | ast::Expr::LoopExpr(e) => { | 356 | ast::Expr::LoopExpr(e) => { |
313 | if let Some(block) = e.loop_body() { | 357 | if let Some(block) = e.loop_body() { |
314 | self.infer_block(block); | 358 | self.infer_block(block)?; |
315 | }; | 359 | }; |
316 | // TODO never, or the type of the break param | 360 | // TODO never, or the type of the break param |
317 | Ty::Unknown | 361 | Ty::Unknown |
@@ -320,59 +364,69 @@ impl InferenceContext { | |||
320 | if let Some(condition) = e.condition() { | 364 | if let Some(condition) = e.condition() { |
321 | if let Some(e) = condition.expr() { | 365 | if let Some(e) = condition.expr() { |
322 | // TODO if no pat, this should be bool | 366 | // TODO if no pat, this should be bool |
323 | self.infer_expr(e); | 367 | self.infer_expr(e)?; |
324 | } | 368 | } |
325 | // TODO write type for pat | 369 | // TODO write type for pat |
326 | }; | 370 | }; |
327 | if let Some(block) = e.loop_body() { | 371 | if let Some(block) = e.loop_body() { |
328 | // TODO | 372 | // TODO |
329 | self.infer_block(block); | 373 | self.infer_block(block)?; |
330 | }; | 374 | }; |
331 | // TODO always unit? | 375 | // TODO always unit? |
332 | Ty::Unknown | 376 | Ty::Unknown |
333 | } | 377 | } |
334 | ast::Expr::ForExpr(e) => { | 378 | ast::Expr::ForExpr(e) => { |
335 | if let Some(expr) = e.iterable() { | 379 | if let Some(expr) = e.iterable() { |
336 | self.infer_expr(expr); | 380 | self.infer_expr(expr)?; |
337 | } | 381 | } |
338 | if let Some(_pat) = e.pat() { | 382 | if let Some(_pat) = e.pat() { |
339 | // TODO write type for pat | 383 | // TODO write type for pat |
340 | } | 384 | } |
341 | if let Some(block) = e.loop_body() { | 385 | if let Some(block) = e.loop_body() { |
342 | self.infer_block(block); | 386 | self.infer_block(block)?; |
343 | } | 387 | } |
344 | // TODO always unit? | 388 | // TODO always unit? |
345 | Ty::Unknown | 389 | Ty::Unknown |
346 | } | 390 | } |
347 | ast::Expr::LambdaExpr(e) => { | 391 | ast::Expr::LambdaExpr(e) => { |
348 | let _body_ty = if let Some(body) = e.body() { | 392 | let _body_ty = if let Some(body) = e.body() { |
349 | self.infer_expr(body) | 393 | self.infer_expr(body)? |
350 | } else { | 394 | } else { |
351 | Ty::Unknown | 395 | Ty::Unknown |
352 | }; | 396 | }; |
353 | Ty::Unknown | 397 | Ty::Unknown |
354 | } | 398 | } |
355 | ast::Expr::CallExpr(e) => { | 399 | ast::Expr::CallExpr(e) => { |
400 | let _callee_ty = if let Some(e) = e.expr() { | ||
401 | self.infer_expr(e)? | ||
402 | } else { | ||
403 | Ty::Unknown | ||
404 | }; | ||
356 | if let Some(arg_list) = e.arg_list() { | 405 | if let Some(arg_list) = e.arg_list() { |
357 | for arg in arg_list.args() { | 406 | for arg in arg_list.args() { |
358 | // TODO unify / expect argument type | 407 | // TODO unify / expect argument type |
359 | self.infer_expr(arg); | 408 | self.infer_expr(arg)?; |
360 | } | 409 | } |
361 | } | 410 | } |
362 | Ty::Unknown | 411 | Ty::Unknown |
363 | } | 412 | } |
364 | ast::Expr::MethodCallExpr(e) => { | 413 | ast::Expr::MethodCallExpr(e) => { |
414 | let _receiver_ty = if let Some(e) = e.expr() { | ||
415 | self.infer_expr(e)? | ||
416 | } else { | ||
417 | Ty::Unknown | ||
418 | }; | ||
365 | if let Some(arg_list) = e.arg_list() { | 419 | if let Some(arg_list) = e.arg_list() { |
366 | for arg in arg_list.args() { | 420 | for arg in arg_list.args() { |
367 | // TODO unify / expect argument type | 421 | // TODO unify / expect argument type |
368 | self.infer_expr(arg); | 422 | self.infer_expr(arg)?; |
369 | } | 423 | } |
370 | } | 424 | } |
371 | Ty::Unknown | 425 | Ty::Unknown |
372 | } | 426 | } |
373 | ast::Expr::MatchExpr(e) => { | 427 | ast::Expr::MatchExpr(e) => { |
374 | let _ty = if let Some(match_expr) = e.expr() { | 428 | let _ty = if let Some(match_expr) = e.expr() { |
375 | self.infer_expr(match_expr) | 429 | self.infer_expr(match_expr)? |
376 | } else { | 430 | } else { |
377 | Ty::Unknown | 431 | Ty::Unknown |
378 | }; | 432 | }; |
@@ -381,7 +435,7 @@ impl InferenceContext { | |||
381 | // TODO type the bindings in pat | 435 | // TODO type the bindings in pat |
382 | // TODO type the guard | 436 | // TODO type the guard |
383 | let _ty = if let Some(e) = arm.expr() { | 437 | let _ty = if let Some(e) = arm.expr() { |
384 | self.infer_expr(e) | 438 | self.infer_expr(e)? |
385 | } else { | 439 | } else { |
386 | Ty::Unknown | 440 | Ty::Unknown |
387 | }; | 441 | }; |
@@ -394,12 +448,12 @@ impl InferenceContext { | |||
394 | } | 448 | } |
395 | ast::Expr::TupleExpr(_e) => Ty::Unknown, | 449 | ast::Expr::TupleExpr(_e) => Ty::Unknown, |
396 | ast::Expr::ArrayExpr(_e) => Ty::Unknown, | 450 | ast::Expr::ArrayExpr(_e) => Ty::Unknown, |
397 | ast::Expr::PathExpr(e) => self.infer_path_expr(e).unwrap_or(Ty::Unknown), | 451 | ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown), |
398 | ast::Expr::ContinueExpr(_e) => Ty::Never, | 452 | ast::Expr::ContinueExpr(_e) => Ty::Never, |
399 | ast::Expr::BreakExpr(_e) => Ty::Never, | 453 | ast::Expr::BreakExpr(_e) => Ty::Never, |
400 | ast::Expr::ParenExpr(e) => { | 454 | ast::Expr::ParenExpr(e) => { |
401 | if let Some(e) = e.expr() { | 455 | if let Some(e) = e.expr() { |
402 | self.infer_expr(e) | 456 | self.infer_expr(e)? |
403 | } else { | 457 | } else { |
404 | Ty::Unknown | 458 | Ty::Unknown |
405 | } | 459 | } |
@@ -408,7 +462,7 @@ impl InferenceContext { | |||
408 | ast::Expr::ReturnExpr(e) => { | 462 | ast::Expr::ReturnExpr(e) => { |
409 | if let Some(e) = e.expr() { | 463 | if let Some(e) = e.expr() { |
410 | // TODO unify with return type | 464 | // TODO unify with return type |
411 | self.infer_expr(e); | 465 | self.infer_expr(e)?; |
412 | }; | 466 | }; |
413 | Ty::Never | 467 | Ty::Never |
414 | } | 468 | } |
@@ -425,7 +479,7 @@ impl InferenceContext { | |||
425 | ast::Expr::FieldExpr(_e) => Ty::Unknown, | 479 | ast::Expr::FieldExpr(_e) => Ty::Unknown, |
426 | ast::Expr::TryExpr(e) => { | 480 | ast::Expr::TryExpr(e) => { |
427 | let _inner_ty = if let Some(e) = e.expr() { | 481 | let _inner_ty = if let Some(e) = e.expr() { |
428 | self.infer_expr(e) | 482 | self.infer_expr(e)? |
429 | } else { | 483 | } else { |
430 | Ty::Unknown | 484 | Ty::Unknown |
431 | }; | 485 | }; |
@@ -433,7 +487,7 @@ impl InferenceContext { | |||
433 | } | 487 | } |
434 | ast::Expr::CastExpr(e) => { | 488 | ast::Expr::CastExpr(e) => { |
435 | let _inner_ty = if let Some(e) = e.expr() { | 489 | let _inner_ty = if let Some(e) = e.expr() { |
436 | self.infer_expr(e) | 490 | self.infer_expr(e)? |
437 | } else { | 491 | } else { |
438 | Ty::Unknown | 492 | Ty::Unknown |
439 | }; | 493 | }; |
@@ -443,7 +497,7 @@ impl InferenceContext { | |||
443 | } | 497 | } |
444 | ast::Expr::RefExpr(e) => { | 498 | ast::Expr::RefExpr(e) => { |
445 | let _inner_ty = if let Some(e) = e.expr() { | 499 | let _inner_ty = if let Some(e) = e.expr() { |
446 | self.infer_expr(e) | 500 | self.infer_expr(e)? |
447 | } else { | 501 | } else { |
448 | Ty::Unknown | 502 | Ty::Unknown |
449 | }; | 503 | }; |
@@ -451,7 +505,7 @@ impl InferenceContext { | |||
451 | } | 505 | } |
452 | ast::Expr::PrefixExpr(e) => { | 506 | ast::Expr::PrefixExpr(e) => { |
453 | let _inner_ty = if let Some(e) = e.expr() { | 507 | let _inner_ty = if let Some(e) = e.expr() { |
454 | self.infer_expr(e) | 508 | self.infer_expr(e)? |
455 | } else { | 509 | } else { |
456 | Ty::Unknown | 510 | Ty::Unknown |
457 | }; | 511 | }; |
@@ -462,10 +516,10 @@ impl InferenceContext { | |||
462 | ast::Expr::Literal(_e) => Ty::Unknown, | 516 | ast::Expr::Literal(_e) => Ty::Unknown, |
463 | }; | 517 | }; |
464 | self.write_ty(expr.syntax(), ty.clone()); | 518 | self.write_ty(expr.syntax(), ty.clone()); |
465 | ty | 519 | Ok(ty) |
466 | } | 520 | } |
467 | 521 | ||
468 | fn infer_block(&mut self, node: ast::Block) -> Ty { | 522 | fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> { |
469 | for stmt in node.statements() { | 523 | for stmt in node.statements() { |
470 | match stmt { | 524 | match stmt { |
471 | ast::Stmt::LetStmt(stmt) => { | 525 | ast::Stmt::LetStmt(stmt) => { |
@@ -476,7 +530,7 @@ impl InferenceContext { | |||
476 | }; | 530 | }; |
477 | let ty = if let Some(expr) = stmt.initializer() { | 531 | let ty = if let Some(expr) = stmt.initializer() { |
478 | // TODO pass expectation | 532 | // TODO pass expectation |
479 | let expr_ty = self.infer_expr(expr); | 533 | let expr_ty = self.infer_expr(expr)?; |
480 | self.unify_with_coercion(&expr_ty, &decl_ty) | 534 | self.unify_with_coercion(&expr_ty, &decl_ty) |
481 | .unwrap_or(decl_ty) | 535 | .unwrap_or(decl_ty) |
482 | } else { | 536 | } else { |
@@ -489,23 +543,28 @@ impl InferenceContext { | |||
489 | } | 543 | } |
490 | ast::Stmt::ExprStmt(expr_stmt) => { | 544 | ast::Stmt::ExprStmt(expr_stmt) => { |
491 | if let Some(expr) = expr_stmt.expr() { | 545 | if let Some(expr) = expr_stmt.expr() { |
492 | self.infer_expr(expr); | 546 | self.infer_expr(expr)?; |
493 | } | 547 | } |
494 | } | 548 | } |
495 | } | 549 | } |
496 | } | 550 | } |
497 | let ty = if let Some(expr) = node.expr() { | 551 | let ty = if let Some(expr) = node.expr() { |
498 | self.infer_expr(expr) | 552 | self.infer_expr(expr)? |
499 | } else { | 553 | } else { |
500 | Ty::unit() | 554 | Ty::unit() |
501 | }; | 555 | }; |
502 | self.write_ty(node.syntax(), ty.clone()); | 556 | self.write_ty(node.syntax(), ty.clone()); |
503 | ty | 557 | Ok(ty) |
504 | } | 558 | } |
505 | } | 559 | } |
506 | 560 | ||
507 | pub fn infer(_db: &impl HirDatabase, node: ast::FnDef, scopes: Arc<FnScopes>) -> InferenceResult { | 561 | pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceResult> { |
508 | let mut ctx = InferenceContext::new(scopes); | 562 | let scopes = function.scopes(db); |
563 | let module = function.module(db)?; | ||
564 | let mut ctx = InferenceContext::new(db, scopes, module); | ||
565 | |||
566 | let syntax = function.syntax(db); | ||
567 | let node = syntax.borrowed(); | ||
509 | 568 | ||
510 | if let Some(param_list) = node.param_list() { | 569 | if let Some(param_list) = node.param_list() { |
511 | for param in param_list.params() { | 570 | for param in param_list.params() { |
@@ -529,12 +588,12 @@ pub fn infer(_db: &impl HirDatabase, node: ast::FnDef, scopes: Arc<FnScopes>) -> | |||
529 | // (see Expectation in rustc_typeck) | 588 | // (see Expectation in rustc_typeck) |
530 | 589 | ||
531 | if let Some(block) = node.body() { | 590 | if let Some(block) = node.body() { |
532 | ctx.infer_block(block); | 591 | ctx.infer_block(block)?; |
533 | } | 592 | } |
534 | 593 | ||
535 | // TODO 'resolve' the types: replace inference variables by their inferred results | 594 | // TODO 'resolve' the types: replace inference variables by their inferred results |
536 | 595 | ||
537 | InferenceResult { | 596 | Ok(InferenceResult { |
538 | type_for: ctx.type_for, | 597 | type_for: ctx.type_for, |
539 | } | 598 | }) |
540 | } | 599 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 0880b51bc..e0458327a 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1,5 +1,8 @@ | |||
1 | use std::fmt::Write; | 1 | use std::fmt::Write; |
2 | use std::path::{PathBuf}; | 2 | use std::path::{PathBuf}; |
3 | use std::sync::Once; | ||
4 | |||
5 | use flexi_logger::Logger; | ||
3 | 6 | ||
4 | use ra_db::{SyntaxDatabase}; | 7 | use ra_db::{SyntaxDatabase}; |
5 | use ra_syntax::ast::{self, AstNode}; | 8 | use ra_syntax::ast::{self, AstNode}; |
@@ -22,7 +25,7 @@ fn infer_file(content: &str) -> String { | |||
22 | let func = source_binder::function_from_source(&db, file_id, fn_def) | 25 | let func = source_binder::function_from_source(&db, file_id, fn_def) |
23 | .unwrap() | 26 | .unwrap() |
24 | .unwrap(); | 27 | .unwrap(); |
25 | let inference_result = func.infer(&db); | 28 | let inference_result = func.infer(&db).unwrap(); |
26 | for (syntax_ptr, ty) in &inference_result.type_for { | 29 | for (syntax_ptr, ty) in &inference_result.type_for { |
27 | let node = syntax_ptr.resolve(&source_file); | 30 | let node = syntax_ptr.resolve(&source_file); |
28 | write!( | 31 | write!( |
@@ -58,6 +61,8 @@ fn ellipsize(mut text: String, max_len: usize) -> String { | |||
58 | 61 | ||
59 | #[test] | 62 | #[test] |
60 | pub fn infer_tests() { | 63 | pub fn infer_tests() { |
64 | static INIT: Once = Once::new(); | ||
65 | INIT.call_once(|| Logger::with_env().start().unwrap()); | ||
61 | dir_tests(&test_data_dir(), &["."], |text, _path| infer_file(text)); | 66 | dir_tests(&test_data_dir(), &["."], |text, _path| infer_file(text)); |
62 | } | 67 | } |
63 | 68 | ||
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.rs b/crates/ra_hir/src/ty/tests/data/0003_paths.rs new file mode 100644 index 000000000..e8b11198b --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/0003_paths.rs | |||
@@ -0,0 +1,10 @@ | |||
1 | fn a() -> u32 { 1 } | ||
2 | |||
3 | mod b { | ||
4 | fn c() -> u32 { 1 } | ||
5 | } | ||
6 | |||
7 | fn test() { | ||
8 | a(); | ||
9 | b::c(); | ||
10 | } | ||
diff --git a/crates/ra_hir/src/ty/tests/data/0003_paths.txt b/crates/ra_hir/src/ty/tests/data/0003_paths.txt new file mode 100644 index 000000000..3a53370a2 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/data/0003_paths.txt | |||
@@ -0,0 +1,9 @@ | |||
1 | [16; 17) '1': [unknown] | ||
2 | [14; 19) '{ 1 }': [unknown] | ||
3 | [47; 52) '{ 1 }': [unknown] | ||
4 | [49; 50) '1': [unknown] | ||
5 | [81; 87) 'b::c()': [unknown] | ||
6 | [66; 90) '{ ...c(); }': () | ||
7 | [72; 73) 'a': fn() -> u32 | ||
8 | [72; 75) 'a()': [unknown] | ||
9 | [81; 85) 'b::c': fn() -> u32 | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index b15c4ef6f..c73533861 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -3083,7 +3083,11 @@ impl<R: TreeRoot<RaTypes>> RetTypeNode<R> { | |||
3083 | } | 3083 | } |
3084 | 3084 | ||
3085 | 3085 | ||
3086 | impl<'a> RetType<'a> {} | 3086 | impl<'a> RetType<'a> { |
3087 | pub fn type_ref(self) -> Option<TypeRef<'a>> { | ||
3088 | super::child_opt(self) | ||
3089 | } | ||
3090 | } | ||
3087 | 3091 | ||
3088 | // ReturnExpr | 3092 | // ReturnExpr |
3089 | #[derive(Debug, Clone, Copy,)] | 3093 | #[derive(Debug, Clone, Copy,)] |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 8dca493ee..e3b9032a0 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -254,7 +254,7 @@ Grammar( | |||
254 | ], | 254 | ], |
255 | options: [ "ParamList", ["body", "Block"], "RetType" ], | 255 | options: [ "ParamList", ["body", "Block"], "RetType" ], |
256 | ), | 256 | ), |
257 | "RetType": (), | 257 | "RetType": (options: ["TypeRef"]), |
258 | "StructDef": ( | 258 | "StructDef": ( |
259 | traits: [ | 259 | traits: [ |
260 | "NameOwner", | 260 | "NameOwner", |