diff options
author | Marco Groppo <[email protected]> | 2019-04-14 23:03:54 +0100 |
---|---|---|
committer | Marco Groppo <[email protected]> | 2019-04-19 23:10:19 +0100 |
commit | e85ee60c42db57368e24ad9ac24840c2494d383c (patch) | |
tree | a94bb45556b404452e2ef282e6d11887f93601ca | |
parent | d55f1136d6444b1f50b9092c36a976d0e1c26202 (diff) |
Initial support for lang items.
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/lang_item.rs | 102 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 54 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 38 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_path.rs | 23 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 14 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 2 |
11 files changed, 204 insertions, 41 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 18627bbc2..b27efcbe3 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -16,6 +16,7 @@ use crate::{ | |||
16 | generics::{GenericParams, GenericDef}, | 16 | generics::{GenericParams, GenericDef}, |
17 | type_ref::TypeRef, | 17 | type_ref::TypeRef, |
18 | traits::TraitData, Trait, ty::TraitRef, | 18 | traits::TraitData, Trait, ty::TraitRef, |
19 | lang_item::LangItems, | ||
19 | ids | 20 | ids |
20 | }; | 21 | }; |
21 | 22 | ||
@@ -100,6 +101,9 @@ pub trait DefDatabase: SourceDatabase { | |||
100 | 101 | ||
101 | #[salsa::invoke(crate::ConstSignature::static_signature_query)] | 102 | #[salsa::invoke(crate::ConstSignature::static_signature_query)] |
102 | fn static_signature(&self, konst: Static) -> Arc<ConstSignature>; | 103 | fn static_signature(&self, konst: Static) -> Arc<ConstSignature>; |
104 | |||
105 | #[salsa::invoke(crate::lang_item::LangItems::lang_items_query)] | ||
106 | fn lang_items(&self, krate: Crate) -> Arc<LangItems>; | ||
103 | } | 107 | } |
104 | 108 | ||
105 | #[salsa::query_group(HirDatabaseStorage)] | 109 | #[salsa::query_group(HirDatabaseStorage)] |
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs new file mode 100644 index 000000000..adcc682a2 --- /dev/null +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -0,0 +1,102 @@ | |||
1 | use std::sync::Arc; | ||
2 | use rustc_hash::FxHashMap; | ||
3 | |||
4 | use ra_syntax::{SmolStr, ast::AttrsOwner}; | ||
5 | |||
6 | use crate::{ | ||
7 | Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, Static, Struct, Trait | ||
8 | }; | ||
9 | |||
10 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
11 | pub enum LangItemTarget { | ||
12 | Enum(Enum), | ||
13 | Function(Function), | ||
14 | Impl(ImplBlock), | ||
15 | Static(Static), | ||
16 | Struct(Struct), | ||
17 | Trait(Trait), | ||
18 | } | ||
19 | |||
20 | impl LangItemTarget { | ||
21 | pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { | ||
22 | match self { | ||
23 | LangItemTarget::Enum(e) => e.module(db).krate(db), | ||
24 | LangItemTarget::Function(f) => f.module(db).krate(db), | ||
25 | LangItemTarget::Impl(i) => i.module().krate(db), | ||
26 | LangItemTarget::Static(s) => s.module(db).krate(db), | ||
27 | LangItemTarget::Struct(s) => s.module(db).krate(db), | ||
28 | LangItemTarget::Trait(t) => t.module(db).krate(db), | ||
29 | } | ||
30 | } | ||
31 | } | ||
32 | |||
33 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
34 | pub struct LangItems { | ||
35 | items: FxHashMap<SmolStr, LangItemTarget>, | ||
36 | } | ||
37 | |||
38 | impl LangItems { | ||
39 | pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> { | ||
40 | self.items.get(item) | ||
41 | } | ||
42 | |||
43 | /// Salsa query. This will query a specific crate for lang items. | ||
44 | pub(crate) fn lang_items_query(db: &impl DefDatabase, krate: Crate) -> Arc<LangItems> { | ||
45 | let mut lang_items = LangItems { items: FxHashMap::default() }; | ||
46 | |||
47 | if let Some(module) = krate.root_module(db) { | ||
48 | lang_items.collect_lang_items_recursive(db, &module); | ||
49 | } | ||
50 | |||
51 | Arc::new(lang_items) | ||
52 | } | ||
53 | |||
54 | fn collect_lang_items_recursive(&mut self, db: &impl DefDatabase, module: &Module) { | ||
55 | // Look for impl targets | ||
56 | let (impl_blocks, source_map) = db.impls_in_module_with_source_map(module.clone()); | ||
57 | let source = module.definition_source(db).1; | ||
58 | for (impl_id, _) in impl_blocks.impls.iter() { | ||
59 | let impl_block = source_map.get(&source, impl_id); | ||
60 | let lang_item_name = impl_block | ||
61 | .attrs() | ||
62 | .filter_map(|a| a.as_key_value()) | ||
63 | .filter(|(key, _)| key == "lang") | ||
64 | .map(|(_, val)| val) | ||
65 | .nth(0); | ||
66 | if let Some(lang_item_name) = lang_item_name { | ||
67 | let imp = ImplBlock::from_id(*module, impl_id); | ||
68 | self.items.entry(lang_item_name).or_insert(LangItemTarget::Impl(imp)); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | // FIXME we should look for the other lang item targets (traits, structs, ...) | ||
73 | |||
74 | // Look for lang items in the children | ||
75 | for child in module.children(db) { | ||
76 | self.collect_lang_items_recursive(db, &child); | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | /// Look for a lang item, starting from the specified crate and recursively traversing its | ||
82 | /// dependencies. | ||
83 | pub(crate) fn lang_item_lookup( | ||
84 | db: &impl DefDatabase, | ||
85 | start_krate: Crate, | ||
86 | item: &str, | ||
87 | ) -> Option<LangItemTarget> { | ||
88 | let lang_items = db.lang_items(start_krate); | ||
89 | let start_krate_target = lang_items.items.get(item); | ||
90 | if start_krate_target.is_some() { | ||
91 | start_krate_target.map(|t| *t) | ||
92 | } else { | ||
93 | for dep in start_krate.dependencies(db) { | ||
94 | let dep_krate = dep.krate; | ||
95 | let dep_target = lang_item_lookup(db, dep_krate, item); | ||
96 | if dep_target.is_some() { | ||
97 | return dep_target; | ||
98 | } | ||
99 | } | ||
100 | None | ||
101 | } | ||
102 | } | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 9292de1b5..4411715de 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -36,6 +36,7 @@ mod type_ref; | |||
36 | mod ty; | 36 | mod ty; |
37 | mod impl_block; | 37 | mod impl_block; |
38 | mod expr; | 38 | mod expr; |
39 | mod lang_item; | ||
39 | mod generics; | 40 | mod generics; |
40 | mod docs; | 41 | mod docs; |
41 | mod resolve; | 42 | mod resolve; |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 0eddfab12..39152360c 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -202,6 +202,10 @@ impl CrateDefMap { | |||
202 | Arc::new(def_map) | 202 | Arc::new(def_map) |
203 | } | 203 | } |
204 | 204 | ||
205 | pub(crate) fn krate(&self) -> Crate { | ||
206 | self.krate | ||
207 | } | ||
208 | |||
205 | pub(crate) fn root(&self) -> CrateModuleId { | 209 | pub(crate) fn root(&self) -> CrateModuleId { |
206 | self.root | 210 | self.root |
207 | } | 211 | } |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 685f4b8b1..61925e832 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -190,7 +190,7 @@ impl Resolver { | |||
190 | .flatten() | 190 | .flatten() |
191 | } | 191 | } |
192 | 192 | ||
193 | fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { | 193 | pub(crate) fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { |
194 | self.scopes.iter().rev().find_map(|scope| match scope { | 194 | self.scopes.iter().rev().find_map(|scope| match scope { |
195 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), | 195 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), |
196 | 196 | ||
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 7ca1ff595..2275ac151 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -462,6 +462,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
462 | let remaining_index = remaining_index.unwrap_or(path.segments.len()); | 462 | let remaining_index = remaining_index.unwrap_or(path.segments.len()); |
463 | let mut actual_def_ty: Option<Ty> = None; | 463 | let mut actual_def_ty: Option<Ty> = None; |
464 | 464 | ||
465 | let krate = resolver.module().map(|t| t.0.krate()); | ||
465 | // resolve intermediate segments | 466 | // resolve intermediate segments |
466 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { | 467 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { |
467 | let ty = match resolved { | 468 | let ty = match resolved { |
@@ -500,38 +501,41 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
500 | // Attempt to find an impl_item for the type which has a name matching | 501 | // Attempt to find an impl_item for the type which has a name matching |
501 | // the current segment | 502 | // the current segment |
502 | log::debug!("looking for path segment: {:?}", segment); | 503 | log::debug!("looking for path segment: {:?}", segment); |
504 | |||
503 | actual_def_ty = Some(ty.clone()); | 505 | actual_def_ty = Some(ty.clone()); |
504 | 506 | ||
505 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| { | 507 | let item: crate::ModuleDef = krate.and_then(|k| { |
506 | let matching_def: Option<crate::ModuleDef> = match item { | 508 | ty.iterate_impl_items(self.db, k, |item| { |
507 | crate::ImplItem::Method(func) => { | 509 | let matching_def: Option<crate::ModuleDef> = match item { |
508 | let sig = func.signature(self.db); | 510 | crate::ImplItem::Method(func) => { |
509 | if segment.name == *sig.name() { | 511 | let sig = func.signature(self.db); |
510 | Some(func.into()) | 512 | if segment.name == *sig.name() { |
511 | } else { | 513 | Some(func.into()) |
512 | None | 514 | } else { |
515 | None | ||
516 | } | ||
513 | } | 517 | } |
514 | } | ||
515 | 518 | ||
516 | crate::ImplItem::Const(konst) => { | 519 | crate::ImplItem::Const(konst) => { |
517 | let sig = konst.signature(self.db); | 520 | let sig = konst.signature(self.db); |
518 | if segment.name == *sig.name() { | 521 | if segment.name == *sig.name() { |
519 | Some(konst.into()) | 522 | Some(konst.into()) |
520 | } else { | 523 | } else { |
521 | None | 524 | None |
525 | } | ||
522 | } | 526 | } |
523 | } | ||
524 | 527 | ||
525 | // FIXME: Resolve associated types | 528 | // FIXME: Resolve associated types |
526 | crate::ImplItem::TypeAlias(_) => None, | 529 | crate::ImplItem::TypeAlias(_) => None, |
527 | }; | 530 | }; |
528 | match matching_def { | 531 | match matching_def { |
529 | Some(_) => { | 532 | Some(_) => { |
530 | self.write_assoc_resolution(id, item); | 533 | self.write_assoc_resolution(id, item); |
531 | return matching_def; | 534 | return matching_def; |
535 | } | ||
536 | None => None, | ||
532 | } | 537 | } |
533 | None => None, | 538 | }) |
534 | } | ||
535 | })?; | 539 | })?; |
536 | 540 | ||
537 | resolved = Resolution::Def(item.into()); | 541 | resolved = Resolution::Def(item.into()); |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 667b66095..ba516313c 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -14,6 +14,8 @@ use crate::{ | |||
14 | resolve::Resolver, | 14 | resolve::Resolver, |
15 | traits::TraitItem, | 15 | traits::TraitItem, |
16 | generics::HasGenericParams, | 16 | generics::HasGenericParams, |
17 | lang_item::lang_item_lookup, | ||
18 | ty::primitive::{UncertainIntTy, UncertainFloatTy} | ||
17 | }; | 19 | }; |
18 | use super::{TraitRef, Substs}; | 20 | use super::{TraitRef, Substs}; |
19 | 21 | ||
@@ -110,10 +112,33 @@ impl CrateImplBlocks { | |||
110 | } | 112 | } |
111 | } | 113 | } |
112 | 114 | ||
113 | fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | 115 | /// Rudimentary check whether an impl exists for a given type and trait; this |
116 | /// will actually be done by chalk. | ||
117 | pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool { | ||
118 | // FIXME use all trait impls in the whole crate graph | ||
119 | let krate = trait_ref.trait_.module(db).krate(db); | ||
120 | let krate = match krate { | ||
121 | Some(krate) => krate, | ||
122 | None => return false, | ||
123 | }; | ||
124 | let crate_impl_blocks = db.impls_in_crate(krate); | ||
125 | let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_); | ||
126 | impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty()) | ||
127 | } | ||
128 | |||
129 | fn def_crate(db: &impl HirDatabase, cur_krate: Crate, ty: &Ty) -> Option<Crate> { | ||
114 | match ty { | 130 | match ty { |
115 | Ty::Apply(a_ty) => match a_ty.ctor { | 131 | Ty::Apply(a_ty) => match a_ty.ctor { |
116 | TypeCtor::Adt(def_id) => def_id.krate(db), | 132 | TypeCtor::Adt(def_id) => def_id.krate(db), |
133 | TypeCtor::Bool => lang_item_lookup(db, cur_krate, "bool")?.krate(db), | ||
134 | TypeCtor::Char => lang_item_lookup(db, cur_krate, "char")?.krate(db), | ||
135 | TypeCtor::Float(UncertainFloatTy::Known(f)) => { | ||
136 | lang_item_lookup(db, cur_krate, f.ty_to_string())?.krate(db) | ||
137 | } | ||
138 | TypeCtor::Int(UncertainIntTy::Known(i)) => { | ||
139 | lang_item_lookup(db, cur_krate, i.ty_to_string())?.krate(db) | ||
140 | } | ||
141 | TypeCtor::Str => lang_item_lookup(db, cur_krate, "str")?.krate(db), | ||
117 | _ => None, | 142 | _ => None, |
118 | }, | 143 | }, |
119 | _ => None, | 144 | _ => None, |
@@ -150,8 +175,11 @@ impl Ty { | |||
150 | // find in the end takes &self, we still do the autoderef step (just as | 175 | // find in the end takes &self, we still do the autoderef step (just as |
151 | // rustc does an autoderef and then autoref again). | 176 | // rustc does an autoderef and then autoref again). |
152 | 177 | ||
178 | let krate = resolver.module().map(|t| t.0.krate())?; | ||
153 | for derefed_ty in self.autoderef(db) { | 179 | for derefed_ty in self.autoderef(db) { |
154 | if let Some(result) = derefed_ty.iterate_inherent_methods(db, name, &mut callback) { | 180 | if let Some(result) = |
181 | derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback) | ||
182 | { | ||
155 | return Some(result); | 183 | return Some(result); |
156 | } | 184 | } |
157 | if let Some(result) = | 185 | if let Some(result) = |
@@ -208,9 +236,10 @@ impl Ty { | |||
208 | &self, | 236 | &self, |
209 | db: &impl HirDatabase, | 237 | db: &impl HirDatabase, |
210 | name: Option<&Name>, | 238 | name: Option<&Name>, |
239 | krate: Crate, | ||
211 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 240 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
212 | ) -> Option<T> { | 241 | ) -> Option<T> { |
213 | let krate = match def_crate(db, self) { | 242 | let krate = match def_crate(db, krate, self) { |
214 | Some(krate) => krate, | 243 | Some(krate) => krate, |
215 | None => return None, | 244 | None => return None, |
216 | }; | 245 | }; |
@@ -239,9 +268,10 @@ impl Ty { | |||
239 | pub fn iterate_impl_items<T>( | 268 | pub fn iterate_impl_items<T>( |
240 | self, | 269 | self, |
241 | db: &impl HirDatabase, | 270 | db: &impl HirDatabase, |
271 | krate: Crate, | ||
242 | mut callback: impl FnMut(ImplItem) -> Option<T>, | 272 | mut callback: impl FnMut(ImplItem) -> Option<T>, |
243 | ) -> Option<T> { | 273 | ) -> Option<T> { |
244 | let krate = def_crate(db, &self)?; | 274 | let krate = def_crate(db, krate, &self)?; |
245 | let impls = db.impls_in_crate(krate); | 275 | let impls = db.impls_in_crate(krate); |
246 | 276 | ||
247 | for impl_block in impls.lookup_impl_blocks(&self) { | 277 | for impl_block in impls.lookup_impl_blocks(&self) { |
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index bc03a7095..c49147b9e 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
@@ -38,18 +38,21 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
38 | } | 38 | } |
39 | hir::ModuleDef::Struct(s) => { | 39 | hir::ModuleDef::Struct(s) => { |
40 | let ty = s.ty(ctx.db); | 40 | let ty = s.ty(ctx.db); |
41 | ty.iterate_impl_items(ctx.db, |item| { | 41 | let krate = ctx.module.and_then(|m| m.krate(ctx.db)); |
42 | match item { | 42 | krate.map_or((), |krate| { |
43 | hir::ImplItem::Method(func) => { | 43 | ty.iterate_impl_items(ctx.db, krate, |item| { |
44 | let sig = func.signature(ctx.db); | 44 | match item { |
45 | if !sig.has_self_param() { | 45 | hir::ImplItem::Method(func) => { |
46 | acc.add_function(ctx, func); | 46 | let sig = func.signature(ctx.db); |
47 | if !sig.has_self_param() { | ||
48 | acc.add_function(ctx, func); | ||
49 | } | ||
47 | } | 50 | } |
51 | hir::ImplItem::Const(ct) => acc.add_const(ctx, ct), | ||
52 | hir::ImplItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
48 | } | 53 | } |
49 | hir::ImplItem::Const(ct) => acc.add_const(ctx, ct), | 54 | None::<()> |
50 | hir::ImplItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | 55 | }); |
51 | } | ||
52 | None::<()> | ||
53 | }); | 56 | }); |
54 | } | 57 | } |
55 | _ => return, | 58 | _ => return, |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index ca33b43e7..5c4c0ffc1 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -65,6 +65,20 @@ impl ast::Attr { | |||
65 | None | 65 | None |
66 | } | 66 | } |
67 | } | 67 | } |
68 | |||
69 | pub fn as_key_value(&self) -> Option<(SmolStr, SmolStr)> { | ||
70 | let tt = self.value()?; | ||
71 | let tt_node = tt.syntax(); | ||
72 | let attr = tt_node.children_with_tokens().nth(1)?; | ||
73 | if attr.kind() == IDENT { | ||
74 | let key = attr.as_token()?.text().clone(); | ||
75 | let val_node = tt_node.children_with_tokens().find(|t| t.kind() == STRING)?; | ||
76 | let val = val_node.as_token()?.text().trim_start_matches("\"").trim_end_matches("\""); | ||
77 | Some((key, SmolStr::new(val))) | ||
78 | } else { | ||
79 | None | ||
80 | } | ||
81 | } | ||
68 | } | 82 | } |
69 | 83 | ||
70 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 84 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 774d9bcc8..29a7ce166 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1325,6 +1325,7 @@ impl ToOwned for ImplBlock { | |||
1325 | 1325 | ||
1326 | 1326 | ||
1327 | impl ast::TypeParamsOwner for ImplBlock {} | 1327 | impl ast::TypeParamsOwner for ImplBlock {} |
1328 | impl ast::AttrsOwner for ImplBlock {} | ||
1328 | impl ImplBlock { | 1329 | impl ImplBlock { |
1329 | pub fn item_list(&self) -> Option<&ItemList> { | 1330 | pub fn item_list(&self) -> Option<&ItemList> { |
1330 | super::child_opt(self) | 1331 | super::child_opt(self) |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index b41241287..41fe35f08 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -341,7 +341,7 @@ Grammar( | |||
341 | ], | 341 | ], |
342 | options: ["TypeRef"] | 342 | options: ["TypeRef"] |
343 | ), | 343 | ), |
344 | "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner"]), | 344 | "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner", "AttrsOwner"]), |
345 | 345 | ||
346 | "ParenType": (options: ["TypeRef"]), | 346 | "ParenType": (options: ["TypeRef"]), |
347 | "TupleType": ( collections: [["fields", "TypeRef"]] ), | 347 | "TupleType": ( collections: [["fields", "TypeRef"]] ), |