Skip to content

Commit 5d4793b

Browse files
committed
support duplicates in the opaque_type_storage
1 parent 0fbb922 commit 5d4793b

File tree

11 files changed

+204
-81
lines changed

11 files changed

+204
-81
lines changed

compiler/rustc_hir_typeck/src/_match.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
601601
// FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone.
602602
ty::Infer(ty::TyVar(_)) => self
603603
.inner
604-
.borrow()
604+
.borrow_mut()
605+
.opaque_types()
605606
.iter_opaque_types()
606607
.find(|(_, v)| v.ty == expected_ty)
607608
.map(|(k, _)| (k.def_id, k.args))?,

compiler/rustc_infer/src/infer/canonical/query_response.rs

+7-19
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,13 @@ impl<'tcx> InferCtxt<'tcx> {
132132

133133
let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
134134

135-
let opaque_types = self.take_opaque_types_for_query_response();
135+
let opaque_types = self
136+
.inner
137+
.borrow_mut()
138+
.opaque_type_storage
139+
.take_opaque_types()
140+
.map(|(k, v)| (k, v.ty))
141+
.collect();
136142

137143
Ok(QueryResponse {
138144
var_values: inference_vars,
@@ -143,24 +149,6 @@ impl<'tcx> InferCtxt<'tcx> {
143149
})
144150
}
145151

146-
/// Used by the new solver as that one takes the opaque types at the end of a probe
147-
/// to deal with multiple candidates without having to recompute them.
148-
pub fn clone_opaque_types_for_query_response(
149-
&self,
150-
) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
151-
self.inner
152-
.borrow()
153-
.opaque_type_storage
154-
.opaque_types
155-
.iter()
156-
.map(|(k, v)| (*k, v.ty))
157-
.collect()
158-
}
159-
160-
fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
161-
self.take_opaque_types().into_iter().map(|(k, v)| (k, v.ty)).collect()
162-
}
163-
164152
/// Given the (canonicalized) result to a canonical query,
165153
/// instantiates the result so it can be used, plugging in the
166154
/// values from the canonical query. (Note that the result may

compiler/rustc_infer/src/infer/mod.rs

+8-17
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ use rustc_middle::traits::solve::Goal;
3131
use rustc_middle::ty::error::{ExpectedFound, TypeError};
3232
use rustc_middle::ty::{
3333
self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs,
34-
GenericArgsRef, GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Term, TermKind,
35-
Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
36-
TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
34+
GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueHiddenType, OpaqueTypeKey,
35+
PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
36+
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
3737
};
3838
use rustc_span::{Span, Symbol};
3939
use snapshot::undo_log::InferCtxtUndoLogs;
@@ -198,7 +198,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
198198
}
199199

200200
#[inline]
201-
fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
201+
pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
202202
self.opaque_type_storage.with_log(&mut self.undo_log)
203203
}
204204

@@ -224,15 +224,6 @@ impl<'tcx> InferCtxtInner<'tcx> {
224224
.expect("region constraints already solved")
225225
.with_log(&mut self.undo_log)
226226
}
227-
228-
// Iterates through the opaque type definitions without taking them; this holds the
229-
// `InferCtxtInner` lock, so make sure to not do anything with `InferCtxt` side-effects
230-
// while looping through this.
231-
pub fn iter_opaque_types(
232-
&self,
233-
) -> impl Iterator<Item = (ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>)> {
234-
self.opaque_type_storage.opaque_types.iter().map(|(&k, &v)| (k, v))
235-
}
236227
}
237228

238229
pub struct InferCtxt<'tcx> {
@@ -954,13 +945,13 @@ impl<'tcx> InferCtxt<'tcx> {
954945
}
955946

956947
#[instrument(level = "debug", skip(self), ret)]
957-
pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
958-
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
948+
pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
949+
self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect()
959950
}
960951

961952
#[instrument(level = "debug", skip(self), ret)]
962-
pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
963-
self.inner.borrow().opaque_type_storage.opaque_types.clone()
953+
pub fn clone_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
954+
self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect()
964955
}
965956

966957
#[inline(always)]

compiler/rustc_infer/src/infer/opaque_types/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use hir::def_id::{DefId, LocalDefId};
2-
use rustc_data_structures::fx::FxIndexMap;
32
use rustc_hir as hir;
43
use rustc_middle::bug;
54
use rustc_middle::traits::ObligationCause;
@@ -19,7 +18,6 @@ use crate::traits::{self, Obligation, PredicateObligations};
1918

2019
mod table;
2120

22-
pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>;
2321
pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
2422

