Skip to content

Commit 07ad2fa

Browse files
lcnrcompiler-errors
authored andcommitted
support duplicates in the opaque_type_storage
1 parent 60411bc commit 07ad2fa

File tree

11 files changed

+203
-80
lines changed

11 files changed

+203
-80
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
@@ -134,7 +134,13 @@ impl<'tcx> InferCtxt<'tcx> {
134134

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

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

139145
Ok(QueryResponse {
140146
var_values: inference_vars,
@@ -145,24 +151,6 @@ impl<'tcx> InferCtxt<'tcx> {
145151
})
146152
}
147153

148-
/// Used by the new solver as that one takes the opaque types at the end of a probe
149-
/// to deal with multiple candidates without having to recompute them.
150-
pub fn clone_opaque_types_for_query_response(
151-
&self,
152-
) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
153-
self.inner
154-
.borrow()
155-
.opaque_type_storage
156-
.opaque_types
157-
.iter()
158-
.map(|(k, v)| (*k, v.ty))
159-
.collect()
160-
}
161-
162-
fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
163-
self.take_opaque_types().into_iter().map(|(k, v)| (k, v.ty)).collect()
164-
}
165-
166154
/// Given the (canonicalized) result to a canonical query,
167155
/// instantiates the result so it can be used, plugging in the
168156
/// 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> {
@@ -955,13 +946,13 @@ impl<'tcx> InferCtxt<'tcx> {
955946
}
956947

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

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

967958
#[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(type_variable::UndoLog<'tcx>),
2223
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
@@ -60,6 +61,7 @@ impl_from! {
6061
impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
6162
fn reverse(&mut self, undo: UndoLog<'tcx>) {
6263
match undo {
64+
UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(),
6365
UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx),
6466
UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
6567
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

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

7382
fn add_item_bounds_for_hidden_type(
7483
&self,

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

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

@@ -242,19 +245,21 @@ where
242245
Default::default()
243246
};
244247

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

260265
/// After calling a canonical query, we apply the constraints returned
@@ -448,7 +453,16 @@ where
448453
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)]) {
449454
for &(key, ty) in opaque_types {
450455
let prev = self.delegate.register_hidden_type_in_storage(key, ty, self.origin_span);
451-
assert_eq!(prev, None);
456+
// We eagerly resolve inference variables when computing the query response.
457+
// This can cause previously distinct opaque type keys to now be structurally equal.
458+
//
459+
// To handle this, we store any duplicate entries in a separate list to check them
460+
// at the end of typeck/borrowck. We could alternatively eagerly equate the hidden
461+
// types here. However, doing so is difficult as it may result in nested goals and
462+
// any errors may make it harder to track the control flow for diagnostics.
463+
if let Some(prev) = prev {
464+
self.delegate.add_duplicate_opaque_type(key, prev, self.origin_span);
465+
}
452466
}
453467
}
454468
}

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() {
@@ -1069,14 +1082,13 @@ where
10691082
&mut self,
10701083
key: ty::OpaqueTypeKey<I>,
10711084
) -> Option<(ty::OpaqueTypeKey<I>, I::Ty)> {
1072-
let mut matching =
1073-
self.delegate.clone_opaque_types_for_query_response().into_iter().filter(
1074-
|(candidate_key, _)| {
1075-
candidate_key.def_id == key.def_id
1076-
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
1077-
.args_may_unify(candidate_key.args, key.args)
1078-
},
1079-
);
1085+
let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter(
1086+
|(candidate_key, _)| {
1087+
candidate_key.def_id == key.def_id
1088+
&& DeepRejectCtxt::relate_rigid_rigid(self.cx())
1089+
.args_may_unify(candidate_key.args, key.args)
1090+
},
1091+
);
10801092
let first = matching.next();
10811093
let second = matching.next();
10821094
assert_eq!(second, None);

0 commit comments

Comments
 (0)