Skip to main content

rustc_type_ir/
unnormalized.rs

1use std::marker::PhantomData;
2
3use derive_where::derive_where;
4#[cfg(feature = "nightly")]
5use rustc_macros::StableHash_NoContext;
6use rustc_type_ir_macros::TypeVisitable_Generic;
7
8use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder};
9use crate::inherent::*;
10use crate::upcast::Upcast;
11use crate::{
12    Binder, BoundConstness, ClauseKind, HostEffectPredicate, Interner, PredicatePolarity,
13    TraitPredicate, TraitRef,
14};
15
16/// A wrapper for values that need normalization.
17///
18/// FIXME(#155345): This is very WIP. The plan is to replace the `skip_norm_wip`
19/// spread throughout the codebase with proper normalization. This is the first
20/// step toward switching to eager normalization with the next solver. See the
21/// normalization refactor plan [here].
22///
23/// We're in a weird intermediate state as the change is too big to land in a
24/// single PR. While this work is in progress, just use `Unnormalized::new_wip`
25/// and `Unnormalized::skip_norm_wip` as needed.
26///
27/// The interner type parameter exists to constraint generic for certain impl,
28/// e.g., `Unnormalized<I, I::Clause>`.
29///
30/// [here]: https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/Eager.20normalization.2C.20ahoy.21/with/582996293
31#[automatically_derived]
impl<I: Interner, T> ::core::fmt::Debug for Unnormalized<I, T> where
    T: ::core::fmt::Debug {
    fn fmt(&self, __f: &mut ::core::fmt::Formatter<'_>)
        -> ::core::fmt::Result {
        match self {
            Unnormalized { value: ref __field_value, _tcx: ref __field__tcx }
                => {
                let mut __builder =
                    ::core::fmt::Formatter::debug_struct(__f, "Unnormalized");
                ::core::fmt::DebugStruct::field(&mut __builder, "value",
                    __field_value);
                ::core::fmt::DebugStruct::finish_non_exhaustive(&mut __builder)
            }
        }
    }
}#[derive_where(Clone, Copy, PartialOrd, PartialEq, Eq, Hash, Debug; T)]
32#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl<I: Interner, T> ::rustc_data_structures::stable_hash::StableHash
            for Unnormalized<I, T> where
            T: ::rustc_data_structures::stable_hash::StableHash,
            PhantomData<fn()
                -> I>: ::rustc_data_structures::stable_hash::StableHash {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    Unnormalized { value: ref __binding_0, _tcx: ref __binding_1
                        } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash_NoContext))]
33#[derive(const _: () =
    {
        impl<I: Interner, T> ::rustc_type_ir::TypeVisitable<I> for
            Unnormalized<I, T> where I: Interner,
            T: ::rustc_type_ir::TypeVisitable<I> {
            fn visit_with<__V: ::rustc_type_ir::TypeVisitor<I>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    Unnormalized { value: ref __binding_0, .. } => {
                        {
                            match ::rustc_type_ir::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_type_ir::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_type_ir::VisitorResult>::output()
            }
        }
    };TypeVisitable_Generic)]