2523
impl<'tcx> InferCtxt<'tcx> {

compiler/rustc_infer/src/infer/opaque_types/table.rs

+66-10
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1+
use std::ops::Deref;
2+
3+
use rustc_data_structures::fx::FxIndexMap;
14
use rustc_data_structures::undo_log::UndoLogs;
25
use rustc_middle::bug;
36
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
47
use tracing::instrument;
58

6-
use super::OpaqueTypeMap;
79
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
810

911
#[derive(Default, Debug, Clone)]
10-
pub(crate) struct OpaqueTypeStorage<'tcx> {
11-
/// Opaque types found in explicit return types and their
12-
/// associated fresh inference variable. Writeback resolves these
13-
/// variables to get the concrete type, which can be used to
14-
/// 'de-opaque' OpaqueHiddenType, after typeck is done with all functions.
15-
pub opaque_types: OpaqueTypeMap<'tcx>,
12+
pub struct OpaqueTypeStorage<'tcx> {
13+
opaque_types: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
14+
duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
1615
}
1716

1817
impl<'tcx> OpaqueTypeStorage<'tcx> {
@@ -33,6 +32,52 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
3332
}
3433
}
3534

35+
pub(crate) fn pop_duplicate_entry(&mut self) {
36+
let entry = self.duplicate_entries.pop();
37+
assert!(entry.is_some());
38+
}
39+
40+
pub(crate) fn is_empty(&self) -> bool {
41+
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
42+
opaque_types.is_empty() && duplicate_entries.is_empty()
43+
}
44+
45+
pub(crate) fn take_opaque_types(
46+
&mut self,
47+
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
48+
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
49+
std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
50+
}
51+
52+
/// Only returns the opaque types from the lookup table. These are used
53+
/// when normalizing opaque types and have a unique key.
54+
///
55+
/// Outside of canonicalization one should generally use `iter_opaque_types`
56+
/// to also consider duplicate entries.
57+
pub fn iter_lookup_table(
58+
&self,
59+
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
60+
self.opaque_types.iter().map(|(k, v)| (*k, *v))
61+
}
62+
63+
/// Only returns the opaque types which are stored in `duplicate_entries`.
64+
///
65+
/// These have to considered when checking all opaque type uses but are e.g.
66+
/// irrelevant for canonical inputs as nested queries never meaningfully
67+
/// accesses them.
68+
pub fn iter_duplicate_entries(
69+
&self,
70+
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
71+
self.duplicate_entries.iter().copied()
72+
}
73+
74+
pub fn iter_opaque_types(
75+
&self,
76+
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
77+
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
78+
opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied())
79+
}
80+
3681
#[inline]
3782
pub(crate) fn with_log<'a>(
3883
&'a mut self,
@@ -44,21 +89,27 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
4489

4590
impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
4691
fn drop(&mut self) {
47-
if !self.opaque_types.is_empty() {
92+
if !self.is_empty() {
4893
ty::tls::with(|tcx| tcx.dcx().delayed_bug(format!("{:?}", self.opaque_types)));
4994
}
5095
}
5196
}
5297

53-
pub(crate) struct OpaqueTypeTable<'a, 'tcx> {
98+
pub struct OpaqueTypeTable<'a, 'tcx> {
5499
storage: &'a mut OpaqueTypeStorage<'tcx>,
55100

56101
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
57102
}
103+
impl<'tcx> Deref for OpaqueTypeTable<'_, 'tcx> {
104+
type Target = OpaqueTypeStorage<'tcx>;
105+
fn deref(&self) -> &Self::Target {
106+
self.storage
107+
}
108+
}
58109

59110
impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
60111
#[instrument(skip(self), level = "debug")]
61-
pub(crate) fn register(
112+
pub fn register(
62113
&mut self,
63114
key: OpaqueTypeKey<'tcx>,
64115
hidden_type: OpaqueHiddenType<'tcx>,
@@ -72,4 +123,9 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
72123
self.undo_log.push(UndoLog::OpaqueTypes(key, None));
73124
None
74125
}
126+
127+
pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>) {
128+
self.storage.duplicate_entries.push((key, hidden_type));
129+
self.undo_log.push(UndoLog::DuplicateOpaqueType);
130+
}
75131
}

compiler/rustc_infer/src/infer/snapshot/undo_log.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub struct Snapshot<'tcx> {
1717
/// Records the "undo" data for a single operation that affects some form of inference variable.
1818
#[derive(Clone)]
1919
pub(crate) enum UndoLog<'tcx> {
20+
DuplicateOpaqueType,
2021
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
2122
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
2223
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
@@ -58,6 +59,7 @@ impl_from! {
5859
impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
5960
fn reverse(&mut self, undo: UndoLog<'tcx>) {
6061
match undo {
62+
UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(),
6163
UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx),
6264
UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
6365
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),

compiler/rustc_next_trait_solver/src/delegate.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
3939
term: <Self::Interner as Interner>::Term,
4040
) -> Option<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>>;
4141

