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 fcab000

Browse files
committed
optimize CanonicalVarValues::instantiate
1 parent 933c883 commit fcab000

File tree

9 files changed

+63
-56
lines changed

9 files changed

+63
-56
lines changed

‎Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4754,6 +4754,7 @@ dependencies = [
47544754
name = "rustc_type_ir"
47554755
version = "0.0.0"
47564756
dependencies = [
4757+
"arrayvec",
47574758
"bitflags",
47584759
"derive-where",
47594760
"ena",

‎compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -403,15 +403,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
403403
// special handling for this "trivial case" is a good idea.
404404

405405
let infcx = &self.infcx;
406-
let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) =
406+
let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) =
407407
infcx.instantiate_canonical(span, &query_input.canonical);
408408
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
409409
MethodAutoderefStepsResult {
410410
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
411-
self_ty: self.make_query_response_ignoring_pending_obligations(
412-
canonical_inference_vars,
413-
self_ty,
414-
),
411+
self_ty: self
412+
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
415413
autoderefs: 0,
416414
from_unsafe_deref: false,
417415
unsize: false,

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

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
pub use instantiate::CanonicalExt;
2525
use rustc_index::IndexVec;
2626
pub use rustc_middle::infer::canonical::*;
27-
use rustc_middle::ty::{self, GenericArg, List,Ty, TyCtxt, TypeFoldable};
27+
use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable};
2828
use rustc_span::Span;
2929

3030
use crate::infer::{InferCtxt, RegionVariableOrigin};
@@ -67,29 +67,12 @@ impl<'tcx> InferCtxt<'tcx> {
6767
.chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
6868
.collect();
6969

70-
let canonical_inference_vars =
71-
self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
72-
let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
73-
(result, canonical_inference_vars)
74-
}
75-
76-
/// Given the "infos" about the canonical variables from some
77-
/// canonical, creates fresh variables with the same
78-
/// characteristics (see `instantiate_canonical_var` for
79-
/// details). You can then use `instantiate` to instantiate the
80-
/// canonical variable with these inference variables.
81-
fn instantiate_canonical_vars(
82-
&self,
83-
span: Span,
84-
variables: &List<CanonicalVarKind<'tcx>>,
85-
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
86-
) -> CanonicalVarValues<'tcx> {
87-
let mut var_values = Vec::with_capacity(variables.len());
88-
for info in variables.iter() {
89-
let value = self.instantiate_canonical_var(span, info, &var_values, &universe_map);
90-
var_values.push(value);
91-
}
92-
CanonicalVarValues { var_values: self.tcx.mk_args(&var_values) }
70+
let var_values =
71+
CanonicalVarValues::instantiate(self.tcx, &canonical.variables, |var_values, info| {
72+
self.instantiate_canonical_var(span, info, &var_values, |ui| universes[ui])
73+
});
74+
let result = canonical.instantiate(self.tcx, &var_values);
75+
(result, var_values)
9376
}
9477

9578
/// Given the "info" about a canonical variable, creates a fresh

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

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -453,16 +453,17 @@ impl<'tcx> InferCtxt<'tcx> {
453453
// Create result arguments: if we found a value for a
454454
// given variable in the loop above, use that. Otherwise, use
455455
// a fresh inference variable.
456-
let mut var_values = Vec::with_capacity(query_response.variables.len());
457-
for (index, kind) in query_response.variables.iter().enumerate() {
458-
let value = if kind.universe() != ty::UniverseIndex::ROOT {
456+
let tcx = self.tcx;
457+
let variables = query_response.variables;
458+
let var_values = CanonicalVarValues::instantiate(tcx, variables, |var_values, kind| {
459+
if kind.universe() != ty::UniverseIndex::ROOT {
459460
// A variable from inside a binder of the query. While ideally these shouldn't
460461
// exist at all, we have to deal with them for now.
461462
self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
462463
universe_map[u.as_usize()]
463464
})
464465
} else if kind.is_existential() {
465-
match opt_values[BoundVar::new(index)] {
466+
match opt_values[BoundVar::new(var_values.len())] {
466467
Some(k) => k,
467468
None => self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
468469
universe_map[u.as_usize()]
@@ -471,20 +472,17 @@ impl<'tcx> InferCtxt<'tcx> {
471472
} else {
472473
// For placeholders which were already part of the input, we simply map this
473474
// universal bound variable back the placeholder of the input.
474-
opt_values[BoundVar::new(index)]
475+
opt_values[BoundVar::new(var_values.len())]
475476
.expect("expected placeholder to be unified with itself during response")
476-
};
477-
var_values.push(value);
478-
}
479-
480-
let result_args = CanonicalVarValues { var_values: self.tcx.mk_args(&var_values) };
477+
}
478+
});
481479

482480
let mut obligations = PredicateObligations::new();
483481

484482
// Carry all newly resolved opaque types to the caller's scope
485483
for &(a, b) in &query_response.value.opaque_types {
486-
let a = instantiate_value(self.tcx, &result_args, a);
487-
let b = instantiate_value(self.tcx, &result_args, b);
484+
let a = instantiate_value(self.tcx, &var_values, a);
485+
let b = instantiate_value(self.tcx, &var_values, b);
488486
debug!(?a, ?b, "constrain opaque type");
489487
// We use equate here instead of, for example, just registering the
490488
// opaque type's hidden value directly, because the hidden type may have been an inference
@@ -501,7 +499,7 @@ impl<'tcx> InferCtxt<'tcx> {
501499
);
502500
}
503501

504-
Ok(InferOk { value: result_args, obligations })
502+
Ok(InferOk { value: var_values, obligations })
505503
}
506504

507505
/// Given a "guess" at the values for the canonical variables in

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

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,8 @@ where
369369
}
370370
}
371371
}
372-
373-
let mut var_values = Vec::with_capacity(response.variables.len());
374-
for (index, kind) in response.variables.iter().enumerate() {
375-
let value = if kind.universe() != ty::UniverseIndex::ROOT {
372+
CanonicalVarValues::instantiate(delegate.cx(), response.variables, |var_values, kind| {
373+
if kind.universe() != ty::UniverseIndex::ROOT {
376374
// A variable from inside a binder of the query. While ideally these shouldn't
377375
// exist at all (see the FIXME at the start of this method), we have to deal with
378376
// them for now.
@@ -387,7 +385,7 @@ where
387385
// more placeholders then they should be able to. However the inference variables have
388386
// to "come from somewhere", so by equating them with the original values of the caller
389387
// later on, we pull them down into their correct universe again.
390-
if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
388+
if let Some(v) = opt_values[ty::BoundVar::from_usize(var_values.len())] {
391389
v
392390
} else {
393391
delegate.instantiate_canonical_var(kind, span, &var_values, |_| prev_universe)
@@ -396,11 +394,8 @@ where
396394
// For placeholders which were already part of the input, we simply map this
397395
// universal bound variable back the placeholder of the input.
398396
original_values[kind.expect_placeholder_index()]
399-
};
400-
var_values.push(value)
401-
}
402-
403-
CanonicalVarValues { var_values: delegate.cx().mk_args(&var_values) }
397+
}
398+
})
404399
}
405400

