Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 41dea37

Browse files
lcnrcompiler-errors
authored andcommitted
support duplicates in the opaque_type_storage
1 parent dbfa01c commit 41dea37

File tree

11 files changed

+203
-80
lines changed

11 files changed

+203
-80
lines changed

‎compiler/rustc_hir_typeck/src/_match.rs

Lines changed: 2 additions & 1 deletion
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

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

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-
fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
201+
pubfn 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(&mutself.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

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) 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

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-
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

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) 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

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::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

Lines changed: 29 additions & 15 deletions
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

Lines changed: 22 additions & 10 deletions
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)

AltStyle によって変換されたページ (->オリジナル) /