Skip to content

Commit 365c0e1

Browse files
committed
Auto merge of #155443 - jdonszelmann:canonical, r=lcnr
Improve caching by introducing `TypingMode::ErasedNotCoherence` r? @lcnr This introduces `TypingMode::ErasedNotCoherence`. Most typing modes contain a list of opaque types, which are quite often unused during canonicalization. With this change, any time we try canonicalization, we replace whichever typing mode we're currently in with `ErasedNotcoherence`, attempt to canonicalize, and if that fails *retry* in the original typing mode. If erased mode succeeds, this is beneficial because that way the opaque types don't end up in the cache key, allowing more cache reuse. This seems to have a small (0.5%) slowdown on most programs, but a dramatic (>60%) speedup in specific cases like the rustc-perf `wg-grammar` benchmark. Some more improvements are expected with "eager normalization", which is work that's under way right now.
2 parents ba1a955 + 36b6eeb commit 365c0e1

42 files changed

Lines changed: 1067 additions & 257 deletions

File tree

Some content is hidden

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

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
374374
assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
375375

376376
if cfg!(debug_assertions) {
377-
match key.typing_env.typing_mode() {
377+
match key.typing_env.typing_mode().assert_not_erased() {
378378
ty::TypingMode::PostAnalysis => {}
379379
ty::TypingMode::Coherence
380380
| ty::TypingMode::Analysis { .. }

compiler/rustc_const_eval/src/const_eval/valtrees.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
237237
cid: GlobalId<'tcx>,
238238
) -> EvalToValTreeResult<'tcx> {
239239
if cfg!(debug_assertions) {
240-
match typing_env.typing_mode() {
240+
match typing_env.typing_mode().assert_not_erased() {
241241
ty::TypingMode::PostAnalysis => {}
242242
ty::TypingMode::Coherence
243243
| ty::TypingMode::Analysis { .. }

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
243243
// types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
244244
// already been revealed, so we'd be able to at least partially observe the hidden types anyways.
245245
if cfg!(debug_assertions) {
246-
match typing_env.typing_mode() {
246+
match typing_env.typing_mode().assert_not_erased() {
247247
TypingMode::PostAnalysis => {}
248248
TypingMode::Coherence
249249
| TypingMode::Analysis { .. }

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum CallStep<'tcx> {
6262
}
6363

6464
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
65+
#[tracing::instrument(skip(self))]
6566
pub(crate) fn check_expr_call(
6667
&self,
6768
call_expr: &'tcx hir::Expr<'tcx>,

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use rustc_hir_analysis::hir_ty_lowering::{
1717
};
1818
use rustc_infer::infer::{self, RegionVariableOrigin};
1919
use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
20-
use rustc_middle::ty::{self, Const, Flags, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
20+
use rustc_middle::ty::{
21+
self, CantBeErased, Const, Flags, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized,
22+
};
2123
use rustc_session::Session;
2224
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span};
2325
use rustc_trait_selection::error_reporting::TypeErrCtxt;
@@ -161,6 +163,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161163
}
162164
}
163165

166+
pub(crate) fn typing_mode(&self) -> TypingMode<'tcx, CantBeErased> {
167+
// `FnCtxt` is never constructed in the trait solver, so we can safely use
168+
// `assert_not_erased`.
169+
self.infcx.typing_mode_raw().assert_not_erased()
170+
}
171+
164172
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'a> {
165173
self.root_ctxt.infcx.dcx()
166174
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> {
7272
query_state,
7373
)
7474
.unchecked_map(|(param_env, value)| param_env.and(value));
75-
CanonicalQueryInput { canonical, typing_mode: TypingModeEqWrapper(self.typing_mode()) }
75+
CanonicalQueryInput { canonical, typing_mode: TypingModeEqWrapper(self.typing_mode_raw()) }
7676
}
7777

7878
/// Canonicalizes a query *response* `V`. When we canonicalize a

compiler/rustc_infer/src/infer/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
2626
self.disable_trait_solver_fast_paths()
2727
}
2828

29-
fn typing_mode(&self) -> ty::TypingMode<'tcx> {
30-
self.typing_mode()
29+
fn typing_mode_raw(&self) -> ty::TypingMode<'tcx> {
30+
self.typing_mode_raw()
3131
}
3232

3333
fn universe(&self) -> ty::UniverseIndex {

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use rustc_middle::ty::{
3434
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
3535
};
3636
use rustc_span::{DUMMY_SP, Span, Symbol};
37+
use rustc_type_ir::MayBeErased;
3738
use snapshot::undo_log::InferCtxtUndoLogs;
3839
use tracing::{debug, instrument};
3940
use type_variable::TypeVariableOrigin;
@@ -640,14 +641,34 @@ impl<'tcx> InferCtxt<'tcx> {
640641
self.next_trait_solver
641642
}
642643

644+
/// This method is deliberately called `..._raw`,
645+
/// since the output may possibly include [`TypingMode::ErasedNotCoherence`](TypingMode::ErasedNotCoherence).
646+
/// `ErasedNotCoherence` is an implementation detail of the next trait solver, see its docs for
647+
/// more information.
648+
///
649+
/// `InferCtxt` has two uses: the trait solver calls some methods on it, because the `InferCtxt`
650+
/// works as a kind of store for for example type unification information.
651+
/// `InferCtxt` is also often used outside the trait solver during typeck.
652+
/// There, we don't care about the `ErasedNotCoherence` case and should never encounter it.
653+
/// To make sure these two uses are never confused, we want to statically encode this information.
654+
///
655+
/// The `FnCtxt`, for example, is only used in the outside-trait-solver case. It has a non-raw
656+
/// version of the `typing_mode` method available that asserts `ErasedNotCoherence` is
657+
/// impossible, and returns a `TypingMode` where `ErasedNotCoherence` is made uninhabited using
658+
/// the [`CantBeErased`](rustc_type_ir::CantBeErased) enum. That way you don't even have to
659+
/// match on the variant and can safely ignore it.
660+
///
661+
/// Prefer non-raw apis if available. e.g.,
662+
/// - On the `FnCtxt`
663+
/// - on the `SelectionCtxt`
643664
#[inline(always)]
644-
pub fn disable_trait_solver_fast_paths(&self) -> bool {
645-
self.tcx.disable_trait_solver_fast_paths()
665+
pub fn typing_mode_raw(&self) -> TypingMode<'tcx> {
666+
self.typing_mode
646667
}
647668

648669
#[inline(always)]
649-
pub fn typing_mode(&self) -> TypingMode<'tcx> {
650-
self.typing_mode
670+
pub fn disable_trait_solver_fast_paths(&self) -> bool {
671+
self.tcx.disable_trait_solver_fast_paths()
651672
}
652673

653674
/// Returns the origin of the type variable identified by `vid`.
@@ -1071,7 +1092,7 @@ impl<'tcx> InferCtxt<'tcx> {
10711092
#[inline(always)]
10721093
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
10731094
debug_assert!(!self.next_trait_solver());
1074-
match self.typing_mode() {
1095+
match self.typing_mode_raw().assert_not_erased() {
10751096
TypingMode::Analysis {
10761097
defining_opaque_types_and_generators: defining_opaque_types,
10771098
}
@@ -1402,7 +1423,7 @@ impl<'tcx> InferCtxt<'tcx> {
14021423
/// which contains the necessary information to use the trait system without
14031424
/// using canonicalization or carrying this inference context around.
14041425
pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
1405-
let typing_mode = match self.typing_mode() {
1426+
let typing_mode = match self.typing_mode_raw() {
14061427
// FIXME(#132279): This erases the `defining_opaque_types` as it isn't possible
14071428
// to handle them without proper canonicalization. This means we may cause cycle
14081429
// errors and fail to reveal opaques while inside of bodies. We should rename this
@@ -1414,6 +1435,7 @@ impl<'tcx> InferCtxt<'tcx> {
14141435
mode @ (ty::TypingMode::Coherence
14151436
| ty::TypingMode::PostBorrowckAnalysis { .. }
14161437
| ty::TypingMode::PostAnalysis) => mode,
1438+
ty::TypingMode::ErasedNotCoherence(MayBeErased) => unreachable!(),
14171439
};
14181440
ty::TypingEnv::new(param_env, typing_mode)
14191441
}

compiler/rustc_infer/src/infer/opaque_types/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ impl<'tcx> InferCtxt<'tcx> {
8989
if def_id.is_local() =>
9090
{
9191
let def_id = def_id.expect_local();
92-
if self.typing_mode().is_coherence() {
92+
if self.typing_mode_raw().is_coherence() {
9393
// See comment on `insert_hidden_type` for why this is sufficient in coherence
9494
return Some(self.register_hidden_type(
9595
OpaqueTypeKey { def_id, args },
@@ -229,7 +229,9 @@ impl<'tcx> InferCtxt<'tcx> {
229229
// value being folded. In simple cases like `-> impl Foo`,
230230
// these are the same span, but not in cases like `-> (impl
231231
// Foo, impl Bar)`.
232-
match self.typing_mode() {
232+
//
233+
// Note: we don't use this function in the next solver so we can safely call `assert_not_erased`
234+
match self.typing_mode_raw().assert_not_erased() {
233235
ty::TypingMode::Coherence => {
234236
// During intercrate we do not define opaque types but instead always
235237
// force ambiguity unless the hidden type is known to not implement

compiler/rustc_infer/src/infer/relate/generalize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
604604
//
605605
// cc trait-system-refactor-initiative#108
606606
if self.infcx.next_trait_solver()
607-
&& !self.infcx.typing_mode().is_coherence()
607+
&& !self.infcx.typing_mode_raw().is_coherence()
608608
&& self.in_alias
609609
{
610610
inner.type_variables().equate(vid, new_var_id);
@@ -736,7 +736,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
736736
// See the comment for type inference variables
737737
// for more details.
738738
if self.infcx.next_trait_solver()
739-
&& !self.infcx.typing_mode().is_coherence()
739+
&& !self.infcx.typing_mode_raw().is_coherence()
740740
&& self.in_alias
741741
{
742742
variable_table.union(vid, new_var_id);

0 commit comments

Comments
 (0)