406401
/// Unify the `original_values` with the `var_values` returned by the canonical query..

‎compiler/rustc_trait_selection/src/infer.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,9 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
184184
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
185185
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
186186
{
187-
let (infcx, key, canonical_inference_vars) =
188-
self.build_with_canonical(DUMMY_SP, canonical_key);
187+
let (infcx, key, var_values) = self.build_with_canonical(DUMMY_SP, canonical_key);
189188
let ocx = ObligationCtxt::new(&infcx);
190189
let value = operation(&ocx, key)?;
191-
ocx.make_canonicalized_query_response(canonical_inference_vars, value)
190+
ocx.make_canonicalized_query_response(var_values, value)
192191
}
193192
}

‎compiler/rustc_traits/src/evaluate_obligation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn evaluate_obligation<'tcx>(
1919
) -> Result<EvaluationResult, OverflowError> {
2020
assert!(!tcx.next_trait_solver_globally());
2121
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
22-
let (ref infcx, goal, _canonical_inference_vars) =
22+
let (ref infcx, goal, _var_values) =
2323
tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal);
2424
debug!("evaluate_obligation: goal={:#?}", goal);
2525
let ParamEnvAnd { param_env, value: predicate } = goal;

‎compiler/rustc_type_ir/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2024"
55

66
[dependencies]
77
# tidy-alphabetical-start
8+
arrayvec = { version = "0.7", default-features = false }
89
bitflags.workspace = true
910
derive-where = "1.2.7"
1011
ena = "0.14.3"

‎compiler/rustc_type_ir/src/canonical.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::fmt;
22
use std::ops::Index;
33

4+
use arrayvec::ArrayVec;
45
use derive_where::derive_where;
56
#[cfg(feature = "nightly")]
67
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
@@ -306,6 +307,37 @@ impl<I: Interner> CanonicalVarValues<I> {
306307
CanonicalVarValues { var_values: Default::default() }
307308
}
308309

310+
pub fn instantiate(
311+
cx: I,
312+
variables: I::CanonicalVarKinds,
313+
mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg,
314+
) -> CanonicalVarValues<I> {
315+
// Instantiating `CanonicalVarValues` is really hot, but limited to less than
316+
// 4 most of the time. Avoid creating a `Vec` here.
317+
if variables.len() <= 4 {
318+
let mut var_values = ArrayVec::<_, 4>::new();
319+
for info in variables.iter() {
320+
var_values.push(f(&var_values, info));
321+
}
322+
CanonicalVarValues { var_values: cx.mk_args(&var_values) }
323+
} else {
324+
CanonicalVarValues::instantiate_cold(cx, variables, f)
325+
}
326+
}
327+
328+
#[cold]
329+
fn instantiate_cold(
330+
cx: I,
331+
variables: I::CanonicalVarKinds,
332+
mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg,
333+
) -> CanonicalVarValues<I> {
334+
let mut var_values = Vec::with_capacity(variables.len());
335+
for info in variables.iter() {
336+
var_values.push(f(&var_values, info));
337+
}
338+
CanonicalVarValues { var_values: cx.mk_args(&var_values) }
339+
}
340+
309341
#[inline]
310342
pub fn len(&self) -> usize {
311343
self.var_values.len()

0 commit comments

Comments
(0)

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