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, SelfAndAssocBounds},
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 SelfAndAssocBounds::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 SelfAndAssocBounds::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: &[SelfAndAssocBounds],
85 mut make_impl_trait: impl FnMut(ImplTraitIdx) -> ImplTraitId,
86 result: &mut Vec<SolverDefId<'db>>,
87 ) {
88 for (opaque_idx, _) in opaques.iter().enumerate() {
89 let opaque_id = InternedOpaqueTyId::new(
90 db,
91 make_impl_trait(ImplTraitIdx::from_raw(la_arena::RawIdx::from_u32(
92 opaque_idx as u32,
93 ))),
94 );
95 result.push(opaque_id.into());
96 }
97 }
98}
99
100#[salsa::tracked(returns(ref))]
103pub(crate) fn rpit_hidden_types(
104 db: &dyn HirDatabase,
105 function: FunctionId,
106) -> ArenaMap<ImplTraitIdx, StoredEarlyBinder<StoredTy>> {
107 let infer = InferenceResult::of(db, DefWithBodyId::from(function));
108 let mut result = ArenaMap::new();
109 for (opaque, hidden_type) in infer.return_position_impl_trait_types(db) {
110 result.insert(opaque, StoredEarlyBinder::bind(hidden_type.store()));
111 }
112 result.shrink_to_fit();
113 result
114}
115
116#[salsa::tracked(returns(ref))]
117pub(crate) fn tait_hidden_types(
118 db: &dyn HirDatabase,
119 type_alias: TypeAliasId,
120) -> ArenaMap<ImplTraitIdx, StoredEarlyBinder<StoredTy>> {
121 let taits_count = SelfAndAssocBounds::type_alias_impl_traits(db, type_alias).len();
123
124 let loc = type_alias.loc(db);
125 let module = loc.module(db);
126 let interner = DbInterner::new_with(db, module.krate(db));
127 let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
128 let mut ocx = ObligationCtxt::new(&infcx);
129 let cause = ObligationCause::dummy();
130 let param_env = db.trait_environment(type_alias.into());
131
132 let defining_bodies = tait_defining_bodies(db, loc);
133
134 let mut result = ArenaMap::with_capacity(taits_count);
135 for defining_body in defining_bodies {
136 let infer = InferenceResult::of(db, defining_body);
137 for (&opaque, hidden_type) in &infer.type_of_opaque {
138 let ImplTraitId::TypeAliasImplTrait(opaque_owner, opaque_idx) = opaque.loc(db) else {
139 continue;
140 };
141 if opaque_owner != type_alias {
142 continue;
143 }
144 let hidden_type = infcx.insert_type_vars(hidden_type.as_ref());
147 match result.entry(opaque_idx) {
148 la_arena::Entry::Vacant(entry) => {
149 entry.insert(StoredEarlyBinder::bind(hidden_type.store()));
150 }
151 la_arena::Entry::Occupied(entry) => {
152 _ = ocx.eq(
153 &cause,
154 param_env,
155 entry.get().get().instantiate_identity().skip_norm_wip(),
156 hidden_type,
157 );
158 }
159 }
160 }
161 }
162
163 _ = ocx.try_evaluate_obligations();
164
165 for idx in 0..taits_count {
167 let idx = la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(idx as u32));
168 match result.entry(idx) {
169 la_arena::Entry::Vacant(entry) => {
170 entry.insert(StoredEarlyBinder::bind(
171 Ty::new_error(interner, ErrorGuaranteed).store(),
172 ));
173 }
174 la_arena::Entry::Occupied(mut entry) => {
175 let hidden_type = entry.get().get().skip_binder();
176 let hidden_type =
177 infcx.resolve_vars_if_possible(hidden_type).replace_infer_with_error(interner);
178 *entry.get_mut() = StoredEarlyBinder::bind(hidden_type.store());
179 }
180 }
181 }
182
183 result
184}
185
186fn tait_defining_bodies(
187 db: &dyn HirDatabase,
188 loc: &AssocItemLoc<ast::TypeAlias>,
189) -> Vec<DefWithBodyId> {
190 let from_assoc_items = |assoc_items: &[(Name, AssocItemId)]| {
191 assoc_items
193 .iter()
194 .filter_map(|&(_, assoc_id)| match assoc_id {
195 AssocItemId::FunctionId(it) => Some(it.into()),
196 AssocItemId::ConstId(it) => Some(it.into()),
197 AssocItemId::TypeAliasId(_) => None,
198 })
199 .collect()
200 };
201 match loc.container {
202 ItemContainerId::ImplId(impl_id)
203 if ImplSignature::of(db, impl_id).target_trait.is_some() =>
204 {
205 return from_assoc_items(&impl_id.impl_items(db).items);
206 }
207 ItemContainerId::TraitId(trait_id) => {
208 return from_assoc_items(&trait_id.trait_items(db).items);
209 }
210 _ => {}
211 }
212
213 Vec::new()
215}