34pub struct Unnormalized<I: Interner, T> {
35    value: T,
36    #[type_visitable(ignore)]
37    #[derive_where(skip(Debug))]
38    _tcx: PhantomData<fn() -> I>,
39}
40
41impl<I: Interner, T> Unnormalized<I, T> {
42    /// Should only be used in limited situations where you produce an potentially
43    /// unnormalized value, like in (Early)Binder/GenericClauses instantiation.
44    pub fn new(value: T) -> Unnormalized<I, T> {
45        Unnormalized { value, _tcx: PhantomData }
46    }
47
48    /// Should be used in case we have an already normalized input as an argument to
49    /// a function that also expects unnormalized inputs, e.g. getting the tail of a
50    /// type is normalized for tuples, but unnormalized for ADTs.
51    pub fn dummy(value: T) -> Unnormalized<I, T> {
52        Unnormalized { value, _tcx: PhantomData }
53    }
54
55    /// FIXME: This is going to be eventually removed once we migrate the relevant
56    /// APIs to return `Unnormalized`.
57    pub fn new_wip(value: T) -> Unnormalized<I, T> {
58        Unnormalized { value, _tcx: PhantomData }
59    }
60
61    /// Intentionally skip normalization.
62    /// You probably should perform normalization in most cases.
63    pub fn skip_normalization(self) -> T {
64        self.value
65    }
66
67    /// FIXME: This is going to be eventually removed.
68    /// If you meet this in codebase, try using one of the normalization routines
69    /// to consume the `Unnormalized` wrapper. Or use `skip_normalization` when normalization
70    /// is really unnecessary.
71    pub fn skip_norm_wip(self) -> T {
72        self.value
73    }
74
75    pub fn map<F, U>(self, f: F) -> Unnormalized<I, U>
76    where
77        F: FnOnce(T) -> U,
78    {
79        Unnormalized { value: f(self.value), _tcx: PhantomData }
80    }
81
82    pub fn as_ref(&self) -> Unnormalized<I, &T> {
83        Unnormalized { value: &self.value, _tcx: PhantomData }
84    }
85
86    pub fn map_ref<U, F>(&self, f: F) -> Unnormalized<I, U>
87    where
88        F: FnOnce(&T) -> U,
89    {
90        Unnormalized { value: f(&self.value), _tcx: PhantomData }
91    }
92}
93
94impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Unnormalized<I, T> {
95    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
96        Ok(Unnormalized::new(self.value.try_fold_with(folder)?))
97    }
98
99    fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
100        Unnormalized::new(self.value.fold_with(folder))
101    }
102}
103
104impl<I: Interner, T, U> Unnormalized<I, (T, U)> {
105    pub fn unzip(self) -> (Unnormalized<I, T>, Unnormalized<I, U>) {
106        (Unnormalized::new(self.value.0), Unnormalized::new(self.value.1))
107    }
108}
109
110impl<I: Interner, T> Unnormalized<I, Binder<I, T>> {
111    pub fn skip_binder(self) -> T {
112        self.value.skip_binder()
113    }
114}
115
116impl<I: Interner> Unnormalized<I, I::Clause> {
117    pub fn as_trait_clause(self) -> Option<Unnormalized<I, Binder<I, TraitPredicate<I>>>> {
118        self.value.as_trait_clause().map(|v| Unnormalized::new(v))
119    }
120
121    pub fn kind(self) -> Unnormalized<I, Binder<I, ClauseKind<I>>> {
122        self.map(|v| v.kind())
123    }
124}
125
126impl<I: Interner> Unnormalized<I, Binder<I, TraitPredicate<I>>> {
127    pub fn self_ty(self) -> Unnormalized<I, Binder<I, I::Ty>> {
128        self.map(|pred| pred.self_ty())
129    }
130
131    pub fn def_id(self) -> I::TraitId {
132        self.value.skip_binder().def_id()
133    }
134
135    #[inline]
136    pub fn polarity(self) -> PredicatePolarity {
137        self.value.skip_binder().polarity
138    }
139}
140
141impl<I: Interner> Unnormalized<I, Binder<I, TraitRef<I>>> {
142    pub fn self_ty(&self) -> Unnormalized<I, Binder<I, I::Ty>> {
143        self.map_ref(|tr| tr.self_ty())
144    }
145
146    pub fn def_id(&self) -> I::TraitId {
147        self.value.skip_binder().def_id
148    }
149
150    pub fn to_host_effect_clause(
151        self,
152        cx: I,
153        constness: BoundConstness,
154    ) -> Unnormalized<I, I::Clause> {
155        let inner = self
156            .value
157            .map_bound(|trait_ref| {
158                ClauseKind::HostEffect(HostEffectPredicate { trait_ref, constness })
159            })
160            .upcast(cx);
161        Unnormalized::new(inner)
162    }
163}