diff --git a/Cargo.lock b/Cargo.lock index 2d16515500878..f426607920f4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4526,6 +4526,7 @@ dependencies = [ "rustc_macros", "rustc_type_ir", "rustc_type_ir_macros", + "thin-vec", "tracing", ] diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index c424ca71c0801..c1652b08325c0 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -96,3 +96,14 @@ impl<'tcx> TypeVisitable> for ExternalConstraints<'tcx> { normalization_nested_goals.visit_with(visitor) } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use rustc_data_structures::static_assert_size; + + use super::*; + // tidy-alphabetical-start + static_assert_size!(GoalStalledOn<'_>, 56); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 05bcabad02f9b..114285a472644 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -11,6 +11,7 @@ rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } +thin-vec = "0.2.19" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 0ff7248ff4246..20402649ceabd 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -6,6 +6,7 @@ use rustc_type_ir::{ Interner, PlaceholderConst, PlaceholderType, Region, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +use thin_vec::ThinVec; use crate::delegate::SolverDelegate; @@ -65,7 +66,7 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate, I: Interner canonicalize_mode: CanonicalizeMode, // Mutable fields. - variables: Vec, + variables: ThinVec, var_kinds: Vec>, variable_lookup_table: HashMap, /// Maps each `sub_unification_table_root_var` to the index of the first @@ -91,10 +92,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { delegate, canonicalize_mode: CanonicalizeMode::Response { max_input_universe }, - variables: Vec::new(), + variables: Default::default(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), - var_kinds: Vec::new(), + var_kinds: Default::default(), cache: Default::default(), }; @@ -113,10 +114,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { fn canonicalize_param_env( delegate: &'a D, param_env: I::ParamEnv, - ) -> (I::ParamEnv, Vec, Vec>, HashMap) - { + ) -> ( + I::ParamEnv, + ThinVec, + Vec>, + HashMap, + ) { if !param_env.has_type_flags(NEEDS_CANONICAL) { - return (param_env, Vec::new(), Vec::new(), Default::default()); + return (param_env, ThinVec::new(), Vec::new(), Default::default()); } // Check whether we can use the global cache for this param_env. As we only use @@ -134,10 +139,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { delegate, canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), - variables: Vec::new(), + variables: Default::default(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), - var_kinds: Vec::new(), + var_kinds: Default::default(), cache: Default::default(), }; @@ -159,7 +164,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // FIXME(nnethercote): for reasons I don't understand, this `new`+`extend` // combination is faster than `variables.clone()`, because it somehow avoids // some allocations. - let mut variables = Vec::new(); + let mut variables = ThinVec::new(); variables.extend(cache_variables.iter().copied()); (param_env, variables, var_kinds.clone(), variable_lookup_table.clone()) }, @@ -169,10 +174,10 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { delegate, canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::ParamEnv), - variables: Vec::new(), + variables: Default::default(), variable_lookup_table: Default::default(), sub_root_lookup_table: Default::default(), - var_kinds: Vec::new(), + var_kinds: Default::default(), cache: Default::default(), }; @@ -198,7 +203,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { pub(super) fn canonicalize_input>( delegate: &'a D, input: QueryInput, - ) -> (Vec, ty::Canonical>) { + ) -> (ThinVec, ty::Canonical>) { // First canonicalize the `param_env` while keeping `'static` let (param_env, variables, var_kinds, variable_lookup_table) = Canonicalizer::canonicalize_param_env(delegate, input.goal.param_env); @@ -280,7 +285,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { ty::BoundVar::from(idx) } - fn finalize(self) -> (ty::UniverseIndex, Vec, I::CanonicalVarKinds) { + fn finalize(self) -> (ty::UniverseIndex, ThinVec, I::CanonicalVarKinds) { let mut var_kinds = self.var_kinds; // See the rustc-dev-guide section about how we deal with universes // during canonicalization in the new solver. diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 941c0b78e464d..1e4e3a90f9c4a 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -21,6 +21,7 @@ use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, Region, TypeFoldable, TypingMode, TypingModeEqWrapper, eager_resolve_vars, }; +use thin_vec::ThinVec; use tracing::instrument; use crate::delegate::SolverDelegate; @@ -57,7 +58,7 @@ pub(super) fn canonicalize_goal( goal: Goal, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], typing_mode: TypingMode, -) -> (Vec, CanonicalInput) +) -> (ThinVec, CanonicalInput) where D: SolverDelegate, I: Interner, @@ -541,7 +542,7 @@ pub fn instantiate_canonical_state( delegate: &D, span: I::Span, param_env: I::ParamEnv, - orig_values: &mut Vec, + orig_values: &mut ThinVec, state: inspect::CanonicalState, ) -> T where diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 2ec0b6fc9e2e8..156dfc4fc1e69 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -19,6 +19,7 @@ use rustc_type_ir::{ OpaqueTypeKey, PredicateKind, Region, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, eager_resolve_vars, }; +use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; use super::has_only_region_constraints; @@ -847,11 +848,11 @@ where &self, canonical_goal: CanonicalInput, certainty: Certainty, - mut stalled_vars: Vec, + mut stalled_vars: ThinVec, previously_succeeded_in_erased: SucceededInErased, ) -> GoalStalledOn { // Remove the canonicalized universal vars, since we only care about stalled existentials. - let mut sub_roots = Vec::new(); + let mut sub_roots = ThinVec::new(); stalled_vars.retain(|arg| match arg.kind() { // Lifetimes can never stall goals. ty::GenericArgKind::Lifetime(_) => false, diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index d3998955ef2c0..bb1e6c168c47b 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::{ }; use rustc_next_trait_solver::solve::{GoalStalledOn, GoalStalledOnOpaques}; use rustc_span::{DUMMY_SP, Span}; +use thin_vec::{ThinVec, thin_vec}; use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph}; @@ -54,12 +55,12 @@ impl<'tcx> SolverDelegate<'tcx> { /// Create a [`ComputeGoalFastPathOutcome`] signalling the goal is stalled /// on a list of [`ty::GenericArg`] fn goal_stalled_on_args<'tcx>( - stalled_vars: Vec>, + stalled_vars: ThinVec>, ) -> ComputeGoalFastPathOutcome<'tcx> { ComputeGoalFastPathOutcome::TriviallyStalled { stalled_on: GoalStalledOn { stalled_vars, - sub_roots: Vec::new(), + sub_roots: ThinVec::new(), stalled_certainty: Certainty::AMBIGUOUS, opaques: GoalStalledOnOpaques::No, }, @@ -70,12 +71,12 @@ fn goal_stalled_on_args<'tcx>( /// on a list of [`ty::GenericArg`] *or* the opaque type storage being nonempty. /// fn goal_stalled_on_args_or_nonempty_opaques<'tcx>( - stalled_vars: Vec>, + stalled_vars: ThinVec>, ) -> ComputeGoalFastPathOutcome<'tcx> { ComputeGoalFastPathOutcome::TriviallyStalled { stalled_on: GoalStalledOn { stalled_vars, - sub_roots: Vec::new(), + sub_roots: ThinVec::new(), stalled_certainty: Certainty::AMBIGUOUS, opaques: GoalStalledOnOpaques::Yes { num_opaques_in_storage: 0, @@ -89,7 +90,7 @@ fn goal_stalled_on_args_or_nonempty_opaques<'tcx>( } struct CollectNonRegionInfer<'tcx> { - infers: Vec>, + infers: ThinVec>, visited: FxHashSet>, } @@ -162,7 +163,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // FIXME: Properly consider opaques here. && self.known_no_opaque_types_in_storage() { - goal_stalled_on_args_or_nonempty_opaques(vec![self_ty.into()]) + goal_stalled_on_args_or_nonempty_opaques(thin_vec![self_ty.into()]) } else if trait_pred.polarity() == ty::PredicatePolarity::Positive { match self.0.tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) | Some(LangItem::MetaSized) => { @@ -249,7 +250,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { self.sub_unify_ty_vids_raw(a_vid, b_vid); - goal_stalled_on_args(vec![a.into(), b.into()]) + goal_stalled_on_args(thin_vec![a.into(), b.into()]) } _ => Outcome::NoFastPath, } @@ -261,7 +262,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< let arg = self.shallow_resolve_const(ct); if arg.is_ct_infer() { - goal_stalled_on_args(vec![arg.into()]) + goal_stalled_on_args(thin_vec![arg.into()]) } else { Outcome::NoFastPath } @@ -275,7 +276,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< if arg.is_trivially_wf(self.tcx) { Outcome::TriviallyHolds } else if arg.is_infer() { - goal_stalled_on_args(vec![arg.into_arg()]) + goal_stalled_on_args(thin_vec![arg.into_arg()]) } else { Outcome::NoFastPath } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index a61c679c9870f..e47c3e8b7d98c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -202,7 +202,7 @@ where let mut errors = Vec::new(); loop { let mut any_changed = false; - for (mut obligation, stalled_on) in self.obligations.drain_pending(|_, _| true) { + for (mut obligation, stalled_on) in mem::take(&mut self.obligations.pending) { let goal = obligation.as_goal(); let delegate = <&SolverDelegate<'tcx>>::from(infcx); @@ -398,3 +398,16 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError<' } } } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use rustc_data_structures::static_assert_size; + + use super::*; + // tidy-alphabetical-start + // Before #160005 this pair was greater than 128 bytes, which triggered the use of (slow) + // `memcpy` for moving elements of `PendingObligations`. + static_assert_size!((PredicateObligation<'_>, Option>>), 104); + // tidy-alphabetical-end +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 37cbdfb66f505..3c581d15f0376 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -19,6 +19,7 @@ use rustc_middle::{bug, ty}; use rustc_next_trait_solver::canonical::instantiate_canonical_state; use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect}; use rustc_span::Span; +use thin_vec::ThinVec; use tracing::instrument; use crate::solve::delegate::SolverDelegate; @@ -30,7 +31,7 @@ pub struct InspectConfig { pub struct InspectGoal<'a, 'tcx> { infcx: &'a SolverDelegate<'tcx>, depth: usize, - orig_values: Vec>, + orig_values: ThinVec>, goal: Goal<'tcx, ty::Predicate<'tcx>>, result: Result, final_revision: &'tcx inspect::Probe>, diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 19afebe4e2a07..2e6ad5388b0f5 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -41,5 +41,6 @@ nightly = [ "rustc_type_ir_macros/nightly", "smallvec/may_dangle", "smallvec/union", + "thin-vec/unstable", ] # tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 3dd4989370ba7..e0cbc0890b761 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -8,6 +8,7 @@ use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash_NoContex use rustc_type_ir_macros::{ GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic, }; +use thin_vec::ThinVec; use crate::data_structures::HashMap; use crate::inherent::*; @@ -366,7 +367,7 @@ impl Index for CanonicalVarValues { #[derive_where(Clone, Debug; I: Interner)] pub struct CanonicalParamEnvCacheEntry { pub param_env: I::ParamEnv, - pub variables: Vec, + pub variables: ThinVec, pub variable_lookup_table: HashMap, pub var_kinds: Vec>, } diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 20432687e5f6b..783ee23fd9fbd 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -19,6 +19,7 @@ use derive_where::derive_where; use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; +use thin_vec::ThinVec; use crate::solve::{CandidateSource, Certainty, Goal, GoalSource, QueryResult}; use crate::{Canonical, CanonicalVarValues, Interner}; @@ -48,7 +49,7 @@ pub type CanonicalState = Canonical>; #[derive_where(PartialEq, Eq, Hash; I: Interner)] pub struct GoalEvaluation { pub uncanonicalized_goal: Goal, - pub orig_values: Vec, + pub orig_values: ThinVec, pub final_revision: I::Probe, pub result: QueryResult, } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 1972154347c38..a916dbd079efa 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -10,6 +10,7 @@ use rustc_macros::{Decodable_NoContext, Encodable_NoContext, StableHash, StableH use rustc_type_ir_macros::{ GenericTypeVisitable, Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic, }; +use thin_vec::ThinVec; use tracing::debug; use crate::lang_items::SolverTraitLangItem; @@ -982,8 +983,10 @@ pub enum GoalStalledOnOpaques { /// The conditions that must change for a goal to warrant #[derive_where(Clone, Debug; I: Interner)] pub struct GoalStalledOn { - pub stalled_vars: Vec, - pub sub_roots: Vec, + // `ThinVec` is important for performance. See #160005. + pub stalled_vars: ThinVec, + // `ThinVec` is important for performance. See #160005. + pub sub_roots: ThinVec, /// The certainty that will be returned on subsequent evaluations if this /// goal remains stalled. pub stalled_certainty: Certainty,