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