support duplicates in the opaque_types_storage
This commit is contained in:
@@ -56,7 +56,10 @@ where
|
||||
&self,
|
||||
goal: Goal<I, T>,
|
||||
) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
|
||||
let opaque_types = self.delegate.clone_opaque_types_for_query_response();
|
||||
// We only care about one entry per `OpaqueTypeKey` here,
|
||||
// so we only canonicalize the lookup table and ignore
|
||||
// duplicate entries.
|
||||
let opaque_types = self.delegate.clone_opaque_types_lookup_table();
|
||||
let (goal, opaque_types) =
|
||||
(goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate));
|
||||
|
||||
@@ -241,19 +244,21 @@ where
|
||||
Default::default()
|
||||
};
|
||||
|
||||
ExternalConstraintsData {
|
||||
region_constraints,
|
||||
opaque_types: self
|
||||
.delegate
|
||||
.clone_opaque_types_for_query_response()
|
||||
.into_iter()
|
||||
// Only return *newly defined* opaque types.
|
||||
.filter(|(a, _)| {
|
||||
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
|
||||
})
|
||||
.collect(),
|
||||
normalization_nested_goals,
|
||||
}
|
||||
// We only return *newly defined* opaque types from canonical queries.
|
||||
//
|
||||
// Constraints for any existing opaque types are already tracked by changes
|
||||
// to the `var_values`.
|
||||
let opaque_types = self
|
||||
.delegate
|
||||
.clone_opaque_types_lookup_table()
|
||||
.into_iter()
|
||||
.filter(|(a, _)| {
|
||||
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
|
||||
})
|
||||
.chain(self.delegate.clone_duplicate_opaque_types())
|
||||
.collect();
|
||||
|
||||
ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
|
||||
}
|
||||
|
||||
/// After calling a canonical query, we apply the constraints returned
|
||||
@@ -432,7 +437,16 @@ where
|
||||
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)]) {
|
||||
for &(key, ty) in opaque_types {
|
||||
let prev = self.delegate.register_hidden_type_in_storage(key, ty, self.origin_span);
|
||||
assert_eq!(prev, None);
|
||||
// We eagerly resolve inference variables when computing the query response.
|
||||
// This can cause previously distinct opaque type keys to now be structurally equal.
|
||||
//
|
||||
// To handle this, we store any duplicate entries in a separate list to check them
|
||||
// at the end of typeck/borrowck. We could alternatively eagerly equate the hidden
|
||||
// types here. However, doing so is difficult as it may result in nested goals and
|
||||
// any errors may make it harder to track the control flow for diagnostics.
|
||||
if let Some(prev) = prev {
|
||||
self.delegate.add_duplicate_opaque_type(key, prev, self.origin_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use rustc_type_ir::{
|
||||
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
TypingMode,
|
||||
};
|
||||
use tracing::{instrument, trace};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::has_only_region_constraints;
|
||||
use crate::coherence;
|
||||
@@ -361,7 +361,20 @@ where
|
||||
|
||||
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
|
||||
let prev = ecx.delegate.register_hidden_type_in_storage(key, ty, ecx.origin_span);
|
||||
assert_eq!(prev, None);
|
||||
// It may be possible that two entries in the opaque type storage end up
|
||||
// with the same key after resolving contained inference variables.
|
||||
//
|
||||
// We could put them in the duplicate list but don't have to. The opaques we
|
||||
// encounter here are already tracked in the caller, so there's no need to
|
||||
// also store them here. We'd take them out when computing the query response
|
||||
// and then discard them, as they're already present in the input.
|
||||
//
|
||||
// Ideally we'd drop duplicate opaque type definitions when computing
|
||||
// the canonical input. This is more annoying to implement and may cause a
|
||||
// perf regression, so we do it inside of the query for now.
|
||||
if let Some(prev) = prev {
|
||||
debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_type_storage`");
|
||||
}
|
||||
}
|
||||
|
||||
if !ecx.nested_goals.is_empty() {
|
||||
@@ -1065,14 +1078,17 @@ where
|
||||
&mut self,
|
||||
key: ty::OpaqueTypeKey<I>,
|
||||
) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
|
||||
let mut matching =
|
||||
self.delegate.clone_opaque_types_for_query_response().into_iter().filter(
|
||||
|(candidate_key, _)| {
|
||||
candidate_key.def_id == key.def_id
|
||||
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
|
||||
.args_may_unify(candidate_key.args, key.args)
|
||||
},
|
||||
);
|
||||
// We shouldn't have any duplicate entries when using
|
||||
// this function during `TypingMode::Analysis`.
|
||||
let duplicate_entries = self.delegate.clone_duplicate_opaque_types();
|
||||
assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}");
|
||||
let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
|
||||
|(candidate_key, _)| {
|
||||
candidate_key.def_id == key.def_id
|
||||
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
|
||||
.args_may_unify(candidate_key.args, key.args)
|
||||
},
|
||||
);
|
||||
let first = matching.next();
|
||||
let second = matching.next();
|
||||
assert_eq!(second, None);
|
||||
|
||||
Reference in New Issue
Block a user