diff options
-rw-r--r-- | crates/ra_hir/src/ty.rs | 178 |
1 files changed, 177 insertions, 1 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index e659f903c..e63775f03 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -20,11 +20,84 @@ pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, ca | |||
20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; | 20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; |
21 | use display::{HirDisplay, HirFormatter}; | 21 | use display::{HirDisplay, HirFormatter}; |
22 | 22 | ||
23 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | ||
24 | pub enum TypeName { | ||
25 | /// The primitive boolean type. Written as `bool`. | ||
26 | Bool, | ||
27 | |||
28 | /// The primitive character type; holds a Unicode scalar value | ||
29 | /// (a non-surrogate code point). Written as `char`. | ||
30 | Char, | ||
31 | |||
32 | /// A primitive integer type. For example, `i32`. | ||
33 | Int(primitive::UncertainIntTy), | ||
34 | |||
35 | /// A primitive floating-point type. For example, `f64`. | ||
36 | Float(primitive::UncertainFloatTy), | ||
37 | |||
38 | /// Structures, enumerations and unions. | ||
39 | Adt(AdtDef), | ||
40 | |||
41 | /// The pointee of a string slice. Written as `str`. | ||
42 | Str, | ||
43 | |||
44 | /// The pointee of an array slice. Written as `[T]`. | ||
45 | Slice, | ||
46 | |||
47 | /// An array with the given length. Written as `[T; n]`. | ||
48 | Array, | ||
49 | |||
50 | /// A raw pointer. Written as `*mut T` or `*const T` | ||
51 | RawPtr(Mutability), | ||
52 | |||
53 | /// A reference; a pointer with an associated lifetime. Written as | ||
54 | /// `&'a mut T` or `&'a T`. | ||
55 | Ref(Mutability), | ||
56 | |||
57 | /// The anonymous type of a function declaration/definition. Each | ||
58 | /// function has a unique type, which is output (for a function | ||
59 | /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`. | ||
60 | /// | ||
61 | /// This includes tuple struct / enum variant constructors as well. | ||
62 | /// | ||
63 | /// For example the type of `bar` here: | ||
64 | /// | ||
65 | /// ```rust | ||
66 | /// fn foo() -> i32 { 1 } | ||
67 | /// let bar = foo; // bar: fn() -> i32 {foo} | ||
68 | /// ``` | ||
69 | FnDef(CallableDef), | ||
70 | |||
71 | /// A pointer to a function. Written as `fn() -> i32`. | ||
72 | /// | ||
73 | /// For example the type of `bar` here: | ||
74 | /// | ||
75 | /// ```rust | ||
76 | /// fn foo() -> i32 { 1 } | ||
77 | /// let bar: fn() -> i32 = foo; | ||
78 | /// ``` | ||
79 | FnPtr, | ||
80 | |||
81 | /// The never type `!`. | ||
82 | Never, | ||
83 | |||
84 | /// A tuple type. For example, `(i32, bool)`. | ||
85 | Tuple, | ||
86 | } | ||
87 | |||
88 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
89 | pub struct ApplicationTy { | ||
90 | pub name: TypeName, | ||
91 | pub parameters: Substs, | ||
92 | } | ||
93 | |||
23 | /// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). | 94 | /// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). |
24 | /// | 95 | /// |
25 | /// This should be cheap to clone. | 96 | /// This should be cheap to clone. |
26 | #[derive(Clone, PartialEq, Eq, Debug)] | 97 | #[derive(Clone, PartialEq, Eq, Debug)] |
27 | pub enum Ty { | 98 | pub enum Ty { |
99 | Apply(ApplicationTy), | ||
100 | |||
28 | /// The primitive boolean type. Written as `bool`. | 101 | /// The primitive boolean type. Written as `bool`. |
29 | Bool, | 102 | Bool, |
30 | 103 | ||
@@ -139,6 +212,13 @@ impl Substs { | |||
139 | } | 212 | } |
140 | self.0 = v.into(); | 213 | self.0 = v.into(); |
141 | } | 214 | } |
215 | |||
216 | pub fn as_single(&self) -> &Ty { | ||
217 | if self.0.len() != 1 { | ||
218 | panic!("expected substs of len 1, got {:?}", self); | ||
219 | } | ||
220 | &self.0[0] | ||
221 | } | ||
142 | } | 222 | } |
143 | 223 | ||
144 | /// A function signature. | 224 | /// A function signature. |
@@ -176,12 +256,20 @@ impl FnSig { | |||
176 | } | 256 | } |
177 | 257 | ||
178 | impl Ty { | 258 | impl Ty { |
259 | pub fn apply(name: TypeName, parameters: Substs) -> Ty { | ||
260 | Ty::Apply(ApplicationTy { name, parameters }) | ||
261 | } | ||
179 | pub fn unit() -> Self { | 262 | pub fn unit() -> Self { |
180 | Ty::Tuple(Substs::empty()) | 263 | Ty::apply(TypeName::Tuple, Substs::empty()) |
181 | } | 264 | } |
182 | 265 | ||
183 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | 266 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { |
184 | match self { | 267 | match self { |
268 | Ty::Apply(a_ty) => { | ||
269 | for t in a_ty.parameters.iter() { | ||
270 | t.walk(f); | ||
271 | } | ||
272 | } | ||
185 | Ty::Slice(t) | Ty::Array(t) => t.walk(f), | 273 | Ty::Slice(t) | Ty::Array(t) => t.walk(f), |
186 | Ty::RawPtr(t, _) => t.walk(f), | 274 | Ty::RawPtr(t, _) => t.walk(f), |
187 | Ty::Ref(t, _) => t.walk(f), | 275 | Ty::Ref(t, _) => t.walk(f), |
@@ -220,6 +308,9 @@ impl Ty { | |||
220 | 308 | ||
221 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 309 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
222 | match self { | 310 | match self { |
311 | Ty::Apply(a_ty) => { | ||
312 | a_ty.parameters.walk_mut(f); | ||
313 | } | ||
223 | Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f), | 314 | Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f), |
224 | Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f), | 315 | Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f), |
225 | Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f), | 316 | Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f), |
@@ -258,6 +349,11 @@ impl Ty { | |||
258 | 349 | ||
259 | fn builtin_deref(&self) -> Option<Ty> { | 350 | fn builtin_deref(&self) -> Option<Ty> { |
260 | match self { | 351 | match self { |
352 | Ty::Apply(a_ty) => match a_ty.name { | ||
353 | TypeName::Ref(..) => Some(Ty::clone(a_ty.parameters.as_single())), | ||
354 | TypeName::RawPtr(..) => Some(Ty::clone(a_ty.parameters.as_single())), | ||
355 | _ => None, | ||
356 | }, | ||
261 | Ty::Ref(t, _) => Some(Ty::clone(t)), | 357 | Ty::Ref(t, _) => Some(Ty::clone(t)), |
262 | Ty::RawPtr(t, _) => Some(Ty::clone(t)), | 358 | Ty::RawPtr(t, _) => Some(Ty::clone(t)), |
263 | _ => None, | 359 | _ => None, |
@@ -270,6 +366,9 @@ impl Ty { | |||
270 | /// `Option<u32>` afterwards.) | 366 | /// `Option<u32>` afterwards.) |
271 | pub fn apply_substs(self, substs: Substs) -> Ty { | 367 | pub fn apply_substs(self, substs: Substs) -> Ty { |
272 | match self { | 368 | match self { |
369 | Ty::Apply(ApplicationTy { name, .. }) => { | ||
370 | Ty::Apply(ApplicationTy { name, parameters: substs }) | ||
371 | } | ||
273 | Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs }, | 372 | Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs }, |
274 | Ty::FnDef { def, .. } => Ty::FnDef { def, substs }, | 373 | Ty::FnDef { def, .. } => Ty::FnDef { def, substs }, |
275 | _ => self, | 374 | _ => self, |
@@ -296,6 +395,7 @@ impl Ty { | |||
296 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | 395 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. |
297 | fn substs(&self) -> Option<Substs> { | 396 | fn substs(&self) -> Option<Substs> { |
298 | match self { | 397 | match self { |
398 | Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), | ||
299 | Ty::Adt { substs, .. } | Ty::FnDef { substs, .. } => Some(substs.clone()), | 399 | Ty::Adt { substs, .. } | Ty::FnDef { substs, .. } => Some(substs.clone()), |
300 | _ => None, | 400 | _ => None, |
301 | } | 401 | } |
@@ -308,9 +408,85 @@ impl HirDisplay for &Ty { | |||
308 | } | 408 | } |
309 | } | 409 | } |
310 | 410 | ||
411 | impl HirDisplay for ApplicationTy { | ||
412 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
413 | match self.name { | ||
414 | TypeName::Bool => write!(f, "bool")?, | ||
415 | TypeName::Char => write!(f, "char")?, | ||
416 | TypeName::Int(t) => write!(f, "{}", t)?, | ||
417 | TypeName::Float(t) => write!(f, "{}", t)?, | ||
418 | TypeName::Str => write!(f, "str")?, | ||
419 | TypeName::Slice | TypeName::Array => { | ||
420 | let t = self.parameters.as_single(); | ||
421 | write!(f, "[{}]", t.display(f.db))?; | ||
422 | } | ||
423 | TypeName::RawPtr(m) => { | ||
424 | let t = self.parameters.as_single(); | ||
425 | write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; | ||
426 | } | ||
427 | TypeName::Ref(m) => { | ||
428 | let t = self.parameters.as_single(); | ||
429 | write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?; | ||
430 | } | ||
431 | TypeName::Never => write!(f, "!")?, | ||
432 | TypeName::Tuple => { | ||
433 | let ts = &self.parameters; | ||
434 | if ts.0.len() == 1 { | ||
435 | write!(f, "({},)", ts.0[0].display(f.db))?; | ||
436 | } else { | ||
437 | write!(f, "(")?; | ||
438 | f.write_joined(&*ts.0, ", ")?; | ||
439 | write!(f, ")")?; | ||
440 | } | ||
441 | } | ||
442 | TypeName::FnPtr => { | ||
443 | let sig = FnSig::from_fn_ptr_substs(&self.parameters); | ||
444 | write!(f, "fn(")?; | ||
445 | f.write_joined(sig.params(), ", ")?; | ||
446 | write!(f, ") -> {}", sig.ret().display(f.db))?; | ||
447 | } | ||
448 | TypeName::FnDef(def) => { | ||
449 | let sig = f.db.callable_item_signature(def); | ||
450 | let name = match def { | ||
451 | CallableDef::Function(ff) => ff.name(f.db), | ||
452 | CallableDef::Struct(s) => s.name(f.db).unwrap_or_else(Name::missing), | ||
453 | CallableDef::EnumVariant(e) => e.name(f.db).unwrap_or_else(Name::missing), | ||
454 | }; | ||
455 | match def { | ||
456 | CallableDef::Function(_) => write!(f, "fn {}", name)?, | ||
457 | CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?, | ||
458 | } | ||
459 | if self.parameters.0.len() > 0 { | ||
460 | write!(f, "<")?; | ||
461 | f.write_joined(&*self.parameters.0, ", ")?; | ||
462 | write!(f, ">")?; | ||
463 | } | ||
464 | write!(f, "(")?; | ||
465 | f.write_joined(sig.params(), ", ")?; | ||
466 | write!(f, ") -> {}", sig.ret().display(f.db))?; | ||
467 | } | ||
468 | TypeName::Adt(def_id) => { | ||
469 | let name = match def_id { | ||
470 | AdtDef::Struct(s) => s.name(f.db), | ||
471 | AdtDef::Enum(e) => e.name(f.db), | ||
472 | } | ||
473 | .unwrap_or_else(Name::missing); | ||
474 | write!(f, "{}", name)?; | ||
475 | if self.parameters.0.len() > 0 { | ||
476 | write!(f, "<")?; | ||
477 | f.write_joined(&*self.parameters.0, ", ")?; | ||
478 | write!(f, ">")?; | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | Ok(()) | ||
483 | } | ||
484 | } | ||
485 | |||
311 | impl HirDisplay for Ty { | 486 | impl HirDisplay for Ty { |
312 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 487 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
313 | match self { | 488 | match self { |
489 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | ||
314 | Ty::Bool => write!(f, "bool")?, | 490 | Ty::Bool => write!(f, "bool")?, |
315 | Ty::Char => write!(f, "char")?, | 491 | Ty::Char => write!(f, "char")?, |
316 | Ty::Int(t) => write!(f, "{}", t)?, | 492 | Ty::Int(t) => write!(f, "{}", t)?, |