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