|
3 | 3 | use crate::ich::NodeIdHashingMode; |
4 | 4 | use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
5 | 5 | use crate::mir::interpret::{sign_extend, truncate}; |
| 6 | +use crate::ty::fold::TypeFolder; |
6 | 7 | use crate::ty::layout::IntegerExt; |
7 | 8 | use crate::ty::query::TyCtxtAt; |
8 | 9 | use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef}; |
9 | 10 | use crate::ty::TyKind::*; |
10 | | -use crate::ty::{self, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable}; |
| 11 | +use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable}; |
11 | 12 | use rustc_apfloat::Float as _; |
12 | 13 | use rustc_ast::ast; |
13 | 14 | use rustc_attr::{self as attr, SignedInt, UnsignedInt}; |
@@ -557,82 +558,84 @@ impl<'tcx> TyCtxt<'tcx> { |
557 | 558 | def_id: DefId, |
558 | 559 | substs: SubstsRef<'tcx>, |
559 | 560 | ) -> Result<Ty<'tcx>, Ty<'tcx>> { |
560 | | - use crate::ty::fold::TypeFolder; |
561 | | - |
562 | | - struct OpaqueTypeExpander<'tcx> { |
563 | | - // Contains the DefIds of the opaque types that are currently being |
564 | | - // expanded. When we expand an opaque type we insert the DefId of |
565 | | - // that type, and when we finish expanding that type we remove the |
566 | | - // its DefId. |
567 | | - seen_opaque_tys: FxHashSet<DefId>, |
568 | | - // Cache of all expansions we've seen so far. This is a critical |
569 | | - // optimization for some large types produced by async fn trees. |
570 | | - expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, |
571 | | - primary_def_id: DefId, |
572 | | - found_recursion: bool, |
573 | | - tcx: TyCtxt<'tcx>, |
574 | | - } |
575 | | - |
576 | | - impl<'tcx> OpaqueTypeExpander<'tcx> { |
577 | | - fn expand_opaque_ty( |
578 | | - &mut self, |
579 | | - def_id: DefId, |
580 | | - substs: SubstsRef<'tcx>, |
581 | | - ) -> Option<Ty<'tcx>> { |
582 | | - if self.found_recursion { |
583 | | - return None; |
584 | | - } |
585 | | - let substs = substs.fold_with(self); |
586 | | - if self.seen_opaque_tys.insert(def_id) { |
587 | | - let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { |
588 | | - Some(expanded_ty) => expanded_ty, |
589 | | - None => { |
590 | | - let generic_ty = self.tcx.type_of(def_id); |
591 | | - let concrete_ty = generic_ty.subst(self.tcx, substs); |
592 | | - let expanded_ty = self.fold_ty(concrete_ty); |
593 | | - self.expanded_cache.insert((def_id, substs), expanded_ty); |
594 | | - expanded_ty |
595 | | - } |
596 | | - }; |
597 | | - self.seen_opaque_tys.remove(&def_id); |
598 | | - Some(expanded_ty) |
599 | | - } else { |
600 | | - // If another opaque type that we contain is recursive, then it |
601 | | - // will report the error, so we don't have to. |
602 | | - self.found_recursion = def_id == self.primary_def_id; |
603 | | - None |
604 | | - } |
605 | | - } |
606 | | - } |
607 | | - |
608 | | - impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { |
609 | | - fn tcx(&self) -> TyCtxt<'tcx> { |
610 | | - self.tcx |
611 | | - } |
612 | | - |
613 | | - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { |
614 | | - if let ty::Opaque(def_id, substs) = t.kind { |
615 | | - self.expand_opaque_ty(def_id, substs).unwrap_or(t) |
616 | | - } else if t.has_opaque_types() { |
617 | | - t.super_fold_with(self) |
618 | | - } else { |
619 | | - t |
620 | | - } |
621 | | - } |
622 | | - } |
623 | | - |
624 | 561 | let mut visitor = OpaqueTypeExpander { |
625 | 562 | seen_opaque_tys: FxHashSet::default(), |
626 | 563 | expanded_cache: FxHashMap::default(), |
627 | | - primary_def_id: def_id, |
| 564 | + primary_def_id: Some(def_id), |
628 | 565 | found_recursion: false, |
| 566 | + check_recursion: true, |
629 | 567 | tcx: self, |
630 | 568 | }; |
| 569 | + |
631 | 570 | let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); |
632 | 571 | if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } |
633 | 572 | } |
634 | 573 | } |
635 | 574 |
|
| 575 | +struct OpaqueTypeExpander<'tcx> { |
| 576 | + // Contains the DefIds of the opaque types that are currently being |
| 577 | + // expanded. When we expand an opaque type we insert the DefId of |
| 578 | + // that type, and when we finish expanding that type we remove the |
| 579 | + // its DefId. |
| 580 | + seen_opaque_tys: FxHashSet<DefId>, |
| 581 | + // Cache of all expansions we've seen so far. This is a critical |
| 582 | + // optimization for some large types produced by async fn trees. |
| 583 | + expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, |
| 584 | + primary_def_id: Option<DefId>, |
| 585 | + found_recursion: bool, |
| 586 | + /// Whether or not to check for recursive opaque types. |
| 587 | + /// This is `true` when we're explicitly checking for opaque type |
| 588 | + /// recursion, and 'false' otherwise to avoid unecessary work. |
| 589 | + check_recursion: bool, |
| 590 | + tcx: TyCtxt<'tcx>, |
| 591 | +} |
| 592 | + |
| 593 | +impl<'tcx> OpaqueTypeExpander<'tcx> { |
| 594 | + fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> { |
| 595 | + if self.found_recursion { |
| 596 | + return None; |
| 597 | + } |
| 598 | + let substs = substs.fold_with(self); |
| 599 | + if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { |
| 600 | + let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { |
| 601 | + Some(expanded_ty) => expanded_ty, |
| 602 | + None => { |
| 603 | + let generic_ty = self.tcx.type_of(def_id); |
| 604 | + let concrete_ty = generic_ty.subst(self.tcx, substs); |
| 605 | + let expanded_ty = self.fold_ty(concrete_ty); |
| 606 | + self.expanded_cache.insert((def_id, substs), expanded_ty); |
| 607 | + expanded_ty |
| 608 | + } |
| 609 | + }; |
| 610 | + if self.check_recursion { |
| 611 | + self.seen_opaque_tys.remove(&def_id); |
| 612 | + } |
| 613 | + Some(expanded_ty) |
| 614 | + } else { |
| 615 | + // If another opaque type that we contain is recursive, then it |
| 616 | + // will report the error, so we don't have to. |
| 617 | + self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap(); |
| 618 | + None |
| 619 | + } |
| 620 | + } |
| 621 | +} |
| 622 | + |
| 623 | +impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { |
| 624 | + fn tcx(&self) -> TyCtxt<'tcx> { |
| 625 | + self.tcx |
| 626 | + } |
| 627 | + |
| 628 | + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { |
| 629 | + if let ty::Opaque(def_id, substs) = t.kind { |
| 630 | + self.expand_opaque_ty(def_id, substs).unwrap_or(t) |
| 631 | + } else if t.has_opaque_types() { |
| 632 | + t.super_fold_with(self) |
| 633 | + } else { |
| 634 | + t |
| 635 | + } |
| 636 | + } |
| 637 | +} |
| 638 | + |
636 | 639 | impl<'tcx> ty::TyS<'tcx> { |
637 | 640 | /// Returns the maximum value for the given numeric type (including `char`s) |
638 | 641 | /// or returns `None` if the type is not numeric. |
@@ -1142,3 +1145,24 @@ pub fn needs_drop_components( |
1142 | 1145 |
|
1143 | 1146 | #[derive(Copy, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)] |
1144 | 1147 | pub struct AlwaysRequiresDrop; |
| 1148 | + |
| 1149 | +/// Normalizes all opaque types in the given value, replacing them |
| 1150 | +/// with their underlying types. |
| 1151 | +pub fn normalize_opaque_types( |
| 1152 | + tcx: TyCtxt<'tcx>, |
| 1153 | + val: &'tcx List<ty::Predicate<'tcx>>, |
| 1154 | +) -> &'tcx List<ty::Predicate<'tcx>> { |
| 1155 | + let mut visitor = OpaqueTypeExpander { |
| 1156 | + seen_opaque_tys: FxHashSet::default(), |
| 1157 | + expanded_cache: FxHashMap::default(), |
| 1158 | + primary_def_id: None, |
| 1159 | + found_recursion: false, |
| 1160 | + check_recursion: false, |
| 1161 | + tcx, |
| 1162 | + }; |
| 1163 | + val.fold_with(&mut visitor) |
| 1164 | +} |
| 1165 | + |
| 1166 | +pub fn provide(providers: &mut ty::query::Providers) { |
| 1167 | + *providers = ty::query::Providers { normalize_opaque_types, ..*providers } |
| 1168 | +} |
0 commit comments