From f8d4cdc170bead42db3ffa647318ecf2bd6430e7 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Mon, 14 Oct 2019 12:56:18 +0900 Subject: Avoid cloning `Arc<[T]>` into a vec if possible --- crates/ra_hir/src/lib.rs | 1 + crates/ra_hir/src/ty.rs | 36 +++++++++++++++++------------------- crates/ra_hir/src/ty/infer/unify.rs | 23 +++++++++++++++-------- crates/ra_hir/src/ty/lower.rs | 7 +++---- crates/ra_hir/src/util.rs | 19 +++++++++++++++++++ 5 files changed, 55 insertions(+), 31 deletions(-) create mode 100644 crates/ra_hir/src/util.rs diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 9cbd9a8ae..ca261e8f5 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -51,6 +51,7 @@ mod lang_item; mod generics; mod resolve; pub mod diagnostics; +mod util; mod code_model; diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d161735e8..fc4909d11 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -17,8 +17,8 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use crate::{ - db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, Crate, DefWithBody, GenericParams, - HasGenericParams, Name, Trait, TypeAlias, + db::HirDatabase, expr::ExprId, type_ref::Mutability, util::make_mut_arc_slice, Adt, Crate, + DefWithBody, GenericParams, HasGenericParams, Name, Trait, TypeAlias, }; use display::{HirDisplay, HirFormatter}; @@ -308,12 +308,11 @@ impl Substs { } pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { - // Without an Arc::make_mut_slice, we can't avoid the clone here: - let mut v: Vec<_> = self.0.iter().cloned().collect(); - for t in &mut v { - t.walk_mut(f); - } - self.0 = v.into(); + make_mut_arc_slice(&mut self.0, |s| { + for t in s { + t.walk_mut(f); + } + }); } pub fn as_single(&self) -> &Ty { @@ -541,12 +540,11 @@ impl TypeWalk for FnSig { } fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { - // Without an Arc::make_mut_slice, we can't avoid the clone here: - let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); - for t in &mut v { - t.walk_mut(f); - } - self.params_and_return = v.into(); + make_mut_arc_slice(&mut self.params_and_return, |s| { + for t in s { + t.walk_mut(f); + } + }); } } @@ -756,11 +754,11 @@ impl TypeWalk for Ty { p_ty.parameters.walk_mut(f); } Ty::Dyn(predicates) | Ty::Opaque(predicates) => { - let mut v: Vec<_> = predicates.iter().cloned().collect(); - for p in &mut v { - p.walk_mut(f); - } - *predicates = v.into(); + make_mut_arc_slice(predicates, |s| { + for p in s { + p.walk_mut(f); + } + }); } Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index d161aa6b3..5e86ed260 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs @@ -6,6 +6,7 @@ use crate::ty::{ Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeWalk, }; +use crate::util::make_mut_arc_slice; impl<'a, D: HirDatabase> InferenceContext<'a, D> { pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> @@ -74,10 +75,13 @@ where }) } - fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef { - let substs = - trait_ref.substs.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect(); - TraitRef { trait_: trait_ref.trait_, substs: Substs(substs) } + fn do_canonicalize_trait_ref(&mut self, mut trait_ref: TraitRef) -> TraitRef { + make_mut_arc_slice(&mut trait_ref.substs.0, |tys| { + for ty in tys { + *ty = self.do_canonicalize_ty(ty.clone()); + } + }); + trait_ref } fn into_canonicalized(self, result: T) -> Canonicalized { @@ -87,10 +91,13 @@ where } } - fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy { - let params = - projection_ty.parameters.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect(); - ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: Substs(params) } + fn do_canonicalize_projection_ty(&mut self, mut projection_ty: ProjectionTy) -> ProjectionTy { + make_mut_arc_slice(&mut projection_ty.parameters.0, |params| { + for ty in params { + *ty = self.do_canonicalize_ty(ty.clone()); + } + }); + projection_ty } fn do_canonicalize_projection_predicate( diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index a604c02e2..003aa9bab 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -392,10 +392,9 @@ impl TraitRef { ) -> Self { let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); if let Some(self_ty) = explicit_self_ty { - // FIXME this could be nicer - let mut substs_vec = substs.0.to_vec(); - substs_vec[0] = self_ty; - substs.0 = substs_vec.into(); + crate::util::make_mut_arc_slice(&mut substs.0, |substs| { + substs[0] = self_ty; + }); } TraitRef { trait_: resolved, substs } } diff --git a/crates/ra_hir/src/util.rs b/crates/ra_hir/src/util.rs new file mode 100644 index 000000000..46f423c91 --- /dev/null +++ b/crates/ra_hir/src/util.rs @@ -0,0 +1,19 @@ +//! Internal utility functions. + +use std::sync::Arc; + +/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices). +/// The underlying values are cloned if there are other strong references. +pub(crate) fn make_mut_arc_slice( + a: &mut Arc<[T]>, + f: impl FnOnce(&mut [T]) -> R, +) -> R { + if let Some(s) = Arc::get_mut(a) { + f(s) + } else { + let mut v = a.to_vec(); + let r = f(&mut v); + *a = Arc::from(v); + r + } +} -- cgit v1.2.3