Skip to content

Commit

Permalink
Swap PredicateObligations to SmallVec
Browse files Browse the repository at this point in the history
  • Loading branch information
GnomedDev committed Oct 9, 2024
1 parent 6e022b4 commit 8df8a1b
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 41 deletions.
3 changes: 2 additions & 1 deletion compiler/rustc_data_structures/src/obligation_forest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ use std::fmt::Debug;
use std::hash;
use std::marker::PhantomData;

use smallvec::SmallVec;
use tracing::debug;

use crate::fx::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -141,7 +142,7 @@ pub trait ObligationProcessor {
#[derive(Debug)]
pub enum ProcessResult<O, E> {
Unchanged,
Changed(Vec<O>),
Changed(SmallVec<[O; 4]>),
Error(E),
}

Expand Down
68 changes: 36 additions & 32 deletions compiler/rustc_data_structures/src/obligation_forest/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::fmt;

use smallvec::smallvec;

use super::*;

impl<'a> super::ForestObligation for &'a str {
Expand Down Expand Up @@ -101,9 +103,9 @@ fn push_pop() {
// |-> A.3
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
"A" => ProcessResult::Changed(smallvec!["A.1", "A.2", "A.3"]),
"B" => ProcessResult::Error("B is for broken"),
"C" => ProcessResult::Changed(vec![]),
"C" => ProcessResult::Changed(smallvec![]),
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -123,8 +125,8 @@ fn push_pop() {
|obligation| match *obligation {
"A.1" => ProcessResult::Unchanged,
"A.2" => ProcessResult::Unchanged,
"A.3" => ProcessResult::Changed(vec!["A.3.i"]),
"D" => ProcessResult::Changed(vec!["D.1", "D.2"]),
"A.3" => ProcessResult::Changed(smallvec!["A.3.i"]),
"D" => ProcessResult::Changed(smallvec!["D.1", "D.2"]),
"A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -139,11 +141,11 @@ fn push_pop() {
// |-> D.2 |-> D.2.i
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A.1" => ProcessResult::Changed(vec![]),
"A.1" => ProcessResult::Changed(smallvec![]),
"A.2" => ProcessResult::Error("A is for apple"),
"A.3.i" => ProcessResult::Changed(vec![]),
"D.1" => ProcessResult::Changed(vec!["D.1.i"]),
"D.2" => ProcessResult::Changed(vec!["D.2.i"]),
"A.3.i" => ProcessResult::Changed(smallvec![]),
"D.1" => ProcessResult::Changed(smallvec!["D.1.i"]),
"D.2" => ProcessResult::Changed(smallvec!["D.2.i"]),
"D.1.i" | "D.2.i" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -158,7 +160,7 @@ fn push_pop() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"D.1.i" => ProcessResult::Error("D is for dumb"),
"D.2.i" => ProcessResult::Changed(vec![]),
"D.2.i" => ProcessResult::Changed(smallvec![]),
_ => panic!("unexpected obligation {:?}", obligation),
},
|_| {},
Expand All @@ -184,10 +186,10 @@ fn success_in_grandchildren() {

let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
"A.1" => ProcessResult::Changed(vec![]),
"A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]),
"A.3" => ProcessResult::Changed(vec![]),
"A" => ProcessResult::Changed(smallvec!["A.1", "A.2", "A.3"]),
"A.1" => ProcessResult::Changed(smallvec![]),
"A.2" => ProcessResult::Changed(smallvec!["A.2.i", "A.2.ii"]),
"A.3" => ProcessResult::Changed(smallvec![]),
"A.2.i" | "A.2.ii" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -201,7 +203,7 @@ fn success_in_grandchildren() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A.2.i" => ProcessResult::Unchanged,
"A.2.ii" => ProcessResult::Changed(vec![]),
"A.2.ii" => ProcessResult::Changed(smallvec![]),
_ => unreachable!(),
},
|_| {},
Expand All @@ -211,7 +213,7 @@ fn success_in_grandchildren() {

let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]),
"A.2.i" => ProcessResult::Changed(smallvec!["A.2.i.a"]),
"A.2.i.a" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -222,7 +224,7 @@ fn success_in_grandchildren() {

let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A.2.i.a" => ProcessResult::Changed(vec![]),
"A.2.i.a" => ProcessResult::Changed(smallvec![]),
_ => unreachable!(),
},
|_| {},
Expand All @@ -247,7 +249,7 @@ fn to_errors_no_throw() {
forest.register_obligation("A");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]),
"A" => ProcessResult::Changed(smallvec!["A.1", "A.2", "A.3"]),
"A.1" | "A.2" | "A.3" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -269,7 +271,7 @@ fn diamond() {
forest.register_obligation("A");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["A.1", "A.2"]),
"A" => ProcessResult::Changed(smallvec!["A.1", "A.2"]),
"A.1" | "A.2" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -280,8 +282,8 @@ fn diamond() {

let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A.1" => ProcessResult::Changed(vec!["D"]),
"A.2" => ProcessResult::Changed(vec!["D"]),
"A.1" => ProcessResult::Changed(smallvec!["D"]),
"A.2" => ProcessResult::Changed(smallvec!["D"]),
"D" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -295,7 +297,7 @@ fn diamond() {
|obligation| match *obligation {
"D" => {
d_count += 1;
ProcessResult::Changed(vec![])
ProcessResult::Changed(smallvec![])
}
_ => unreachable!(),
},
Expand All @@ -313,7 +315,7 @@ fn diamond() {
forest.register_obligation("A'");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]),
"A'" => ProcessResult::Changed(smallvec!["A'.1", "A'.2"]),
"A'.1" | "A'.2" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -324,8 +326,8 @@ fn diamond() {

let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A'.1" => ProcessResult::Changed(vec!["D'", "A'"]),
"A'.2" => ProcessResult::Changed(vec!["D'"]),
"A'.1" => ProcessResult::Changed(smallvec!["D'", "A'"]),
"A'.2" => ProcessResult::Changed(smallvec!["D'"]),
"D'" | "A'" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand Down Expand Up @@ -366,7 +368,7 @@ fn done_dependency() {

let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]),
"A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(smallvec![]),
_ => unreachable!(),
},
|_| {},
Expand All @@ -379,7 +381,9 @@ fn done_dependency() {
forest.register_obligation("(A,B,C): Sized");
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]),
"(A,B,C): Sized" => {
ProcessResult::Changed(smallvec!["A: Sized", "B: Sized", "C: Sized"])
}
_ => unreachable!(),
},
|_| {},
Expand All @@ -399,10 +403,10 @@ fn orphan() {

let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A" => ProcessResult::Changed(vec!["D", "E"]),
"A" => ProcessResult::Changed(smallvec!["D", "E"]),
"B" => ProcessResult::Unchanged,
"C1" => ProcessResult::Changed(vec![]),
"C2" => ProcessResult::Changed(vec![]),
"C1" => ProcessResult::Changed(smallvec![]),
"C2" => ProcessResult::Changed(smallvec![]),
"D" | "E" => ProcessResult::Unchanged,
_ => unreachable!(),
},
Expand All @@ -416,7 +420,7 @@ fn orphan() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"D" | "E" => ProcessResult::Unchanged,
"B" => ProcessResult::Changed(vec!["D"]),
"B" => ProcessResult::Changed(smallvec!["D"]),
_ => unreachable!(),
},
|_| {},
Expand Down Expand Up @@ -459,7 +463,7 @@ fn simultaneous_register_and_error() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A" => ProcessResult::Error("An error"),
"B" => ProcessResult::Changed(vec!["A"]),
"B" => ProcessResult::Changed(smallvec!["A"]),
_ => unreachable!(),
},
|_| {},
Expand All @@ -474,7 +478,7 @@ fn simultaneous_register_and_error() {
let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(
|obligation| match *obligation {
"A" => ProcessResult::Error("An error"),
"B" => ProcessResult::Changed(vec!["A"]),
"B" => ProcessResult::Changed(smallvec!["A"]),
_ => unreachable!(),
},
|_| {},
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_infer/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_middle::traits::solve::Certainty;
pub use rustc_middle::traits::*;
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span;
use smallvec::SmallVec;

pub use self::ImplSource::*;
pub use self::SelectionError::*;
Expand Down Expand Up @@ -84,7 +85,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::TraitPredicate<'tcx>>;
pub type PolyTraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;

pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
pub type PredicateObligations<'tcx> = SmallVec<[PredicateObligation<'tcx>; 4]>;

impl<'tcx> PredicateObligation<'tcx> {
/// Flips the polarity of the inner predicate.
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -625,14 +625,14 @@ pub enum ImplSource<'tcx, N> {
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
/// any).
Param(Vec<N>),
Param(SmallVec<[N; 4]>),

/// Successful resolution for a builtin impl.
Builtin(BuiltinImplSource, Vec<N>),
Builtin(BuiltinImplSource, SmallVec<[N; 4]>),
}

impl<'tcx, N> ImplSource<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> {
pub fn nested_obligations(self) -> SmallVec<[N; 4]> {
match self {
ImplSource::UserDefined(i) => i.nested,
ImplSource::Param(n) | ImplSource::Builtin(_, n) => n,
Expand Down Expand Up @@ -686,7 +686,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
pub struct ImplSourceUserDefinedData<'tcx, N> {
pub impl_def_id: DefId,
pub args: GenericArgsRef<'tcx>,
pub nested: Vec<N>,
pub nested: SmallVec<[N; 4]>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
smallvec = { version = "1.8.1", features = ["union", "may_dangle", "drain_filter"] }
tracing = "0.1"
# tidy-alphabetical-end
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl<'tcx> ObligationStorage<'tcx> {
// we get all obligations involved in the overflow. We pretty much check: if
// we were to do another step of `select_where_possible`, which goals would
// change.
self.overflowed.extend(self.pending.extract_if(|o| {
self.overflowed.extend(self.pending.drain_filter(|o| {
let goal = o.clone().into();
let result = <&SolverDelegate<'tcx>>::from(infcx)
.evaluate_root_goal(goal, GenerateProofTree::No)
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
use smallvec::SmallVec;
use tracing::{debug, debug_span, instrument};

use super::project::{self, ProjectAndUnifyResult};
Expand All @@ -28,7 +29,7 @@ use crate::traits::normalize::normalize_with_depth_to;
use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
use crate::traits::query::evaluate_obligation::InferCtxtExt;

pub(crate) type PendingPredicateObligations<'tcx> = Vec<PendingPredicateObligation<'tcx>>;
pub(crate) type PendingPredicateObligations<'tcx> = SmallVec<[PendingPredicateObligation<'tcx>; 4]>;

impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
/// Note that we include both the `ParamEnv` and the `Predicate`,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_type_ir/src/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
use std::mem;

use rustc_index::{Idx, IndexVec};
use smallvec::SmallVec;
use tracing::instrument;

use crate::data_structures::Lrc;
Expand Down Expand Up @@ -322,6 +323,12 @@ impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
}
}

impl<I: Interner, T: TypeFoldable<I>, const N: usize> TypeFoldable<I> for SmallVec<[T; N]> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.into_iter().map(|t| t.try_fold_with(folder)).collect()
}
}

impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice)
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_type_ir/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use std::ops::ControlFlow;
use rustc_ast_ir::visit::VisitorResult;
use rustc_ast_ir::{try_visit, walk_visitable_list};
use rustc_index::{Idx, IndexVec};
use smallvec::SmallVec;

use crate::data_structures::Lrc;
use crate::inherent::*;
Expand Down Expand Up @@ -184,6 +185,13 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
}
}

impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for SmallVec<[T; N]> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
walk_visitable_list!(visitor, self.iter());
V::Result::output()
}
}

// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
// case, because we can't return a new slice. But note that there are a couple
// of trivial impls of `TypeFoldable` for specific slice types elsewhere.
Expand Down

0 comments on commit 8df8a1b

Please sign in to comment.