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, OpaqueTypeKey, ProvisionalHiddenType, Ty, TyCtxt, TypeFoldable,
9 TypeVisitableExt, Unnormalized,
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 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 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::AliasTy { kind: ty::Opaque { 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 if true {
if !!self.next_trait_solver() {
::core::panicking::panic("assertion failed: !self.next_trait_solver()")
};
};debug_assert!(!self.next_trait_solver());
87 let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
88 ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. })
89 if def_id.is_local() =>
90 {
91 let def_id = def_id.expect_local();
92 if self.typing_mode().is_coherence() {
93 return Some(self.register_hidden_type(
95 OpaqueTypeKey { def_id, args },
96 span,
97 param_env,
98 b,
99 ));
100 }
101 if !self.can_define_opaque_ty(def_id) {
136 return None;
137 }
138
139 if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id: b_def_id }, .. }) =
140 *b.kind()
141 {
142 if self.can_define_opaque_ty(b_def_id)
148 && #[allow(non_exhaustive_omitted_patterns)] match self.tcx.opaque_ty_origin(b_def_id)
{
hir::OpaqueTyOrigin::TyAlias { .. } => true,
_ => false,
}matches!(
149 self.tcx.opaque_ty_origin(b_def_id),
150 hir::OpaqueTyOrigin::TyAlias { .. }
151 )
152 {
153 self.dcx().emit_err(OpaqueHiddenTypeDiag {
154 span,
155 hidden_type: self.tcx.def_span(b_def_id),
156 opaque_type: self.tcx.def_span(def_id),
157 });
158 }
159 }
160 Some(self.register_hidden_type(OpaqueTypeKey { def_id, args }, span, param_env, b))
161 }
162 _ => None,
163 };
164 if let Some(res) = process(a, b) {
165 res
166 } else if let Some(res) = process(b, a) {
167 res
168 } else {
169 let (a, b) = self.resolve_vars_if_possible((a, b));
170 Err(TypeError::Sorts(ExpectedFound::new(a, b)))
171 }
172 }
173}
174
175impl<'tcx> InferCtxt<'tcx> {
176 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("register_hidden_type",
"rustc_infer::infer::opaque_types", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/opaque_types/mod.rs"),
::tracing_core::__macro_support::Option::Some(176u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::opaque_types"),
::tracing_core::field::FieldSet::new(&["opaque_type_key",
"span", "param_env", "hidden_ty"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&opaque_type_key)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&span)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(¶m_env)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&hidden_ty)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return:
Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
TypeError<'tcx>> = loop {};
return __tracing_attr_fake_return;
}
{
let mut goals = Vec::new();
self.insert_hidden_type(opaque_type_key, span, param_env,
hidden_ty, &mut goals)?;
self.add_item_bounds_for_hidden_type(opaque_type_key.def_id.to_def_id(),
opaque_type_key.args, param_env, hidden_ty, &mut goals);
Ok(goals)
}
}
}#[instrument(skip(self), level = "debug")]
177 fn register_hidden_type(
178 &self,
179 opaque_type_key: OpaqueTypeKey<'tcx>,
180 span: Span,
181 param_env: ty::ParamEnv<'tcx>,
182 hidden_ty: Ty<'tcx>,
183 ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, TypeError<'tcx>> {
184 let mut goals = Vec::new();
185
186 self.insert_hidden_type(opaque_type_key, span, param_env, hidden_ty, &mut goals)?;
187
188 self.add_item_bounds_for_hidden_type(
189 opaque_type_key.def_id.to_def_id(),
190 opaque_type_key.args,
191 param_env,
192 hidden_ty,
193 &mut goals,
194 );
195
196 Ok(goals)
197 }
198
199 pub fn register_hidden_type_in_storage(
204 &self,
205 opaque_type_key: OpaqueTypeKey<'tcx>,
206 hidden_ty: ProvisionalHiddenType<'tcx>,
207 ) -> Option<Ty<'tcx>> {
208 self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty)
209 }
210
211 pub fn insert_hidden_type(
219 &self,
220 opaque_type_key: OpaqueTypeKey<'tcx>,
221 span: Span,
222 param_env: ty::ParamEnv<'tcx>,
223 hidden_ty: Ty<'tcx>,
224 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
225 ) -> Result<(), TypeError<'tcx>> {
226 let tcx = self.tcx;
227 match self.typing_mode() {
233 ty::TypingMode::Coherence => {
234 goals.push(Goal::new(tcx, param_env, ty::PredicateKind::Ambiguous));
238 }
239 ty::TypingMode::Analysis { .. } => {
240 let prev = self
241 .inner
242 .borrow_mut()
243 .opaque_types()
244 .register(opaque_type_key, ProvisionalHiddenType { ty: hidden_ty, span });
245 if let Some(prev) = prev {
246 goals.extend(
247 self.at(&ObligationCause::dummy_with_span(span), param_env)
248 .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
249 .obligations
250 .into_iter()
251 .map(|obligation| obligation.as_goal()),
252 );
253 }
254 }
255 ty::TypingMode::Borrowck { .. } => {
256 let prev = self
257 .inner
258 .borrow_mut()
259 .opaque_types()
260 .register(opaque_type_key, ProvisionalHiddenType { ty: hidden_ty, span });
261
262 let actual = prev.unwrap_or_else(|| {
265 let actual = tcx
266 .type_of_opaque_hir_typeck(opaque_type_key.def_id)
267 .instantiate(self.tcx, opaque_type_key.args)
268 .skip_norm_wip();
269 let actual = ty::fold_regions(tcx, actual, |re, _dbi| match re.kind() {
270 ty::ReErased => self.next_region_var(RegionVariableOrigin::Misc(span)),
271 _ => re,
272 });
273 actual
274 });
275
276 goals.extend(
277 self.at(&ObligationCause::dummy_with_span(span), param_env)
278 .eq(DefineOpaqueTypes::Yes, hidden_ty, actual)?
279 .obligations
280 .into_iter()
281 .map(|obligation| obligation.as_goal()),
282 );
283 }
284 mode @ (ty::TypingMode::PostBorrowckAnalysis { .. } | ty::TypingMode::PostAnalysis) => {
285 ::rustc_middle::util::bug::bug_fmt(format_args!("insert hidden type in {0:?}",
mode))bug!("insert hidden type in {mode:?}")
286 }
287 }
288
289 Ok(())
290 }
291
292 pub fn add_item_bounds_for_hidden_type(
293 &self,
294 def_id: DefId,
295 args: ty::GenericArgsRef<'tcx>,
296 param_env: ty::ParamEnv<'tcx>,
297 hidden_ty: Ty<'tcx>,
298 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
299 ) {
300 let tcx = self.tcx;
301 goals.push(Goal::new(tcx, param_env, ty::ClauseKind::WellFormed(hidden_ty.into())));
313
314 let replace_opaques_in = |clause: ty::Clause<'tcx>, goals: &mut Vec<_>| {
315 clause.fold_with(&mut BottomUpFolder {
316 tcx,
317 ty_op: |ty| match *ty.kind() {
318 ty::Alias(
323 projection_ty @ ty::AliasTy { kind: ty::Projection { def_id }, .. },
324 ) if !projection_ty.has_escaping_bound_vars()
325 && !tcx.is_impl_trait_in_trait(def_id)
326 && !self.next_trait_solver() =>
327 {
328 let ty_var = self.next_ty_var(self.tcx.def_span(def_id));
329 goals.push(Goal::new(
330 self.tcx,
331 param_env,
332 ty::PredicateKind::Clause(ty::ClauseKind::Projection(
333 ty::ProjectionPredicate {
334 projection_term: projection_ty.into(),
335 term: ty_var.into(),
336 },
337 )),
338 ));
339 ty_var
340 }
341 ty::Alias(ty::AliasTy {
344 kind: ty::Opaque { def_id: def_id2 },
345 args: args2,
346 ..
347 }) if def_id == def_id2 && args == args2 => hidden_ty,
348 _ => ty,
349 },
350 lt_op: |lt| lt,
351 ct_op: |ct| ct,
352 })
353 };
354
355 let item_bounds = tcx.explicit_item_bounds(def_id);
356 for (predicate, _) in
357 item_bounds.iter_instantiated_copied(tcx, args).map(Unnormalized::skip_norm_wip)
358 {
359 let predicate = replace_opaques_in(predicate, goals);
360
361 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/opaque_types/mod.rs:362",
"rustc_infer::infer::opaque_types", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/opaque_types/mod.rs"),
::tracing_core::__macro_support::Option::Some(362u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::opaque_types"),
::tracing_core::field::FieldSet::new(&["predicate"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&predicate)
as &dyn Value))])
});
} else { ; }
};debug!(?predicate);
363 goals.push(Goal::new(self.tcx, param_env, predicate));
364 }
365
366 if self.tcx.is_conditionally_const(def_id) {
368 let item_bounds = tcx.explicit_implied_const_bounds(def_id);
369 for (predicate, _) in
370 item_bounds.iter_instantiated_copied(tcx, args).map(Unnormalized::skip_norm_wip)
371 {
372 let predicate = replace_opaques_in(
373 predicate.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe),
374 goals,
375 );
376
377 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_infer/src/infer/opaque_types/mod.rs:378",
"rustc_infer::infer::opaque_types", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_infer/src/infer/opaque_types/mod.rs"),
::tracing_core::__macro_support::Option::Some(378u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::opaque_types"),
::tracing_core::field::FieldSet::new(&["predicate"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&predicate)
as &dyn Value))])
});
} else { ; }
};debug!(?predicate);
379 goals.push(Goal::new(self.tcx, param_env, predicate));
380 }
381 }
382 }
383}