Skip to content

Commit aff74a1

Browse files
authored
Rollup merge of #93810 - matthewjasper:chalk-and-canonical-universes, r=jackh726
Improve chalk integration - Support subtype bounds in chalk lowering - Handle universes in canonicalization - Handle type parameters in chalk responses - Use `chalk_ir::LifetimeData::Empty` for `ty::ReEmpty` - Remove `ignore-compare-mode-chalk` for tests that no longer hang (they may still fail or ICE) This is enough to get a hello world program to compile with `-Zchalk` now. Some of the remaining issues that are needed to get Chalk integration working on larger programs are: - rust-lang/chalk#234 - rust-lang/chalk#548 - rust-lang/chalk#734 - Generators are handled differently in chalk and rustc r? `@jackh726`
2 parents 953c4dc + 030c508 commit aff74a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+362
-219
lines changed

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

+158-17
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
4949
Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
5050
}
5151

52+
/// Like [Self::canonicalize_query], but preserves distinct universes. For
53+
/// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
54+
/// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
55+
/// in `U2`.
56+
///
57+
/// This is used for Chalk integration.
58+
pub fn canonicalize_query_preserving_universes<V>(
59+
&self,
60+
value: V,
61+
query_state: &mut OriginalQueryValues<'tcx>,
62+
) -> Canonicalized<'tcx, V>
63+
where
64+
V: TypeFoldable<'tcx>,
65+
{
66+
self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
67+
68+
Canonicalizer::canonicalize(
69+
value,
70+
self,
71+
self.tcx,
72+
&CanonicalizeAllFreeRegionsPreservingUniverses,
73+
query_state,
74+
)
75+
}
76+
5277
/// Canonicalizes a query *response* `V`. When we canonicalize a
5378
/// query response, we only canonicalize unbound inference
5479
/// variables, and we leave other free regions alone. So,
@@ -133,19 +158,22 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
133158
/// maximally general query. But if we are canonicalizing a *query
134159
/// response*, then we don't typically replace free regions, as they
135160
/// must have been introduced from other parts of the system.
136-
trait CanonicalizeRegionMode {
161+
trait CanonicalizeMode {
137162
fn canonicalize_free_region<'tcx>(
138163
&self,
139164
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
140165
r: ty::Region<'tcx>,
141166
) -> ty::Region<'tcx>;
142167

143168
fn any(&self) -> bool;
169+
170+
// Do we preserve universe of variables.
171+
fn preserve_universes(&self) -> bool;
144172
}
145173

146174
struct CanonicalizeQueryResponse;
147175

148-
impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
176+
impl CanonicalizeMode for CanonicalizeQueryResponse {
149177
fn canonicalize_free_region<'tcx>(
150178
&self,
151179
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -198,11 +226,15 @@ impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
198226
fn any(&self) -> bool {
199227
false
200228
}
229+
230+
fn preserve_universes(&self) -> bool {
231+
true
232+
}
201233
}
202234

203235
struct CanonicalizeUserTypeAnnotation;
204236

205-
impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
237+
impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
206238
fn canonicalize_free_region<'tcx>(
207239
&self,
208240
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -221,11 +253,15 @@ impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
221253
fn any(&self) -> bool {
222254
false
223255
}
256+
257+
fn preserve_universes(&self) -> bool {
258+
false
259+
}
224260
}
225261

226262
struct CanonicalizeAllFreeRegions;
227263

228-
impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
264+
impl CanonicalizeMode for CanonicalizeAllFreeRegions {
229265
fn canonicalize_free_region<'tcx>(
230266
&self,
231267
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -237,11 +273,39 @@ impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
237273
fn any(&self) -> bool {
238274
true
239275
}
276+
277+
fn preserve_universes(&self) -> bool {
278+
false
279+
}
280+
}
281+
282+
struct CanonicalizeAllFreeRegionsPreservingUniverses;
283+
284+
impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
285+
fn canonicalize_free_region<'tcx>(
286+
&self,
287+
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
288+
r: ty::Region<'tcx>,
289+
) -> ty::Region<'tcx> {
290+
let universe = canonicalizer.infcx.universe_of_region(r);
291+
canonicalizer.canonical_var_for_region(
292+
CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
293+
r,
294+
)
295+
}
296+
297+
fn any(&self) -> bool {
298+
true
299+
}
300+
301+
fn preserve_universes(&self) -> bool {
302+
true
303+
}
240304
}
241305

