rustc_hir_analysis/collect/type_of/
opaque.rs1use rustc_hir::def::DefKind;
2use rustc_hir::def_id::LocalDefId;
3use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit};
4use rustc_middle::bug;
5use rustc_middle::hir::nested_filter;
6use rustc_middle::ty::{self, DefiningScopeKind, EarlyBinder, Ty, TyCtxt, TypeVisitableExt};
7use rustc_trait_selection::opaque_types::report_item_does_not_constrain_error;
8use tracing::{debug, instrument, trace};
9
10use crate::errors::UnconstrainedOpaqueType;
11
12#[instrument(skip(tcx), level = "debug")]
15pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
16 tcx: TyCtxt<'_>,
17 def_id: LocalDefId,
18 opaque_types_from: DefiningScopeKind,
19) -> EarlyBinder<'_, Ty<'_>> {
20 let mut parent_def_id = def_id;
21 while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
22 parent_def_id = tcx.local_parent(parent_def_id);
24 }
25 let impl_def_id = tcx.local_parent(parent_def_id);
26 match tcx.def_kind(impl_def_id) {
27 DefKind::Impl { .. } => {}
28 other => bug!("invalid impl trait in assoc type parent: {other:?}"),
29 }
30
31 let mut locator = TaitConstraintLocator { def_id, tcx, found: None, opaque_types_from };
32
33 for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
34 let assoc = tcx.associated_item(assoc_id);
35 match assoc.kind {
36 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
37 locator.check(assoc_id.expect_local())
38 }
39 ty::AssocKind::Type { .. } => {}
41 }
42 }
43
44 if let Some(hidden) = locator.found {
45 hidden.ty
46 } else {
47 let guar = tcx.dcx().emit_err(UnconstrainedOpaqueType {
48 span: tcx.def_span(def_id),
49 name: tcx.item_ident(parent_def_id.to_def_id()),
50 what: "impl",
51 });
52 EarlyBinder::bind(Ty::new_error(tcx, guar))
53 }
54}
55
56#[instrument(skip(tcx), level = "debug")]
75pub(super) fn find_opaque_ty_constraints_for_tait(
76 tcx: TyCtxt<'_>,
77 def_id: LocalDefId,
78 opaque_types_from: DefiningScopeKind,
79) -> EarlyBinder<'_, Ty<'_>> {
80 let mut locator = TaitConstraintLocator { def_id, tcx, found: None, opaque_types_from };
81
82 tcx.hir_walk_toplevel_module(&mut locator);
83
84 if let Some(hidden) = locator.found {
85 hidden.ty
86 } else {
87 let mut parent_def_id = def_id;
88 while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
89 parent_def_id = tcx.local_parent(parent_def_id);
91 }
92 let guar = tcx.dcx().emit_err(UnconstrainedOpaqueType {
93 span: tcx.def_span(def_id),
94 name: tcx.item_ident(parent_def_id.to_def_id()),
95 what: "crate",
96 });
97 EarlyBinder::bind(Ty::new_error(tcx, guar))
98 }
99}
100
101struct TaitConstraintLocator<'tcx> {
102 tcx: TyCtxt<'tcx>,
103
104 def_id: LocalDefId,
106
107 found: Option<ty::DefinitionSiteHiddenType<'tcx>>,
113
114 opaque_types_from: DefiningScopeKind,
115}
116
117impl<'tcx> TaitConstraintLocator<'tcx> {
118 fn insert_found(&mut self, hidden_ty: ty::DefinitionSiteHiddenType<'tcx>) {
119 if let Some(prev) = &mut self.found {
120 if hidden_ty.ty != prev.ty {
121 let (Ok(guar) | Err(guar)) =
122 prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit());
123 *prev = ty::DefinitionSiteHiddenType::new_error(self.tcx, guar);
124 }
125 } else {
126 self.found = Some(hidden_ty);
127 }
128 }
129
130 fn non_defining_use_in_defining_scope(&mut self, item_def_id: LocalDefId) {
131 assert!(!self.tcx.next_trait_solver_globally());
135 let guar = report_item_does_not_constrain_error(self.tcx, item_def_id, self.def_id, None);
136 self.insert_found(ty::DefinitionSiteHiddenType::new_error(self.tcx, guar));
137 }
138
139 #[instrument(skip(self), level = "debug")]
140 fn check(&mut self, item_def_id: LocalDefId) {
141 let tcx = self.tcx;
143 if !tcx.has_typeck_results(item_def_id) {
144 debug!("no constraint: no typeck results");
145 return;
146 }
147
148 let opaque_types_defined_by = tcx.opaque_types_defined_by(item_def_id);
149 if !opaque_types_defined_by.contains(&self.def_id) {
151 debug!("no constraint: no opaque types defined");
152 return;
153 }
154
155 let hir_node = tcx.hir_node_by_def_id(item_def_id);
160 debug_assert!(
161 !matches!(hir_node, Node::ForeignItem(..)),
162 "foreign items cannot constrain opaque types",
163 );
164 if let Some(hir_sig) = hir_node.fn_sig()
165 && hir_sig.decl.output.is_suggestable_infer_ty().is_some()
166 {
167 let guar = self.tcx.dcx().span_delayed_bug(
168 hir_sig.decl.output.span(),
169 "inferring return types and opaque types do not mix well",
170 );
171 self.found = Some(ty::DefinitionSiteHiddenType::new_error(tcx, guar));
172 return;
173 }
174
175 match self.opaque_types_from {
176 DefiningScopeKind::HirTypeck => {
177 let tables = tcx.typeck(item_def_id);
178 if let Some(guar) = tables.tainted_by_errors {
179 self.insert_found(ty::DefinitionSiteHiddenType::new_error(tcx, guar));
180 } else if let Some(&hidden_type) = tables.hidden_types.get(&self.def_id) {
181 self.insert_found(hidden_type);
182 } else {
183 self.non_defining_use_in_defining_scope(item_def_id);
184 }
185 }
186 DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(item_def_id) {
187 Err(guar) => self.insert_found(ty::DefinitionSiteHiddenType::new_error(tcx, guar)),
188 Ok(hidden_types) => {
189 if let Some(&hidden_type) = hidden_types.get(&self.def_id) {
190 debug!(?hidden_type, "found constraint");
191 self.insert_found(hidden_type);
192 } else if let Err(guar) =
193 tcx.type_of_opaque_hir_typeck(self.def_id).skip_binder().error_reported()
194 {
195 self.insert_found(ty::DefinitionSiteHiddenType::new_error(tcx, guar));
196 } else {
197 self.non_defining_use_in_defining_scope(item_def_id);
198 }
199 }
200 },
201 }
202 }
203}
204
205impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
206 type NestedFilter = nested_filter::All;
207
208 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
209 self.tcx
210 }
211 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
212 intravisit::walk_expr(self, ex);
213 }
214 fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
215 trace!(?it.owner_id);
216 self.check(it.owner_id.def_id);
217 intravisit::walk_item(self, it);
218 }
219 fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
220 trace!(?it.owner_id);
221 self.check(it.owner_id.def_id);
222 intravisit::walk_impl_item(self, it);
223 }
224 fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
225 trace!(?it.owner_id);
226 self.check(it.owner_id.def_id);
227 intravisit::walk_trait_item(self, it);
228 }
229 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
230 trace!(?it.owner_id);
231 assert_ne!(it.owner_id.def_id, self.def_id);
232 intravisit::walk_foreign_item(self, it);
234 }
235}
236
237pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
238 tcx: TyCtxt<'tcx>,
239 def_id: LocalDefId,
240 owner_def_id: LocalDefId,
241 opaque_types_from: DefiningScopeKind,
242) -> EarlyBinder<'tcx, Ty<'tcx>> {
243 if !tcx.opaque_types_defined_by(owner_def_id).contains(&def_id) {
246 let opaque_type_span = tcx.def_span(def_id);
247 let guar = tcx
248 .dcx()
249 .span_delayed_bug(opaque_type_span, "cannot infer type for stranded opaque type");
250 return EarlyBinder::bind(Ty::new_error(tcx, guar));
251 }
252
253 match opaque_types_from {
254 DefiningScopeKind::HirTypeck => {
255 let tables = tcx.typeck(owner_def_id);
256 if let Some(guar) = tables.tainted_by_errors {
257 EarlyBinder::bind(Ty::new_error(tcx, guar))
258 } else if let Some(hidden_ty) = tables.hidden_types.get(&def_id) {
259 hidden_ty.ty
260 } else {
261 assert!(!tcx.next_trait_solver_globally());
262 EarlyBinder::bind(tcx.types.unit)
269 }
270 }
271 DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) {
272 Ok(hidden_types) => {
273 if let Some(hidden_ty) = hidden_types.get(&def_id) {
274 hidden_ty.ty
275 } else {
276 let hir_ty = tcx.type_of_opaque_hir_typeck(def_id);
277 if let Err(guar) = hir_ty.skip_binder().error_reported() {
278 EarlyBinder::bind(Ty::new_error(tcx, guar))
279 } else {
280 assert!(!tcx.next_trait_solver_globally());
281 hir_ty
282 }
283 }
284 }
285 Err(guar) => EarlyBinder::bind(Ty::new_error(tcx, guar)),
286 },
287 }
288}