1use rustc_hir::def::DefKind;
2use rustc_infer::traits::ObligationCause;
3use rustc_middle::ty::{
4self, DefiningScopeKind, DefinitionSiteHiddenType, OpaqueTypeKey, ProvisionalHiddenType,
5TypeVisitableExt, TypingMode,
6};
7use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
8use rustc_trait_selection::opaque_types::{
9 NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error,
10};
11use rustc_trait_selection::solve;
12use tracing::{debug, instrument};
1314use crate::FnCtxt;
1516impl<'tcx> FnCtxt<'_, 'tcx> {
17/// This takes all the opaque type uses during HIR typeck. It first computes
18 /// the hidden type by iterating over all defining uses.
19 ///
20 /// A use during HIR typeck is defining if all non-lifetime arguments are
21 /// unique generic parameters and the hidden type does not reference any
22 /// inference variables.
23 ///
24 /// It then uses these defining uses to guide inference for all other uses.
25 ///
26 /// Unlike `handle_opaque_type_uses_next`, this does not report errors.
27#[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("try_handle_opaque_type_uses_next",
"rustc_hir_typeck::opaque_types", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/opaque_types.rs"),
::tracing_core::__macro_support::Option::Some(27u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::opaque_types"),
::tracing_core::field::FieldSet::new(&[],
::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,
&{ meta.fields().value_set(&[]) })
} 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: () = loop {};
return __tracing_attr_fake_return;
}
{
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
self.compute_definition_site_hidden_types(opaque_types, false);
}
}
}#[instrument(level = "debug", skip(self))]28pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
29// We clone the opaques instead of stealing them here as we still need
30 // to use them after fallback.
31let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
3233self.compute_definition_site_hidden_types(opaque_types, false);
34 }
3536/// This takes all the opaque type uses during HIR typeck. It first computes
37 /// the concrete hidden type by iterating over all defining uses.
38 ///
39 /// A use during HIR typeck is defining if all non-lifetime arguments are
40 /// unique generic parameters and the hidden type does not reference any
41 /// inference variables.
42 ///
43 /// It then uses these defining uses to guide inference for all other uses.
44#[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("handle_opaque_type_uses_next",
"rustc_hir_typeck::opaque_types", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/opaque_types.rs"),
::tracing_core::__macro_support::Option::Some(44u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::opaque_types"),
::tracing_core::field::FieldSet::new(&[],
::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,
&{ meta.fields().value_set(&[]) })
} 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: () = loop {};
return __tracing_attr_fake_return;
}
{
let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
let num_entries =
self.inner.borrow_mut().opaque_types().num_entries();
let prev =
self.checked_opaque_types_storage_entries.replace(Some(num_entries));
if true {
match (&prev, &None) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
};
self.compute_definition_site_hidden_types(opaque_types, true);
}
}
}#[instrument(level = "debug", skip(self))]45pub(super) fn handle_opaque_type_uses_next(&mut self) {
46// We clone the opaques instead of stealing them here as they are still used for
47 // normalization in the next generation trait solver.
48let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
49let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
50let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
51debug_assert_eq!(prev, None);
5253self.compute_definition_site_hidden_types(opaque_types, true);
54 }
55}
5657#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for UsageKind<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for UsageKind<'tcx> {
#[inline]
fn clone(&self) -> UsageKind<'tcx> {
let _: ::core::clone::AssertParamIsClone<OpaqueTypeKey<'tcx>>;
let _: ::core::clone::AssertParamIsClone<ProvisionalHiddenType<'tcx>>;
let _: ::core::clone::AssertParamIsClone<ProvisionalHiddenType<'tcx>>;
let _:
::core::clone::AssertParamIsClone<DefinitionSiteHiddenType<'tcx>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for UsageKind<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
UsageKind::None => ::core::fmt::Formatter::write_str(f, "None"),
UsageKind::NonDefiningUse(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"NonDefiningUse", __self_0, &__self_1),
UsageKind::UnconstrainedHiddenType(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"UnconstrainedHiddenType", &__self_0),
UsageKind::HasDefiningUse(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"HasDefiningUse", &__self_0),
}
}
}Debug)]
58enum UsageKind<'tcx> {
59None,
60 NonDefiningUse(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>),
61 UnconstrainedHiddenType(ProvisionalHiddenType<'tcx>),
62 HasDefiningUse(DefinitionSiteHiddenType<'tcx>),
63}
6465impl<'tcx> UsageKind<'tcx> {
66fn merge(&mut self, other: UsageKind<'tcx>) {
67match (&*self, &other) {
68 (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
69 (UsageKind::None, _) => *self = other,
70// When mergining non-defining uses, prefer earlier ones. This means
71 // the error happens as early as possible.
72(
73 UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
74 UsageKind::NonDefiningUse(..),
75 ) => {}
76// When merging unconstrained hidden types, we prefer later ones. This is
77 // used as in most cases, the defining use is the final return statement
78 // of our function, and other uses with defining arguments are likely not
79 // intended to be defining.
80(
81 UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
82 UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
83 ) => *self = other,
84 }
85 }
86}
8788impl<'tcx> FnCtxt<'_, 'tcx> {
89fn compute_definition_site_hidden_types(
90&mut self,
91mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>,
92 error_on_missing_defining_use: bool,
93 ) {
94for entry in opaque_types.iter_mut() {
95*entry = self.resolve_vars_if_possible(*entry);
96 }
97{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_hir_typeck/src/opaque_types.rs:97",
"rustc_hir_typeck::opaque_types", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_typeck/src/opaque_types.rs"),
::tracing_core::__macro_support::Option::Some(97u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_typeck::opaque_types"),
::tracing_core::field::FieldSet::new(&["opaque_types"],
::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(&opaque_types)
as &dyn Value))])
});
} else { ; }
};debug!(?opaque_types);
9899let tcx = self.tcx;
100let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
101else {
102::core::panicking::panic("internal error: entered unreachable code");unreachable!();
103 };
104105for def_id in defining_opaque_types_and_generators {
106match tcx.def_kind(def_id) {
107 DefKind::OpaqueTy => {}
108 DefKind::Closure => continue,
109_ => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("not opaque or generator: {0:?}", def_id)));
}unreachable!("not opaque or generator: {def_id:?}"),
110 }
111112// We do actually need to check this the second pass (we can't just
113 // store this), because we can go from `UnconstrainedHiddenType` to
114 // `HasDefiningUse` (because of fallback)
115let mut usage_kind = UsageKind::None;
116for &(opaque_type_key, hidden_type) in &opaque_types {
117if opaque_type_key.def_id != def_id {
118continue;
119 }
120121 usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
122123if let UsageKind::HasDefiningUse(..) = usage_kind {
124break;
125 }
126 }
127128if let UsageKind::HasDefiningUse(ty) = usage_kind {
129for &(opaque_type_key, hidden_type) in &opaque_types {
130if opaque_type_key.def_id != def_id {
131continue;
132 }
133134let expected = ty.ty.instantiate(tcx, opaque_type_key.args);
135self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
136 }
137138// Being explicit here: it may be possible that we in a
139 // previous call to this function we did an insert, but this
140 // should be just fine, since they all get equated anyways and
141 // we shouldn't ever go from `HasDefiningUse` to anyway else.
142let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
143 }
144145// If we're in `fn try_handle_opaque_type_uses_next` then do not
146 // report any errors.
147if !error_on_missing_defining_use {
148continue;
149 }
150151let guar = match usage_kind {
152 UsageKind::HasDefiningUse(_) => continue,
153 UsageKind::None => {
154if let Some(guar) = self.tainted_by_errors() {
155 guar
156 } else {
157 report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None)
158 }
159 }
160 UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => {
161 report_item_does_not_constrain_error(
162self.tcx,
163self.body_id,
164 def_id,
165Some((opaque_type_key, hidden_type.span)),
166 )
167 }
168 UsageKind::UnconstrainedHiddenType(hidden_type) => {
169if let Some(guar) = self.tainted_by_errors() {
170 guar
171 } else {
172let infer_var = hidden_type
173 .ty
174 .walk()
175 .filter_map(ty::GenericArg::as_term)
176 .find(|term| term.is_infer())
177 .unwrap_or_else(|| hidden_type.ty.into());
178self.err_ctxt()
179 .emit_inference_failure_err(
180self.body_id,
181 hidden_type.span,
182 infer_var,
183 TypeAnnotationNeeded::E0282,
184false,
185 )
186 .emit()
187 }
188 }
189 };
190191self.typeck_results
192 .borrow_mut()
193 .hidden_types
194 .insert(def_id, DefinitionSiteHiddenType::new_error(tcx, guar));
195self.set_tainted_by_errors(guar);
196 }
197 }
198199x;#[tracing::instrument(skip(self), ret)]200fn consider_opaque_type_use(
201&self,
202 opaque_type_key: OpaqueTypeKey<'tcx>,
203 hidden_type: ProvisionalHiddenType<'tcx>,
204 ) -> UsageKind<'tcx> {
205if let Err(err) = opaque_type_has_defining_use_args(
206&self,
207 opaque_type_key,
208 hidden_type.span,
209 DefiningScopeKind::HirTypeck,
210 ) {
211match err {
212 NonDefiningUseReason::Tainted(guar) => {
213return UsageKind::HasDefiningUse(DefinitionSiteHiddenType::new_error(
214self.tcx, guar,
215 ));
216 }
217_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
218 };
219 }
220221// We ignore uses of the opaque if they have any inference variables
222 // as this can frequently happen with recursive calls.
223 //
224 // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
225if hidden_type.ty.has_non_region_infer() {
226return UsageKind::UnconstrainedHiddenType(hidden_type);
227 }
228229let cause = ObligationCause::misc(hidden_type.span, self.body_id);
230let at = self.at(&cause, self.param_env);
231let hidden_type = match solve::deeply_normalize(at, hidden_type) {
232Ok(hidden_type) => hidden_type,
233Err(errors) => {
234let guar = self.err_ctxt().report_fulfillment_errors(errors);
235 ProvisionalHiddenType::new_error(self.tcx, guar)
236 }
237 };
238let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
239 opaque_type_key,
240self.tcx,
241 DefiningScopeKind::HirTypeck,
242 );
243 UsageKind::HasDefiningUse(hidden_type)
244 }
245246/// We may in theory add further uses of an opaque after cloning the opaque
247 /// types storage during writeback when computing the defining uses.
248 ///
249 /// Silently ignoring them is dangerous and could result in ICE or even in
250 /// unsoundness, so we make sure we catch such cases here. There's currently
251 /// no known code where this actually happens, even with the new solver which
252 /// does normalize types in writeback after cloning the opaque type storage.
253 ///
254 /// FIXME(@lcnr): I believe this should be possible in theory and would like
255 /// an actual test here. After playing around with this for an hour, I wasn't
256 /// able to do anything which didn't already try to normalize the opaque before
257 /// then, either allowing compilation to succeed or causing an ambiguity error.
258pub(super) fn detect_opaque_types_added_during_writeback(&self) {
259let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
260for (key, hidden_type) in
261self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
262 {
263let opaque_type_string = self.tcx.def_path_str(key.def_id);
264let msg = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unexpected cyclic definition of `{0}`",
opaque_type_string))
})format!("unexpected cyclic definition of `{opaque_type_string}`");
265self.dcx().span_delayed_bug(hidden_type.span, msg);
266 }
267let _ = self.take_opaque_types();
268 }
269}