Cleanup opaque_type computation a bit
This commit is contained in:
parent
db3c9b640e
commit
9a5cef155f
1 changed files with 56 additions and 47 deletions
|
|
@ -4,6 +4,7 @@ use rustc_middle::ty::{
|
|||
self, DefiningScopeKind, EarlyBinder, OpaqueHiddenType, OpaqueTypeKey, TypeVisitableExt,
|
||||
TypingMode,
|
||||
};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||
use rustc_trait_selection::opaque_types::{
|
||||
NonDefiningUseReason, opaque_type_has_defining_use_args, report_item_does_not_constrain_error,
|
||||
|
|
@ -24,6 +25,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
/// It then uses these defining uses to guide inference for all other uses.
|
||||
///
|
||||
/// Unlike `handle_opaque_type_uses_next`, this does not report errors.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn try_handle_opaque_type_uses_next(&mut self) {
|
||||
// We clone the opaques instead of stealing them here as they are still used for
|
||||
// normalization in the next generation trait solver.
|
||||
|
|
@ -34,7 +36,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
debug!(?opaque_types);
|
||||
|
||||
self.compute_definition_site_hidden_types(&opaque_types, true);
|
||||
self.apply_definition_site_hidden_types(&opaque_types);
|
||||
}
|
||||
|
||||
/// This takes all the opaque type uses during HIR typeck. It first computes
|
||||
|
|
@ -59,22 +60,29 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
debug!(?opaque_types);
|
||||
|
||||
self.compute_definition_site_hidden_types(&opaque_types, false);
|
||||
self.apply_definition_site_hidden_types(&opaque_types);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum UsageKind<'tcx> {
|
||||
None,
|
||||
NonDefiningUse(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>),
|
||||
UnconstrainedHiddenType(OpaqueHiddenType<'tcx>),
|
||||
HasDefiningUse,
|
||||
HasDefiningUse(OpaqueHiddenType<'tcx>),
|
||||
// `type_of_opaque_hir_typeck` reported an error
|
||||
HasError(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
impl<'tcx> UsageKind<'tcx> {
|
||||
fn merge(&mut self, other: UsageKind<'tcx>) {
|
||||
match (&*self, &other) {
|
||||
(UsageKind::HasDefiningUse, _) | (_, UsageKind::None) => unreachable!(),
|
||||
(UsageKind::HasDefiningUse(_), _) | (_, UsageKind::None) => unreachable!(),
|
||||
(UsageKind::None, _) => *self = other,
|
||||
// If `type_of_opaque_hir_typeck` reported an error, then the hidden
|
||||
// type is an error, but we also want to still report errors for
|
||||
// remaining hidden types (really just normalization errors).
|
||||
(UsageKind::HasError(_), _) => {}
|
||||
(_, UsageKind::HasError(_)) => *self = other,
|
||||
// When mergining non-defining uses, prefer earlier ones. This means
|
||||
// the error happens as early as possible.
|
||||
(
|
||||
|
|
@ -87,7 +95,7 @@ impl<'tcx> UsageKind<'tcx> {
|
|||
// intended to be defining.
|
||||
(
|
||||
UsageKind::NonDefiningUse(..) | UsageKind::UnconstrainedHiddenType(..),
|
||||
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse,
|
||||
UsageKind::UnconstrainedHiddenType(..) | UsageKind::HasDefiningUse(_),
|
||||
) => *self = other,
|
||||
}
|
||||
}
|
||||
|
|
@ -112,22 +120,55 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
_ => unreachable!("not opaque or generator: {def_id:?}"),
|
||||
}
|
||||
|
||||
// We do actually need to check this the second pass (we can't just
|
||||
// store this), because we can go from `UnconstrainedHiddenType` to
|
||||
// `HasDefiningUse` (because of fallback)
|
||||
let mut usage_kind = UsageKind::None;
|
||||
for &(opaque_type_key, hidden_type) in opaque_types {
|
||||
if opaque_type_key.def_id != def_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
usage_kind.merge(self.consider_opaque_type_use(
|
||||
opaque_type_key,
|
||||
hidden_type,
|
||||
first_pass,
|
||||
));
|
||||
if let UsageKind::HasDefiningUse = usage_kind {
|
||||
usage_kind.merge(self.consider_opaque_type_use(opaque_type_key, hidden_type));
|
||||
|
||||
if let UsageKind::HasDefiningUse(..) = usage_kind {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let UsageKind::HasDefiningUse(first_use) = usage_kind {
|
||||
for &(opaque_type_key, hidden_type) in opaque_types {
|
||||
if opaque_type_key.def_id != def_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
let expected =
|
||||
EarlyBinder::bind(first_use.ty).instantiate(tcx, opaque_type_key.args);
|
||||
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
|
||||
}
|
||||
}
|
||||
|
||||
match usage_kind {
|
||||
UsageKind::HasDefiningUse(hidden_type) => {
|
||||
let prev =
|
||||
self.typeck_results.borrow_mut().hidden_types.insert(def_id, hidden_type);
|
||||
|
||||
// We do want to insert opaque types the first pass, because
|
||||
// we want to equate them. So, the second pass (where we
|
||||
// report errors) may have a hidden type inserted.
|
||||
if first_pass {
|
||||
assert!(prev.is_none());
|
||||
}
|
||||
}
|
||||
UsageKind::HasError(guar) => {
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.hidden_types
|
||||
.insert(def_id, OpaqueHiddenType::new_error(self.tcx, guar));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// If this the first pass (`try_handle_opaque_type_uses_next`),
|
||||
// then do not report any errors.
|
||||
if first_pass {
|
||||
|
|
@ -135,6 +176,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
let guar = match usage_kind {
|
||||
UsageKind::HasDefiningUse(_) | UsageKind::HasError(_) => continue,
|
||||
UsageKind::None => {
|
||||
if let Some(guar) = self.tainted_by_errors() {
|
||||
guar
|
||||
|
|
@ -171,7 +213,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
.emit()
|
||||
}
|
||||
}
|
||||
UsageKind::HasDefiningUse => continue,
|
||||
};
|
||||
|
||||
self.typeck_results
|
||||
|
|
@ -182,11 +223,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self), ret)]
|
||||
fn consider_opaque_type_use(
|
||||
&mut self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
hidden_type: OpaqueHiddenType<'tcx>,
|
||||
first_pass: bool,
|
||||
) -> UsageKind<'tcx> {
|
||||
if let Err(err) = opaque_type_has_defining_use_args(
|
||||
&self,
|
||||
|
|
@ -196,11 +237,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
) {
|
||||
match err {
|
||||
NonDefiningUseReason::Tainted(guar) => {
|
||||
self.typeck_results.borrow_mut().hidden_types.insert(
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType::new_error(self.tcx, guar),
|
||||
);
|
||||
return UsageKind::HasDefiningUse;
|
||||
return UsageKind::HasError(guar);
|
||||
}
|
||||
_ => return UsageKind::NonDefiningUse(opaque_type_key, hidden_type),
|
||||
};
|
||||
|
|
@ -228,35 +265,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
self.tcx,
|
||||
DefiningScopeKind::HirTypeck,
|
||||
);
|
||||
|
||||
let prev = self
|
||||
.typeck_results
|
||||
.borrow_mut()
|
||||
.hidden_types
|
||||
.insert(opaque_type_key.def_id, hidden_type);
|
||||
|
||||
// We do want to insert opaque types the first pass, because we want to
|
||||
// equate them. So, the second pass (where we report errors) will have
|
||||
// a hidden type inserted.
|
||||
if first_pass {
|
||||
assert!(prev.is_none());
|
||||
}
|
||||
UsageKind::HasDefiningUse
|
||||
}
|
||||
|
||||
fn apply_definition_site_hidden_types(
|
||||
&mut self,
|
||||
opaque_types: &[(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)],
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
for &(key, hidden_type) in opaque_types {
|
||||
// On the first pass to this function, some opaque types may not
|
||||
// have a hidden type assigned.
|
||||
if let Some(expected) = self.typeck_results.borrow_mut().hidden_types.get(&key.def_id) {
|
||||
let expected = EarlyBinder::bind(expected.ty).instantiate(tcx, key.args);
|
||||
self.demand_eqtype(hidden_type.span, expected, hidden_type.ty);
|
||||
}
|
||||
}
|
||||
UsageKind::HasDefiningUse(hidden_type)
|
||||
}
|
||||
|
||||
/// We may in theory add further uses of an opaque after cloning the opaque
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue