Skip to content

Commit f3c9c21

Browse files
Prepopulate opaques in canonical input
1 parent a2d7ffc commit f3c9c21

File tree

11 files changed

+243
-81
lines changed

11 files changed

+243
-81
lines changed

compiler/rustc_middle/src/arena.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ macro_rules! arena_types {
121121
>,
122122
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
123123
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
124+
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
124125
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
125126
[] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
126127
[] mod_child: rustc_middle::metadata::ModChild,

compiler/rustc_middle/src/traits/solve.rs

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use rustc_query_system::cache::Cache;
55

66
use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
77
use crate::traits::query::NoSolution;
8-
use crate::traits::Canonical;
8+
use crate::traits::{Canonical, DefiningAnchor};
99
use crate::ty::{
1010
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
1111
TypeVisitor,
1212
};
1313

14-
pub type EvaluationCache<'tcx> = Cache<CanonicalGoal<'tcx>, QueryResult<'tcx>>;
14+
pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>;
1515

1616
/// A goal is a statement, i.e. `predicate`, we want to prove
1717
/// given some assumptions, i.e. `param_env`.
@@ -96,7 +96,31 @@ pub enum MaybeCause {
9696
Overflow,
9797
}
9898

99-
pub type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>;
99+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
100+
pub struct QueryInput<'tcx, T> {
101+
pub goal: Goal<'tcx, T>,
102+
pub anchor: DefiningAnchor,
103+
pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
104+
}
105+
106+
/// Additional constraints returned on success.
107+
#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
108+
pub struct PredefinedOpaquesData<'tcx> {
109+
pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
110+
}
111+
112+
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
113+
pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>);
114+
115+
impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
116+
type Target = PredefinedOpaquesData<'tcx>;
117+
118+
fn deref(&self) -> &Self::Target {
119+
&self.0
120+
}
121+
}
122+
123+
pub type CanonicalInput<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, QueryInput<'tcx, T>>;
100124

101125
pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
102126

@@ -165,3 +189,40 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
165189
ControlFlow::Continue(())
166190
}
167191
}
192+
193+
// FIXME: Having to clone `region_constraints` for folding feels bad and
194+
// probably isn't great wrt performance.
195+
//
196+
// Not sure how to fix this, maybe we should also intern `opaque_types` and
197+
// `region_constraints` here or something.
198+
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
199+
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
200+
self,
201+
folder: &mut F,
202+
) -> Result<Self, F::Error> {
203+
Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body(
204+
PredefinedOpaquesData {
205+
opaque_types: self
206+
.opaque_types
207+
.iter()
208+
.map(|opaque| opaque.try_fold_with(folder))
209+
.collect::<Result<_, F::Error>>()?,
210+
},
211+
))
212+
}
213+
214+
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
215+
TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData {
216+
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
217+
})
218+
}
219+
}
220+
221+
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
222+
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
223+
&self,
224+
visitor: &mut V,
225+
) -> std::ops::ControlFlow<V::BreakTy> {
226+
self.opaque_types.visit_with(visitor)
227+
}
228+
}

compiler/rustc_middle/src/ty/context.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use crate::query::{IntoQueryParam, TyCtxtAt};
2121
use crate::thir::Thir;
2222
use crate::traits;
2323
use crate::traits::solve;
24-
use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData};
24+
use crate::traits::solve::{
25+
ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
26+
};
2527
use crate::ty::{
2628
self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid,
2729
GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
@@ -140,6 +142,7 @@ pub struct CtxtInterners<'tcx> {
140142
layout: InternedSet<'tcx, LayoutS>,
141143
adt_def: InternedSet<'tcx, AdtDefData>,
142144
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
145+
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
143146
fields: InternedSet<'tcx, List<FieldIdx>>,
144147
}
145148

@@ -164,6 +167,7 @@ impl<'tcx> CtxtInterners<'tcx> {
164167
layout: Default::default(),
165168
adt_def: Default::default(),
166169
external_constraints: Default::default(),
170+
predefined_opaques_in_body: Default::default(),
167171
fields: Default::default(),
168172
}
169173
}
@@ -1520,6 +1524,8 @@ direct_interners! {
15201524
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
15211525
external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>):
15221526
ExternalConstraints -> ExternalConstraints<'tcx>,
1527+
predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>):
1528+
PredefinedOpaques -> PredefinedOpaques<'tcx>,
15231529
}
15241530

