]>
Commit | Line | Data |
---|---|---|
fc512014 XL |
1 | #![feature(never_type)] |
2 | #![feature(const_panic)] | |
3 | #![feature(control_flow_enum)] | |
4 | ||
5 | #[macro_use] | |
6 | extern crate bitflags; | |
5869c6ff XL |
7 | #[macro_use] |
8 | extern crate rustc_macros; | |
fc512014 XL |
9 | |
10 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | |
5869c6ff XL |
11 | use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; |
12 | use std::fmt; | |
13 | use std::mem::discriminant; | |
fc512014 XL |
14 | |
15 | bitflags! { | |
16 | /// Flags that we track on types. These flags are propagated upwards | |
17 | /// through the type during type construction, so that we can quickly check | |
18 | /// whether the type has various kinds of types in it without recursing | |
19 | /// over the type itself. | |
20 | pub struct TypeFlags: u32 { | |
21 | // Does this have parameters? Used to determine whether substitution is | |
22 | // required. | |
23 | /// Does this have `Param`? | |
24 | const HAS_TY_PARAM = 1 << 0; | |
25 | /// Does this have `ReEarlyBound`? | |
26 | const HAS_RE_PARAM = 1 << 1; | |
27 | /// Does this have `ConstKind::Param`? | |
28 | const HAS_CT_PARAM = 1 << 2; | |
29 | ||
30 | const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits | |
31 | | TypeFlags::HAS_RE_PARAM.bits | |
32 | | TypeFlags::HAS_CT_PARAM.bits; | |
33 | ||
34 | /// Does this have `Infer`? | |
35 | const HAS_TY_INFER = 1 << 3; | |
36 | /// Does this have `ReVar`? | |
37 | const HAS_RE_INFER = 1 << 4; | |
38 | /// Does this have `ConstKind::Infer`? | |
39 | const HAS_CT_INFER = 1 << 5; | |
40 | ||
41 | /// Does this have inference variables? Used to determine whether | |
42 | /// inference is required. | |
43 | const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits | |
44 | | TypeFlags::HAS_RE_INFER.bits | |
45 | | TypeFlags::HAS_CT_INFER.bits; | |
46 | ||
47 | /// Does this have `Placeholder`? | |
48 | const HAS_TY_PLACEHOLDER = 1 << 6; | |
49 | /// Does this have `RePlaceholder`? | |
50 | const HAS_RE_PLACEHOLDER = 1 << 7; | |
51 | /// Does this have `ConstKind::Placeholder`? | |
52 | const HAS_CT_PLACEHOLDER = 1 << 8; | |
53 | ||
54 | /// `true` if there are "names" of regions and so forth | |
55 | /// that are local to a particular fn/inferctxt | |
56 | const HAS_FREE_LOCAL_REGIONS = 1 << 9; | |
57 | ||
58 | /// `true` if there are "names" of types and regions and so forth | |
59 | /// that are local to a particular fn | |
60 | const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits | |
61 | | TypeFlags::HAS_CT_PARAM.bits | |
62 | | TypeFlags::HAS_TY_INFER.bits | |
63 | | TypeFlags::HAS_CT_INFER.bits | |
64 | | TypeFlags::HAS_TY_PLACEHOLDER.bits | |
65 | | TypeFlags::HAS_CT_PLACEHOLDER.bits | |
66 | | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; | |
67 | ||
68 | /// Does this have `Projection`? | |
69 | const HAS_TY_PROJECTION = 1 << 10; | |
70 | /// Does this have `Opaque`? | |
71 | const HAS_TY_OPAQUE = 1 << 11; | |
72 | /// Does this have `ConstKind::Unevaluated`? | |
73 | const HAS_CT_PROJECTION = 1 << 12; | |
74 | ||
75 | /// Could this type be normalized further? | |
76 | const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits | |
77 | | TypeFlags::HAS_TY_OPAQUE.bits | |
78 | | TypeFlags::HAS_CT_PROJECTION.bits; | |
79 | ||
80 | /// Is an error type/const reachable? | |
81 | const HAS_ERROR = 1 << 13; | |
82 | ||
83 | /// Does this have any region that "appears free" in the type? | |
84 | /// Basically anything but `ReLateBound` and `ReErased`. | |
85 | const HAS_FREE_REGIONS = 1 << 14; | |
86 | ||
87 | /// Does this have any `ReLateBound` regions? Used to check | |
88 | /// if a global bound is safe to evaluate. | |
89 | const HAS_RE_LATE_BOUND = 1 << 15; | |
90 | ||
91 | /// Does this have any `ReErased` regions? | |
92 | const HAS_RE_ERASED = 1 << 16; | |
93 | ||
94 | /// Does this value have parameters/placeholders/inference variables which could be | |
95 | /// replaced later, in a way that would change the results of `impl` specialization? | |
96 | const STILL_FURTHER_SPECIALIZABLE = 1 << 17; | |
97 | } | |
98 | } | |
99 | ||
100 | rustc_index::newtype_index! { | |
101 | /// A [De Bruijn index][dbi] is a standard means of representing | |
102 | /// regions (and perhaps later types) in a higher-ranked setting. In | |
103 | /// particular, imagine a type like this: | |
104 | /// | |
105 | /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) | |
106 | /// ^ ^ | | | | |
107 | /// | | | | | | |
108 | /// | +------------+ 0 | | | |
109 | /// | | | | |
110 | /// +----------------------------------+ 1 | | |
111 | /// | | | |
112 | /// +----------------------------------------------+ 0 | |
113 | /// | |
114 | /// In this type, there are two binders (the outer fn and the inner | |
115 | /// fn). We need to be able to determine, for any given region, which | |
116 | /// fn type it is bound by, the inner or the outer one. There are | |
117 | /// various ways you can do this, but a De Bruijn index is one of the | |
118 | /// more convenient and has some nice properties. The basic idea is to | |
119 | /// count the number of binders, inside out. Some examples should help | |
120 | /// clarify what I mean. | |
121 | /// | |
122 | /// Let's start with the reference type `&'b isize` that is the first | |
123 | /// argument to the inner function. This region `'b` is assigned a De | |
124 | /// Bruijn index of 0, meaning "the innermost binder" (in this case, a | |
125 | /// fn). The region `'a` that appears in the second argument type (`&'a | |
126 | /// isize`) would then be assigned a De Bruijn index of 1, meaning "the | |
127 | /// second-innermost binder". (These indices are written on the arrows | |
128 | /// in the diagram). | |
129 | /// | |
130 | /// What is interesting is that De Bruijn index attached to a particular | |
131 | /// variable will vary depending on where it appears. For example, | |
132 | /// the final type `&'a char` also refers to the region `'a` declared on | |
133 | /// the outermost fn. But this time, this reference is not nested within | |
134 | /// any other binders (i.e., it is not an argument to the inner fn, but | |
135 | /// rather the outer one). Therefore, in this case, it is assigned a | |
136 | /// De Bruijn index of 0, because the innermost binder in that location | |
137 | /// is the outer fn. | |
138 | /// | |
139 | /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index | |
140 | pub struct DebruijnIndex { | |
141 | DEBUG_FORMAT = "DebruijnIndex({})", | |
142 | const INNERMOST = 0, | |
143 | } | |
144 | } | |
145 | ||
146 | impl DebruijnIndex { | |
147 | /// Returns the resulting index when this value is moved into | |
148 | /// `amount` number of new binders. So, e.g., if you had | |
149 | /// | |
150 | /// for<'a> fn(&'a x) | |
151 | /// | |
152 | /// and you wanted to change it to | |
153 | /// | |
154 | /// for<'a> fn(for<'b> fn(&'a x)) | |
155 | /// | |
156 | /// you would need to shift the index for `'a` into a new binder. | |
157 | #[must_use] | |
158 | pub fn shifted_in(self, amount: u32) -> DebruijnIndex { | |
159 | DebruijnIndex::from_u32(self.as_u32() + amount) | |
160 | } | |
161 | ||
162 | /// Update this index in place by shifting it "in" through | |
163 | /// `amount` number of binders. | |
164 | pub fn shift_in(&mut self, amount: u32) { | |
165 | *self = self.shifted_in(amount); | |
166 | } | |
167 | ||
168 | /// Returns the resulting index when this value is moved out from | |
169 | /// `amount` number of new binders. | |
170 | #[must_use] | |
171 | pub fn shifted_out(self, amount: u32) -> DebruijnIndex { | |
172 | DebruijnIndex::from_u32(self.as_u32() - amount) | |
173 | } | |
174 | ||
175 | /// Update in place by shifting out from `amount` binders. | |
176 | pub fn shift_out(&mut self, amount: u32) { | |
177 | *self = self.shifted_out(amount); | |
178 | } | |
179 | ||
180 | /// Adjusts any De Bruijn indices so as to make `to_binder` the | |
181 | /// innermost binder. That is, if we have something bound at `to_binder`, | |
182 | /// it will now be bound at INNERMOST. This is an appropriate thing to do | |
183 | /// when moving a region out from inside binders: | |
184 | /// | |
185 | /// ``` | |
186 | /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) | |
187 | /// // Binder: D3 D2 D1 ^^ | |
188 | /// ``` | |
189 | /// | |
190 | /// Here, the region `'a` would have the De Bruijn index D3, | |
191 | /// because it is the bound 3 binders out. However, if we wanted | |
192 | /// to refer to that region `'a` in the second argument (the `_`), | |
193 | /// those two binders would not be in scope. In that case, we | |
194 | /// might invoke `shift_out_to_binder(D3)`. This would adjust the | |
195 | /// De Bruijn index of `'a` to D1 (the innermost binder). | |
196 | /// | |
197 | /// If we invoke `shift_out_to_binder` and the region is in fact | |
198 | /// bound by one of the binders we are shifting out of, that is an | |
199 | /// error (and should fail an assertion failure). | |
200 | pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { | |
201 | self.shifted_out(to_binder.as_u32() - INNERMOST.as_u32()) | |
202 | } | |
203 | } | |
204 | ||
5869c6ff XL |
205 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
206 | #[derive(Encodable, Decodable)] | |
207 | pub enum IntTy { | |
208 | Isize, | |
209 | I8, | |
210 | I16, | |
211 | I32, | |
212 | I64, | |
213 | I128, | |
214 | } | |
215 | ||
216 | impl IntTy { | |
217 | pub fn name_str(&self) -> &'static str { | |
218 | match *self { | |
219 | IntTy::Isize => "isize", | |
220 | IntTy::I8 => "i8", | |
221 | IntTy::I16 => "i16", | |
222 | IntTy::I32 => "i32", | |
223 | IntTy::I64 => "i64", | |
224 | IntTy::I128 => "i128", | |
225 | } | |
226 | } | |
227 | ||
228 | pub fn bit_width(&self) -> Option<u64> { | |
229 | Some(match *self { | |
230 | IntTy::Isize => return None, | |
231 | IntTy::I8 => 8, | |
232 | IntTy::I16 => 16, | |
233 | IntTy::I32 => 32, | |
234 | IntTy::I64 => 64, | |
235 | IntTy::I128 => 128, | |
236 | }) | |
237 | } | |
238 | ||
239 | pub fn normalize(&self, target_width: u32) -> Self { | |
240 | match self { | |
241 | IntTy::Isize => match target_width { | |
242 | 16 => IntTy::I16, | |
243 | 32 => IntTy::I32, | |
244 | 64 => IntTy::I64, | |
245 | _ => unreachable!(), | |
246 | }, | |
247 | _ => *self, | |
248 | } | |
249 | } | |
250 | } | |
251 | ||
252 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] | |
253 | #[derive(Encodable, Decodable)] | |
254 | pub enum UintTy { | |
255 | Usize, | |
256 | U8, | |
257 | U16, | |
258 | U32, | |
259 | U64, | |
260 | U128, | |
261 | } | |
262 | ||
263 | impl UintTy { | |
264 | pub fn name_str(&self) -> &'static str { | |
265 | match *self { | |
266 | UintTy::Usize => "usize", | |
267 | UintTy::U8 => "u8", | |
268 | UintTy::U16 => "u16", | |
269 | UintTy::U32 => "u32", | |
270 | UintTy::U64 => "u64", | |
271 | UintTy::U128 => "u128", | |
272 | } | |
273 | } | |
274 | ||
275 | pub fn bit_width(&self) -> Option<u64> { | |
276 | Some(match *self { | |
277 | UintTy::Usize => return None, | |
278 | UintTy::U8 => 8, | |
279 | UintTy::U16 => 16, | |
280 | UintTy::U32 => 32, | |
281 | UintTy::U64 => 64, | |
282 | UintTy::U128 => 128, | |
283 | }) | |
284 | } | |
285 | ||
286 | pub fn normalize(&self, target_width: u32) -> Self { | |
287 | match self { | |
288 | UintTy::Usize => match target_width { | |
289 | 16 => UintTy::U16, | |
290 | 32 => UintTy::U32, | |
291 | 64 => UintTy::U64, | |
292 | _ => unreachable!(), | |
293 | }, | |
294 | _ => *self, | |
295 | } | |
296 | } | |
297 | } | |
298 | ||
299 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | |
300 | #[derive(Encodable, Decodable)] | |
301 | pub enum FloatTy { | |
302 | F32, | |
303 | F64, | |
304 | } | |
305 | ||
306 | impl FloatTy { | |
307 | pub fn name_str(self) -> &'static str { | |
308 | match self { | |
309 | FloatTy::F32 => "f32", | |
310 | FloatTy::F64 => "f64", | |
311 | } | |
312 | } | |
313 | ||
314 | pub fn bit_width(self) -> u64 { | |
315 | match self { | |
316 | FloatTy::F32 => 32, | |
317 | FloatTy::F64 => 64, | |
318 | } | |
319 | } | |
320 | } | |
321 | ||
322 | #[derive(Clone, Copy, PartialEq, Eq)] | |
323 | pub enum IntVarValue { | |
324 | IntType(IntTy), | |
325 | UintType(UintTy), | |
326 | } | |
327 | ||
328 | #[derive(Clone, Copy, PartialEq, Eq)] | |
329 | pub struct FloatVarValue(pub FloatTy); | |
330 | ||
331 | /// A **ty**pe **v**ariable **ID**. | |
332 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] | |
333 | pub struct TyVid { | |
334 | pub index: u32, | |
335 | } | |
336 | ||
337 | /// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**. | |
338 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] | |
339 | pub struct IntVid { | |
340 | pub index: u32, | |
341 | } | |
342 | ||
343 | /// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**. | |
344 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] | |
345 | pub struct FloatVid { | |
346 | pub index: u32, | |
347 | } | |
348 | ||
349 | /// A placeholder for a type that hasn't been inferred yet. | |
350 | /// | |
351 | /// E.g., if we have an empty array (`[]`), then we create a fresh | |
352 | /// type variable for the element type since we won't know until it's | |
353 | /// used what the element type is supposed to be. | |
354 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] | |
355 | pub enum InferTy { | |
356 | /// A type variable. | |
357 | TyVar(TyVid), | |
358 | /// An integral type variable (`{integer}`). | |
359 | /// | |
360 | /// These are created when the compiler sees an integer literal like | |
361 | /// `1` that could be several different types (`u8`, `i32`, `u32`, etc.). | |
362 | /// We don't know until it's used what type it's supposed to be, so | |
363 | /// we create a fresh type variable. | |
364 | IntVar(IntVid), | |
365 | /// A floating-point type variable (`{float}`). | |
366 | /// | |
367 | /// These are created when the compiler sees an float literal like | |
368 | /// `1.0` that could be either an `f32` or an `f64`. | |
369 | /// We don't know until it's used what type it's supposed to be, so | |
370 | /// we create a fresh type variable. | |
371 | FloatVar(FloatVid), | |
372 | ||
373 | /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement | |
374 | /// for an unbound type variable. This is convenient for caching etc. See | |
375 | /// `rustc_infer::infer::freshen` for more details. | |
376 | /// | |
377 | /// Compare with [`TyVar`][Self::TyVar]. | |
378 | FreshTy(u32), | |
379 | /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar]. | |
380 | FreshIntTy(u32), | |
381 | /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar]. | |
382 | FreshFloatTy(u32), | |
383 | } | |
384 | ||
385 | /// Raw `TyVid` are used as the unification key for `sub_relations`; | |
386 | /// they carry no values. | |
387 | impl UnifyKey for TyVid { | |
388 | type Value = (); | |
389 | fn index(&self) -> u32 { | |
390 | self.index | |
391 | } | |
392 | fn from_index(i: u32) -> TyVid { | |
393 | TyVid { index: i } | |
394 | } | |
395 | fn tag() -> &'static str { | |
396 | "TyVid" | |
397 | } | |
398 | } | |
399 | ||
400 | impl EqUnifyValue for IntVarValue {} | |
401 | ||
402 | impl UnifyKey for IntVid { | |
403 | type Value = Option<IntVarValue>; | |
404 | fn index(&self) -> u32 { | |
405 | self.index | |
406 | } | |
407 | fn from_index(i: u32) -> IntVid { | |
408 | IntVid { index: i } | |
409 | } | |
410 | fn tag() -> &'static str { | |
411 | "IntVid" | |
412 | } | |
413 | } | |
414 | ||
415 | impl EqUnifyValue for FloatVarValue {} | |
416 | ||
417 | impl UnifyKey for FloatVid { | |
418 | type Value = Option<FloatVarValue>; | |
419 | fn index(&self) -> u32 { | |
420 | self.index | |
421 | } | |
422 | fn from_index(i: u32) -> FloatVid { | |
423 | FloatVid { index: i } | |
424 | } | |
425 | fn tag() -> &'static str { | |
426 | "FloatVid" | |
427 | } | |
428 | } | |
429 | ||
6a06907d | 430 | #[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)] |
5869c6ff XL |
431 | pub enum Variance { |
432 | Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type | |
433 | Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell | |
434 | Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type | |
435 | Bivariant, // T<A> <: T<B> -- e.g., unused type parameter | |
436 | } | |
437 | ||
438 | impl Variance { | |
439 | /// `a.xform(b)` combines the variance of a context with the | |
440 | /// variance of a type with the following meaning. If we are in a | |
441 | /// context with variance `a`, and we encounter a type argument in | |
442 | /// a position with variance `b`, then `a.xform(b)` is the new | |
443 | /// variance with which the argument appears. | |
444 | /// | |
445 | /// Example 1: | |
446 | /// | |
447 | /// *mut Vec<i32> | |
448 | /// | |
449 | /// Here, the "ambient" variance starts as covariant. `*mut T` is | |
450 | /// invariant with respect to `T`, so the variance in which the | |
451 | /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which | |
452 | /// yields `Invariant`. Now, the type `Vec<T>` is covariant with | |
453 | /// respect to its type argument `T`, and hence the variance of | |
454 | /// the `i32` here is `Invariant.xform(Covariant)`, which results | |
455 | /// (again) in `Invariant`. | |
456 | /// | |
457 | /// Example 2: | |
458 | /// | |
459 | /// fn(*const Vec<i32>, *mut Vec<i32) | |
460 | /// | |
461 | /// The ambient variance is covariant. A `fn` type is | |
462 | /// contravariant with respect to its parameters, so the variance | |
463 | /// within which both pointer types appear is | |
464 | /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const | |
465 | /// T` is covariant with respect to `T`, so the variance within | |
466 | /// which the first `Vec<i32>` appears is | |
467 | /// `Contravariant.xform(Covariant)` or `Contravariant`. The same | |
468 | /// is true for its `i32` argument. In the `*mut T` case, the | |
469 | /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`, | |
470 | /// and hence the outermost type is `Invariant` with respect to | |
471 | /// `Vec<i32>` (and its `i32` argument). | |
472 | /// | |
473 | /// Source: Figure 1 of "Taming the Wildcards: | |
474 | /// Combining Definition- and Use-Site Variance" published in PLDI'11. | |
475 | pub fn xform(self, v: Variance) -> Variance { | |
476 | match (self, v) { | |
477 | // Figure 1, column 1. | |
478 | (Variance::Covariant, Variance::Covariant) => Variance::Covariant, | |
479 | (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant, | |
480 | (Variance::Covariant, Variance::Invariant) => Variance::Invariant, | |
481 | (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant, | |
482 | ||
483 | // Figure 1, column 2. | |
484 | (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant, | |
485 | (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant, | |
486 | (Variance::Contravariant, Variance::Invariant) => Variance::Invariant, | |
487 | (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant, | |
488 | ||
489 | // Figure 1, column 3. | |
490 | (Variance::Invariant, _) => Variance::Invariant, | |
491 | ||
492 | // Figure 1, column 4. | |
493 | (Variance::Bivariant, _) => Variance::Bivariant, | |
494 | } | |
495 | } | |
496 | } | |
497 | ||
fc512014 XL |
498 | impl<CTX> HashStable<CTX> for DebruijnIndex { |
499 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
500 | self.as_u32().hash_stable(ctx, hasher); | |
501 | } | |
502 | } | |
5869c6ff XL |
503 | |
504 | impl<CTX> HashStable<CTX> for IntTy { | |
505 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
506 | discriminant(self).hash_stable(ctx, hasher); | |
507 | } | |
508 | } | |
509 | ||
510 | impl<CTX> HashStable<CTX> for UintTy { | |
511 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
512 | discriminant(self).hash_stable(ctx, hasher); | |
513 | } | |
514 | } | |
515 | ||
516 | impl<CTX> HashStable<CTX> for FloatTy { | |
517 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
518 | discriminant(self).hash_stable(ctx, hasher); | |
519 | } | |
520 | } | |
521 | ||
522 | impl<CTX> HashStable<CTX> for InferTy { | |
523 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
524 | use InferTy::*; | |
525 | match self { | |
526 | TyVar(v) => v.index.hash_stable(ctx, hasher), | |
527 | IntVar(v) => v.index.hash_stable(ctx, hasher), | |
528 | FloatVar(v) => v.index.hash_stable(ctx, hasher), | |
529 | FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher), | |
530 | } | |
531 | } | |
532 | } | |
533 | ||
534 | impl<CTX> HashStable<CTX> for Variance { | |
535 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
536 | discriminant(self).hash_stable(ctx, hasher); | |
537 | } | |
538 | } | |
539 | ||
540 | impl fmt::Debug for IntVarValue { | |
541 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
542 | match *self { | |
543 | IntVarValue::IntType(ref v) => v.fmt(f), | |
544 | IntVarValue::UintType(ref v) => v.fmt(f), | |
545 | } | |
546 | } | |
547 | } | |
548 | ||
549 | impl fmt::Debug for FloatVarValue { | |
550 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
551 | self.0.fmt(f) | |
552 | } | |
553 | } | |
554 | ||
555 | impl fmt::Debug for TyVid { | |
556 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
557 | write!(f, "_#{}t", self.index) | |
558 | } | |
559 | } | |
560 | ||
561 | impl fmt::Debug for IntVid { | |
562 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
563 | write!(f, "_#{}i", self.index) | |
564 | } | |
565 | } | |
566 | ||
567 | impl fmt::Debug for FloatVid { | |
568 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
569 | write!(f, "_#{}f", self.index) | |
570 | } | |
571 | } | |
572 | ||
573 | impl fmt::Debug for InferTy { | |
574 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
575 | use InferTy::*; | |
576 | match *self { | |
577 | TyVar(ref v) => v.fmt(f), | |
578 | IntVar(ref v) => v.fmt(f), | |
579 | FloatVar(ref v) => v.fmt(f), | |
580 | FreshTy(v) => write!(f, "FreshTy({:?})", v), | |
581 | FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), | |
582 | FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v), | |
583 | } | |
584 | } | |
585 | } | |
586 | ||
587 | impl fmt::Debug for Variance { | |
588 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
589 | f.write_str(match *self { | |
590 | Variance::Covariant => "+", | |
591 | Variance::Contravariant => "-", | |
592 | Variance::Invariant => "o", | |
593 | Variance::Bivariant => "*", | |
594 | }) | |
595 | } | |
596 | } | |
597 | ||
598 | impl fmt::Display for InferTy { | |
599 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
600 | use InferTy::*; | |
601 | match *self { | |
602 | TyVar(_) => write!(f, "_"), | |
603 | IntVar(_) => write!(f, "{}", "{integer}"), | |
604 | FloatVar(_) => write!(f, "{}", "{float}"), | |
605 | FreshTy(v) => write!(f, "FreshTy({})", v), | |
606 | FreshIntTy(v) => write!(f, "FreshIntTy({})", v), | |
607 | FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v), | |
608 | } | |
609 | } | |
610 | } |