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, 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) -> 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 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) -> 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 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::OpaqueHiddenType<'tcx>>,
113
114 opaque_types_from: DefiningScopeKind,
115}
116
117impl<'tcx> TaitConstraintLocator<'tcx> {
118 fn insert_found(&mut self, hidden_ty: ty::OpaqueHiddenType<'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 = Ty::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::OpaqueHiddenType::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::OpaqueHiddenType::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::OpaqueHiddenType::new_error(tcx, guar));
180 } else if let Some(&hidden_type) = tables.concrete_opaque_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::OpaqueHiddenType::new_error(tcx, guar)),
188 Ok(concrete_opaque_types) => {
189 if let Some(&hidden_type) = concrete_opaque_types.0.get(&self.def_id) {
190 debug!(?hidden_type, "found constraint");
191 self.insert_found(hidden_type);
192 } else if let Err(guar) = tcx
193 .type_of_opaque_hir_typeck(self.def_id)
194 .instantiate_identity()
195 .error_reported()
196 {
197 self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
198 } else {
199 self.non_defining_use_in_defining_scope(item_def_id);
200 }
201 }
202 },
203 }
204 }
205}
206
207impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
208 type NestedFilter = nested_filter::All;
209
210 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
211 self.tcx
212 }
213 fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
214 intravisit::walk_expr(self, ex);
215 }
216 fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
217 trace!(?it.owner_id);
218 self.check(it.owner_id.def_id);
219 intravisit::walk_item(self, it);
220 }
221 fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
222 trace!(?it.owner_id);
223 self.check(it.owner_id.def_id);
224 intravisit::walk_impl_item(self, it);
225 }
226 fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
227 trace!(?it.owner_id);
228 self.check(it.owner_id.def_id);
229 intravisit::walk_trait_item(self, it);
230 }
231 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
232 trace!(?it.owner_id);
233 assert_ne!(it.owner_id.def_id, self.def_id);
234 intravisit::walk_foreign_item(self, it);
236 }
237}
238
239pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
240 tcx: TyCtxt<'tcx>,
241 def_id: LocalDefId,
242 owner_def_id: LocalDefId,
243 opaque_types_from: DefiningScopeKind,
244) -> Ty<'tcx> {
245 match opaque_types_from {
246 DefiningScopeKind::HirTypeck => {
247 let tables = tcx.typeck(owner_def_id);
248 if let Some(guar) = tables.tainted_by_errors {
249 Ty::new_error(tcx, guar)
250 } else if let Some(hidden_ty) = tables.concrete_opaque_types.get(&def_id) {
251 hidden_ty.ty
252 } else {
253 assert!(!tcx.next_trait_solver_globally());
254 Ty::new_diverging_default(tcx)
261 }
262 }
263 DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) {
264 Ok(concrete_opaque_types) => {
265 if let Some(hidden_ty) = concrete_opaque_types.0.get(&def_id) {
266 hidden_ty.ty
267 } else {
268 let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
269 if let Err(guar) = hir_ty.error_reported() {
270 Ty::new_error(tcx, guar)
271 } else {
272 assert!(!tcx.next_trait_solver_globally());
273 hir_ty
274 }
275 }
276 }
277 Err(guar) => Ty::new_error(tcx, guar),
278 },
279 }
280}