1use rustc_type_ir::{TypeVisitableExt, fold_regions};
4use tracing::{debug, instrument};
5
6use crate::{
7 Span,
8 infer::InferenceContext,
9 next_solver::{
10 EarlyBinder, OpaqueTypeKey, SolverDefId, TypingMode,
11 infer::{opaque_types::OpaqueHiddenType, traits::ObligationCause},
12 },
13};
14
15impl<'db> InferenceContext<'db> {
16 #[instrument(level = "debug", skip(self))]
25 pub(super) fn handle_opaque_type_uses(&mut self) {
26 let opaque_types: Vec<_> = self.table.infer_ctxt.clone_opaque_types();
29
30 self.compute_definition_site_hidden_types(opaque_types);
31 }
32}
33
34#[expect(unused, reason = "rustc has this")]
35#[derive(Copy, Clone, Debug)]
36enum UsageKind<'db> {
37 None,
38 NonDefiningUse(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>),
39 UnconstrainedHiddenType(OpaqueHiddenType<'db>),
40 HasDefiningUse(OpaqueHiddenType<'db>),
41}
42
43impl<'db> UsageKind<'db> {
44 fn merge(&mut self, other: UsageKind<'db>) {
45 match (&*self, &other) {
46 (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
47 (UsageKind::None, _) => *self = other,
48 (
51 UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
52 UsageKind::NonDefiningUse(..),
53 ) => {}
54 (
59 UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
60 UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
61 ) => *self = other,
62 }
63 }
64}
65
66impl<'db> InferenceContext<'db> {
67 fn compute_definition_site_hidden_types(
68 &mut self,
69 mut opaque_types: Vec<(OpaqueTypeKey<'db>, OpaqueHiddenType<'db>)>,
70 ) {
71 for entry in opaque_types.iter_mut() {
72 *entry = self.resolve_vars_if_possible(*entry);
73 }
74 debug!(?opaque_types);
75
76 let interner = self.interner();
77 let TypingMode::Analysis { defining_opaque_types_and_generators } =
78 self.table.infer_ctxt.typing_mode_raw()
79 else {
80 unreachable!();
81 };
82
83 for def_id in defining_opaque_types_and_generators {
84 let def_id = match def_id {
85 SolverDefId::InternedOpaqueTyId(it) => it,
86 _ => continue,
87 };
88
89 let mut usage_kind = UsageKind::None;
93 for &(opaque_type_key, hidden_type) in &opaque_types {
94 if opaque_type_key.def_id != def_id.into() {
95 continue;
96 }
97
98 usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
99
100 if let UsageKind::HasDefiningUse(..) = usage_kind {
101 break;
102 }
103 }
104
105 if let UsageKind::HasDefiningUse(ty) = usage_kind {
106 for &(opaque_type_key, hidden_type) in &opaque_types {
107 if opaque_type_key.def_id != def_id.into() {
108 continue;
109 }
110
111 let expected = EarlyBinder::bind(ty.ty)
112 .instantiate(interner, opaque_type_key.args)
113 .skip_norm_wip();
114 _ = self.demand_eqtype_fixme_no_diag(expected, hidden_type.ty);
115 }
116
117 self.result.type_of_opaque.insert(def_id, ty.ty.store());
118
119 continue;
120 }
121
122 self.result.type_of_opaque.insert(def_id, self.types.types.error.store());
123 }
124 }
125
126 #[tracing::instrument(skip(self), ret)]
127 fn consider_opaque_type_use(
128 &self,
129 opaque_type_key: OpaqueTypeKey<'db>,
130 hidden_type: OpaqueHiddenType<'db>,
131 ) -> UsageKind<'db> {
132 if hidden_type.ty.has_non_region_infer() {
137 return UsageKind::UnconstrainedHiddenType(hidden_type);
138 }
139
140 let cause = ObligationCause::new(Span::Dummy);
142 let at = self.table.infer_ctxt.at(&cause, self.table.param_env);
143 let hidden_type = match at.deeply_normalize(hidden_type) {
144 Ok(hidden_type) => hidden_type,
145 Err(_errors) => OpaqueHiddenType { ty: self.types.types.error },
146 };
147 let hidden_type =
148 fold_regions(self.interner(), hidden_type, |_, _| self.types.regions.erased);
149 UsageKind::HasDefiningUse(hidden_type)
150 }
151}