42-
fn clone_opaque_types_for_query_response(
42+
fn clone_opaque_types_lookup_table(
43+
&self,
44+
) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
45+
fn clone_duplicate_opaque_types(
4346
&self,
4447
) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
4548

@@ -68,6 +71,12 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
6871
hidden_ty: <Self::Interner as Interner>::Ty,
6972
span: <Self::Interner as Interner>::Span,
7073
) -> Option<<Self::Interner as Interner>::Ty>;
74+
fn add_duplicate_opaque_type(
75+
&self,
76+
opaque_type_key: ty::OpaqueTypeKey<Self::Interner>,
77+
hidden_ty: <Self::Interner as Interner>::Ty,
78+
span: <Self::Interner as Interner>::Span,
79+
);
7180

7281
fn add_item_bounds_for_hidden_type(
7382
&self,

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs

+29-15
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ where
5656
&self,
5757
goal: Goal<I, T>,
5858
) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
59-
let opaque_types = self.delegate.clone_opaque_types_for_query_response();
59+
// We only care about one entry per `OpaqueTypeKey` here,
60+
// so we only canonicalize the lookup table and ignore
61+
// duplicate entries.
62+
let opaque_types = self.delegate.clone_opaque_types_lookup_table();
6063
let (goal, opaque_types) =
6164
(goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate));
6265

@@ -241,19 +244,21 @@ where
241244
Default::default()
242245
};
243246

244-
ExternalConstraintsData {
245-
region_constraints,
246-
opaque_types: self
247-
.delegate
248-
.clone_opaque_types_for_query_response()
249-
.into_iter()
250-
// Only return *newly defined* opaque types.
251-
.filter(|(a, _)| {
252-
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
253-
})
254-
.collect(),
255-
normalization_nested_goals,
256-
}
247+
// We only return *newly defined* opaque types from canonical queries.
248+
//
249+
// Constraints for any existing opaque types are already tracked by changes
250+
// to the `var_values`.
251+
let opaque_types = self
252+
.delegate
253+
.clone_opaque_types_lookup_table()
254+
.into_iter()
255+
.filter(|(a, _)| {
256+
self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
257+
})
258+
.chain(self.delegate.clone_duplicate_opaque_types())
259+
.collect();
260+
261+
ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
257262
}
258263

259264
/// After calling a canonical query, we apply the constraints returned
@@ -432,7 +437,16 @@ where
432437
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)]) {
433438
for &(key, ty) in opaque_types {
434439
let prev = self.delegate.register_hidden_type_in_storage(key, ty, self.origin_span);
435-
assert_eq!(prev, None);
440+
// We eagerly resolve inference variables when computing the query response.
441+
// This can cause previously distinct opaque type keys to now be structurally equal.
442+
//
443+
// To handle this, we store any duplicate entries in a separate list to check them
444+
// at the end of typeck/borrowck. We could alternatively eagerly equate the hidden
445+
// types here. However, doing so is difficult as it may result in nested goals and
446+
// any errors may make it harder to track the control flow for diagnostics.
447+
if let Some(prev) = prev {
448+
self.delegate.add_duplicate_opaque_type(key, prev, self.origin_span);
449+
}
436450
}
437451
}
438452
}

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_type_ir::{
1414
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
1515
TypingMode,
1616
};
17-
use tracing::{instrument, trace};
17+
use tracing::{debug, instrument, trace};
1818

1919
use super::has_only_region_constraints;
2020
use crate::coherence;
@@ -361,7 +361,20 @@ where
361361

362362
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
363363
let prev = ecx.delegate.register_hidden_type_in_storage(key, ty, ecx.origin_span);
364-
assert_eq!(prev, None);
364+
// It may be possible that two entries in the opaque type storage end up
365+
// with the same key after resolving contained inference variables.
366+
//
367+
// We could put them in the duplicate list but don't have to. The opaques we
368+
// encounter here are already tracked in the caller, so there's no need to
369+
// also store them here. We'd take them out when computing the query response
370+
// and then discard them, as they're already present in the input.
371+
//
372+
// Ideally we'd drop duplicate opaque type definitions when computing
373+
// the canonical input. This is more annoying to implement and may cause a
374+
// perf regression, so we do it inside of the query for now.
375+
if let Some(prev) = prev {
376+
debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_type_storage`");
377+
}
365378
}
366379

367380
if !ecx.nested_goals.is_empty() {
@@ -1065,14 +1078,13 @@ where
10651078
&mut self,
10661079
key: ty::OpaqueTypeKey<I>,
10671080
) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1068-
let mut matching =
1069-
self.delegate.clone_opaque_types_for_query_response().into_iter().filter(
1070-
|(candidate_key, _)| {
1071-
candidate_key.def_id == key.def_id
1072-
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
1073-
.args_may_unify(candidate_key.args, key.args)
1074-
},
1075-
);
1081+
let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
1082+
|(candidate_key, _)| {
1083+
candidate_key.def_id == key.def_id
1084+
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
1085+
.args_may_unify(candidate_key.args, key.args)
1086+
},
1087+
);
10761088
let first = matching.next();
10771089
let second = matching.next();
10781090
assert_eq!(second, None);

0 commit comments

Comments
 (0)