242306
struct CanonicalizeFreeRegionsOtherThanStatic;
243307

244-
impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
308+
impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
245309
fn canonicalize_free_region<'tcx>(
246310
&self,
247311
canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -257,6 +321,10 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
257321
fn any(&self) -> bool {
258322
true
259323
}
324+
325+
fn preserve_universes(&self) -> bool {
326+
false
327+
}
260328
}
261329

262330
struct Canonicalizer<'cx, 'tcx> {
@@ -267,7 +335,7 @@ struct Canonicalizer<'cx, 'tcx> {
267335
// Note that indices is only used once `var_values` is big enough to be
268336
// heap-allocated.
269337
indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
270-
canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
338+
canonicalize_mode: &'cx dyn CanonicalizeMode,
271339
needs_canonical_flags: TypeFlags,
272340

273341
binder_index: ty::DebruijnIndex,
@@ -311,15 +379,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
311379
vid, r
312380
);
313381
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
314-
self.canonicalize_region_mode.canonicalize_free_region(self, r)
382+
self.canonicalize_mode.canonicalize_free_region(self, r)
315383
}
316384

317385
ty::ReStatic
318386
| ty::ReEarlyBound(..)
319387
| ty::ReFree(_)
320388
| ty::ReEmpty(_)
321389
| ty::RePlaceholder(..)
322-
| ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
390+
| ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
323391
}
324392
}
325393

