diff options
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 448 |
1 files changed, 271 insertions, 177 deletions
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}; | |||
11 | use ra_db::{LocalSyntaxPtr, Cancelable}; | 11 | use ra_db::{LocalSyntaxPtr, Cancelable}; |
12 | use ra_syntax::{ | 12 | use 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 | ||
18 | use crate::{Def, DefId, FnScopes, Module, Function, Path, db::HirDatabase}; | 18 | use 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)] |
21 | pub enum Ty { | 26 | pub 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 | ||
108 | type TyRef = Arc<Ty>; | 121 | type TyRef = Arc<Ty>; |
109 | 122 | ||
110 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | 123 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
111 | pub struct FnSig { | 124 | pub struct FnSig { |
112 | input: Vec<Ty>, | 125 | input: Vec<Ty>, |
113 | output: Ty, | 126 | output: Ty, |
114 | } | 127 | } |
115 | 128 | ||
116 | impl Ty { | 129 | impl 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 | ||
197 | pub fn type_for_fn(db: &impl HirDatabase, f: Function) -> Cancelable<Ty> { | 259 | pub 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 | 277 | pub 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 | |||
286 | pub 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 | |||
227 | pub fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Ty> { | 295 | pub 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 | ||
312 | pub(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)] |
243 | pub struct InferenceResult { | 340 | pub 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 |