|
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