aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/Cargo.toml7
-rw-r--r--crates/ra_hir_def/src/attr.rs84
-rw-r--r--crates/ra_hir_def/src/db.rs18
-rw-r--r--crates/ra_hir_def/src/lib.rs93
-rw-r--r--crates/ra_hir_def/src/nameres.rs3
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs400
-rw-r--r--crates/ra_hir_def/src/path.rs420
-rw-r--r--crates/ra_hir_def/src/type_ref.rs162
8 files changed, 1186 insertions, 1 deletions
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index 75e93f254..746c907e8 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -6,9 +6,16 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8log = "0.4.5" 8log = "0.4.5"
9once_cell = "1.0.1"
10relative-path = "1.0.0"
11rustc-hash = "1.0"
9 12
10ra_arena = { path = "../ra_arena" } 13ra_arena = { path = "../ra_arena" }
11ra_db = { path = "../ra_db" } 14ra_db = { path = "../ra_db" }
12ra_syntax = { path = "../ra_syntax" } 15ra_syntax = { path = "../ra_syntax" }
13ra_prof = { path = "../ra_prof" } 16ra_prof = { path = "../ra_prof" }
14hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } 17hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" }
18test_utils = { path = "../test_utils" }
19mbe = { path = "../ra_mbe", package = "ra_mbe" }
20ra_cfg = { path = "../ra_cfg" }
21tt = { path = "../ra_tt", package = "ra_tt" }
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
new file mode 100644
index 000000000..0e961ca12
--- /dev/null
+++ b/crates/ra_hir_def/src/attr.rs
@@ -0,0 +1,84 @@
1//! A higher level attributes based on TokenTree, with also some shortcuts.
2
3use std::sync::Arc;
4
5use hir_expand::hygiene::Hygiene;
6use mbe::ast_to_token_tree;
7use ra_cfg::CfgOptions;
8use ra_syntax::{
9 ast::{self, AstNode, AttrsOwner},
10 SmolStr,
11};
12use tt::Subtree;
13
14use crate::path::Path;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct Attr {
18 pub(crate) path: Path,
19 pub(crate) input: Option<AttrInput>,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum AttrInput {
24 Literal(SmolStr),
25 TokenTree(Subtree),
26}
27
28impl Attr {
29 pub(crate) fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
30 let path = Path::from_src(ast.path()?, hygiene)?;
31 let input = match ast.input() {
32 None => None,
33 Some(ast::AttrInput::Literal(lit)) => {
34 // FIXME: escape? raw string?
35 let value = lit.syntax().first_token()?.text().trim_matches('"').into();
36 Some(AttrInput::Literal(value))
37 }
38 Some(ast::AttrInput::TokenTree(tt)) => {
39 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
40 }
41 };
42
43 Some(Attr { path, input })
44 }
45
46 pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Option<Arc<[Attr]>> {
47 let mut attrs = owner.attrs().peekable();
48 if attrs.peek().is_none() {
49 // Avoid heap allocation
50 return None;
51 }
52 Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
53 }
54
55 pub fn is_simple_atom(&self, name: &str) -> bool {
56 // FIXME: Avoid cloning
57 self.path.as_ident().map_or(false, |s| s.to_string() == name)
58 }
59
60 // FIXME: handle cfg_attr :-)
61 pub fn as_cfg(&self) -> Option<&Subtree> {
62 if !self.is_simple_atom("cfg") {
63 return None;
64 }
65 match &self.input {
66 Some(AttrInput::TokenTree(subtree)) => Some(subtree),
67 _ => None,
68 }
69 }
70
71 pub fn as_path(&self) -> Option<&SmolStr> {
72 if !self.is_simple_atom("path") {
73 return None;
74 }
75 match &self.input {
76 Some(AttrInput::Literal(it)) => Some(it),
77 _ => None,
78 }
79 }
80
81 pub fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> {
82 cfg_options.is_cfg_enabled(self.as_cfg()?)
83 }
84}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index f6f976c86..b271636b0 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -1,8 +1,12 @@
1//! Defines database & queries for name resolution. 1//! Defines database & queries for name resolution.
2use std::sync::Arc;
2 3
4use hir_expand::{db::AstDatabase, HirFileId};
3use ra_db::{salsa, SourceDatabase}; 5use ra_db::{salsa, SourceDatabase};
4use ra_syntax::ast; 6use ra_syntax::ast;
5 7
8use crate::nameres::raw::{ImportSourceMap, RawItems};
9
6#[salsa::query_group(InternDatabaseStorage)] 10#[salsa::query_group(InternDatabaseStorage)]
7pub trait InternDatabase: SourceDatabase { 11pub trait InternDatabase: SourceDatabase {
8 #[salsa::interned] 12 #[salsa::interned]
@@ -10,6 +14,8 @@ pub trait InternDatabase: SourceDatabase {
10 #[salsa::interned] 14 #[salsa::interned]
11 fn intern_struct(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::StructId; 15 fn intern_struct(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::StructId;
12 #[salsa::interned] 16 #[salsa::interned]
17 fn intern_union(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::UnionId;
18 #[salsa::interned]
13 fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId; 19 fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId;
14 #[salsa::interned] 20 #[salsa::interned]
15 fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId; 21 fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId;
@@ -20,3 +26,15 @@ pub trait InternDatabase: SourceDatabase {
20 #[salsa::interned] 26 #[salsa::interned]
21 fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId; 27 fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId;
22} 28}
29
30#[salsa::query_group(DefDatabase2Storage)]
31pub trait DefDatabase2: InternDatabase + AstDatabase {
32 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
33 fn raw_items_with_source_map(
34 &self,
35 file_id: HirFileId,
36 ) -> (Arc<RawItems>, Arc<ImportSourceMap>);
37
38 #[salsa::invoke(RawItems::raw_items_query)]
39 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
40}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 4d6b9db03..7a6c7b301 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -8,12 +8,18 @@
8//! actually true. 8//! actually true.
9 9
10pub mod db; 10pub mod db;
11pub mod attr;
12pub mod path;
13pub mod type_ref;
14
15// FIXME: this should be private
16pub mod nameres;
11 17
12use std::hash::{Hash, Hasher}; 18use std::hash::{Hash, Hasher};
13 19
14use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; 20use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId};
15use ra_arena::{impl_arena_id, RawId}; 21use ra_arena::{impl_arena_id, RawId};
16use ra_db::{salsa, CrateId}; 22use ra_db::{salsa, CrateId, FileId};
17use ra_syntax::{ast, AstNode, SyntaxNode}; 23use ra_syntax::{ast, AstNode, SyntaxNode};
18 24
19use crate::db::InternDatabase; 25use crate::db::InternDatabase;
@@ -24,6 +30,68 @@ pub struct Source<T> {
24 pub ast: T, 30 pub ast: T,
25} 31}
26 32
33pub enum ModuleSource {
34 SourceFile(ast::SourceFile),
35 Module(ast::Module),
36}
37
38impl ModuleSource {
39 pub fn new(
40 db: &impl db::DefDatabase2,
41 file_id: Option<FileId>,
42 decl_id: Option<AstId<ast::Module>>,
43 ) -> ModuleSource {
44 match (file_id, decl_id) {
45 (Some(file_id), _) => {
46 let source_file = db.parse(file_id).tree();
47 ModuleSource::SourceFile(source_file)
48 }
49 (None, Some(item_id)) => {
50 let module = item_id.to_node(db);
51 assert!(module.item_list().is_some(), "expected inline module");
52 ModuleSource::Module(module)
53 }
54 (None, None) => panic!(),
55 }
56 }
57
58 // FIXME: this methods do not belong here
59 pub fn from_position(
60 db: &impl db::DefDatabase2,
61 position: ra_db::FilePosition,
62 ) -> ModuleSource {
63 let parse = db.parse(position.file_id);
64 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
65 parse.tree().syntax(),
66 position.offset,
67 ) {
68 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
69 _ => {
70 let source_file = parse.tree();
71 ModuleSource::SourceFile(source_file)
72 }
73 }
74 }
75
76 pub fn from_child_node(
77 db: &impl db::DefDatabase2,
78 file_id: FileId,
79 child: &SyntaxNode,
80 ) -> ModuleSource {
81 if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
82 ModuleSource::Module(m)
83 } else {
84 let source_file = db.parse(file_id).tree();
85 ModuleSource::SourceFile(source_file)
86 }
87 }
88
89 pub fn from_file_id(db: &impl db::DefDatabase2, file_id: FileId) -> ModuleSource {
90 let source_file = db.parse(file_id).tree();
91 ModuleSource::SourceFile(source_file)
92 }
93}
94
27impl<T> Source<T> { 95impl<T> Source<T> {
28 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { 96 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
29 Source { file_id: self.file_id, ast: f(self.ast) } 97 Source { file_id: self.file_id, ast: f(self.ast) }
@@ -156,6 +224,18 @@ impl AstItemDef<ast::StructDef> for StructId {
156} 224}
157 225
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
227pub struct UnionId(salsa::InternId);
228impl_intern_key!(UnionId);
229impl AstItemDef<ast::StructDef> for UnionId {
230 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
231 db.intern_union(loc)
232 }
233 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
234 db.lookup_intern_union(self)
235 }
236}
237
238#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
159pub struct EnumId(salsa::InternId); 239pub struct EnumId(salsa::InternId);
160impl_intern_key!(EnumId); 240impl_intern_key!(EnumId);
161impl AstItemDef<ast::EnumDef> for EnumId { 241impl AstItemDef<ast::EnumDef> for EnumId {
@@ -167,6 +247,17 @@ impl AstItemDef<ast::EnumDef> for EnumId {
167 } 247 }
168} 248}
169 249
250// FIXME: rename to `VariantId`, only enums can ave variants
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
252pub struct EnumVariantId {
253 parent: EnumId,
254 local_id: LocalEnumVariantId,
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
258pub(crate) struct LocalEnumVariantId(RawId);
259impl_arena_id!(LocalEnumVariantId);
260
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 261#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub struct ConstId(salsa::InternId); 262pub struct ConstId(salsa::InternId);
172impl_intern_key!(ConstId); 263impl_intern_key!(ConstId);
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
new file mode 100644
index 000000000..5893708e8
--- /dev/null
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -0,0 +1,3 @@
1//! FIXME: write short doc here
2
3pub mod raw;
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
new file mode 100644
index 000000000..86c05d602
--- /dev/null
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -0,0 +1,400 @@
1//! FIXME: write short doc here
2
3use std::{ops::Index, sync::Arc};
4
5use hir_expand::{
6 ast_id_map::AstIdMap,
7 db::AstDatabase,
8 either::Either,
9 hygiene::Hygiene,
10 name::{AsName, Name},
11};
12use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
13use ra_syntax::{
14 ast::{self, AttrsOwner, NameOwner},
15 AstNode, AstPtr, SourceFile,
16};
17
18use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source};
19
20/// `RawItems` is a set of top-level items in a file (except for impls).
21///
22/// It is the input to name resolution algorithm. `RawItems` are not invalidated
23/// on most edits.
24#[derive(Debug, Default, PartialEq, Eq)]
25pub struct RawItems {
26 modules: Arena<Module, ModuleData>,
27 imports: Arena<ImportId, ImportData>,
28 defs: Arena<Def, DefData>,
29 macros: Arena<Macro, MacroData>,
30 /// items for top-level module
31 items: Vec<RawItem>,
32}
33
34#[derive(Debug, Default, PartialEq, Eq)]
35pub struct ImportSourceMap {
36 map: ArenaMap<ImportId, ImportSourcePtr>,
37}
38
39type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
40type ImportSource = Either<ast::UseTree, ast::ExternCrateItem>;
41
42fn to_node(ptr: ImportSourcePtr, file: &SourceFile) -> ImportSource {
43 ptr.map(|ptr| ptr.to_node(file.syntax()), |ptr| ptr.to_node(file.syntax()))
44}
45
46impl ImportSourceMap {
47 fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) {
48 self.map.insert(import, ptr)
49 }
50
51 pub fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource {
52 let file = match source {
53 ModuleSource::SourceFile(file) => file.clone(),
54 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
55 };
56
57 to_node(self.map[import], &file)
58 }
59}
60
61impl RawItems {
62 pub(crate) fn raw_items_query(
63 db: &(impl DefDatabase2 + AstDatabase),
64 file_id: HirFileId,
65 ) -> Arc<RawItems> {
66 db.raw_items_with_source_map(file_id).0
67 }
68
69 pub(crate) fn raw_items_with_source_map_query(
70 db: &(impl DefDatabase2 + AstDatabase),
71 file_id: HirFileId,
72 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
73 let mut collector = RawItemsCollector {
74 raw_items: RawItems::default(),
75 source_ast_id_map: db.ast_id_map(file_id),
76 source_map: ImportSourceMap::default(),
77 file_id,
78 hygiene: Hygiene::new(db, file_id),
79 };
80 if let Some(node) = db.parse_or_expand(file_id) {
81 if let Some(source_file) = ast::SourceFile::cast(node.clone()) {
82 collector.process_module(None, source_file);
83 } else if let Some(item_list) = ast::MacroItems::cast(node) {
84 collector.process_module(None, item_list);
85 }
86 }
87 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
88 }
89
90 pub fn items(&self) -> &[RawItem] {
91 &self.items
92 }
93}
94
95impl Index<Module> for RawItems {
96 type Output = ModuleData;
97 fn index(&self, idx: Module) -> &ModuleData {
98 &self.modules[idx]
99 }
100}
101
102impl Index<ImportId> for RawItems {
103 type Output = ImportData;
104 fn index(&self, idx: ImportId) -> &ImportData {
105 &self.imports[idx]
106 }
107}
108
109impl Index<Def> for RawItems {
110 type Output = DefData;
111 fn index(&self, idx: Def) -> &DefData {
112 &self.defs[idx]
113 }
114}
115
116impl Index<Macro> for RawItems {
117 type Output = MacroData;
118 fn index(&self, idx: Macro) -> &MacroData {
119 &self.macros[idx]
120 }
121}
122
123// Avoid heap allocation on items without attributes.
124type Attrs = Option<Arc<[Attr]>>;
125
126#[derive(Debug, PartialEq, Eq, Clone)]
127pub struct RawItem {
128 attrs: Attrs,
129 pub kind: RawItemKind,
130}
131
132impl RawItem {
133 pub fn attrs(&self) -> &[Attr] {
134 self.attrs.as_ref().map_or(&[], |it| &*it)
135 }
136}
137
138#[derive(Debug, PartialEq, Eq, Clone, Copy)]
139pub enum RawItemKind {
140 Module(Module),
141 Import(ImportId),
142 Def(Def),
143 Macro(Macro),
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
147pub struct Module(RawId);
148impl_arena_id!(Module);
149
150#[derive(Debug, PartialEq, Eq)]
151pub enum ModuleData {
152 Declaration { name: Name, ast_id: FileAstId<ast::Module> },
153 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
157pub struct ImportId(RawId);
158impl_arena_id!(ImportId);
159
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct ImportData {
162 pub path: Path,
163 pub alias: Option<Name>,
164 pub is_glob: bool,
165 pub is_prelude: bool,
166 pub is_extern_crate: bool,
167 pub is_macro_use: bool,
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
171pub struct Def(RawId);
172impl_arena_id!(Def);
173
174#[derive(Debug, PartialEq, Eq)]
175pub struct DefData {
176 pub name: Name,
177 pub kind: DefKind,
178}
179
180#[derive(Debug, PartialEq, Eq, Clone, Copy)]
181pub enum DefKind {
182 Function(FileAstId<ast::FnDef>),
183 Struct(FileAstId<ast::StructDef>),
184 Union(FileAstId<ast::StructDef>),
185 Enum(FileAstId<ast::EnumDef>),
186 Const(FileAstId<ast::ConstDef>),
187 Static(FileAstId<ast::StaticDef>),
188 Trait(FileAstId<ast::TraitDef>),
189 TypeAlias(FileAstId<ast::TypeAliasDef>),
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
193pub struct Macro(RawId);
194impl_arena_id!(Macro);
195
196#[derive(Debug, PartialEq, Eq)]
197pub struct MacroData {
198 pub ast_id: FileAstId<ast::MacroCall>,
199 pub path: Path,
200 pub name: Option<Name>,
201 pub export: bool,
202}
203
204struct RawItemsCollector {
205 raw_items: RawItems,
206 source_ast_id_map: Arc<AstIdMap>,
207 source_map: ImportSourceMap,
208 file_id: HirFileId,
209 hygiene: Hygiene,
210}
211
212impl RawItemsCollector {
213 fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) {
214 for item_or_macro in body.items_with_macros() {
215 match item_or_macro {
216 ast::ItemOrMacro::Macro(m) => self.add_macro(current_module, m),
217 ast::ItemOrMacro::Item(item) => self.add_item(current_module, item),
218 }
219 }
220 }
221
222 fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) {
223 let attrs = self.parse_attrs(&item);
224 let (kind, name) = match item {
225 ast::ModuleItem::Module(module) => {
226 self.add_module(current_module, module);
227 return;
228 }
229 ast::ModuleItem::UseItem(use_item) => {
230 self.add_use_item(current_module, use_item);
231 return;
232 }
233 ast::ModuleItem::ExternCrateItem(extern_crate) => {
234 self.add_extern_crate_item(current_module, extern_crate);
235 return;
236 }
237 ast::ModuleItem::ImplBlock(_) => {
238 // impls don't participate in name resolution
239 return;
240 }
241 ast::ModuleItem::StructDef(it) => {
242 let id = self.source_ast_id_map.ast_id(&it);
243 let name = it.name();
244 if it.is_union() {
245 (DefKind::Union(id), name)
246 } else {
247 (DefKind::Struct(id), name)
248 }
249 }
250 ast::ModuleItem::EnumDef(it) => {
251 (DefKind::Enum(self.source_ast_id_map.ast_id(&it)), it.name())
252 }
253 ast::ModuleItem::FnDef(it) => {
254 (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
255 }
256 ast::ModuleItem::TraitDef(it) => {
257 (DefKind::Trait(self.source_ast_id_map.ast_id(&it)), it.name())
258 }
259 ast::ModuleItem::TypeAliasDef(it) => {
260 (DefKind::TypeAlias(self.source_ast_id_map.ast_id(&it)), it.name())
261 }
262 ast::ModuleItem::ConstDef(it) => {
263 (DefKind::Const(self.source_ast_id_map.ast_id(&it)), it.name())
264 }
265 ast::ModuleItem::StaticDef(it) => {
266 (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
267 }
268 };
269 if let Some(name) = name {
270 let name = name.as_name();
271 let def = self.raw_items.defs.alloc(DefData { name, kind });
272 self.push_item(current_module, attrs, RawItemKind::Def(def));
273 }
274 }
275
276 fn add_module(&mut self, current_module: Option<Module>, module: ast::Module) {
277 let name = match module.name() {
278 Some(it) => it.as_name(),
279 None => return,
280 };
281 let attrs = self.parse_attrs(&module);
282
283 let ast_id = self.source_ast_id_map.ast_id(&module);
284 if module.has_semi() {
285 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
286 self.push_item(current_module, attrs, RawItemKind::Module(item));
287 return;
288 }
289
290 if let Some(item_list) = module.item_list() {
291 let item = self.raw_items.modules.alloc(ModuleData::Definition {
292 name,
293 ast_id,
294 items: Vec::new(),
295 });
296 self.process_module(Some(item), item_list);
297 self.push_item(current_module, attrs, RawItemKind::Module(item));
298 return;
299 }
300 // FIXME: restore this mark once we complete hir splitting
301 // tested_by!(name_res_works_for_broken_modules);
302 }
303
304 fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) {
305 // FIXME: cfg_attr
306 let is_prelude = use_item.has_atom_attr("prelude_import");
307 let attrs = self.parse_attrs(&use_item);
308
309 let mut buf = Vec::new();
310 Path::expand_use_item(
311 Source { ast: use_item, file_id: self.file_id },
312 &self.hygiene,
313 |path, use_tree, is_glob, alias| {
314 let import_data = ImportData {
315 path,
316 alias,
317 is_glob,
318 is_prelude,
319 is_extern_crate: false,
320 is_macro_use: false,
321 };
322 buf.push((import_data, Either::A(AstPtr::new(use_tree))));
323 },
324 );
325 for (import_data, ptr) in buf {
326 self.push_import(current_module, attrs.clone(), import_data, ptr);
327 }
328 }
329
330 fn add_extern_crate_item(
331 &mut self,
332 current_module: Option<Module>,
333 extern_crate: ast::ExternCrateItem,
334 ) {
335 if let Some(name_ref) = extern_crate.name_ref() {
336 let path = Path::from_name_ref(&name_ref);
337 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
338 let attrs = self.parse_attrs(&extern_crate);
339 // FIXME: cfg_attr
340 let is_macro_use = extern_crate.has_atom_attr("macro_use");
341 let import_data = ImportData {
342 path,
343 alias,
344 is_glob: false,
345 is_prelude: false,
346 is_extern_crate: true,
347 is_macro_use,
348 };
349 self.push_import(
350 current_module,
351 attrs,
352 import_data,
353 Either::B(AstPtr::new(&extern_crate)),
354 );
355 }
356 }
357
358 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
359 let attrs = self.parse_attrs(&m);
360 let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) {
361 Some(it) => it,
362 _ => return,
363 };
364
365 let name = m.name().map(|it| it.as_name());
366 let ast_id = self.source_ast_id_map.ast_id(&m);
367 // FIXME: cfg_attr
368 let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
369
370 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
371 self.push_item(current_module, attrs, RawItemKind::Macro(m));
372 }
373
374 fn push_import(
375 &mut self,
376 current_module: Option<Module>,
377 attrs: Attrs,
378 data: ImportData,
379 source: ImportSourcePtr,
380 ) {
381 let import = self.raw_items.imports.alloc(data);
382 self.source_map.insert(import, source);
383 self.push_item(current_module, attrs, RawItemKind::Import(import))
384 }
385
386 fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) {
387 match current_module {
388 Some(module) => match &mut self.raw_items.modules[module] {
389 ModuleData::Definition { items, .. } => items,
390 ModuleData::Declaration { .. } => unreachable!(),
391 },
392 None => &mut self.raw_items.items,
393 }
394 .push(RawItem { attrs, kind })
395 }
396
397 fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs {
398 Attr::from_attrs_owner(item, &self.hygiene)
399 }
400}
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
new file mode 100644
index 000000000..04039376f
--- /dev/null
+++ b/crates/ra_hir_def/src/path.rs
@@ -0,0 +1,420 @@
1//! FIXME: write short doc here
2
3use std::{iter, sync::Arc};
4
5use hir_expand::{
6 either::Either,
7 hygiene::Hygiene,
8 name::{self, AsName, Name},
9};
10use ra_db::CrateId;
11use ra_syntax::{
12 ast::{self, NameOwner, TypeAscriptionOwner},
13 AstNode,
14};
15
16use crate::{type_ref::TypeRef, Source};
17
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Path {
20 pub kind: PathKind,
21 pub segments: Vec<PathSegment>,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct PathSegment {
26 pub name: Name,
27 pub args_and_bindings: Option<Arc<GenericArgs>>,
28}
29
30/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
31/// can (in the future) also include bindings of associated types, like in
32/// `Iterator<Item = Foo>`.
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct GenericArgs {
35 pub args: Vec<GenericArg>,
36 /// This specifies whether the args contain a Self type as the first
37 /// element. This is the case for path segments like `<T as Trait>`, where
38 /// `T` is actually a type parameter for the path `Trait` specifying the
39 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
40 /// is left out.
41 pub has_self_type: bool,
42 /// Associated type bindings like in `Iterator<Item = T>`.
43 pub bindings: Vec<(Name, TypeRef)>,
44}
45
46/// A single generic argument.
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48pub enum GenericArg {
49 Type(TypeRef),
50 // or lifetime...
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum PathKind {
55 Plain,
56 Self_,
57 Super,
58 Crate,
59 // Absolute path
60 Abs,
61 // Type based path like `<T>::foo`
62 Type(Box<TypeRef>),
63 // `$crate` from macro expansion
64 DollarCrate(CrateId),
65}
66
67impl Path {
68 /// Calls `cb` with all paths, represented by this use item.
69 pub fn expand_use_item(
70 item_src: Source<ast::UseItem>,
71 hygiene: &Hygiene,
72 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
73 ) {
74 if let Some(tree) = item_src.ast.use_tree() {
75 expand_use_tree(None, tree, hygiene, &mut cb);
76 }
77 }
78
79 pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path {
80 Path {
81 kind,
82 segments: segments
83 .into_iter()
84 .map(|name| PathSegment { name, args_and_bindings: None })
85 .collect(),
86 }
87 }
88
89 /// Converts an `ast::Path` to `Path`. Works with use trees.
90 /// DEPRECATED: It does not handle `$crate` from macro call.
91 pub fn from_ast(path: ast::Path) -> Option<Path> {
92 Path::from_src(path, &Hygiene::new_unhygienic())
93 }
94
95 /// Converts an `ast::Path` to `Path`. Works with use trees.
96 /// It correctly handles `$crate` based path from macro call.
97 pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
98 let mut kind = PathKind::Plain;
99 let mut segments = Vec::new();
100 loop {
101 let segment = path.segment()?;
102
103 if segment.has_colon_colon() {
104 kind = PathKind::Abs;
105 }
106
107 match segment.kind()? {
108 ast::PathSegmentKind::Name(name_ref) => {
109 // FIXME: this should just return name
110 match hygiene.name_ref_to_name(name_ref) {
111 Either::A(name) => {
112 let args = segment
113 .type_arg_list()
114 .and_then(GenericArgs::from_ast)
115 .or_else(|| {
116 GenericArgs::from_fn_like_path_ast(
117 segment.param_list(),
118 segment.ret_type(),
119 )
120 })
121 .map(Arc::new);
122 let segment = PathSegment { name, args_and_bindings: args };
123 segments.push(segment);
124 }
125 Either::B(crate_id) => {
126 kind = PathKind::DollarCrate(crate_id);
127 break;
128 }
129 }
130 }
131 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
132 assert!(path.qualifier().is_none()); // this can only occur at the first segment
133
134 let self_type = TypeRef::from_ast(type_ref?);
135
136 match trait_ref {
137 // <T>::foo
138 None => {
139 kind = PathKind::Type(Box::new(self_type));
140 }
141 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
142 Some(trait_ref) => {
143 let path = Path::from_src(trait_ref.path()?, hygiene)?;
144 kind = path.kind;
145 let mut prefix_segments = path.segments;
146 prefix_segments.reverse();
147 segments.extend(prefix_segments);
148 // Insert the type reference (T in the above example) as Self parameter for the trait
149 let mut last_segment = segments.last_mut()?;
150 if last_segment.args_and_bindings.is_none() {
151 last_segment.args_and_bindings =
152 Some(Arc::new(GenericArgs::empty()));
153 };
154 let args = last_segment.args_and_bindings.as_mut().unwrap();
155 let mut args_inner = Arc::make_mut(args);
156 args_inner.has_self_type = true;
157 args_inner.args.insert(0, GenericArg::Type(self_type));
158 }
159 }
160 }
161 ast::PathSegmentKind::CrateKw => {
162 kind = PathKind::Crate;
163 break;
164 }
165 ast::PathSegmentKind::SelfKw => {
166 kind = PathKind::Self_;
167 break;
168 }
169 ast::PathSegmentKind::SuperKw => {
170 kind = PathKind::Super;
171 break;
172 }
173 }
174 path = match qualifier(&path) {
175 Some(it) => it,
176 None => break,
177 };
178 }
179 segments.reverse();
180 return Some(Path { kind, segments });
181
182 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
183 if let Some(q) = path.qualifier() {
184 return Some(q);
185 }
186 // FIXME: this bottom up traversal is not too precise.
187 // Should we handle do a top-down analysis, recording results?
188 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
189 let use_tree = use_tree_list.parent_use_tree();
190 use_tree.path()
191 }
192 }
193
194 /// Converts an `ast::NameRef` into a single-identifier `Path`.
195 pub fn from_name_ref(name_ref: &ast::NameRef) -> Path {
196 name_ref.as_name().into()
197 }
198
199 /// `true` is this path is a single identifier, like `foo`
200 pub fn is_ident(&self) -> bool {
201 self.kind == PathKind::Plain && self.segments.len() == 1
202 }
203
204 /// `true` if this path is just a standalone `self`
205 pub fn is_self(&self) -> bool {
206 self.kind == PathKind::Self_ && self.segments.is_empty()
207 }
208
209 /// If this path is a single identifier, like `foo`, return its name.
210 pub fn as_ident(&self) -> Option<&Name> {
211 if self.kind != PathKind::Plain || self.segments.len() > 1 {
212 return None;
213 }
214 self.segments.first().map(|s| &s.name)
215 }
216
217 pub fn expand_macro_expr(&self) -> Option<Name> {
218 self.as_ident().and_then(|name| Some(name.clone()))
219 }
220
221 pub fn is_type_relative(&self) -> bool {
222 match self.kind {
223 PathKind::Type(_) => true,
224 _ => false,
225 }
226 }
227}
228
229impl GenericArgs {
230 pub fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
231 let mut args = Vec::new();
232 for type_arg in node.type_args() {
233 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
234 args.push(GenericArg::Type(type_ref));
235 }
236 // lifetimes ignored for now
237 let mut bindings = Vec::new();
238 for assoc_type_arg in node.assoc_type_args() {
239 if let Some(name_ref) = assoc_type_arg.name_ref() {
240 let name = name_ref.as_name();
241 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
242 bindings.push((name, type_ref));
243 }
244 }
245 if args.is_empty() && bindings.is_empty() {
246 None
247 } else {
248 Some(GenericArgs { args, has_self_type: false, bindings })
249 }
250 }
251
252 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
253 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
254 pub(crate) fn from_fn_like_path_ast(
255 params: Option<ast::ParamList>,
256 ret_type: Option<ast::RetType>,
257 ) -> Option<GenericArgs> {
258 let mut args = Vec::new();
259 let mut bindings = Vec::new();
260 if let Some(params) = params {
261 let mut param_types = Vec::new();
262 for param in params.params() {
263 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
264 param_types.push(type_ref);
265 }
266 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
267 args.push(arg);
268 }
269 if let Some(ret_type) = ret_type {
270 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
271 bindings.push((name::OUTPUT_TYPE, type_ref))
272 }
273 if args.is_empty() && bindings.is_empty() {
274 None
275 } else {
276 Some(GenericArgs { args, has_self_type: false, bindings })
277 }
278 }
279
280 pub(crate) fn empty() -> GenericArgs {
281 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
282 }
283}
284
285impl From<Name> for Path {
286 fn from(name: Name) -> Path {
287 Path::from_simple_segments(PathKind::Plain, iter::once(name))
288 }
289}
290
291fn expand_use_tree(
292 prefix: Option<Path>,
293 tree: ast::UseTree,
294 hygiene: &Hygiene,
295 cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>),
296) {
297 if let Some(use_tree_list) = tree.use_tree_list() {
298 let prefix = match tree.path() {
299 // E.g. use something::{{{inner}}};
300 None => prefix,
301 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
302 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
303 Some(path) => match convert_path(prefix, path, hygiene) {
304 Some(it) => Some(it),
305 None => return, // FIXME: report errors somewhere
306 },
307 };
308 for child_tree in use_tree_list.use_trees() {
309 expand_use_tree(prefix.clone(), child_tree, hygiene, cb);
310 }
311 } else {
312 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
313 if let Some(ast_path) = tree.path() {
314 // Handle self in a path.
315 // E.g. `use something::{self, <...>}`
316 if ast_path.qualifier().is_none() {
317 if let Some(segment) = ast_path.segment() {
318 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
319 if let Some(prefix) = prefix {
320 cb(prefix, &tree, false, alias);
321 return;
322 }
323 }
324 }
325 }
326 if let Some(path) = convert_path(prefix, ast_path, hygiene) {
327 let is_glob = tree.has_star();
328 cb(path, &tree, is_glob, alias)
329 }
330 // FIXME: report errors somewhere
331 // We get here if we do
332 }
333 }
334}
335
336fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
337 let prefix = if let Some(qual) = path.qualifier() {
338 Some(convert_path(prefix, qual, hygiene)?)
339 } else {
340 prefix
341 };
342
343 let segment = path.segment()?;
344 let res = match segment.kind()? {
345 ast::PathSegmentKind::Name(name_ref) => {
346 match hygiene.name_ref_to_name(name_ref) {
347 Either::A(name) => {
348 // no type args in use
349 let mut res = prefix.unwrap_or_else(|| Path {
350 kind: PathKind::Plain,
351 segments: Vec::with_capacity(1),
352 });
353 res.segments.push(PathSegment {
354 name,
355 args_and_bindings: None, // no type args in use
356 });
357 res
358 }
359 Either::B(crate_id) => {
360 return Some(Path::from_simple_segments(
361 PathKind::DollarCrate(crate_id),
362 iter::empty(),
363 ))
364 }
365 }
366 }
367 ast::PathSegmentKind::CrateKw => {
368 if prefix.is_some() {
369 return None;
370 }
371 Path::from_simple_segments(PathKind::Crate, iter::empty())
372 }
373 ast::PathSegmentKind::SelfKw => {
374 if prefix.is_some() {
375 return None;
376 }
377 Path::from_simple_segments(PathKind::Self_, iter::empty())
378 }
379 ast::PathSegmentKind::SuperKw => {
380 if prefix.is_some() {
381 return None;
382 }
383 Path::from_simple_segments(PathKind::Super, iter::empty())
384 }
385 ast::PathSegmentKind::Type { .. } => {
386 // not allowed in imports
387 return None;
388 }
389 };
390 Some(res)
391}
392
393pub mod known {
394 use hir_expand::name;
395
396 use super::{Path, PathKind};
397
398 pub fn std_iter_into_iterator() -> Path {
399 Path::from_simple_segments(
400 PathKind::Abs,
401 vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE],
402 )
403 }
404
405 pub fn std_ops_try() -> Path {
406 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
407 }
408
409 pub fn std_result_result() -> Path {
410 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
411 }
412
413 pub fn std_future_future() -> Path {
414 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE])
415 }
416
417 pub fn std_boxed_box() -> Path {
418 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE])
419 }
420}
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs
new file mode 100644
index 000000000..8af061116
--- /dev/null
+++ b/crates/ra_hir_def/src/type_ref.rs
@@ -0,0 +1,162 @@
1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries.
3
4use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner};
5
6use crate::path::Path;
7
8#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
9pub enum Mutability {
10 Shared,
11 Mut,
12}
13
14impl Mutability {
15 pub fn from_mutable(mutable: bool) -> Mutability {
16 if mutable {
17 Mutability::Mut
18 } else {
19 Mutability::Shared
20 }
21 }
22
23 pub fn as_keyword_for_ref(self) -> &'static str {
24 match self {
25 Mutability::Shared => "",
26 Mutability::Mut => "mut ",
27 }
28 }
29
30 pub fn as_keyword_for_ptr(self) -> &'static str {
31 match self {
32 Mutability::Shared => "const ",
33 Mutability::Mut => "mut ",
34 }
35 }
36}
37
38/// Compare ty::Ty
39#[derive(Clone, PartialEq, Eq, Hash, Debug)]
40pub enum TypeRef {
41 Never,
42 Placeholder,
43 Tuple(Vec<TypeRef>),
44 Path(Path),
45 RawPtr(Box<TypeRef>, Mutability),
46 Reference(Box<TypeRef>, Mutability),
47 Array(Box<TypeRef> /*, Expr*/),
48 Slice(Box<TypeRef>),
49 /// A fn pointer. Last element of the vector is the return type.
50 Fn(Vec<TypeRef>),
51 // For
52 ImplTrait(Vec<TypeBound>),
53 DynTrait(Vec<TypeBound>),
54 Error,
55}
56
57#[derive(Clone, PartialEq, Eq, Hash, Debug)]
58pub enum TypeBound {
59 Path(Path),
60 // also for<> bounds
61 // also Lifetimes
62 Error,
63}
64
65impl TypeRef {
66 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
67 pub fn from_ast(node: ast::TypeRef) -> Self {
68 match node {
69 ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
70 ast::TypeRef::TupleType(inner) => {
71 TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect())
72 }
73 ast::TypeRef::NeverType(..) => TypeRef::Never,
74 ast::TypeRef::PathType(inner) => {
75 // FIXME: Use `Path::from_src`
76 inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error)
77 }
78 ast::TypeRef::PointerType(inner) => {
79 let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
80 let mutability = Mutability::from_mutable(inner.is_mut());
81 TypeRef::RawPtr(Box::new(inner_ty), mutability)
82 }
83 ast::TypeRef::ArrayType(inner) => {
84 TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref())))
85 }
86 ast::TypeRef::SliceType(inner) => {
87 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref())))
88 }
89 ast::TypeRef::ReferenceType(inner) => {
90 let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
91 let mutability = Mutability::from_mutable(inner.is_mut());
92 TypeRef::Reference(Box::new(inner_ty), mutability)
93 }
94 ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder,
95 ast::TypeRef::FnPointerType(inner) => {
96 let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref()));
97 let mut params = if let Some(pl) = inner.param_list() {
98 pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect()
99 } else {
100 Vec::new()
101 };
102 params.push(ret_ty);
103 TypeRef::Fn(params)
104 }
105 // for types are close enough for our purposes to the inner type for now...
106 ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
107 ast::TypeRef::ImplTraitType(inner) => {
108 TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list()))
109 }
110 ast::TypeRef::DynTraitType(inner) => {
111 TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list()))
112 }
113 }
114 }
115
116 pub fn from_ast_opt(node: Option<ast::TypeRef>) -> Self {
117 if let Some(node) = node {
118 TypeRef::from_ast(node)
119 } else {
120 TypeRef::Error
121 }
122 }
123
124 pub fn unit() -> TypeRef {
125 TypeRef::Tuple(Vec::new())
126 }
127}
128
129pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
130 if let Some(type_bounds) = type_bounds_opt {
131 type_bounds.bounds().map(TypeBound::from_ast).collect()
132 } else {
133 vec![]
134 }
135}
136
137impl TypeBound {
138 pub fn from_ast(node: ast::TypeBound) -> Self {
139 match node.kind() {
140 ast::TypeBoundKind::PathType(path_type) => {
141 let path = match path_type.path() {
142 Some(p) => p,
143 None => return TypeBound::Error,
144 };
145 // FIXME: Use `Path::from_src`
146 let path = match Path::from_ast(path) {
147 Some(p) => p,
148 None => return TypeBound::Error,
149 };
150 TypeBound::Path(path)
151 }
152 ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
153 }
154 }
155
156 pub fn as_path(&self) -> Option<&Path> {
157 match self {
158 TypeBound::Path(p) => Some(p),
159 _ => None,
160 }
161 }
162}