rustc_infer/infer/opaque_types/mod.rs
1use hir::def_id::{DefId, LocalDefId};
2use rustc_hir as hir;
3use rustc_middle::bug;
4use rustc_middle::traits::ObligationCause;
5use rustc_middle::traits::solve::Goal;
6use rustc_middle::ty::error::{ExpectedFound, TypeError};
7use rustc_middle::ty::{
8 self, BottomUpFolder, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
9 TypeVisitableExt,
10};
11use rustc_span::Span;
12use tracing::{debug, instrument};
13
14use super::{DefineOpaqueTypes, RegionVariableOrigin};
15use crate::errors::OpaqueHiddenTypeDiag;
16use crate::infer::{InferCtxt, InferOk};
17use crate::traits::{self, Obligation, PredicateObligations};
18
19mod table;
20
21pub use table::{OpaqueTypeStorage, OpaqueTypeStorageEntries, OpaqueTypeTable};
22
23impl<'tcx> InferCtxt<'tcx> {
24 /// This is a backwards compatibility hack to prevent breaking changes from
25 /// lazy TAIT around RPIT handling.
26 pub fn replace_opaque_types_with_inference_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
27 &self,
28 value: T,
29 body_id: LocalDefId,
30 span: Span,
31 param_env: ty::ParamEnv<'tcx>,
32 ) -> InferOk<'tcx, T> {
33 // We handle opaque types differently in the new solver.
34 if self.next_trait_solver() {
35 return InferOk { value, obligations: PredicateObligations::new() };
36 }
37
38 if !value.has_opaque_types() {
39 return InferOk { value, obligations: PredicateObligations::new() };
40 }
41
42 let mut obligations = PredicateObligations::new();
43 let value = value.fold_with(&mut BottomUpFolder {
44 tcx: self.tcx,
45 lt_op: |lt| lt,
46 ct_op: |ct| ct,
47 ty_op: |ty| match *ty.kind() {
48 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
49 if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() =>
50 {
51 let def_span = self.tcx.def_span(def_id);
52 let span = if span.contains(def_span) { def_span } else { span };
53 let ty_var = self.next_ty_var(span);
54 obligations.extend(
55 self.handle_opaque_type(ty, ty_var, span, param_env)
56 .unwrap()
57 .into_iter()
58 .map(|goal| {
59 Obligation::new(
60 self.tcx,
61 ObligationCause::new(
62 span,
63 body_id,
64 traits::ObligationCauseCode::OpaqueReturnType(None),
65 ),
66 goal.param_env,
67 goal.predicate,
68 )
69 }),
70 );
71 ty_var
72 }
73 _ => ty,
74 },
75 });
76 InferOk { value, obligations }
77 }
78
79 pub fn handle_opaque_type(
80 &self,
81 a: Ty<'tcx>,
82 b: Ty<'tcx>,
83 span: Span,
84 param_env: ty::ParamEnv<'tcx>,
85 ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
86 debug_assert!(!self.next_trait_solver());
87 let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
88 ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
89 let def_id = def_id.expect_local();
90 if let ty::TypingMode::Coherence = self.typing_mode() {
91 // See comment on `insert_hidden_type` for why this is sufficient in coherence
92 return Some(self.register_hidden_type(
93 OpaqueTypeKey { def_id, args },
94 span,
95 param_env,
96 b,
97 ));
98 }
99 // Check that this is `impl Trait` type is
100 // declared by `parent_def_id` -- i.e., one whose
101 // value we are inferring. At present, this is
102 // always true during the first phase of
103 // type-check, but not always true later on during
104 // NLL. Once we support named opaque types more fully,
105 // this same scenario will be able to arise during all phases.
106 //
107 // Here is an example using type alias `impl Trait`
108 // that indicates the distinction we are checking for:
109 //
110 // ```rust
111 // mod a {
112 // pub type Foo = impl Iterator;
113 // pub fn make_foo() -> Foo { .. }
114 // }
115 //
116 // mod b {
117 // fn foo() -> a::Foo { a::make_foo() }
118 // }
119 // ```
120 //
121 // Here, the return type of `foo` references an
122 // `Opaque` indeed, but not one whose value is
123 // presently being inferred. You can get into a
124 // similar situation with closure return types
125 // today:
126 //
127 // ```rust
128 // fn foo() -> impl Iterator { .. }
129 // fn bar() {
130 // let x = || foo(); // returns the Opaque assoc with `foo`
131 // }
132 // ```
133 if !self.can_define_opaque_ty(def_id) {
134 return None;
135 }
136
137 if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
138 // We could accept this, but there are various ways to handle this situation,
139 // and we don't want to make a decision on it right now. Likely this case is so
140 // super rare anyway, that no one encounters it in practice. It does occur
141 // however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, where
142 // it is of no concern, so we only check for TAITs.
143 if self.can_define_opaque_ty(b_def_id)
144 && matches!(
145 self.tcx.opaque_ty_origin(b_def_id),
146 hir::OpaqueTyOrigin::TyAlias { .. }
147 )
148 {
149 self.dcx().emit_err(OpaqueHiddenTypeDiag {
150 span,
151 hidden_type: self.tcx.def_span(b_def_id),
152 opaque_type: self.tcx.def_span(def_id),
153 });
154 }
155 }
156 Some(self.register_hidden_type(OpaqueTypeKey { def_id, args }, span, param_env, b))
157 }
158 _ => None,
159 };
160 if let Some(res) = process(a, b) {
161 res
162 } else if let Some(res) = process(b, a) {
163 res
164 } else {
165 let (a, b) = self.resolve_vars_if_possible((a, b));
166 Err(TypeError::Sorts(ExpectedFound::new(a, b)))
167 }
168 }
169}
170
171impl<'tcx> InferCtxt<'tcx> {
172 #[instrument(skip(self), level = "debug")]
173 fn register_hidden_type(
174 &self,
175 opaque_type_key: OpaqueTypeKey<'tcx>,
176 span: Span,
177 param_env: ty::ParamEnv<'tcx>,
178 hidden_ty: Ty<'tcx>,
179 ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
180 let mut goals = Vec::new();
181
182 self.insert_hidden_type(opaque_type_key, span, param_env, hidden_ty, &mut goals)?;
183
184 self.add_item_bounds_for_hidden_type(
185 opaque_type_key.def_id.to_def_id(),
186 opaque_type_key.args,
187 param_env,
188 hidden_ty,
189 &mut goals,
190 );
191
192 Ok(goals)
193 }
194
195 /// Insert a hidden type into the opaque type storage, making sure
196 /// it hasn't previously been defined. This does not emit any
197 /// constraints and it's the responsibility of the caller to make
198 /// sure that the item bounds of the opaque are checked.
199 pub fn register_hidden_type_in_storage(
200 &self,
201 opaque_type_key: OpaqueTypeKey<'tcx>,
202 hidden_ty: OpaqueHiddenType<'tcx>,
203 ) -> Option<Ty<'tcx>> {
204 self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty)
205 }
206
207 /// Insert a hidden type into the opaque type storage, equating it
208 /// with any previous entries if necessary.
209 ///
210 /// This **does not** add the item bounds of the opaque as nested
211 /// obligations. That is only necessary when normalizing the opaque
212 /// itself, not when getting the opaque type constraints from
213 /// somewhere else.
214 pub fn insert_hidden_type(
215 &self,
216 opaque_type_key: OpaqueTypeKey<'tcx>,
217 span: Span,
218 param_env: ty::ParamEnv<'tcx>,
219 hidden_ty: Ty<'tcx>,
220 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
221 ) -> Result<(), TypeError<'tcx>> {
222 let tcx = self.tcx;
223 // Ideally, we'd get the span where *this specific `ty` came
224 // from*, but right now we just use the span from the overall
225 // value being folded. In simple cases like `-> impl Foo`,
226 // these are the same span, but not in cases like `-> (impl
227 // Foo, impl Bar)`.
228 match self.typing_mode() {
229 ty::TypingMode::Coherence => {
230 // During intercrate we do not define opaque types but instead always
231 // force ambiguity unless the hidden type is known to not implement
232 // our trait.
233 goals.push(Goal::new(tcx, param_env, ty::PredicateKind::Ambiguous));
234 }
235 ty::TypingMode::Analysis { .. } => {
236 let prev = self
237 .inner
238 .borrow_mut()
239 .opaque_types()
240 .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
241 if let Some(prev) = prev {
242 goals.extend(
243 self.at(&ObligationCause::dummy_with_span(span), param_env)
244 .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
245 .obligations
246 .into_iter()
247 .map(|obligation| obligation.as_goal()),
248 );
249 }
250 }
251 ty::TypingMode::Borrowck { .. } => {
252 let prev = self
253 .inner
254 .borrow_mut()
255 .opaque_types()
256 .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
257
258 // We either equate the new hidden type with the previous entry or with the type
259 // inferred by HIR typeck.
260 let actual = prev.unwrap_or_else(|| {
261 let actual = tcx
262 .type_of_opaque_hir_typeck(opaque_type_key.def_id)
263 .instantiate(self.tcx, opaque_type_key.args);
264 let actual = ty::fold_regions(tcx, actual, |re, _dbi| match re.kind() {
265 ty::ReErased => {
266 self.next_region_var(RegionVariableOrigin::MiscVariable(span))
267 }
268 _ => re,
269 });
270 actual
271 });
272
273 goals.extend(
274 self.at(&ObligationCause::dummy_with_span(span), param_env)
275 .eq(DefineOpaqueTypes::Yes, hidden_ty, actual)?
276 .obligations
277 .into_iter()
278 .map(|obligation| obligation.as_goal()),
279 );
280 }
281 mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
282 bug!("insert hidden type in {mode:?}")
283 }
284 }
285
286 Ok(())
287 }
288
289 pub fn add_item_bounds_for_hidden_type(
290 &self,
291 def_id: DefId,
292 args: ty::GenericArgsRef<'tcx>,
293 param_env: ty::ParamEnv<'tcx>,
294 hidden_ty: Ty<'tcx>,
295 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
296 ) {
297 let tcx = self.tcx;
298 // Require that the hidden type is well-formed. We have to
299 // make sure we wf-check the hidden type to fix #114728.
300 //
301 // However, we don't check that all types are well-formed.
302 // We only do so for types provided by the user or if they are
303 // "used", e.g. for method selection.
304 //
305 // This means we never check the wf requirements of the hidden
306 // type during MIR borrowck, causing us to infer the wrong
307 // lifetime for its member constraints which then results in
308 // unexpected region errors.
309 goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into())));
310
311 let replace_opaques_in = |clause: ty::Clause<'tcx>, goals: &mut Vec<_>| {
312 clause.fold_with(&mut BottomUpFolder {
313 tcx,
314 ty_op: |ty| match *ty.kind() {
315 // We can't normalize associated types from `rustc_infer`,
316 // but we can eagerly register inference variables for them.
317 // FIXME(RPITIT): Don't replace RPITITs with inference vars.
318 // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
319 ty::Alias(ty::Projection, projection_ty)
320 if !projection_ty.has_escaping_bound_vars()
321 && !tcx.is_impl_trait_in_trait(projection_ty.def_id)
322 && !self.next_trait_solver() =>
323 {
324 let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
325 goals.push(Goal::new(
326 self.tcx,
327 param_env,
328 ty::PredicateKind::Clause(ty::ClauseKind::Projection(
329 ty::ProjectionPredicate {
330 projection_term: projection_ty.into(),
331 term: ty_var.into(),
332 },
333 )),
334 ));
335 ty_var
336 }
337 // Replace all other mentions of the same opaque type with the hidden type,
338 // as the bounds must hold on the hidden type after all.
339 ty::Alias(ty::Opaque, ty::AliasTy { def_id: def_id2, args: args2, .. })
340 if def_id == def_id2 && args == args2 =>
341 {
342 hidden_ty
343 }
344 _ => ty,
345 },
346 lt_op: |lt| lt,
347 ct_op: |ct| ct,
348 })
349 };
350
351 let item_bounds = tcx.explicit_item_bounds(def_id);
352 for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
353 let predicate = replace_opaques_in(predicate, goals);
354
355 // Require that the predicate holds for the concrete type.
356 debug!(?predicate);
357 goals.push(Goal::new(self.tcx, param_env, predicate));
358 }
359
360 // If this opaque is being defined and it's conditionally const,
361 if self.tcx.is_conditionally_const(def_id) {
362 let item_bounds = tcx.explicit_implied_const_bounds(def_id);
363 for (predicate, _) in item_bounds.iter_instantiated_copied(tcx, args) {
364 let predicate = replace_opaques_in(
365 predicate.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe),
366 goals,
367 );
368
369 // Require that the predicate holds for the concrete type.
370 debug!(?predicate);
371 goals.push(Goal::new(self.tcx, param_env, predicate));
372 }
373 }
374 }
375}