1use hir_def::{
4 AssocItemId, AssocItemLoc, DefWithBodyId, FunctionId, HasModule, ItemContainerId, TypeAliasId,
5 signatures::ImplSignature,
6};
7use hir_expand::name::Name;
8use la_arena::ArenaMap;
9use rustc_type_ir::inherent::Ty as _;
10use syntax::ast;
11
12use crate::{
13 ImplTraitId, InferBodyId, InferenceResult,
14 db::{HirDatabase, InternedOpaqueTyId},
15 lower::{ImplTraitIdx, ImplTraits},
16 next_solver::{
17 DbInterner, ErrorGuaranteed, SolverDefId, StoredEarlyBinder, StoredTy, Ty, TypingMode,
18 infer::{DbInternerInferExt, traits::ObligationCause},
19 obligation_ctxt::ObligationCtxt,
20 },
21};
22
23pub(crate) fn opaque_types_defined_by<'db>(
24 db: &'db dyn HirDatabase,
25 def_id: InferBodyId<'_>,
26 result: &mut Vec<SolverDefId<'db>>,
27) {
28 if let Some(func) = def_id.as_function() {
29 extend_with_opaques(
31 db,
32 ImplTraits::return_type_impl_traits(db, func),
33 |opaque_idx| ImplTraitId::ReturnTypeImplTrait(func, opaque_idx),
34 result,
35 );
36 }
37
38 let extend_with_taits = |type_alias| {
39 extend_with_opaques(
40 db,
41 ImplTraits::type_alias_impl_traits(db, type_alias),
42 |opaque_idx| ImplTraitId::TypeAliasImplTrait(type_alias, opaque_idx),
43 result,
44 );
45 };
46
47 let extend_with_atpit_from_assoc_items = |assoc_items: &[(Name, AssocItemId)]| {
49 assoc_items
50 .iter()
51 .filter_map(|&(_, assoc_id)| match assoc_id {
52 AssocItemId::TypeAliasId(it) => Some(it),
53 AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => None,
54 })
55 .for_each(extend_with_taits);
56 };
57 let extend_with_atpit_from_container = |container| match container {
58 ItemContainerId::ImplId(impl_id)
59 if ImplSignature::of(db, impl_id).target_trait.is_some() =>
60 {
61 extend_with_atpit_from_assoc_items(&impl_id.impl_items(db).items);
62 }
63 ItemContainerId::TraitId(trait_id) => {
64 extend_with_atpit_from_assoc_items(&trait_id.trait_items(db).items);
65 }
66 _ => {}
67 };
68 match def_id {
69 InferBodyId::DefWithBodyId(DefWithBodyId::ConstId(id)) => {
70 extend_with_atpit_from_container(id.loc(db).container)
71 }
72 InferBodyId::DefWithBodyId(DefWithBodyId::FunctionId(id)) => {
73 extend_with_atpit_from_container(id.loc(db).container)
74 }
75 InferBodyId::DefWithBodyId(DefWithBodyId::StaticId(_))
76 | InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(_))
77 | InferBodyId::AnonConstId(_) => {}
78 }
79
80 fn extend_with_opaques<'db>(
83 db: &'db dyn HirDatabase,
84 opaques: &Option<Box<StoredEarlyBinder<ImplTraits>>>,
85 mut make_impl_trait: impl FnMut(ImplTraitIdx) -> ImplTraitId,
86 result: &mut Vec<SolverDefId<'db>>,
87 ) {
88 if let Some(opaques) = opaques {
89 for (opaque_idx, _) in (**opaques).as_ref().skip_binder().impl_traits.iter() {
90 let opaque_id = InternedOpaqueTyId::new(db, make_impl_trait(opaque_idx));
91 result.push(opaque_id.into());
92 }
93 }
94 }
95}
96
97#[salsa::tracked(returns(ref))]
100pub(crate) fn rpit_hidden_types(
101 db: &dyn HirDatabase,
102 function: FunctionId,
103) -> ArenaMap<ImplTraitIdx, StoredEarlyBinder<StoredTy>> {
104 let infer = InferenceResult::of(db, DefWithBodyId::from(function));
105 let mut result = ArenaMap::new();
106 for (opaque, hidden_type) in infer.return_position_impl_trait_types(db) {
107 result.insert(opaque, StoredEarlyBinder::bind(hidden_type.store()));
108 }
109 result.shrink_to_fit();
110 result
111}
112
113#[salsa::tracked(returns(ref))]
114pub(crate) fn tait_hidden_types(
115 db: &dyn HirDatabase,
116 type_alias: TypeAliasId,
117) -> ArenaMap<ImplTraitIdx, StoredEarlyBinder<StoredTy>> {
118 let Some(taits_count) = ImplTraits::type_alias_impl_traits(db, type_alias)
120 .as_deref()
121 .map(|taits| taits.as_ref().skip_binder().impl_traits.len())
122 else {
123 return ArenaMap::new();
124 };
125
126 let loc = type_alias.loc(db);
127 let module = loc.module(db);
128 let interner = DbInterner::new_with(db, module.krate(db));
129 let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
130 let mut ocx = ObligationCtxt::new(&infcx);
131 let cause = ObligationCause::dummy();
132 let param_env = db.trait_environment(type_alias.into());
133
134 let defining_bodies = tait_defining_bodies(db, loc);
135
136 let mut result = ArenaMap::with_capacity(taits_count);
137 for defining_body in defining_bodies {
138 let infer = InferenceResult::of(db, defining_body);
139 for (&opaque, hidden_type) in &infer.type_of_opaque {
140 let ImplTraitId::TypeAliasImplTrait(opaque_owner, opaque_idx) = opaque.loc(db) else {
141 continue;
142 };
143 if opaque_owner != type_alias {
144 continue;
145 }
146 let hidden_type = infcx.insert_type_vars(hidden_type.as_ref());
149 match result.entry(opaque_idx) {
150 la_arena::Entry::Vacant(entry) => {
151 entry.insert(StoredEarlyBinder::bind(hidden_type.store()));
152 }
153 la_arena::Entry::Occupied(entry) => {
154 _ = ocx.eq(
155 &cause,
156 param_env,
157 entry.get().get().instantiate_identity().skip_norm_wip(),
158 hidden_type,
159 );
160 }
161 }
162 }
163 }
164
165 _ = ocx.try_evaluate_obligations();
166
167 for idx in 0..taits_count {
169 let idx = la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(idx as u32));
170 match result.entry(idx) {
171 la_arena::Entry::Vacant(entry) => {
172 entry.insert(StoredEarlyBinder::bind(
173 Ty::new_error(interner, ErrorGuaranteed).store(),
174 ));
175 }
176 la_arena::Entry::Occupied(mut entry) => {
177 let hidden_type = entry.get().get().skip_binder();
178 let hidden_type =
179 infcx.resolve_vars_if_possible(hidden_type).replace_infer_with_error(interner);
180 *entry.get_mut() = StoredEarlyBinder::bind(hidden_type.store());
181 }
182 }
183 }
184
185 result
186}
187
188fn tait_defining_bodies(
189 db: &dyn HirDatabase,
190 loc: &AssocItemLoc<ast::TypeAlias>,
191) -> Vec<DefWithBodyId> {
192 let from_assoc_items = |assoc_items: &[(Name, AssocItemId)]| {
193 assoc_items
195 .iter()
196 .filter_map(|&(_, assoc_id)| match assoc_id {
197 AssocItemId::FunctionId(it) => Some(it.into()),
198 AssocItemId::ConstId(it) => Some(it.into()),
199 AssocItemId::TypeAliasId(_) => None,
200 })
201 .collect()
202 };
203 match loc.container {
204 ItemContainerId::ImplId(impl_id)
205 if ImplSignature::of(db, impl_id).target_trait.is_some() =>
206 {
207 return from_assoc_items(&impl_id.impl_items(db).items);
208 }
209 ItemContainerId::TraitId(trait_id) => {
210 return from_assoc_items(&trait_id.trait_items(db).items);
211 }
212 _ => {}
213 }
214
215 Vec::new()
217}