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