@@ -337,8 +405,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
337405
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
338406
// result.
339407
Err(mut ui) => {
340-
// FIXME: perf problem described in #55921.
341-
ui = ty::UniverseIndex::ROOT;
408+
if !self.canonicalize_mode.preserve_universes() {
409+
// FIXME: perf problem described in #55921.
410+
ui = ty::UniverseIndex::ROOT;
411+
}
342412
self.canonicalize_ty_var(
343413
CanonicalVarInfo {
344414
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
@@ -422,8 +492,10 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
422492
// `ConstVar(vid)` is unresolved, track its universe index in the
423493
// canonicalized result
424494
Err(mut ui) => {
425-
// FIXME: perf problem described in #55921.
426-
ui = ty::UniverseIndex::ROOT;
495+
if !self.canonicalize_mode.preserve_universes() {
496+
// FIXME: perf problem described in #55921.
497+
ui = ty::UniverseIndex::ROOT;
498+
}
427499
return self.canonicalize_const_var(
428500
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
429501
ct,
@@ -462,7 +534,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
462534
value: V,
463535
infcx: &InferCtxt<'_, 'tcx>,
464536
tcx: TyCtxt<'tcx>,
465-
canonicalize_region_mode: &dyn CanonicalizeRegionMode,
537+
canonicalize_region_mode: &dyn CanonicalizeMode,
466538
query_state: &mut OriginalQueryValues<'tcx>,
467539
) -> Canonicalized<'tcx, V>
468540
where
@@ -493,7 +565,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
493565
let mut canonicalizer = Canonicalizer {
494566
infcx,
495567
tcx,
496-
canonicalize_region_mode,
568+
canonicalize_mode: canonicalize_region_mode,
497569
needs_canonical_flags,
498570
variables: SmallVec::new(),
499571
query_state,
@@ -504,10 +576,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
504576

505577
// Once we have canonicalized `out_value`, it should not
506578
// contain anything that ties it to this inference context
507-
// anymore, so it should live in the global arena.
508-
debug_assert!(!out_value.needs_infer());
579+
// anymore.
580+
debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
509581

510-
let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables);
582+
let canonical_variables =
583+
tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
511584

512585
let max_universe = canonical_variables
513586
.iter()
@@ -527,6 +600,19 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
527600

528601
let var_values = &mut query_state.var_values;
529602

603+
let universe = info.universe();
604+
if universe != ty::UniverseIndex::ROOT {
605+
assert!(self.canonicalize_mode.preserve_universes());
606+
607+
// Insert universe into the universe map. To preserve the order of the
608+
// universes in the value being canonicalized, we don't update the
609+
// universe in `info` until we have finished canonicalizing.
610+
match query_state.universe_map.binary_search(&universe) {
611+
Err(idx) => query_state.universe_map.insert(idx, universe),
612+
Ok(_) => {}
613+
}
614+
}
615+
530616
// This code is hot. `variables` and `var_values` are usually small
531617
// (fewer than 8 elements ~95% of the time). They are SmallVec's to
532618
// avoid allocations in those cases. We also don't use `indices` to
@@ -569,6 +655,61 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
569655
}
570656
}
571657

658+
/// Replaces the universe indexes used in `var_values` with their index in
659+
/// `query_state.universe_map`. This minimizes the maximum universe used in
660+
/// the canonicalized value.
661+
fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
662+
if self.query_state.universe_map.len() == 1 {
663+
return self.variables;
664+
}
665+
666+
let reverse_universe_map: FxHashMap<ty::UniverseIndex, ty::UniverseIndex> = self
667+
.query_state
668+
.universe_map
669+
.iter()
670+
.enumerate()
671+
.map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx)))
672+
.collect();
673+
674+
self.variables
675+
.iter()
676+
.map(|v| CanonicalVarInfo {
677+
kind: match v.kind {
678+
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
679+
return *v;
680+
}
681+
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
682+
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
683+
}
684+
CanonicalVarKind::Region(u) => {
685+
CanonicalVarKind::Region(reverse_universe_map[&u])
686+
}
687+
CanonicalVarKind::Const(u, t) => {
688+
CanonicalVarKind::Const(reverse_universe_map[&u], t)
689+
}
690+
CanonicalVarKind::PlaceholderTy(placeholder) => {
691+
CanonicalVarKind::PlaceholderTy(ty::Placeholder {
692+
universe: reverse_universe_map[&placeholder.universe],
693+
..placeholder
694+
})
695+
}
696+
CanonicalVarKind::PlaceholderRegion(placeholder) => {
697+
CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
698+
universe: reverse_universe_map[&placeholder.universe],
699+
..placeholder
700+
})
701+
}
702+
CanonicalVarKind::PlaceholderConst(placeholder) => {
703+
CanonicalVarKind::PlaceholderConst(ty::Placeholder {
704+
universe: reverse_universe_map[&placeholder.universe],
705+
..placeholder
706+
})
707+
}
708+
},
709+
})
710+
.collect()
711+
}
712+
572713
/// Shorthand helper that creates a canonical region variable for
573714
/// `r` (always in the root universe). The reason that we always
574715
/// put these variables into the root universe is because this

compiler/rustc_middle/src/infer/canonical.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ pub struct CanonicalVarValues<'tcx> {
6464
/// result.
6565
#[derive(Clone, Debug)]
6666
pub struct OriginalQueryValues<'tcx> {
67-
/// Map from the universes that appear in the query to the
68-
/// universes in the caller context. For the time being, we only
69-
/// ever put ROOT values into the query, so this map is very
67+
/// Map from the universes that appear in the query to the universes in the
68+
/// caller context. For all queries except `evaluate_goal` (used by Chalk),
69+
/// we only ever put ROOT values into the query, so this map is very
7070
/// simple.
7171
pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
7272

compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::traits::{
88
PredicateObligation, SelectionError, TraitEngine,
99
};
1010
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
11-
use rustc_middle::ty::{self, Ty};
11+
use rustc_middle::ty::{self, Ty, TypeFoldable};
1212

1313
pub struct FulfillmentContext<'tcx> {
1414
obligations: FxIndexSet<PredicateObligation<'tcx>>,
@@ -91,7 +91,12 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
9191
let environment = obligation.param_env.caller_bounds();
9292
let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
9393
let mut orig_values = OriginalQueryValues::default();
94-
let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
94+
if goal.references_error() {
95+
continue;
96+
}
97+
98+
let canonical_goal =
99+
infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
95100

96101
match infcx.tcx.evaluate_goal(canonical_goal) {
97102
Ok(response) => {

0 commit comments

Comments
 (0)