1use rustc_hir::def::DefKind;
2use rustc_infer::traits::ObligationCause;
3use rustc_middle::bug;
4use rustc_middle::ty::{
5self, DefiningScopeKind, DefinitionSiteHiddenType, OpaqueTypeKey, ProvisionalHiddenType,
6TypeVisitableExt, Unnormalized,
7};
8use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
9use rustc_trait_selection::opaque_types::{
10 NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error,
11};
12use rustc_trait_selection::solve;
13use tracing::{debug, instrument};
1415use crate::FnCtxt;
1617impl<'tcx> FnCtxt<'_, 'tcx> {
18/// This takes all the opaque type uses during HIR typeck. It first computes
19 /// the hidden type by iterating over all defining uses.
20 ///
21 /// A use during HIR typeck is defining if all non-lifetime arguments are
22 /// unique generic parameters and the hidden type does not reference any
23 /// inference variables.
24 ///
25 /// It then uses these defining uses to guide inference for all other uses.
26 ///
27 /// Unlike `handle_opaque_type_uses_next`, this does not report errors.
28#[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(28u32),
::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))]29pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
30// We clone the opaques instead of stealing them here as we still need
31 // to use them after fallback.
32let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
3334self.compute_definition_site_hidden_types(opaque_types, false);
35 }
3637/// This takes all the opaque type uses during HIR typeck. It first computes
38 /// the concrete hidden type by iterating over all defining uses.
39 ///
40 /// A use during HIR typeck is defining if all non-lifetime arguments are
41 /// unique generic parameters and the hidden type does not reference any
42 /// inference variables.
43 ///
44 /// It then uses these defining uses to guide inference for all other uses.
45#[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(45u32),
::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))]46pub(super) fn handle_opaque_type_uses_next(&mut self) {
47// We clone the opaques instead of stealing them here as they are still used for
48 // normalization in the next generation trait solver.
49let opaque_types: Vec<_> = self.infcx.clone_opaque_types();
50let num_entries = self.inner.borrow_mut().opaque_types().num_entries();
51let prev = self.checked_opaque_types_storage_entries.replace(Some(num_entries));
52debug_assert_eq!(prev, None);
5354self.compute_definition_site_hidden_types(opaque_types, true);
55 }
56}
5758#[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)]
59enum UsageKind<'tcx> {
60None,
61 NonDefiningUse(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>),
62 UnconstrainedHiddenType(ProvisionalHiddenType<'tcx>),
63 HasDefiningUse(DefinitionSiteHiddenType<'tcx>),
64}
6566impl<'tcx> UsageKind<'tcx> {
67fn merge(&mut self, other: UsageKind<'tcx>) {
68match (&*self, &other) {
69 (UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
70 (UsageKind::None, _) => *self = other,
71// When mergining non-defining uses, prefer earlier ones. This means
72 // the error happens as early as possible.
73(
74 UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
75 UsageKind::NonDefiningUse(..),
76 ) => {}
77// When merging unconstrained hidden types, we prefer later ones. This is
78 // used as in most cases, the defining use is the final return statement
79 // of our function, and other uses with defining arguments are likely not
80 // intended to be defining.
81(
82 UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
83 UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
84 ) => *self = other,
85 }
86 }
87}
8889impl<'tcx> FnCtxt<'_, 'tcx> {
90fn compute_definition_site_hidden_types(
91&mut self,
92mut opaque_types: Vec<(OpaqueTypeKey<'tcx>, ProvisionalHiddenType<'tcx>)>,
93 error_on_missing_defining_use: bool,
94 ) {
95for entry in opaque_types.iter_mut() {
96*entry = self.resolve_vars_if_possible(*entry);
97 }
98{
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:98",
"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(98u32),
::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);
99100let tcx = self.tcx;
101let defining_opaque_types_and_generators = match self.typing_mode() {
102 ty::TypingMode::Analysis { defining_opaque_types_and_generators } => {
103defining_opaque_types_and_generators104 }
105 ty::TypingMode::Coherence106 | ty::TypingMode::Borrowck { .. }
107 | ty::TypingMode::PostBorrowckAnalysis { .. }
108 | ty::TypingMode::PostAnalysis => {
109::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!()110 }
111 };
112113for def_id in defining_opaque_types_and_generators {
114match tcx.def_kind(def_id) {
115 DefKind::OpaqueTy => {}
116 DefKind::Closure => continue,
117_ => {
::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:?}"),
118 }
119120// We do actually need to check this the second pass (we can't just
121 // store this), because we can go from `UnconstrainedHiddenType` to
122 // `HasDefiningUse` (because of fallback)
123let mut usage_kind = UsageKind::None;
124for &(opaque_type_key, hidden_type) in &opaque_types {
125if opaque_type_key.def_id != def_id {
126continue;
127 }
128129 usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
130131if let UsageKind::HasDefiningUse(..) = usage_kind {
132break;
133 }
134 }
135136if let UsageKind::HasDefiningUse(ty) = usage_kind {
137for &(opaque_type_key, hidden_type) in &opaque_types {
138if opaque_type_key.def_id != def_id {
139continue;
140 }
141142let expected = ty.ty.instantiate(tcx, opaque_type_key.args).skip_norm_wip();
143self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
144 }
145146// Being explicit here: it may be possible that we in a
147 // previous call to this function we did an insert, but this
148 // should be just fine, since they all get equated anyways and
149 // we shouldn't ever go from `HasDefiningUse` to anyway else.
150let _ = self.typeck_results.borrow_mut().hidden_types.insert(def_id, ty);
151 }
152153// If we're in `fn try_handle_opaque_type_uses_next` then do not
154 // report any errors.
155if !error_on_missing_defining_use {
156continue;
157 }
158159let guar = match usage_kind {
160 UsageKind::HasDefiningUse(_) => continue,
161 UsageKind::None => {
162if let Some(guar) = self.tainted_by_errors() {
163 guar
164 } else {
165 report_item_does_not_constrain_error(self.tcx, self.body_id, def_id, None)
166 }
167 }
168 UsageKind::NonDefiningUse(opaque_type_key, hidden_type) => {
169 report_item_does_not_constrain_error(
170self.tcx,
171self.body_id,
172 def_id,
173Some((opaque_type_key, hidden_type.span)),
174 )
175 }
176 UsageKind::UnconstrainedHiddenType(hidden_type) => {
177if let Some(guar) = self.tainted_by_errors() {
178 guar
179 } else {
180let infer_var = hidden_type
181 .ty
182 .walk()
183 .filter_map(ty::GenericArg::as_term)
184 .find(|term| term.is_infer())
185 .unwrap_or_else(|| hidden_type.ty.into());
186self.err_ctxt()
187 .emit_inference_failure_err(
188self.body_id,
189 hidden_type.span,
190 infer_var,
191 TypeAnnotationNeeded::E0282,
192false,
193 )
194 .emit()
195 }
196 }
197 };
198199self.typeck_results
200 .borrow_mut()
201 .hidden_types
202 .insert(def_id, DefinitionSiteHiddenType::new_error(tcx, guar));
203self.set_tainted_by_errors(guar);
204 }
205 }
206207x;#[tracing::instrument(skip(self), ret)]208fn consider_opaque_type_use(
209&self,
210 opaque_type_key: OpaqueTypeKey<'tcx>,
211 hidden_type: ProvisionalHiddenType<'tcx>,
212 ) -> UsageKind<'tcx> {
213if let Err(err) = opaque_type_has_defining_use_args(
214&self,
215 opaque_type_key,
216 hidden_type.span,
217 DefiningScopeKind::HirTypeck,
218 ) {
219match err {
220 NonDefiningUseReason::Tainted(guar) => {
221return UsageKind::HasDefiningUse(DefinitionSiteHiddenType::new_error(
222self.tcx, guar,
223 ));
224 }
225_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
226 };
227 }
228229// We ignore uses of the opaque if they have any inference variables
230 // as this can frequently happen with recursive calls.
231 //
232 // See `tests/ui/traits/next-solver/opaques/universal-args-non-defining.rs`.
233if hidden_type.ty.has_non_region_infer() {
234return UsageKind::UnconstrainedHiddenType(hidden_type);
235 }
236237let cause = ObligationCause::misc(hidden_type.span, self.body_id);
238let at = self.at(&cause, self.param_env);
239let hidden_type = match solve::deeply_normalize(at, Unnormalized::new_wip(hidden_type)) {
240Ok(hidden_type) => hidden_type,
241Err(errors) => {
242let guar = self.err_ctxt().report_fulfillment_errors(errors);
243 ProvisionalHiddenType::new_error(self.tcx, guar)
244 }
245 };
246let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
247 opaque_type_key,
248self.tcx,
249 DefiningScopeKind::HirTypeck,
250 );
251 UsageKind::HasDefiningUse(hidden_type)
252 }
253254/// We may in theory add further uses of an opaque after cloning the opaque
255 /// types storage during writeback when computing the defining uses.
256 ///
257 /// Silently ignoring them is dangerous and could result in ICE or even in
258 /// unsoundness, so we make sure we catch such cases here. There's currently
259 /// no known code where this actually happens, even with the new solver which
260 /// does normalize types in writeback after cloning the opaque type storage.
261 ///
262 /// FIXME(@lcnr): I believe this should be possible in theory and would like
263 /// an actual test here. After playing around with this for an hour, I wasn't
264 /// able to do anything which didn't already try to normalize the opaque before
265 /// then, either allowing compilation to succeed or causing an ambiguity error.
266pub(super) fn detect_opaque_types_added_during_writeback(&self) {
267let num_entries = self.checked_opaque_types_storage_entries.take().unwrap();
268for (key, hidden_type) in
269self.inner.borrow_mut().opaque_types().opaque_types_added_since(num_entries)
270 {
271let opaque_type_string = self.tcx.def_path_str(key.def_id);
272let 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}`");
273self.dcx().span_delayed_bug(hidden_type.span, msg);
274 }
275let _ = self.take_opaque_types();
276 }
277}