diff options
| author | Shotaro Yamada <sinkuu@sinkuu.xyz> | 2019-10-14 12:56:18 +0900 |
|---|---|---|
| committer | Shotaro Yamada <sinkuu@sinkuu.xyz> | 2019-10-14 14:25:05 +0900 |
| commit | f8d4cdc170bead42db3ffa647318ecf2bd6430e7 (patch) | |
| tree | 2c020016af1fd5239fdad65b816b4cccea97df41 | |
| parent | 77f2dd96a122e59a8d8df8afb53a741df9b1af76 (diff) | |
| download | rust-f8d4cdc170bead42db3ffa647318ecf2bd6430e7.tar.gz rust-f8d4cdc170bead42db3ffa647318ecf2bd6430e7.zip | |
Avoid cloning `Arc<[T]>` into a vec if possible
| -rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
| -rw-r--r-- | crates/ra_hir/src/ty.rs | 36 | ||||
| -rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 23 | ||||
| -rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 7 | ||||
| -rw-r--r-- | crates/ra_hir/src/util.rs | 19 |
5 files changed, 55 insertions, 31 deletions
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 9cbd9a8aef8..ca261e8f541 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 d161735e8fb..fc4909d110d 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 d161aa6b390..5e86ed26070 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<T>(self, result: T) -> Canonicalized<T> { @@ -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 a604c02e2d6..003aa9babcd 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 00000000000..46f423c9155 --- /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<T: Clone, R>( + 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 + } +} |
