aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-12-27 10:08:34 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-12-27 10:08:34 +0000
commit1d6dcef5c584d0dffdf5386eec993e41daad0210 (patch)
tree1e67675b7031115b1811863d0f186ad1f98b1fce /crates/ra_hir
parent700165cf17290561dea511565278b9869ed61625 (diff)
parentbc745a139674f289386f3081458793f756cab5b9 (diff)
Merge #332
332: Struct types r=matklad a=flodiebold Infer types for struct fields, and add basic field completions. There's also some code for enums, but I focused on getting structs working. There's still ways to go before this becomes useful: There's no autoderef (or even reference types) and no inference for `self`, for example. Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/adt.rs194
-rw-r--r--crates/ra_hir/src/db.rs17
-rw-r--r--crates/ra_hir/src/function.rs3
-rw-r--r--crates/ra_hir/src/lib.rs47
-rw-r--r--crates/ra_hir/src/mock.rs3
-rw-r--r--crates/ra_hir/src/module.rs44
-rw-r--r--crates/ra_hir/src/module/nameres.rs154
-rw-r--r--crates/ra_hir/src/module/nameres/tests.rs6
-rw-r--r--crates/ra_hir/src/path.rs4
-rw-r--r--crates/ra_hir/src/query_definitions.rs29
-rw-r--r--crates/ra_hir/src/ty.rs448
-rw-r--r--crates/ra_hir/src/ty/tests.rs45
-rw-r--r--crates/ra_hir/src/ty/tests/data/0001_basics.txt4
-rw-r--r--crates/ra_hir/src/ty/tests/data/0004_struct.txt16
-rw-r--r--crates/ra_hir/src/ty/tests/data/0005_refs.txt23
-rw-r--r--crates/ra_hir/src/type_ref.rs110
16 files changed, 900 insertions, 247 deletions
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
new file mode 100644
index 000000000..65c461148
--- /dev/null
+++ b/crates/ra_hir/src/adt.rs
@@ -0,0 +1,194 @@
1use std::sync::Arc;
2
3use ra_syntax::{SmolStr, ast::{self, NameOwner, StructFlavor}};
4
5use crate::{
6 DefId, Cancelable,
7 db::{HirDatabase},
8 type_ref::TypeRef,
9};
10
11pub struct Struct {
12 def_id: DefId,
13}
14
15impl Struct {
16 pub(crate) fn new(def_id: DefId) -> Self {
17 Struct { def_id }
18 }
19
20 pub fn def_id(&self) -> DefId {
21 self.def_id
22 }
23
24 pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
25 Ok(db.struct_data(self.def_id)?.variant_data.clone())
26 }
27
28 pub fn struct_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<StructData>> {
29 Ok(db.struct_data(self.def_id)?)
30 }
31
32 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<SmolStr>> {
33 Ok(db.struct_data(self.def_id)?.name.clone())
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct StructData {
39 name: Option<SmolStr>,
40 variant_data: Arc<VariantData>,
41}
42
43impl StructData {
44 pub(crate) fn new(struct_def: ast::StructDef) -> StructData {
45 let name = struct_def.name().map(|n| n.text());
46 let variant_data = VariantData::new(struct_def.flavor());
47 let variant_data = Arc::new(variant_data);
48 StructData { name, variant_data }
49 }
50
51 pub fn name(&self) -> Option<&SmolStr> {
52 self.name.as_ref()
53 }
54
55 pub fn variant_data(&self) -> &Arc<VariantData> {
56 &self.variant_data
57 }
58}
59
60pub struct Enum {
61 def_id: DefId,
62}
63
64impl Enum {
65 pub(crate) fn new(def_id: DefId) -> Self {
66 Enum { def_id }
67 }
68
69 pub fn def_id(&self) -> DefId {
70 self.def_id
71 }
72
73 pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<SmolStr>> {
74 Ok(db.enum_data(self.def_id)?.name.clone())
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct EnumData {
80 name: Option<SmolStr>,
81 variants: Vec<(SmolStr, Arc<VariantData>)>,
82}
83
84impl EnumData {
85 pub(crate) fn new(enum_def: ast::EnumDef) -> Self {
86 let name = enum_def.name().map(|n| n.text());
87 let variants = if let Some(evl) = enum_def.variant_list() {
88 evl.variants()
89 .map(|v| {
90 (
91 v.name()
92 .map(|n| n.text())
93 .unwrap_or_else(|| SmolStr::new("[error]")),
94 Arc::new(VariantData::new(v.flavor())),
95 )
96 })
97 .collect()
98 } else {
99 Vec::new()
100 };
101 EnumData { name, variants }
102 }
103}
104
105/// A single field of an enum variant or struct
106#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct StructField {
108 name: SmolStr,
109 type_ref: TypeRef,
110}
111
112impl StructField {
113 pub fn name(&self) -> SmolStr {
114 self.name.clone()
115 }
116 pub fn type_ref(&self) -> &TypeRef {
117 &self.type_ref
118 }
119}
120
121/// Fields of an enum variant or struct
122#[derive(Debug, Clone, PartialEq, Eq)]
123pub enum VariantData {
124 Struct(Vec<StructField>),
125 Tuple(Vec<StructField>),
126 Unit,
127}
128
129impl VariantData {
130 pub fn new(flavor: StructFlavor) -> Self {
131 match flavor {
132 StructFlavor::Tuple(fl) => {
133 let fields = fl
134 .fields()
135 .enumerate()
136 .map(|(i, fd)| StructField {
137 name: SmolStr::new(i.to_string()),
138 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
139 })
140 .collect();
141 VariantData::Tuple(fields)
142 }
143 StructFlavor::Named(fl) => {
144 let fields = fl
145 .fields()
146 .map(|fd| StructField {
147 name: fd
148 .name()
149 .map(|n| n.text())
150 .unwrap_or_else(|| SmolStr::new("[error]")),
151 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
152 })
153 .collect();
154 VariantData::Struct(fields)
155 }
156 StructFlavor::Unit => VariantData::Unit,
157 }
158 }
159
160 pub(crate) fn get_field_type_ref(&self, field_name: &str) -> Option<&TypeRef> {
161 self.fields()
162 .iter()
163 .find(|f| f.name == field_name)
164 .map(|f| &f.type_ref)
165 }
166
167 pub fn fields(&self) -> &[StructField] {
168 match *self {
169 VariantData::Struct(ref fields) | VariantData::Tuple(ref fields) => fields,
170 _ => &[],
171 }
172 }
173 pub fn is_struct(&self) -> bool {
174 if let VariantData::Struct(..) = *self {
175 true
176 } else {
177 false
178 }
179 }
180 pub fn is_tuple(&self) -> bool {
181 if let VariantData::Tuple(..) = *self {
182 true
183 } else {
184 false
185 }
186 }
187 pub fn is_unit(&self) -> bool {
188 if let VariantData::Unit = *self {
189 true
190 } else {
191 false
192 }
193 }
194}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index d94f75857..e7f9afa77 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,6 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 SmolStr,
4 SyntaxNode, 5 SyntaxNode,
5 ast::FnDefNode, 6 ast::FnDefNode,
6}; 7};
@@ -15,6 +16,7 @@ use crate::{
15 module::{ModuleId, ModuleTree, ModuleSource, 16 module::{ModuleId, ModuleTree, ModuleSource,
16 nameres::{ItemMap, InputModuleItems}}, 17 nameres::{ItemMap, InputModuleItems}},
17 ty::{InferenceResult, Ty}, 18 ty::{InferenceResult, Ty},
19 adt::{StructData, EnumData},
18}; 20};
19 21
20salsa::query_group! { 22salsa::query_group! {
@@ -31,6 +33,16 @@ pub trait HirDatabase: SyntaxDatabase
31 use fn query_definitions::fn_syntax; 33 use fn query_definitions::fn_syntax;
32 } 34 }
33 35
36 fn struct_data(def_id: DefId) -> Cancelable<Arc<StructData>> {
37 type StructDataQuery;
38 use fn query_definitions::struct_data;
39 }
40
41 fn enum_data(def_id: DefId) -> Cancelable<Arc<EnumData>> {
42 type EnumDataQuery;
43 use fn query_definitions::enum_data;
44 }
45
34 fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> { 46 fn infer(fn_id: FnId) -> Cancelable<Arc<InferenceResult>> {
35 type InferQuery; 47 type InferQuery;
36 use fn query_definitions::infer; 48 use fn query_definitions::infer;
@@ -41,6 +53,11 @@ pub trait HirDatabase: SyntaxDatabase
41 use fn query_definitions::type_for_def; 53 use fn query_definitions::type_for_def;
42 } 54 }
43 55
56 fn type_for_field(def_id: DefId, field: SmolStr) -> Cancelable<Ty> {
57 type TypeForFieldQuery;
58 use fn query_definitions::type_for_field;
59 }
60
44 fn file_items(file_id: FileId) -> Arc<SourceFileItems> { 61 fn file_items(file_id: FileId) -> Arc<SourceFileItems> {
45 type SourceFileItemsQuery; 62 type SourceFileItemsQuery;
46 use fn query_definitions::file_items; 63 use fn query_definitions::file_items;
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index d36477b48..01f0f3a66 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -46,8 +46,7 @@ impl Function {
46 } 46 }
47 47
48 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> { 48 pub fn module(&self, db: &impl HirDatabase) -> Cancelable<Module> {
49 let loc = self.fn_id.0.loc(db); 49 self.fn_id.0.module(db)
50 Module::new(db, loc.source_root_id, loc.module_id)
51 } 50 }
52} 51}
53 52
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index a0d99a84d..f1cc0ccd0 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -25,6 +25,8 @@ pub mod source_binder;
25mod krate; 25mod krate;
26mod module; 26mod module;
27mod function; 27mod function;
28mod adt;
29mod type_ref;
28mod ty; 30mod ty;
29 31
30use std::ops::Index; 32use std::ops::Index;
@@ -40,8 +42,10 @@ use crate::{
40pub use self::{ 42pub use self::{
41 path::{Path, PathKind}, 43 path::{Path, PathKind},
42 krate::Crate, 44 krate::Crate,
43 module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution}, 45 module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
44 function::{Function, FnScopes}, 46 function::{Function, FnScopes},
47 adt::{Struct, Enum},
48 ty::Ty,
45}; 49};
46 50
47pub use self::function::FnSignatureInfo; 51pub use self::function::FnSignatureInfo;
@@ -56,7 +60,11 @@ ra_db::impl_numeric_id!(DefId);
56pub(crate) enum DefKind { 60pub(crate) enum DefKind {
57 Module, 61 Module,
58 Function, 62 Function,
63 Struct,
64 Enum,
59 Item, 65 Item,
66
67 StructCtor,
60} 68}
61 69
62#[derive(Clone, Debug, PartialEq, Eq, Hash)] 70#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -68,18 +76,18 @@ pub struct DefLoc {
68} 76}
69 77
70impl DefKind { 78impl DefKind {
71 pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> Option<DefKind> { 79 pub(crate) fn for_syntax_kind(kind: SyntaxKind) -> PerNs<DefKind> {
72 match kind { 80 match kind {
73 SyntaxKind::FN_DEF => Some(DefKind::Function), 81 SyntaxKind::FN_DEF => PerNs::values(DefKind::Function),
74 SyntaxKind::MODULE => Some(DefKind::Module), 82 SyntaxKind::MODULE => PerNs::types(DefKind::Module),
83 SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor),
84 SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum),
75 // These define items, but don't have their own DefKinds yet: 85 // These define items, but don't have their own DefKinds yet:
76 SyntaxKind::STRUCT_DEF => Some(DefKind::Item), 86 SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Item),
77 SyntaxKind::ENUM_DEF => Some(DefKind::Item), 87 SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Item),
78 SyntaxKind::TRAIT_DEF => Some(DefKind::Item), 88 SyntaxKind::CONST_DEF => PerNs::values(DefKind::Item),
79 SyntaxKind::TYPE_DEF => Some(DefKind::Item), 89 SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Item),
80 SyntaxKind::CONST_DEF => Some(DefKind::Item), 90 _ => PerNs::none(),
81 SyntaxKind::STATIC_DEF => Some(DefKind::Item),
82 _ => None,
83 } 91 }
84 } 92 }
85} 93}
@@ -99,6 +107,8 @@ impl DefLoc {
99pub enum Def { 107pub enum Def {
100 Module(Module), 108 Module(Module),
101 Function(Function), 109 Function(Function),
110 Struct(Struct),
111 Enum(Enum),
102 Item, 112 Item,
103} 113}
104 114
@@ -114,10 +124,25 @@ impl DefId {
114 let function = Function::new(self); 124 let function = Function::new(self);
115 Def::Function(function) 125 Def::Function(function)
116 } 126 }
127 DefKind::Struct => {
128 let struct_def = Struct::new(self);
129 Def::Struct(struct_def)
130 }
131 DefKind::Enum => {
132 let enum_def = Enum::new(self);
133 Def::Enum(enum_def)
134 }
135 DefKind::StructCtor => Def::Item,
117 DefKind::Item => Def::Item, 136 DefKind::Item => Def::Item,
118 }; 137 };
119 Ok(res) 138 Ok(res)
120 } 139 }
140
141 /// For a module, returns that module; for any other def, returns the containing module.
142 pub fn module(self, db: &impl HirDatabase) -> Cancelable<Module> {
143 let loc = self.loc(db);
144 Module::new(db, loc.source_root_id, loc.module_id)
145 }
121} 146}
122 147
123/// Identifier of item within a specific file. This is stable over reparses, so 148/// Identifier of item within a specific file. This is stable over reparses, so
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index b5a997170..f6882cb77 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -193,6 +193,9 @@ salsa::database_storage! {
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 fn type_for_def() for db::TypeForDefQuery;
196 fn type_for_field() for db::TypeForFieldQuery;
197 fn struct_data() for db::StructDataQuery;
198 fn enum_data() for db::EnumDataQuery;
196 } 199 }
197 } 200 }
198} 201}
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs
index 891119953..b9d36f01f 100644
--- a/crates/ra_hir/src/module.rs
+++ b/crates/ra_hir/src/module.rs
@@ -17,7 +17,7 @@ use crate::{
17 arena::{Arena, Id}, 17 arena::{Arena, Id},
18}; 18};
19 19
20pub use self::nameres::{ModuleScope, Resolution}; 20pub use self::nameres::{ModuleScope, Resolution, Namespace, PerNs};
21 21
22/// `Module` is API entry point to get all the information 22/// `Module` is API entry point to get all the information
23/// about a particular module. 23/// about a particular module.
@@ -115,16 +115,29 @@ impl Module {
115 Ok(res) 115 Ok(res)
116 } 116 }
117 117
118 pub fn resolve_path(&self, db: &impl HirDatabase, path: Path) -> Cancelable<Option<DefId>> { 118 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
119 let mut curr = match path.kind { 119 let mut curr_per_ns = PerNs::types(
120 PathKind::Crate => self.crate_root(), 120 match path.kind {
121 PathKind::Self_ | PathKind::Plain => self.clone(), 121 PathKind::Crate => self.crate_root(),
122 PathKind::Super => ctry!(self.parent()), 122 PathKind::Self_ | PathKind::Plain => self.clone(),
123 } 123 PathKind::Super => {
124 .def_id(db); 124 if let Some(p) = self.parent() {
125 p
126 } else {
127 return Ok(PerNs::none());
128 }
129 }
130 }
131 .def_id(db),
132 );
125 133
126 let segments = path.segments; 134 let segments = &path.segments;
127 for name in segments.iter() { 135 for name in segments.iter() {
136 let curr = if let Some(r) = curr_per_ns.as_ref().take(Namespace::Types) {
137 r
138 } else {
139 return Ok(PerNs::none());
140 };
128 let module = match curr.loc(db) { 141 let module = match curr.loc(db) {
129 DefLoc { 142 DefLoc {
130 kind: DefKind::Module, 143 kind: DefKind::Module,
@@ -132,12 +145,17 @@ impl Module {
132 module_id, 145 module_id,
133 .. 146 ..
134 } => Module::new(db, source_root_id, module_id)?, 147 } => Module::new(db, source_root_id, module_id)?,
135 _ => return Ok(None), 148 // TODO here would be the place to handle enum variants...
149 _ => return Ok(PerNs::none()),
136 }; 150 };
137 let scope = module.scope(db)?; 151 let scope = module.scope(db)?;
138 curr = ctry!(ctry!(scope.get(&name)).def_id); 152 curr_per_ns = if let Some(r) = scope.get(&name) {
153 r.def_id
154 } else {
155 return Ok(PerNs::none());
156 };
139 } 157 }
140 Ok(Some(curr)) 158 Ok(curr_per_ns)
141 } 159 }
142 160
143 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> { 161 pub fn problems(&self, db: &impl HirDatabase) -> Vec<(SyntaxNode, Problem)> {
@@ -145,7 +163,7 @@ impl Module {
145 } 163 }
146} 164}
147 165
148/// Phisically, rust source is organized as a set of files, but logically it is 166/// Physically, rust source is organized as a set of files, but logically it is
149/// organized as a tree of modules. Usually, a single file corresponds to a 167/// organized as a tree of modules. Usually, a single file corresponds to a
150/// single module, but it is not nessary the case. 168/// single module, but it is not nessary the case.
151/// 169///
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 0b152a406..98cd225dd 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -118,22 +118,96 @@ enum ImportKind {
118#[derive(Debug, Clone, PartialEq, Eq)] 118#[derive(Debug, Clone, PartialEq, Eq)]
119pub struct Resolution { 119pub struct Resolution {
120 /// None for unresolved 120 /// None for unresolved
121 pub def_id: Option<DefId>, 121 pub def_id: PerNs<DefId>,
122 /// ident by whitch this is imported into local scope. 122 /// ident by whitch this is imported into local scope.
123 pub import: Option<NamedImport>, 123 pub import: Option<NamedImport>,
124} 124}
125 125
126// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 126#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
127// enum Namespace { 127pub enum Namespace {
128// Types, 128 Types,
129// Values, 129 Values,
130// } 130}
131
132#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
133pub struct PerNs<T> {
134 pub types: Option<T>,
135 pub values: Option<T>,
136}
137
138impl<T> PerNs<T> {
139 pub fn none() -> PerNs<T> {
140 PerNs {
141 types: None,
142 values: None,
143 }
144 }
145
146 pub fn values(t: T) -> PerNs<T> {
147 PerNs {
148 types: None,
149 values: Some(t),
150 }
151 }
152
153 pub fn types(t: T) -> PerNs<T> {
154 PerNs {
155 types: Some(t),
156 values: None,
157 }
158 }
159
160 pub fn both(types: T, values: T) -> PerNs<T> {
161 PerNs {
162 types: Some(types),
163 values: Some(values),
164 }
165 }
166
167 pub fn is_none(&self) -> bool {
168 self.types.is_none() && self.values.is_none()
169 }
170
171 pub fn take(self, namespace: Namespace) -> Option<T> {
172 match namespace {
173 Namespace::Types => self.types,
174 Namespace::Values => self.values,
175 }
176 }
177
178 pub fn take_types(self) -> Option<T> {
179 self.types
180 }
181
182 pub fn take_values(self) -> Option<T> {
183 self.values
184 }
131 185
132// #[derive(Debug)] 186 pub fn get(&self, namespace: Namespace) -> Option<&T> {
133// struct PerNs<T> { 187 self.as_ref().take(namespace)
134// types: Option<T>, 188 }
135// values: Option<T>, 189
136// } 190 pub fn as_ref(&self) -> PerNs<&T> {
191 PerNs {
192 types: self.types.as_ref(),
193 values: self.values.as_ref(),
194 }
195 }
196
197 pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> {
198 PerNs {
199 types: self.types.and_then(&f),
200 values: self.values.and_then(&f),
201 }
202 }
203
204 pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> {
205 PerNs {
206 types: self.types.map(&f),
207 values: self.values.map(&f),
208 }
209 }
210}
137 211
138impl InputModuleItems { 212impl InputModuleItems {
139 pub(crate) fn new<'a>( 213 pub(crate) fn new<'a>(
@@ -254,7 +328,7 @@ where
254 for dep in krate.dependencies(self.db) { 328 for dep in krate.dependencies(self.db) {
255 if let Some(module) = dep.krate.root_module(self.db)? { 329 if let Some(module) = dep.krate.root_module(self.db)? {
256 let def_id = module.def_id(self.db); 330 let def_id = module.def_id(self.db);
257 self.add_module_item(&mut module_items, dep.name, def_id); 331 self.add_module_item(&mut module_items, dep.name, PerNs::types(def_id));
258 } 332 }
259 } 333 }
260 }; 334 };
@@ -265,7 +339,7 @@ where
265 module_items.items.insert( 339 module_items.items.insert(
266 name.clone(), 340 name.clone(),
267 Resolution { 341 Resolution {
268 def_id: None, 342 def_id: PerNs::none(),
269 import: Some(import), 343 import: Some(import),
270 }, 344 },
271 ); 345 );
@@ -277,18 +351,23 @@ where
277 if item.kind == MODULE { 351 if item.kind == MODULE {
278 continue; 352 continue;
279 } 353 }
280 let def_loc = DefLoc { 354 // depending on the item kind, the location can define something in
281 kind: DefKind::for_syntax_kind(item.kind).unwrap_or(DefKind::Item), 355 // the values namespace, the types namespace, or both
282 source_root_id: self.source_root, 356 let kind = DefKind::for_syntax_kind(item.kind);
283 module_id, 357 let def_id = kind.map(|k| {
284 source_item_id: SourceItemId { 358 let def_loc = DefLoc {
285 file_id, 359 kind: k,
286 item_id: Some(item.id), 360 source_root_id: self.source_root,
287 }, 361 module_id,
288 }; 362 source_item_id: SourceItemId {
289 let def_id = def_loc.id(self.db); 363 file_id,
364 item_id: Some(item.id),
365 },
366 };
367 def_loc.id(self.db)
368 });
290 let resolution = Resolution { 369 let resolution = Resolution {
291 def_id: Some(def_id), 370 def_id,
292 import: None, 371 import: None,
293 }; 372 };
294 module_items.items.insert(item.name.clone(), resolution); 373 module_items.items.insert(item.name.clone(), resolution);
@@ -303,16 +382,16 @@ where
303 source_item_id: module_id.source(&self.module_tree).0, 382 source_item_id: module_id.source(&self.module_tree).0,
304 }; 383 };
305 let def_id = def_loc.id(self.db); 384 let def_id = def_loc.id(self.db);
306 self.add_module_item(&mut module_items, name, def_id); 385 self.add_module_item(&mut module_items, name, PerNs::types(def_id));
307 } 386 }
308 387
309 self.result.per_module.insert(module_id, module_items); 388 self.result.per_module.insert(module_id, module_items);
310 Ok(()) 389 Ok(())
311 } 390 }
312 391
313 fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: DefId) { 392 fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, def_id: PerNs<DefId>) {
314 let resolution = Resolution { 393 let resolution = Resolution {
315 def_id: Some(def_id), 394 def_id,
316 import: None, 395 import: None,
317 }; 396 };
318 module_items.items.insert(name, resolution); 397 module_items.items.insert(name, resolution);
@@ -347,15 +426,17 @@ where
347 let is_last = i == import.path.segments.len() - 1; 426 let is_last = i == import.path.segments.len() - 1;
348 427
349 let def_id = match self.result.per_module[&curr].items.get(name) { 428 let def_id = match self.result.per_module[&curr].items.get(name) {
350 None => return Ok(()), 429 Some(res) if !res.def_id.is_none() => res.def_id,
351 Some(res) => match res.def_id { 430 _ => return Ok(()),
352 Some(it) => it,
353 None => return Ok(()),
354 },
355 }; 431 };
356 432
357 if !is_last { 433 if !is_last {
358 curr = match def_id.loc(self.db) { 434 let type_def_id = if let Some(d) = def_id.take(Namespace::Types) {
435 d
436 } else {
437 return Ok(());
438 };
439 curr = match type_def_id.loc(self.db) {
359 DefLoc { 440 DefLoc {
360 kind: DefKind::Module, 441 kind: DefKind::Module,
361 module_id: target_module_id, 442 module_id: target_module_id,
@@ -370,10 +451,11 @@ where
370 segments: import.path.segments[i + 1..].iter().cloned().collect(), 451 segments: import.path.segments[i + 1..].iter().cloned().collect(),
371 kind: PathKind::Crate, 452 kind: PathKind::Crate,
372 }; 453 };
373 if let Some(def_id) = module.resolve_path(self.db, path)? { 454 let def_id = module.resolve_path(self.db, &path)?;
455 if !def_id.is_none() {
374 self.update(module_id, |items| { 456 self.update(module_id, |items| {
375 let res = Resolution { 457 let res = Resolution {
376 def_id: Some(def_id), 458 def_id: def_id,
377 import: Some(ptr), 459 import: Some(ptr),
378 }; 460 };
379 items.items.insert(name.clone(), res); 461 items.items.insert(name.clone(), res);
@@ -387,7 +469,7 @@ where
387 } else { 469 } else {
388 self.update(module_id, |items| { 470 self.update(module_id, |items| {
389 let res = Resolution { 471 let res = Resolution {
390 def_id: Some(def_id), 472 def_id: def_id,
391 import: Some(ptr), 473 import: Some(ptr),
392 }; 474 };
393 items.items.insert(name.clone(), res); 475 items.items.insert(name.clone(), res);
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs
index 3e29c3954..03ea5c1d6 100644
--- a/crates/ra_hir/src/module/nameres/tests.rs
+++ b/crates/ra_hir/src/module/nameres/tests.rs
@@ -40,7 +40,7 @@ fn item_map_smoke_test() {
40 ); 40 );
41 let name = SmolStr::from("Baz"); 41 let name = SmolStr::from("Baz");
42 let resolution = &item_map.per_module[&module_id].items[&name]; 42 let resolution = &item_map.per_module[&module_id].items[&name];
43 assert!(resolution.def_id.is_some()); 43 assert!(resolution.def_id.take_types().is_some());
44} 44}
45 45
46#[test] 46#[test]
@@ -59,7 +59,7 @@ fn test_self() {
59 ); 59 );
60 let name = SmolStr::from("Baz"); 60 let name = SmolStr::from("Baz");
61 let resolution = &item_map.per_module[&module_id].items[&name]; 61 let resolution = &item_map.per_module[&module_id].items[&name];
62 assert!(resolution.def_id.is_some()); 62 assert!(resolution.def_id.take_types().is_some());
63} 63}
64 64
65#[test] 65#[test]
@@ -92,7 +92,7 @@ fn item_map_across_crates() {
92 92
93 let name = SmolStr::from("Baz"); 93 let name = SmolStr::from("Baz");
94 let resolution = &item_map.per_module[&module_id].items[&name]; 94 let resolution = &item_map.per_module[&module_id].items[&name];
95 assert!(resolution.def_id.is_some()); 95 assert!(resolution.def_id.take_types().is_some());
96} 96}
97 97
98#[test] 98#[test]
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index e04d00900..0b260072c 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -1,12 +1,12 @@
1use ra_syntax::{SmolStr, ast, AstNode, TextRange}; 1use ra_syntax::{SmolStr, ast, AstNode, TextRange};
2 2
3#[derive(Debug, Clone, PartialEq, Eq)] 3#[derive(Debug, Clone, PartialEq, Eq, Hash)]
4pub struct Path { 4pub struct Path {
5 pub kind: PathKind, 5 pub kind: PathKind,
6 pub segments: Vec<SmolStr>, 6 pub segments: Vec<SmolStr>,
7} 7}
8 8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)] 9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum PathKind { 10pub enum PathKind {
11 Plain, 11 Plain,
12 Self_, 12 Self_,
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index b654af920..4a7958a12 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -19,7 +19,8 @@ use crate::{
19 imp::Submodule, 19 imp::Submodule,
20 nameres::{InputModuleItems, ItemMap, Resolver}, 20 nameres::{InputModuleItems, ItemMap, Resolver},
21 }, 21 },
22 ty::{self, InferenceResult, Ty} 22 ty::{self, InferenceResult, Ty},
23 adt::{StructData, EnumData},
23}; 24};
24 25
25/// Resolve `FnId` to the corresponding `SyntaxNode` 26/// Resolve `FnId` to the corresponding `SyntaxNode`
@@ -45,6 +46,32 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<T
45 ty::type_for_def(db, def_id) 46 ty::type_for_def(db, def_id)
46} 47}
47 48
49pub(super) fn type_for_field(
50 db: &impl HirDatabase,
51 def_id: DefId,
52 field: SmolStr,
53) -> Cancelable<Ty> {
54 ty::type_for_field(db, def_id, field)
55}
56
57pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
58 let def_loc = def_id.loc(db);
59 assert!(def_loc.kind == DefKind::Struct);
60 let syntax = db.file_item(def_loc.source_item_id);
61 let struct_def =
62 ast::StructDef::cast(syntax.borrowed()).expect("struct def should point to StructDef node");
63 Ok(Arc::new(StructData::new(struct_def.borrowed())))
64}
65
66pub(super) fn enum_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<EnumData>> {
67 let def_loc = def_id.loc(db);
68 assert!(def_loc.kind == DefKind::Enum);
69 let syntax = db.file_item(def_loc.source_item_id);
70 let enum_def =
71 ast::EnumDef::cast(syntax.borrowed()).expect("enum def should point to EnumDef node");
72 Ok(Arc::new(EnumData::new(enum_def.borrowed())))
73}
74
48pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { 75pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
49 let mut res = SourceFileItems::new(file_id); 76 let mut res = SourceFileItems::new(file_id);
50 let source_file = db.source_file(file_id); 77 let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index c759d4c8b..67b523c2c 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -11,13 +11,18 @@ use rustc_hash::{FxHashMap};
11use ra_db::{LocalSyntaxPtr, Cancelable}; 11use ra_db::{LocalSyntaxPtr, Cancelable};
12use ra_syntax::{ 12use ra_syntax::{
13 SmolStr, 13 SmolStr,
14 ast::{self, AstNode, LoopBodyOwner, ArgListOwner}, 14 ast::{self, AstNode, LoopBodyOwner, ArgListOwner, PrefixOp},
15 SyntaxNodeRef 15 SyntaxNodeRef
16}; 16};
17 17
18use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase}; 18use crate::{
19 Def, DefId, FnScopes, Module, Function, Struct, Enum, Path,
20 db::HirDatabase,
21 adt::VariantData,
22 type_ref::{TypeRef, Mutability},
23};
19 24
20#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 25#[derive(Clone, PartialEq, Eq, Hash, Debug)]
21pub enum Ty { 26pub enum Ty {
22 /// The primitive boolean type. Written as `bool`. 27 /// The primitive boolean type. Written as `bool`.
23 Bool, 28 Bool,
@@ -35,8 +40,15 @@ pub enum Ty {
35 /// A primitive floating-point type. For example, `f64`. 40 /// A primitive floating-point type. For example, `f64`.
36 Float(primitive::FloatTy), 41 Float(primitive::FloatTy),
37 42
38 // Structures, enumerations and unions. 43 /// Structures, enumerations and unions.
39 // Adt(AdtDef, Substs), 44 Adt {
45 /// The DefId of the struct/enum.
46 def_id: DefId,
47 /// The name, for displaying.
48 name: SmolStr,
49 // later we'll need generic substitutions here
50 },
51
40 /// The pointee of a string slice. Written as `str`. 52 /// The pointee of a string slice. Written as `str`.
41 Str, 53 Str,
42 54
@@ -45,12 +57,13 @@ pub enum Ty {
45 /// The pointee of an array slice. Written as `[T]`. 57 /// The pointee of an array slice. Written as `[T]`.
46 Slice(TyRef), 58 Slice(TyRef),
47 59
48 // A raw pointer. Written as `*mut T` or `*const T` 60 /// A raw pointer. Written as `*mut T` or `*const T`
49 // RawPtr(TypeAndMut<'tcx>), 61 RawPtr(TyRef, Mutability),
62
63 /// A reference; a pointer with an associated lifetime. Written as
64 /// `&'a mut T` or `&'a T`.
65 Ref(TyRef, Mutability),
50 66
51 // A reference; a pointer with an associated lifetime. Written as
52 // `&'a mut T` or `&'a T`.
53 // Ref(Ty<'tcx>, hir::Mutability),
54 /// A pointer to a function. Written as `fn() -> i32`. 67 /// A pointer to a function. Written as `fn() -> i32`.
55 /// 68 ///
56 /// For example the type of `bar` here: 69 /// For example the type of `bar` here:
@@ -107,58 +120,104 @@ pub enum Ty {
107 120
108type TyRef = Arc<Ty>; 121type TyRef = Arc<Ty>;
109 122
110#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 123#[derive(Clone, PartialEq, Eq, Hash, Debug)]
111pub struct FnSig { 124pub struct FnSig {
112 input: Vec<Ty>, 125 input: Vec<Ty>,
113 output: Ty, 126 output: Ty,
114} 127}
115 128
116impl Ty { 129impl Ty {
117 pub fn new(_db: &impl HirDatabase, node: ast::TypeRef) -> Cancelable<Self> { 130 pub(crate) fn from_hir(
118 use ra_syntax::ast::TypeRef::*; 131 db: &impl HirDatabase,
119 Ok(match node { 132 module: &Module,
120 ParenType(_inner) => Ty::Unknown, // TODO 133 type_ref: &TypeRef,
121 TupleType(_inner) => Ty::Unknown, // TODO 134 ) -> Cancelable<Self> {
122 NeverType(..) => Ty::Never, 135 Ok(match type_ref {
123 PathType(inner) => { 136 TypeRef::Never => Ty::Never,
124 let path = if let Some(p) = inner.path() { 137 TypeRef::Tuple(inner) => {
125 p 138 let inner_tys = inner
126 } else { 139 .iter()
127 return Ok(Ty::Unknown); 140 .map(|tr| Ty::from_hir(db, module, tr))
141 .collect::<Cancelable<_>>()?;
142 Ty::Tuple(inner_tys)
143 }
144 TypeRef::Path(path) => Ty::from_hir_path(db, module, path)?,
145 TypeRef::RawPtr(inner, mutability) => {
146 let inner_ty = Ty::from_hir(db, module, inner)?;
147 Ty::RawPtr(Arc::new(inner_ty), *mutability)
148 }
149 TypeRef::Array(_inner) => Ty::Unknown, // TODO
150 TypeRef::Slice(inner) => {
151 let inner_ty = Ty::from_hir(db, module, inner)?;
152 Ty::Slice(Arc::new(inner_ty))
153 }
154 TypeRef::Reference(inner, mutability) => {
155 let inner_ty = Ty::from_hir(db, module, inner)?;
156 Ty::Ref(Arc::new(inner_ty), *mutability)
157 }
158 TypeRef::Placeholder => Ty::Unknown, // TODO
159 TypeRef::Fn(params) => {
160 let mut inner_tys = params
161 .iter()
162 .map(|tr| Ty::from_hir(db, module, tr))
163 .collect::<Cancelable<Vec<_>>>()?;
164 let return_ty = inner_tys
165 .pop()
166 .expect("TypeRef::Fn should always have at least return type");
167 let sig = FnSig {
168 input: inner_tys,
169 output: return_ty,
128 }; 170 };
129 if path.qualifier().is_none() { 171 Ty::FnPtr(Arc::new(sig))
130 let name = path
131 .segment()
132 .and_then(|s| s.name_ref())
133 .map(|n| n.text())
134 .unwrap_or(SmolStr::new(""));
135 if let Some(int_ty) = primitive::IntTy::from_string(&name) {
136 Ty::Int(int_ty)
137 } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) {
138 Ty::Uint(uint_ty)
139 } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
140 Ty::Float(float_ty)
141 } else {
142 // TODO
143 Ty::Unknown
144 }
145 } else {
146 // TODO
147 Ty::Unknown
148 }
149 } 172 }
150 PointerType(_inner) => Ty::Unknown, // TODO 173 TypeRef::Error => Ty::Unknown,
151 ArrayType(_inner) => Ty::Unknown, // TODO
152 SliceType(_inner) => Ty::Unknown, // TODO
153 ReferenceType(_inner) => Ty::Unknown, // TODO
154 PlaceholderType(_inner) => Ty::Unknown, // TODO
155 FnPointerType(_inner) => Ty::Unknown, // TODO
156 ForType(_inner) => Ty::Unknown, // TODO
157 ImplTraitType(_inner) => Ty::Unknown, // TODO
158 DynTraitType(_inner) => Ty::Unknown, // TODO
159 }) 174 })
160 } 175 }
161 176
177 pub(crate) fn from_hir_path(
178 db: &impl HirDatabase,
179 module: &Module,
180 path: &Path,
181 ) -> Cancelable<Self> {
182 if path.is_ident() {
183 let name = &path.segments[0];
184 if let Some(int_ty) = primitive::IntTy::from_string(&name) {
185 return Ok(Ty::Int(int_ty));
186 } else if let Some(uint_ty) = primitive::UintTy::from_string(&name) {
187 return Ok(Ty::Uint(uint_ty));
188 } else if let Some(float_ty) = primitive::FloatTy::from_string(&name) {
189 return Ok(Ty::Float(float_ty));
190 }
191 }
192
193 // Resolve in module (in type namespace)
194 let resolved = if let Some(r) = module.resolve_path(db, path)?.take_types() {
195 r
196 } else {
197 return Ok(Ty::Unknown);
198 };
199 let ty = db.type_for_def(resolved)?;
200 Ok(ty)
201 }
202
203 // TODO: These should not be necessary long-term, since everything will work on HIR
204 pub(crate) fn from_ast_opt(
205 db: &impl HirDatabase,
206 module: &Module,
207 node: Option<ast::TypeRef>,
208 ) -> Cancelable<Self> {
209 node.map(|n| Ty::from_ast(db, module, n))
210 .unwrap_or(Ok(Ty::Unknown))
211 }
212
213 pub(crate) fn from_ast(
214 db: &impl HirDatabase,
215 module: &Module,
216 node: ast::TypeRef,
217 ) -> Cancelable<Self> {
218 Ty::from_hir(db, module, &TypeRef::from_ast(node))
219 }
220
162 pub fn unit() -> Self { 221 pub fn unit() -> Self {
163 Ty::Tuple(Vec::new()) 222 Ty::Tuple(Vec::new())
164 } 223 }
@@ -174,6 +233,8 @@ impl fmt::Display for Ty {
174 Ty::Float(t) => write!(f, "{}", t.ty_to_string()), 233 Ty::Float(t) => write!(f, "{}", t.ty_to_string()),
175 Ty::Str => write!(f, "str"), 234 Ty::Str => write!(f, "str"),
176 Ty::Slice(t) => write!(f, "[{}]", t), 235 Ty::Slice(t) => write!(f, "[{}]", t),
236 Ty::RawPtr(t, m) => write!(f, "*{}{}", m.as_keyword_for_ptr(), t),
237 Ty::Ref(t, m) => write!(f, "&{}{}", m.as_keyword_for_ref(), t),
177 Ty::Never => write!(f, "!"), 238 Ty::Never => write!(f, "!"),
178 Ty::Tuple(ts) => { 239 Ty::Tuple(ts) => {
179 write!(f, "(")?; 240 write!(f, "(")?;
@@ -189,6 +250,7 @@ impl fmt::Display for Ty {
189 } 250 }
190 write!(f, ") -> {}", sig.output) 251 write!(f, ") -> {}", sig.output)
191 } 252 }
253 Ty::Adt { name, .. } => write!(f, "{}", name),
192 Ty::Unknown => write!(f, "[unknown]"), 254 Ty::Unknown => write!(f, "[unknown]"),
193 } 255 }
194 } 256 }
@@ -196,34 +258,40 @@ impl fmt::Display for Ty {
196 258
197pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { 259pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> {
198 let syntax = f.syntax(db); 260 let syntax = f.syntax(db);
261 let module = f.module(db)?;
199 let node = syntax.borrowed(); 262 let node = syntax.borrowed();
200 // TODO we ignore type parameters for now 263 // TODO we ignore type parameters for now
201 let input = node 264 let input = node
202 .param_list() 265 .param_list()
203 .map(|pl| { 266 .map(|pl| {
204 pl.params() 267 pl.params()
205 .map(|p| { 268 .map(|p| Ty::from_ast_opt(db, &module, p.type_ref()))
206 p.type_ref()
207 .map(|t| Ty::new(db, t))
208 .unwrap_or(Ok(Ty::Unknown))
209 })
210 .collect() 269 .collect()
211 }) 270 })
212 .unwrap_or_else(|| Ok(Vec::new()))?; 271 .unwrap_or_else(|| Ok(Vec::new()))?;
213 let output = node 272 let output = Ty::from_ast_opt(db, &module, node.ret_type().and_then(|rt| rt.type_ref()))?;
214 .ret_type()
215 .and_then(|rt| rt.type_ref())
216 .map(|t| Ty::new(db, t))
217 .unwrap_or(Ok(Ty::Unknown))?;
218 let sig = FnSig { input, output }; 273 let sig = FnSig { input, output };
219 Ok(Ty::FnPtr(Arc::new(sig))) 274 Ok(Ty::FnPtr(Arc::new(sig)))
220} 275}
221 276
222// TODO this should probably be per namespace (i.e. types vs. values), since for 277pub fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Cancelable<Ty> {
223// a tuple struct `struct Foo(Bar)`, Foo has function type as a value, but 278 Ok(Ty::Adt {
224// defines the struct type Foo when used in the type namespace. rustc has a 279 def_id: s.def_id(),
225// separate DefId for the constructor, but with the current DefId approach, that 280 name: s
226// seems complicated. 281 .name(db)?
282 .unwrap_or_else(|| SmolStr::new("[unnamed struct]")),
283 })
284}
285
286pub fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Cancelable<Ty> {
287 Ok(Ty::Adt {
288 def_id: s.def_id(),
289 name: s
290 .name(db)?
291 .unwrap_or_else(|| SmolStr::new("[unnamed enum]")),
292 })
293}
294
227pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { 295pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
228 let def = def_id.resolve(db)?; 296 let def = def_id.resolve(db)?;
229 match def { 297 match def {
@@ -232,6 +300,8 @@ pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
232 Ok(Ty::Unknown) 300 Ok(Ty::Unknown)
233 } 301 }
234 Def::Function(f) => type_for_fn(db, f), 302 Def::Function(f) => type_for_fn(db, f),
303 Def::Struct(s) => type_for_struct(db, s),
304 Def::Enum(e) => type_for_enum(db, e),
235 Def::Item => { 305 Def::Item => {
236 log::debug!("trying to get type for item of unknown type {:?}", def_id); 306 log::debug!("trying to get type for item of unknown type {:?}", def_id);
237 Ok(Ty::Unknown) 307 Ok(Ty::Unknown)
@@ -239,6 +309,33 @@ pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> {
239 } 309 }
240} 310}
241 311
312pub(super) fn type_for_field(
313 db: &impl HirDatabase,
314 def_id: DefId,
315 field: SmolStr,
316) -> Cancelable<Ty> {
317 let def = def_id.resolve(db)?;
318 let variant_data = match def {
319 Def::Struct(s) => {
320 let variant_data = s.variant_data(db)?;
321 variant_data
322 }
323 // TODO: unions
324 // TODO: enum variants
325 _ => panic!(
326 "trying to get type for field in non-struct/variant {:?}",
327 def_id
328 ),
329 };
330 let module = def_id.module(db)?;
331 let type_ref = if let Some(tr) = variant_data.get_field_type_ref(&field) {
332 tr
333 } else {
334 return Ok(Ty::Unknown);
335 };
336 Ty::from_hir(db, &module, &type_ref)
337}
338
242#[derive(Clone, PartialEq, Eq, Debug)] 339#[derive(Clone, PartialEq, Eq, Debug)]
243pub struct InferenceResult { 340pub struct InferenceResult {
244 type_of: FxHashMap<LocalSyntaxPtr, Ty>, 341 type_of: FxHashMap<LocalSyntaxPtr, Ty>,
@@ -305,32 +402,54 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
305 }; 402 };
306 403
307 // resolve in module 404 // resolve in module
308 let resolved = ctry!(self.module.resolve_path(self.db, path)?); 405 let resolved = ctry!(self.module.resolve_path(self.db, &path)?.take_values());
309 let ty = self.db.type_for_def(resolved)?; 406 let ty = self.db.type_for_def(resolved)?;
310 // TODO we will need to add type variables for type parameters etc. here 407 // TODO we will need to add type variables for type parameters etc. here
311 Ok(Some(ty)) 408 Ok(Some(ty))
312 } 409 }
313 410
411 fn resolve_variant(
412 &self,
413 path: Option<ast::Path>,
414 ) -> Cancelable<(Ty, Option<Arc<VariantData>>)> {
415 let path = if let Some(path) = path.and_then(Path::from_ast) {
416 path
417 } else {
418 return Ok((Ty::Unknown, None));
419 };
420 let def_id = if let Some(def_id) = self.module.resolve_path(self.db, &path)?.take_types() {
421 def_id
422 } else {
423 return Ok((Ty::Unknown, None));
424 };
425 Ok(match def_id.resolve(self.db)? {
426 Def::Struct(s) => {
427 let struct_data = self.db.struct_data(def_id)?;
428 let ty = type_for_struct(self.db, s)?;
429 (ty, Some(struct_data.variant_data().clone()))
430 }
431 _ => (Ty::Unknown, None),
432 })
433 }
434
435 fn infer_expr_opt(&mut self, expr: Option<ast::Expr>) -> Cancelable<Ty> {
436 if let Some(e) = expr {
437 self.infer_expr(e)
438 } else {
439 Ok(Ty::Unknown)
440 }
441 }
442
314 fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> { 443 fn infer_expr(&mut self, expr: ast::Expr) -> Cancelable<Ty> {
315 let ty = match expr { 444 let ty = match expr {
316 ast::Expr::IfExpr(e) => { 445 ast::Expr::IfExpr(e) => {
317 if let Some(condition) = e.condition() { 446 if let Some(condition) = e.condition() {
318 if let Some(e) = condition.expr() { 447 // TODO if no pat, this should be bool
319 // TODO if no pat, this should be bool 448 self.infer_expr_opt(condition.expr())?;
320 self.infer_expr(e)?;
321 }
322 // TODO write type for pat 449 // TODO write type for pat
323 }; 450 };
324 let if_ty = if let Some(block) = e.then_branch() { 451 let if_ty = self.infer_block_opt(e.then_branch())?;
325 self.infer_block(block)? 452 let else_ty = self.infer_block_opt(e.else_branch())?;
326 } else {
327 Ty::Unknown
328 };
329 let else_ty = if let Some(block) = e.else_branch() {
330 self.infer_block(block)?
331 } else {
332 Ty::Unknown
333 };
334 if let Some(ty) = self.unify(&if_ty, &else_ty) { 453 if let Some(ty) = self.unify(&if_ty, &else_ty) {
335 ty 454 ty
336 } else { 455 } else {
@@ -338,62 +457,37 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
338 Ty::Unknown 457 Ty::Unknown
339 } 458 }
340 } 459 }
341 ast::Expr::BlockExpr(e) => { 460 ast::Expr::BlockExpr(e) => self.infer_block_opt(e.block())?,
342 if let Some(block) = e.block() {
343 self.infer_block(block)?
344 } else {
345 Ty::Unknown
346 }
347 }
348 ast::Expr::LoopExpr(e) => { 461 ast::Expr::LoopExpr(e) => {
349 if let Some(block) = e.loop_body() { 462 self.infer_block_opt(e.loop_body())?;
350 self.infer_block(block)?;
351 };
352 // TODO never, or the type of the break param 463 // TODO never, or the type of the break param
353 Ty::Unknown 464 Ty::Unknown
354 } 465 }
355 ast::Expr::WhileExpr(e) => { 466 ast::Expr::WhileExpr(e) => {
356 if let Some(condition) = e.condition() { 467 if let Some(condition) = e.condition() {
357 if let Some(e) = condition.expr() { 468 // TODO if no pat, this should be bool
358 // TODO if no pat, this should be bool 469 self.infer_expr_opt(condition.expr())?;
359 self.infer_expr(e)?;
360 }
361 // TODO write type for pat 470 // TODO write type for pat
362 }; 471 };
363 if let Some(block) = e.loop_body() { 472 self.infer_block_opt(e.loop_body())?;
364 // TODO
365 self.infer_block(block)?;
366 };
367 // TODO always unit? 473 // TODO always unit?
368 Ty::Unknown 474 Ty::Unknown
369 } 475 }
370 ast::Expr::ForExpr(e) => { 476 ast::Expr::ForExpr(e) => {
371 if let Some(expr) = e.iterable() { 477 let _iterable_ty = self.infer_expr_opt(e.iterable());
372 self.infer_expr(expr)?;
373 }
374 if let Some(_pat) = e.pat() { 478 if let Some(_pat) = e.pat() {
375 // TODO write type for pat 479 // TODO write type for pat
376 } 480 }
377 if let Some(block) = e.loop_body() { 481 self.infer_block_opt(e.loop_body())?;
378 self.infer_block(block)?;
379 }
380 // TODO always unit? 482 // TODO always unit?
381 Ty::Unknown 483 Ty::Unknown
382 } 484 }
383 ast::Expr::LambdaExpr(e) => { 485 ast::Expr::LambdaExpr(e) => {
384 let _body_ty = if let Some(body) = e.body() { 486 let _body_ty = self.infer_expr_opt(e.body())?;
385 self.infer_expr(body)?
386 } else {
387 Ty::Unknown
388 };
389 Ty::Unknown 487 Ty::Unknown
390 } 488 }
391 ast::Expr::CallExpr(e) => { 489 ast::Expr::CallExpr(e) => {
392 let callee_ty = if let Some(e) = e.expr() { 490 let callee_ty = self.infer_expr_opt(e.expr())?;
393 self.infer_expr(e)?
394 } else {
395 Ty::Unknown
396 };
397 if let Some(arg_list) = e.arg_list() { 491 if let Some(arg_list) = e.arg_list() {
398 for arg in arg_list.args() { 492 for arg in arg_list.args() {
399 // TODO unify / expect argument type 493 // TODO unify / expect argument type
@@ -410,11 +504,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
410 } 504 }
411 } 505 }
412 ast::Expr::MethodCallExpr(e) => { 506 ast::Expr::MethodCallExpr(e) => {
413 let _receiver_ty = if let Some(e) = e.expr() { 507 let _receiver_ty = self.infer_expr_opt(e.expr())?;
414 self.infer_expr(e)?
415 } else {
416 Ty::Unknown
417 };
418 if let Some(arg_list) = e.arg_list() { 508 if let Some(arg_list) = e.arg_list() {
419 for arg in arg_list.args() { 509 for arg in arg_list.args() {
420 // TODO unify / expect argument type 510 // TODO unify / expect argument type
@@ -424,20 +514,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
424 Ty::Unknown 514 Ty::Unknown
425 } 515 }
426 ast::Expr::MatchExpr(e) => { 516 ast::Expr::MatchExpr(e) => {
427 let _ty = if let Some(match_expr) = e.expr() { 517 let _ty = self.infer_expr_opt(e.expr())?;
428 self.infer_expr(match_expr)?
429 } else {
430 Ty::Unknown
431 };
432 if let Some(match_arm_list) = e.match_arm_list() { 518 if let Some(match_arm_list) = e.match_arm_list() {
433 for arm in match_arm_list.arms() { 519 for arm in match_arm_list.arms() {
434 // TODO type the bindings in pat 520 // TODO type the bindings in pat
435 // TODO type the guard 521 // TODO type the guard
436 let _ty = if let Some(e) = arm.expr() { 522 let _ty = self.infer_expr_opt(arm.expr())?;
437 self.infer_expr(e)?
438 } else {
439 Ty::Unknown
440 };
441 } 523 }
442 // TODO unify all the match arm types 524 // TODO unify all the match arm types
443 Ty::Unknown 525 Ty::Unknown
@@ -450,68 +532,78 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
450 ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown), 532 ast::Expr::PathExpr(e) => self.infer_path_expr(e)?.unwrap_or(Ty::Unknown),
451 ast::Expr::ContinueExpr(_e) => Ty::Never, 533 ast::Expr::ContinueExpr(_e) => Ty::Never,
452 ast::Expr::BreakExpr(_e) => Ty::Never, 534 ast::Expr::BreakExpr(_e) => Ty::Never,
453 ast::Expr::ParenExpr(e) => { 535 ast::Expr::ParenExpr(e) => self.infer_expr_opt(e.expr())?,
454 if let Some(e) = e.expr() {
455 self.infer_expr(e)?
456 } else {
457 Ty::Unknown
458 }
459 }
460 ast::Expr::Label(_e) => Ty::Unknown, 536 ast::Expr::Label(_e) => Ty::Unknown,
461 ast::Expr::ReturnExpr(e) => { 537 ast::Expr::ReturnExpr(e) => {
462 if let Some(e) = e.expr() { 538 self.infer_expr_opt(e.expr())?;
463 // TODO unify with return type
464 self.infer_expr(e)?;
465 };
466 Ty::Never 539 Ty::Never
467 } 540 }
468 ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => { 541 ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
469 // Can this even occur outside of a match expression? 542 // Can this even occur outside of a match expression?
470 Ty::Unknown 543 Ty::Unknown
471 } 544 }
472 ast::Expr::StructLit(_e) => Ty::Unknown, 545 ast::Expr::StructLit(e) => {
546 let (ty, _variant_data) = self.resolve_variant(e.path())?;
547 if let Some(nfl) = e.named_field_list() {
548 for field in nfl.fields() {
549 // TODO unify with / expect field type
550 self.infer_expr_opt(field.expr())?;
551 }
552 }
553 ty
554 }
473 ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => { 555 ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => {
474 // Can this even occur outside of a struct literal? 556 // Can this even occur outside of a struct literal?
475 Ty::Unknown 557 Ty::Unknown
476 } 558 }
477 ast::Expr::IndexExpr(_e) => Ty::Unknown, 559 ast::Expr::IndexExpr(_e) => Ty::Unknown,
478 ast::Expr::FieldExpr(_e) => Ty::Unknown, 560 ast::Expr::FieldExpr(e) => {
479 ast::Expr::TryExpr(e) => { 561 let receiver_ty = self.infer_expr_opt(e.expr())?;
480 let _inner_ty = if let Some(e) = e.expr() { 562 if let Some(nr) = e.name_ref() {
481 self.infer_expr(e)? 563 let text = nr.text();
564 match receiver_ty {
565 Ty::Tuple(fields) => {
566 let i = text.parse::<usize>().ok();
567 i.and_then(|i| fields.get(i).cloned())
568 .unwrap_or(Ty::Unknown)
569 }
570 Ty::Adt { def_id, .. } => self.db.type_for_field(def_id, text)?,
571 _ => Ty::Unknown,
572 }
482 } else { 573 } else {
483 Ty::Unknown 574 Ty::Unknown
484 }; 575 }
576 }
577 ast::Expr::TryExpr(e) => {
578 let _inner_ty = self.infer_expr_opt(e.expr())?;
485 Ty::Unknown 579 Ty::Unknown
486 } 580 }
487 ast::Expr::CastExpr(e) => { 581 ast::Expr::CastExpr(e) => {
488 let _inner_ty = if let Some(e) = e.expr() { 582 let _inner_ty = self.infer_expr_opt(e.expr())?;
489 self.infer_expr(e)? 583 let cast_ty = Ty::from_ast_opt(self.db, &self.module, e.type_ref())?;
490 } else {
491 Ty::Unknown
492 };
493 let cast_ty = e
494 .type_ref()
495 .map(|t| Ty::new(self.db, t))
496 .unwrap_or(Ok(Ty::Unknown))?;
497 // TODO do the coercion... 584 // TODO do the coercion...
498 cast_ty 585 cast_ty
499 } 586 }
500 ast::Expr::RefExpr(e) => { 587 ast::Expr::RefExpr(e) => {
501 let _inner_ty = if let Some(e) = e.expr() { 588 let inner_ty = self.infer_expr_opt(e.expr())?;
502 self.infer_expr(e)? 589 let m = Mutability::from_mutable(e.is_mut());
503 } else { 590 // TODO reference coercions etc.
504 Ty::Unknown 591 Ty::Ref(Arc::new(inner_ty), m)
505 };
506 Ty::Unknown
507 } 592 }
508 ast::Expr::PrefixExpr(e) => { 593 ast::Expr::PrefixExpr(e) => {
509 let _inner_ty = if let Some(e) = e.expr() { 594 let inner_ty = self.infer_expr_opt(e.expr())?;
510 self.infer_expr(e)? 595 match e.op() {
511 } else { 596 Some(PrefixOp::Deref) => {
512 Ty::Unknown 597 match inner_ty {
513 }; 598 // builtin deref:
514 Ty::Unknown 599 Ty::Ref(ref_inner, _) => (*ref_inner).clone(),
600 Ty::RawPtr(ptr_inner, _) => (*ptr_inner).clone(),
601 // TODO Deref::deref
602 _ => Ty::Unknown,
603 }
604 }
605 _ => Ty::Unknown,
606 }
515 } 607 }
516 ast::Expr::RangeExpr(_e) => Ty::Unknown, 608 ast::Expr::RangeExpr(_e) => Ty::Unknown,
517 ast::Expr::BinExpr(_e) => Ty::Unknown, 609 ast::Expr::BinExpr(_e) => Ty::Unknown,
@@ -521,15 +613,19 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
521 Ok(ty) 613 Ok(ty)
522 } 614 }
523 615
616 fn infer_block_opt(&mut self, node: Option<ast::Block>) -> Cancelable<Ty> {
617 if let Some(b) = node {
618 self.infer_block(b)
619 } else {
620 Ok(Ty::Unknown)
621 }
622 }
623
524 fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> { 624 fn infer_block(&mut self, node: ast::Block) -> Cancelable<Ty> {
525 for stmt in node.statements() { 625 for stmt in node.statements() {
526 match stmt { 626 match stmt {
527 ast::Stmt::LetStmt(stmt) => { 627 ast::Stmt::LetStmt(stmt) => {
528 let decl_ty = if let Some(type_ref) = stmt.type_ref() { 628 let decl_ty = Ty::from_ast_opt(self.db, &self.module, stmt.type_ref())?;
529 Ty::new(self.db, type_ref)?
530 } else {
531 Ty::Unknown
532 };
533 let ty = if let Some(expr) = stmt.initializer() { 629 let ty = if let Some(expr) = stmt.initializer() {
534 // TODO pass expectation 630 // TODO pass expectation
535 let expr_ty = self.infer_expr(expr)?; 631 let expr_ty = self.infer_expr(expr)?;
@@ -544,9 +640,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
544 }; 640 };
545 } 641 }
546 ast::Stmt::ExprStmt(expr_stmt) => { 642 ast::Stmt::ExprStmt(expr_stmt) => {
547 if let Some(expr) = expr_stmt.expr() { 643 self.infer_expr_opt(expr_stmt.expr())?;
548 self.infer_expr(expr)?;
549 }
550 } 644 }
551 } 645 }
552 } 646 }
@@ -576,7 +670,7 @@ pub fn infer(db: &impl HirDatabase, function: Function) -> Cancelable<InferenceR
576 continue; 670 continue;
577 }; 671 };
578 if let Some(type_ref) = param.type_ref() { 672 if let Some(type_ref) = param.type_ref() {
579 let ty = Ty::new(db, type_ref)?; 673 let ty = Ty::from_ast(db, &ctx.module, type_ref)?;
580 ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty); 674 ctx.type_of.insert(LocalSyntaxPtr::new(pat.syntax()), ty);
581 } else { 675 } else {
582 // TODO self param 676 // TODO self param
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index b6c02cd80..a76925b58 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -68,6 +68,51 @@ fn test() {
68 ); 68 );
69} 69}
70 70
71#[test]
72fn infer_struct() {
73 check_inference(
74 r#"
75struct A {
76 b: B,
77 c: C,
78}
79struct B;
80struct C(usize);
81
82fn test() {
83 let c = C(1);
84 B;
85 let a: A = A { b: B, c: C(1) };
86 a.b;
87 a.c;
88}
89"#,
90 "0004_struct.txt",
91 );
92}
93
94#[test]
95fn infer_refs_and_ptrs() {
96 check_inference(
97 r#"
98fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
99 a;
100 *a;
101 &a;
102 &mut a;
103 b;
104 *b;
105 &b;
106 c;
107 *c;
108 d;
109 *d;
110}
111"#,
112 "0005_refs.txt",
113 );
114}
115
71fn infer(content: &str) -> String { 116fn infer(content: &str) -> String {
72 let (db, _, file_id) = MockDatabase::with_single_file(content); 117 let (db, _, file_id) = MockDatabase::with_single_file(content);
73 let source_file = db.source_file(file_id); 118 let source_file = db.source_file(file_id);
diff --git a/crates/ra_hir/src/ty/tests/data/0001_basics.txt b/crates/ra_hir/src/ty/tests/data/0001_basics.txt
index 0c46f243a..212e92e00 100644
--- a/crates/ra_hir/src/ty/tests/data/0001_basics.txt
+++ b/crates/ra_hir/src/ty/tests/data/0001_basics.txt
@@ -1,4 +1,4 @@
1[33; 34) 'd': [unknown] 1[33; 34) 'd': &[unknown]
2[88; 94) '1isize': [unknown] 2[88; 94) '1isize': [unknown]
3[48; 49) 'a': u32 3[48; 49) 'a': u32
4[55; 56) 'b': isize 4[55; 56) 'b': isize
@@ -10,4 +10,4 @@
10[17; 18) 'b': isize 10[17; 18) 'b': isize
11[100; 106) '"test"': [unknown] 11[100; 106) '"test"': [unknown]
12[42; 121) '{ ...f32; }': () 12[42; 121) '{ ...f32; }': ()
13[69; 70) 'd': [unknown] 13[69; 70) 'd': &[unknown]
diff --git a/crates/ra_hir/src/ty/tests/data/0004_struct.txt b/crates/ra_hir/src/ty/tests/data/0004_struct.txt
new file mode 100644
index 000000000..cc8f3665b
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0004_struct.txt
@@ -0,0 +1,16 @@
1[86; 90) 'C(1)': [unknown]
2[121; 122) 'B': [unknown]
3[86; 87) 'C': [unknown]
4[129; 130) '1': [unknown]
5[107; 108) 'a': A
6[127; 128) 'C': [unknown]
7[139; 142) 'a.b': B
8[114; 133) 'A { b:...C(1) }': A
9[148; 151) 'a.c': C
10[148; 149) 'a': A
11[139; 140) 'a': A
12[72; 154) '{ ...a.c; }': ()
13[96; 97) 'B': [unknown]
14[88; 89) '1': [unknown]
15[82; 83) 'c': [unknown]
16[127; 131) 'C(1)': [unknown]
diff --git a/crates/ra_hir/src/ty/tests/data/0005_refs.txt b/crates/ra_hir/src/ty/tests/data/0005_refs.txt
new file mode 100644
index 000000000..296e955c1
--- /dev/null
+++ b/crates/ra_hir/src/ty/tests/data/0005_refs.txt
@@ -0,0 +1,23 @@
1[115; 117) '&b': &&mut u32
2[88; 94) '&mut a': &mut &u32
3[146; 147) 'd': *mut u32
4[145; 147) '*d': u32
5[65; 66) 'a': &u32
6[46; 47) 'd': *mut u32
7[59; 150) '{ ... *d; }': ()
8[116; 117) 'b': &mut u32
9[131; 132) 'c': *const u32
10[130; 132) '*c': u32
11[72; 74) '*a': u32
12[107; 109) '*b': u32
13[108; 109) 'b': &mut u32
14[9; 10) 'a': &u32
15[18; 19) 'b': &mut u32
16[93; 94) 'a': &u32
17[100; 101) 'b': &mut u32
18[81; 82) 'a': &u32
19[80; 82) '&a': &&u32
20[73; 74) 'a': &u32
21[123; 124) 'c': *const u32
22[31; 32) 'c': *const u32
23[138; 139) 'd': *mut u32
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
new file mode 100644
index 000000000..b36bb35d8
--- /dev/null
+++ b/crates/ra_hir/src/type_ref.rs
@@ -0,0 +1,110 @@
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;
5
6use crate::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,
53 // DynTrait,
54 Error,
55}
56
57impl TypeRef {
58 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
59 pub(crate) fn from_ast(node: ast::TypeRef) -> Self {
60 use ra_syntax::ast::TypeRef::*;
61 match node {
62 ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
63 TupleType(inner) => TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()),
64 NeverType(..) => TypeRef::Never,
65 PathType(inner) => inner
66 .path()
67 .and_then(Path::from_ast)
68 .map(TypeRef::Path)
69 .unwrap_or(TypeRef::Error),
70 PointerType(inner) => {
71 let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
72 let mutability = Mutability::from_mutable(inner.is_mut());
73 TypeRef::RawPtr(Box::new(inner_ty), mutability)
74 }
75 ArrayType(inner) => TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref()))),
76 SliceType(inner) => TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref()))),
77 ReferenceType(inner) => {
78 let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
79 let mutability = Mutability::from_mutable(inner.is_mut());
80 TypeRef::Reference(Box::new(inner_ty), mutability)
81 }
82 PlaceholderType(_inner) => TypeRef::Placeholder,
83 FnPointerType(inner) => {
84 let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref()));
85 let mut params = if let Some(pl) = inner.param_list() {
86 pl.params()
87 .map(|p| p.type_ref())
88 .map(TypeRef::from_ast_opt)
89 .collect()
90 } else {
91 Vec::new()
92 };
93 params.push(ret_ty);
94 TypeRef::Fn(params)
95 }
96 // for types are close enough for our purposes to the inner type for now...
97 ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()),
98 ImplTraitType(_inner) => TypeRef::Error,
99 DynTraitType(_inner) => TypeRef::Error,
100 }
101 }
102
103 pub(crate) fn from_ast_opt(node: Option<ast::TypeRef>) -> Self {
104 if let Some(node) = node {
105 TypeRef::from_ast(node)
106 } else {
107 TypeRef::Error
108 }
109 }
110}