diff options
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 261 |
1 files changed, 150 insertions, 111 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 2ea3b341f..7d25ade47 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -20,11 +20,11 @@ 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 | /// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). | 23 | /// A type constructor or type name: this might be something like the primitive |
24 | /// | 24 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
25 | /// This should be cheap to clone. | 25 | /// tuples. |
26 | #[derive(Clone, PartialEq, Eq, Debug)] | 26 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
27 | pub enum Ty { | 27 | pub enum TypeCtor { |
28 | /// The primitive boolean type. Written as `bool`. | 28 | /// The primitive boolean type. Written as `bool`. |
29 | Bool, | 29 | Bool, |
30 | 30 | ||
@@ -39,28 +39,23 @@ pub enum Ty { | |||
39 | Float(primitive::UncertainFloatTy), | 39 | Float(primitive::UncertainFloatTy), |
40 | 40 | ||
41 | /// Structures, enumerations and unions. | 41 | /// Structures, enumerations and unions. |
42 | Adt { | 42 | Adt(AdtDef), |
43 | /// The definition of the struct/enum. | ||
44 | def_id: AdtDef, | ||
45 | /// Substitutions for the generic parameters of the type. | ||
46 | substs: Substs, | ||
47 | }, | ||
48 | 43 | ||
49 | /// The pointee of a string slice. Written as `str`. | 44 | /// The pointee of a string slice. Written as `str`. |
50 | Str, | 45 | Str, |
51 | 46 | ||
52 | /// The pointee of an array slice. Written as `[T]`. | 47 | /// The pointee of an array slice. Written as `[T]`. |
53 | Slice(Arc<Ty>), | 48 | Slice, |
54 | 49 | ||
55 | /// An array with the given length. Written as `[T; n]`. | 50 | /// An array with the given length. Written as `[T; n]`. |
56 | Array(Arc<Ty>), | 51 | Array, |
57 | 52 | ||
58 | /// A raw pointer. Written as `*mut T` or `*const T` | 53 | /// A raw pointer. Written as `*mut T` or `*const T` |
59 | RawPtr(Arc<Ty>, Mutability), | 54 | RawPtr(Mutability), |
60 | 55 | ||
61 | /// A reference; a pointer with an associated lifetime. Written as | 56 | /// A reference; a pointer with an associated lifetime. Written as |
62 | /// `&'a mut T` or `&'a T`. | 57 | /// `&'a mut T` or `&'a T`. |
63 | Ref(Arc<Ty>, Mutability), | 58 | Ref(Mutability), |
64 | 59 | ||
65 | /// The anonymous type of a function declaration/definition. Each | 60 | /// The anonymous type of a function declaration/definition. Each |
66 | /// function has a unique type, which is output (for a function | 61 | /// function has a unique type, which is output (for a function |
@@ -74,12 +69,7 @@ pub enum Ty { | |||
74 | /// fn foo() -> i32 { 1 } | 69 | /// fn foo() -> i32 { 1 } |
75 | /// let bar = foo; // bar: fn() -> i32 {foo} | 70 | /// let bar = foo; // bar: fn() -> i32 {foo} |
76 | /// ``` | 71 | /// ``` |
77 | FnDef { | 72 | FnDef(CallableDef), |
78 | /// The definition of the function / constructor. | ||
79 | def: CallableDef, | ||
80 | /// Substitutions for the generic parameters of the type | ||
81 | substs: Substs, | ||
82 | }, | ||
83 | 73 | ||
84 | /// A pointer to a function. Written as `fn() -> i32`. | 74 | /// A pointer to a function. Written as `fn() -> i32`. |
85 | /// | 75 | /// |
@@ -89,13 +79,36 @@ pub enum Ty { | |||
89 | /// fn foo() -> i32 { 1 } | 79 | /// fn foo() -> i32 { 1 } |
90 | /// let bar: fn() -> i32 = foo; | 80 | /// let bar: fn() -> i32 = foo; |
91 | /// ``` | 81 | /// ``` |
92 | FnPtr(FnSig), | 82 | FnPtr, |
93 | 83 | ||
94 | /// The never type `!`. | 84 | /// The never type `!`. |
95 | Never, | 85 | Never, |
96 | 86 | ||
97 | /// A tuple type. For example, `(i32, bool)`. | 87 | /// A tuple type. For example, `(i32, bool)`. |
98 | Tuple(Arc<[Ty]>), | 88 | Tuple, |
89 | } | ||
90 | |||
91 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | ||
92 | /// type like `bool`, a struct, tuple, function pointer, reference or | ||
93 | /// several other things. | ||
94 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
95 | pub struct ApplicationTy { | ||
96 | pub ctor: TypeCtor, | ||
97 | pub parameters: Substs, | ||
98 | } | ||
99 | |||
100 | /// A type. | ||
101 | /// | ||
102 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | ||
103 | /// the same thing (but in a different way). | ||
104 | /// | ||
105 | /// This should be cheap to clone. | ||
106 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
107 | pub enum Ty { | ||
108 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | ||
109 | /// type like `bool`, a struct, tuple, function pointer, reference or | ||
110 | /// several other things. | ||
111 | Apply(ApplicationTy), | ||
99 | 112 | ||
100 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} | 113 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} |
101 | Param { | 114 | Param { |
@@ -127,6 +140,18 @@ impl Substs { | |||
127 | Substs(Arc::new([])) | 140 | Substs(Arc::new([])) |
128 | } | 141 | } |
129 | 142 | ||
143 | pub fn single(ty: Ty) -> Substs { | ||
144 | Substs(Arc::new([ty])) | ||
145 | } | ||
146 | |||
147 | pub fn iter(&self) -> impl Iterator<Item = &Ty> { | ||
148 | self.0.iter() | ||
149 | } | ||
150 | |||
151 | pub fn len(&self) -> usize { | ||
152 | self.0.len() | ||
153 | } | ||
154 | |||
130 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 155 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
131 | // Without an Arc::make_mut_slice, we can't avoid the clone here: | 156 | // Without an Arc::make_mut_slice, we can't avoid the clone here: |
132 | let mut v: Vec<_> = self.0.iter().cloned().collect(); | 157 | let mut v: Vec<_> = self.0.iter().cloned().collect(); |
@@ -135,9 +160,17 @@ impl Substs { | |||
135 | } | 160 | } |
136 | self.0 = v.into(); | 161 | self.0 = v.into(); |
137 | } | 162 | } |
163 | |||
164 | pub fn as_single(&self) -> &Ty { | ||
165 | if self.0.len() != 1 { | ||
166 | panic!("expected substs of len 1, got {:?}", self); | ||
167 | } | ||
168 | &self.0[0] | ||
169 | } | ||
138 | } | 170 | } |
139 | 171 | ||
140 | /// A function signature. | 172 | /// A function signature as seen by type inference: Several parameter types and |
173 | /// one return type. | ||
141 | #[derive(Clone, PartialEq, Eq, Debug)] | 174 | #[derive(Clone, PartialEq, Eq, Debug)] |
142 | pub struct FnSig { | 175 | pub struct FnSig { |
143 | params_and_return: Arc<[Ty]>, | 176 | params_and_return: Arc<[Ty]>, |
@@ -148,6 +181,11 @@ impl FnSig { | |||
148 | params.push(ret); | 181 | params.push(ret); |
149 | FnSig { params_and_return: params.into() } | 182 | FnSig { params_and_return: params.into() } |
150 | } | 183 | } |
184 | |||
185 | pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig { | ||
186 | FnSig { params_and_return: Arc::clone(&substs.0) } | ||
187 | } | ||
188 | |||
151 | pub fn params(&self) -> &[Ty] { | 189 | pub fn params(&self) -> &[Ty] { |
152 | &self.params_and_return[0..self.params_and_return.len() - 1] | 190 | &self.params_and_return[0..self.params_and_return.len() - 1] |
153 | } | 191 | } |
@@ -167,80 +205,37 @@ impl FnSig { | |||
167 | } | 205 | } |
168 | 206 | ||
169 | impl Ty { | 207 | impl Ty { |
208 | pub fn simple(ctor: TypeCtor) -> Ty { | ||
209 | Ty::Apply(ApplicationTy { ctor, parameters: Substs::empty() }) | ||
210 | } | ||
211 | pub fn apply_one(ctor: TypeCtor, param: Ty) -> Ty { | ||
212 | Ty::Apply(ApplicationTy { ctor, parameters: Substs::single(param) }) | ||
213 | } | ||
214 | pub fn apply(ctor: TypeCtor, parameters: Substs) -> Ty { | ||
215 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
216 | } | ||
170 | pub fn unit() -> Self { | 217 | pub fn unit() -> Self { |
171 | Ty::Tuple(Arc::new([])) | 218 | Ty::apply(TypeCtor::Tuple, Substs::empty()) |
172 | } | 219 | } |
173 | 220 | ||
174 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | 221 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { |
175 | match self { | 222 | match self { |
176 | Ty::Slice(t) | Ty::Array(t) => t.walk(f), | 223 | Ty::Apply(a_ty) => { |
177 | Ty::RawPtr(t, _) => t.walk(f), | 224 | for t in a_ty.parameters.iter() { |
178 | Ty::Ref(t, _) => t.walk(f), | ||
179 | Ty::Tuple(ts) => { | ||
180 | for t in ts.iter() { | ||
181 | t.walk(f); | ||
182 | } | ||
183 | } | ||
184 | Ty::FnPtr(sig) => { | ||
185 | for input in sig.params() { | ||
186 | input.walk(f); | ||
187 | } | ||
188 | sig.ret().walk(f); | ||
189 | } | ||
190 | Ty::FnDef { substs, .. } => { | ||
191 | for t in substs.0.iter() { | ||
192 | t.walk(f); | 225 | t.walk(f); |
193 | } | 226 | } |
194 | } | 227 | } |
195 | Ty::Adt { substs, .. } => { | 228 | Ty::Param { .. } | Ty::Infer(_) | Ty::Unknown => {} |
196 | for t in substs.0.iter() { | ||
197 | t.walk(f); | ||
198 | } | ||
199 | } | ||
200 | Ty::Bool | ||
201 | | Ty::Char | ||
202 | | Ty::Int(_) | ||
203 | | Ty::Float(_) | ||
204 | | Ty::Str | ||
205 | | Ty::Never | ||
206 | | Ty::Param { .. } | ||
207 | | Ty::Infer(_) | ||
208 | | Ty::Unknown => {} | ||
209 | } | 229 | } |
210 | f(self); | 230 | f(self); |
211 | } | 231 | } |
212 | 232 | ||
213 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 233 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
214 | match self { | 234 | match self { |
215 | Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f), | 235 | Ty::Apply(a_ty) => { |
216 | Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f), | 236 | a_ty.parameters.walk_mut(f); |
217 | Ty::Ref(t, _) => Arc::make_mut(t).walk_mut(f), | ||
218 | Ty::Tuple(ts) => { | ||
219 | // Without an Arc::make_mut_slice, we can't avoid the clone here: | ||
220 | let mut v: Vec<_> = ts.iter().cloned().collect(); | ||
221 | for t in &mut v { | ||
222 | t.walk_mut(f); | ||
223 | } | ||
224 | *ts = v.into(); | ||
225 | } | ||
226 | Ty::FnPtr(sig) => { | ||
227 | sig.walk_mut(f); | ||
228 | } | 237 | } |
229 | Ty::FnDef { substs, .. } => { | 238 | Ty::Param { .. } | Ty::Infer(_) | Ty::Unknown => {} |
230 | substs.walk_mut(f); | ||
231 | } | ||
232 | Ty::Adt { substs, .. } => { | ||
233 | substs.walk_mut(f); | ||
234 | } | ||
235 | Ty::Bool | ||
236 | | Ty::Char | ||
237 | | Ty::Int(_) | ||
238 | | Ty::Float(_) | ||
239 | | Ty::Str | ||
240 | | Ty::Never | ||
241 | | Ty::Param { .. } | ||
242 | | Ty::Infer(_) | ||
243 | | Ty::Unknown => {} | ||
244 | } | 239 | } |
245 | f(self); | 240 | f(self); |
246 | } | 241 | } |
@@ -253,10 +248,38 @@ impl Ty { | |||
253 | self | 248 | self |
254 | } | 249 | } |
255 | 250 | ||
251 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { | ||
252 | match self { | ||
253 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { | ||
254 | Some((parameters.as_single(), *mutability)) | ||
255 | } | ||
256 | _ => None, | ||
257 | } | ||
258 | } | ||
259 | |||
260 | pub fn as_adt(&self) -> Option<(AdtDef, &Substs)> { | ||
261 | match self { | ||
262 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => { | ||
263 | Some((*adt_def, parameters)) | ||
264 | } | ||
265 | _ => None, | ||
266 | } | ||
267 | } | ||
268 | |||
269 | pub fn as_tuple(&self) -> Option<&Substs> { | ||
270 | match self { | ||
271 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple, parameters }) => Some(parameters), | ||
272 | _ => None, | ||
273 | } | ||
274 | } | ||
275 | |||
256 | fn builtin_deref(&self) -> Option<Ty> { | 276 | fn builtin_deref(&self) -> Option<Ty> { |
257 | match self { | 277 | match self { |
258 | Ty::Ref(t, _) => Some(Ty::clone(t)), | 278 | Ty::Apply(a_ty) => match a_ty.ctor { |
259 | Ty::RawPtr(t, _) => Some(Ty::clone(t)), | 279 | TypeCtor::Ref(..) => Some(Ty::clone(a_ty.parameters.as_single())), |
280 | TypeCtor::RawPtr(..) => Some(Ty::clone(a_ty.parameters.as_single())), | ||
281 | _ => None, | ||
282 | }, | ||
260 | _ => None, | 283 | _ => None, |
261 | } | 284 | } |
262 | } | 285 | } |
@@ -267,8 +290,10 @@ impl Ty { | |||
267 | /// `Option<u32>` afterwards.) | 290 | /// `Option<u32>` afterwards.) |
268 | pub fn apply_substs(self, substs: Substs) -> Ty { | 291 | pub fn apply_substs(self, substs: Substs) -> Ty { |
269 | match self { | 292 | match self { |
270 | Ty::Adt { def_id, .. } => Ty::Adt { def_id, substs }, | 293 | Ty::Apply(ApplicationTy { ctor, parameters: previous_substs }) => { |
271 | Ty::FnDef { def, .. } => Ty::FnDef { def, substs }, | 294 | assert_eq!(previous_substs.len(), substs.len()); |
295 | Ty::Apply(ApplicationTy { ctor, parameters: substs }) | ||
296 | } | ||
272 | _ => self, | 297 | _ => self, |
273 | } | 298 | } |
274 | } | 299 | } |
@@ -293,7 +318,7 @@ impl Ty { | |||
293 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | 318 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. |
294 | fn substs(&self) -> Option<Substs> { | 319 | fn substs(&self) -> Option<Substs> { |
295 | match self { | 320 | match self { |
296 | Ty::Adt { substs, .. } | Ty::FnDef { substs, .. } => Some(substs.clone()), | 321 | Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), |
297 | _ => None, | 322 | _ => None, |
298 | } | 323 | } |
299 | } | 324 | } |
@@ -305,40 +330,45 @@ impl HirDisplay for &Ty { | |||
305 | } | 330 | } |
306 | } | 331 | } |
307 | 332 | ||
308 | impl HirDisplay for Ty { | 333 | impl HirDisplay for ApplicationTy { |
309 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 334 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
310 | match self { | 335 | match self.ctor { |
311 | Ty::Bool => write!(f, "bool")?, | 336 | TypeCtor::Bool => write!(f, "bool")?, |
312 | Ty::Char => write!(f, "char")?, | 337 | TypeCtor::Char => write!(f, "char")?, |
313 | Ty::Int(t) => write!(f, "{}", t)?, | 338 | TypeCtor::Int(t) => write!(f, "{}", t)?, |
314 | Ty::Float(t) => write!(f, "{}", t)?, | 339 | TypeCtor::Float(t) => write!(f, "{}", t)?, |
315 | Ty::Str => write!(f, "str")?, | 340 | TypeCtor::Str => write!(f, "str")?, |
316 | Ty::Slice(t) | Ty::Array(t) => { | 341 | TypeCtor::Slice | TypeCtor::Array => { |
342 | let t = self.parameters.as_single(); | ||
317 | write!(f, "[{}]", t.display(f.db))?; | 343 | write!(f, "[{}]", t.display(f.db))?; |
318 | } | 344 | } |
319 | Ty::RawPtr(t, m) => { | 345 | TypeCtor::RawPtr(m) => { |
346 | let t = self.parameters.as_single(); | ||
320 | write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; | 347 | write!(f, "*{}{}", m.as_keyword_for_ptr(), t.display(f.db))?; |
321 | } | 348 | } |
322 | Ty::Ref(t, m) => { | 349 | TypeCtor::Ref(m) => { |
350 | let t = self.parameters.as_single(); | ||
323 | write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?; | 351 | write!(f, "&{}{}", m.as_keyword_for_ref(), t.display(f.db))?; |
324 | } | 352 | } |
325 | Ty::Never => write!(f, "!")?, | 353 | TypeCtor::Never => write!(f, "!")?, |
326 | Ty::Tuple(ts) => { | 354 | TypeCtor::Tuple => { |
327 | if ts.len() == 1 { | 355 | let ts = &self.parameters; |
328 | write!(f, "({},)", ts[0].display(f.db))?; | 356 | if ts.0.len() == 1 { |
357 | write!(f, "({},)", ts.0[0].display(f.db))?; | ||
329 | } else { | 358 | } else { |
330 | write!(f, "(")?; | 359 | write!(f, "(")?; |
331 | f.write_joined(&**ts, ", ")?; | 360 | f.write_joined(&*ts.0, ", ")?; |
332 | write!(f, ")")?; | 361 | write!(f, ")")?; |
333 | } | 362 | } |
334 | } | 363 | } |
335 | Ty::FnPtr(sig) => { | 364 | TypeCtor::FnPtr => { |
365 | let sig = FnSig::from_fn_ptr_substs(&self.parameters); | ||
336 | write!(f, "fn(")?; | 366 | write!(f, "fn(")?; |
337 | f.write_joined(sig.params(), ", ")?; | 367 | f.write_joined(sig.params(), ", ")?; |
338 | write!(f, ") -> {}", sig.ret().display(f.db))?; | 368 | write!(f, ") -> {}", sig.ret().display(f.db))?; |
339 | } | 369 | } |
340 | Ty::FnDef { def, substs, .. } => { | 370 | TypeCtor::FnDef(def) => { |
341 | let sig = f.db.callable_item_signature(*def); | 371 | let sig = f.db.callable_item_signature(def); |
342 | let name = match def { | 372 | let name = match def { |
343 | CallableDef::Function(ff) => ff.name(f.db), | 373 | CallableDef::Function(ff) => ff.name(f.db), |
344 | CallableDef::Struct(s) => s.name(f.db).unwrap_or_else(Name::missing), | 374 | CallableDef::Struct(s) => s.name(f.db).unwrap_or_else(Name::missing), |
@@ -348,28 +378,37 @@ impl HirDisplay for Ty { | |||
348 | CallableDef::Function(_) => write!(f, "fn {}", name)?, | 378 | CallableDef::Function(_) => write!(f, "fn {}", name)?, |
349 | CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?, | 379 | CallableDef::Struct(_) | CallableDef::EnumVariant(_) => write!(f, "{}", name)?, |
350 | } | 380 | } |
351 | if substs.0.len() > 0 { | 381 | if self.parameters.0.len() > 0 { |
352 | write!(f, "<")?; | 382 | write!(f, "<")?; |
353 | f.write_joined(&*substs.0, ", ")?; | 383 | f.write_joined(&*self.parameters.0, ", ")?; |
354 | write!(f, ">")?; | 384 | write!(f, ">")?; |
355 | } | 385 | } |
356 | write!(f, "(")?; | 386 | write!(f, "(")?; |
357 | f.write_joined(sig.params(), ", ")?; | 387 | f.write_joined(sig.params(), ", ")?; |
358 | write!(f, ") -> {}", sig.ret().display(f.db))?; | 388 | write!(f, ") -> {}", sig.ret().display(f.db))?; |
359 | } | 389 | } |
360 | Ty::Adt { def_id, substs, .. } => { | 390 | TypeCtor::Adt(def_id) => { |
361 | let name = match def_id { | 391 | let name = match def_id { |
362 | AdtDef::Struct(s) => s.name(f.db), | 392 | AdtDef::Struct(s) => s.name(f.db), |
363 | AdtDef::Enum(e) => e.name(f.db), | 393 | AdtDef::Enum(e) => e.name(f.db), |
364 | } | 394 | } |
365 | .unwrap_or_else(Name::missing); | 395 | .unwrap_or_else(Name::missing); |
366 | write!(f, "{}", name)?; | 396 | write!(f, "{}", name)?; |
367 | if substs.0.len() > 0 { | 397 | if self.parameters.0.len() > 0 { |
368 | write!(f, "<")?; | 398 | write!(f, "<")?; |
369 | f.write_joined(&*substs.0, ", ")?; | 399 | f.write_joined(&*self.parameters.0, ", ")?; |
370 | write!(f, ">")?; | 400 | write!(f, ">")?; |
371 | } | 401 | } |
372 | } | 402 | } |
403 | } | ||
404 | Ok(()) | ||
405 | } | ||
406 | } | ||
407 | |||
408 | impl HirDisplay for Ty { | ||
409 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
410 | match self { | ||
411 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | ||
373 | Ty::Param { name, .. } => write!(f, "{}", name)?, | 412 | Ty::Param { name, .. } => write!(f, "{}", name)?, |
374 | Ty::Unknown => write!(f, "{{unknown}}")?, | 413 | Ty::Unknown => write!(f, "{{unknown}}")?, |
375 | Ty::Infer(..) => write!(f, "_")?, | 414 | Ty::Infer(..) => write!(f, "_")?, |