Skip to content

Commit bda326f

Browse files
authored
Rollup merge of #140607 - lcnr:opaque-type-storage, r=compiler-errors
support duplicate entries in the opaque_type_storage Necessary for the new solver as we may unify keys when eagerly resolving for canonical queries. See the relevant comment when instantiating query responses: ```rust // 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); } ``` This will be far more relevant with #140497. r? `@compiler-errors`
2 parents 25631ff + 431f02d commit bda326f

13 files changed

Lines changed: 207 additions & 82 deletions

File tree

‎Cargo.lock‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4516,7 +4516,6 @@ dependencies = [
45164516
"rustc_session",
45174517
"rustc_span",
45184518
"rustc_transmute",
4519-
"rustc_type_ir",
45204519
"smallvec",
45214520
"thin-vec",
45224521
"tracing",

‎compiler/rustc_hir_typeck/src/_match.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
603603
// FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone.
604604
ty::Infer(ty::TyVar(_)) => self
605605
.inner
606-
.borrow()
606+
.borrow_mut()
607+
.opaque_types()
607608
.iter_opaque_types()
608609
.find(|(_, v)| v.ty == expected_ty)
609610
.map(|(k, _)| (k.def_id, k.args))?,

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

Lines changed: 7 additions & 19 deletions
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-
pubfnclone_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-
fntake_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‎

Lines changed: 8 additions & 17 deletions
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-
fnopaque_types(&mutself) -> opaque_types::OpaqueTypeTable<'_,'tcx>{
201+
pubfnopaque_types(&mutself) -> opaque_types::OpaqueTypeTable<'_,'tcx>{
202202
self.opaque_type_storage.with_log(&mutself.undo_log)
203203
}
204204

@@ -224,15 +224,6 @@ impl<'tcx> InferCtxtInner<'tcx> {
224224
.expect("region constraints already solved")
225225
.with_log(&mutself.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-
pubfniter_opaque_types(
232-
&self,
233-
) -> implIterator<Item = (ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>)>{
234-
self.opaque_type_storage.opaque_types.iter().map(|(&k,&v)| (k, v))
235-
}
236227
}
237228

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

956947
#[instrument(level = "debug", skip(self), ret)]
957-
pubfntake_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx>{
958-
std::mem::take(&mutself.inner.borrow_mut().opaque_type_storage.opaque_types)
948+
pubfntake_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-
pubfnclone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx>{
963-
self.inner.borrow().opaque_type_storage.opaque_types.clone()
953+
pubfnclone_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‎

Lines changed: 0 additions & 2 deletions
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)typeOpaqueTypeMap<'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‎

Lines changed: 66 additions & 10 deletions
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-
usesuper::OpaqueTypeMap;
79
usecrate::infer::snapshot::undo_log::{InferCtxtUndoLogs,UndoLog};
810

911
#[derive(Default,Debug,Clone)]
10-
pub(crate)structOpaqueTypeStorage<'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-
pubopaque_types:OpaqueTypeMap<'tcx>,
12+
pubstructOpaqueTypeStorage<'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)fnpop_duplicate_entry(&mutself){
36+
let entry = self.duplicate_entries.pop();
37+
assert!(entry.is_some());
38+
}
39+
40+
pub(crate)fnis_empty(&self) -> bool{
41+
letOpaqueTypeStorage{ opaque_types, duplicate_entries } = self;
42+
opaque_types.is_empty() && duplicate_entries.is_empty()
43+
}
44+
45+
pub(crate)fntake_opaque_types(
46+
&mutself,
47+
) -> implIterator<Item = (OpaqueTypeKey<'tcx>,OpaqueHiddenType<'tcx>)>{
48+
letOpaqueTypeStorage{ 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+
pubfniter_lookup_table(
58+
&self,
59+
) -> implIterator<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+
pubfniter_duplicate_entries(
69+
&self,
70+
) -> implIterator<Item = (OpaqueTypeKey<'tcx>,OpaqueHiddenType<'tcx>)>{
71+
self.duplicate_entries.iter().copied()
72+
}
73+
74+
pubfniter_opaque_types(
75+
&self,
76+
) -> implIterator<Item = (OpaqueTypeKey<'tcx>,OpaqueHiddenType<'tcx>)>{
77+
letOpaqueTypeStorage{ 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)fnwith_log<'a>(
3883
&'amutself,
@@ -44,21 +89,27 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
4489

4590
impl<'tcx>DropforOpaqueTypeStorage<'tcx>{
4691
fndrop(&mutself){
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)structOpaqueTypeTable<'a,'tcx>{
98+
pubstructOpaqueTypeTable<'a,'tcx>{
5499
storage:&'amutOpaqueTypeStorage<'tcx>,
55100

56101
undo_log:&'amutInferCtxtUndoLogs<'tcx>,
57102
}
103+
impl<'tcx>DerefforOpaqueTypeTable<'_,'tcx>{
104+
typeTarget = OpaqueTypeStorage<'tcx>;
105+
fnderef(&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)fnregister(
112+
pubfnregister(
62113
&mutself,
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+
pubfnadd_duplicate(&mutself,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‎

Lines changed: 2 additions & 0 deletions
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)enumUndoLog<'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>>forInferCtxtInner<'tcx>{
5960
fnreverse(&mutself,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‎

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

42-
fnclone_opaque_types_for_query_response(
42+
fnclone_opaque_types_lookup_table(
43+
&self,
44+
) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::InternerasInterner>::Ty)>;
45+
fnclone_duplicate_opaque_types(
4346
&self,
4447
) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::InternerasInterner>::Ty)>;
4548

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

7281
fnadd_item_bounds_for_hidden_type(
7382
&self,

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

Lines changed: 29 additions & 15 deletions
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(&mutEagerResolver::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
fnregister_new_opaque_types(&mutself,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+
ifletSome(prev) = prev {
448+
self.delegate.add_duplicate_opaque_type(key, prev,self.origin_span);
449+
}
436450
}
437451
}
438452
}

0 commit comments

Comments
 (0)