15251531
macro_rules! slice_interners {

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
333333
candidates: &mut Vec<Candidate<'tcx>>,
334334
) {
335335
let tcx = self.tcx();
336-
// FIXME: We also have to normalize opaque types, not sure where to best fit that in.
337-
let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
336+
let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else {
338337
return
339338
};
340339

@@ -356,8 +355,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
356355
}),
357356
);
358357
ecx.add_goal(normalizes_to_goal);
359-
let _ = ecx.try_evaluate_added_goals()?;
358+
let _ = ecx.try_evaluate_added_goals().inspect_err(|_| {
359+
debug!("self type normalization failed");
360+
})?;
360361
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
362+
debug!(?normalized_ty, "self type normalized");
361363
// NOTE: Alternatively we could call `evaluate_goal` here and only
362364
// have a `Normalized` candidate. This doesn't work as long as we
363365
// use `CandidateSource` in winnowing.

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use rustc_infer::infer::{
99
use rustc_infer::traits::query::NoSolution;
1010
use rustc_infer::traits::ObligationCause;
1111
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
12-
use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
12+
use rustc_middle::traits::solve::{
13+
CanonicalInput, Certainty, MaybeCause, PredefinedOpaques, PredefinedOpaquesData, QueryResult,
14+
};
15+
use rustc_middle::traits::DefiningAnchor;
1316
use rustc_middle::ty::{
1417
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
1518
TypeVisitor,
@@ -44,6 +47,9 @@ pub struct EvalCtxt<'a, 'tcx> {
4447
infcx: &'a InferCtxt<'tcx>,
4548

4649
pub(super) var_values: CanonicalVarValues<'tcx>,
50+
51+
predefined_opaques_in_body: PredefinedOpaques<'tcx>,
52+
4753
/// The highest universe index nameable by the caller.
4854
///
4955
/// When we enter a new binder inside of the query we create new universes
@@ -126,6 +132,11 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
126132
let mut ecx = EvalCtxt {
127133
search_graph: &mut search_graph,
128134
infcx: self,
135+
// Only relevant when canonicalizing the response,
136+
// which we don't do within this evaluation context.
137+
predefined_opaques_in_body: self
138+
.tcx
139+
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
129140
// Only relevant when canonicalizing the response.
130141
max_input_universe: ty::UniverseIndex::ROOT,
131142
var_values: CanonicalVarValues::dummy(),
@@ -162,29 +173,59 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
162173
fn evaluate_canonical_goal(
163174
tcx: TyCtxt<'tcx>,
164175
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
165-
canonical_goal: CanonicalGoal<'tcx>,
176+
canonical_input: CanonicalInput<'tcx>,
166177
) -> QueryResult<'tcx> {
167178
// Deal with overflow, caching, and coinduction.
168179
//
169180
// The actual solver logic happens in `ecx.compute_goal`.
170-
search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
181+
search_graph.with_new_goal(tcx, canonical_input, |search_graph| {
171182
let intercrate = match search_graph.solver_mode() {
172183
SolverMode::Normal => false,
173184
SolverMode::Coherence => true,
174185
};
175-
let (ref infcx, goal, var_values) = tcx
186+
let (ref infcx, input, var_values) = tcx
176187
.infer_ctxt()
177188
.intercrate(intercrate)
178-
.build_with_canonical(DUMMY_SP, &canonical_goal);
189+
.with_opaque_type_inference(canonical_input.value.anchor)
190+
.build_with_canonical(DUMMY_SP, &canonical_input);
191+
192+
for &(a, b) in &input.predefined_opaques_in_body.opaque_types {
193+
let InferOk { value: (), obligations } = infcx
194+
.handle_opaque_type(
195+
tcx.mk_opaque(a.def_id.to_def_id(), a.substs),
196+
b,
197+
true,
198+
&ObligationCause::dummy(),
199+
input.goal.param_env,
200+
)
201+
.expect("expected opaque type instantiation to succeed");
202+
// We're only registering opaques already defined by the caller,
203+
// so we're not responsible for proving that they satisfy their
204+
// item bounds, unless we use them in a normalizes-to goal,
205+
// which is handled in `EvalCtxt::unify_existing_opaque_tys`.
206+
let _ = obligations;
207+
}
179208
let mut ecx = EvalCtxt {
180209
infcx,
181210
var_values,
182-
max_input_universe: canonical_goal.max_universe,
211+
predefined_opaques_in_body: input.predefined_opaques_in_body,
212+
max_input_universe: canonical_input.max_universe,
183213
search_graph,
184214
nested_goals: NestedGoals::new(),
185215
tainted: Ok(()),
186216
};
187-
ecx.compute_goal(goal)
217+
218+
let result = ecx.compute_goal(input.goal);
219+
220+
// When creating a query response we clone the opaque type constraints
221+
// instead of taking them. This would cause an ICE here, since we have
222+
// assertions against dropping an `InferCtxt` without taking opaques.
223+
// FIXME: Once we remove support for the old impl we can remove this.
224+
if input.anchor != DefiningAnchor::Error {
225+
let _ = infcx.take_opaque_types();
226+
}
227+
228+
result
188229
})
189230
}
190231

@@ -199,7 +240,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
199240
let canonical_response =
200241
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
201242

202-
let has_changed = !canonical_response.value.var_values.is_identity();
243+
let has_changed = !canonical_response.value.var_values.is_identity()
244+
|| !canonical_response.value.external_constraints.opaque_types.is_empty();
203245
let (certainty, nested_goals) = self.instantiate_and_apply_query_response(
204246
goal.param_env,
205247
orig_values,
@@ -418,6 +460,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
418460
let mut ecx = EvalCtxt {
419461
infcx: self.infcx,
420462
var_values: self.var_values,
463+
predefined_opaques_in_body: self.predefined_opaques_in_body,
421464
max_input_universe: self.max_input_universe,
422465
search_graph: self.search_graph,
423466
nested_goals: self.nested_goals.clone(),
@@ -682,4 +725,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
682725
| rustc_transmute::Answer::IfAny(_) => Err(NoSolution),
683726
}
684727
}
728+
729+
pub(super) fn handle_opaque_ty(
730+
&mut self,
731+
a: Ty<'tcx>,
732+
b: Ty<'tcx>,
733+
param_env: ty::ParamEnv<'tcx>,
734+
) -> Result<(), NoSolution> {
735+
let InferOk { value: (), obligations } =
736+
self.infcx.handle_opaque_type(a, b, true, &ObligationCause::dummy(), param_env)?;
737+
self.add_goals(obligations.into_iter().map(|obligation| obligation.into()));
738+
Ok(())
739+
}
685740
}

0 commit comments

Comments
 (0)