From b8c1e402fa3a40c7e979750d60d7b003f9cb7b0d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 3 Sep 2019 13:10:00 +0200 Subject: Make type walking infrastructure a bit nicer If/when we switch to using Chalk's Ty, we'll need to replace this by its `Fold` trait, but I didn't want to import the whole thing just yet. --- crates/ra_cli/src/analysis_stats.rs | 2 +- crates/ra_hir/src/lib.rs | 4 +- crates/ra_hir/src/ty.rs | 233 ++++++++++++----------- crates/ra_hir/src/ty/autoderef.rs | 2 +- crates/ra_hir/src/ty/infer.rs | 2 +- crates/ra_hir/src/ty/infer/unify.rs | 2 +- crates/ra_hir/src/ty/lower.rs | 1 + crates/ra_hir/src/ty/traits.rs | 20 +- crates/ra_hir/src/ty/traits/chalk.rs | 1 + crates/ra_ide_api/src/completion/presentation.rs | 2 +- 10 files changed, 134 insertions(+), 135 deletions(-) (limited to 'crates') diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index 5c0a9dd98..1fad5b233 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs @@ -1,7 +1,7 @@ use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; use ra_db::SourceDatabase; -use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty}; +use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty, TypeWalk}; use ra_syntax::AstNode; use crate::Result; diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 752653ad7..c3e589921 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -69,7 +69,9 @@ pub use self::{ resolve::Resolution, source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, source_id::{AstIdMap, ErasedFileAstId}, - ty::{display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor}, + ty::{ + display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, + }, type_ref::Mutability, }; diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index c0c609d78..a3df08827 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -130,12 +130,14 @@ impl ProjectionTy { substs: self.parameters.clone(), } } +} - pub fn walk(&self, f: &mut impl FnMut(&Ty)) { +impl TypeWalk for ProjectionTy { + fn walk(&self, f: &mut impl FnMut(&Ty)) { self.parameters.walk(f); } - pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { + fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { self.parameters.walk_mut(f); } } @@ -146,12 +148,12 @@ pub struct UnselectedProjectionTy { pub parameters: Substs, } -impl UnselectedProjectionTy { - pub fn walk(&self, f: &mut impl FnMut(&Ty)) { +impl TypeWalk for UnselectedProjectionTy { + fn walk(&self, f: &mut impl FnMut(&Ty)) { self.parameters.walk(f); } - pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { + fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { self.parameters.walk_mut(f); } } @@ -312,20 +314,14 @@ impl TraitRef { pub fn self_ty(&self) -> &Ty { &self.substs[0] } +} - pub fn subst(mut self, substs: &Substs) -> TraitRef { - self.substs.walk_mut(&mut |ty_mut| { - let ty = mem::replace(ty_mut, Ty::Unknown); - *ty_mut = ty.subst(substs); - }); - self - } - - pub fn walk(&self, f: &mut impl FnMut(&Ty)) { +impl TypeWalk for TraitRef { + fn walk(&self, f: &mut impl FnMut(&Ty)) { self.substs.walk(f); } - pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { + fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { self.substs.walk_mut(f); } } @@ -365,20 +361,10 @@ impl GenericPredicate { GenericPredicate::Error => None, } } +} - pub fn subst(self, substs: &Substs) -> GenericPredicate { - match self { - GenericPredicate::Implemented(trait_ref) => { - GenericPredicate::Implemented(trait_ref.subst(substs)) - } - GenericPredicate::Projection(projection_predicate) => { - GenericPredicate::Projection(projection_predicate.subst(substs)) - } - GenericPredicate::Error => self, - } - } - - pub fn walk(&self, f: &mut impl FnMut(&Ty)) { +impl TypeWalk for GenericPredicate { + fn walk(&self, f: &mut impl FnMut(&Ty)) { match self { GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), GenericPredicate::Projection(projection_pred) => projection_pred.walk(f), @@ -386,7 +372,7 @@ impl GenericPredicate { } } - pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { + fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { match self { GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f), @@ -430,16 +416,16 @@ impl FnSig { pub fn ret(&self) -> &Ty { &self.params_and_return[self.params_and_return.len() - 1] } +} - /// Applies the given substitutions to all types in this signature and - /// returns the result. - pub fn subst(&self, substs: &Substs) -> FnSig { - let result: Vec<_> = - self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); - FnSig { params_and_return: result.into() } +impl TypeWalk for FnSig { + fn walk(&self, f: &mut impl FnMut(&Ty)) { + for t in self.params_and_return.iter() { + t.walk(f); + } } - pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { + 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 { @@ -463,64 +449,6 @@ impl Ty { Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) } - pub fn walk(&self, f: &mut impl FnMut(&Ty)) { - match self { - Ty::Apply(a_ty) => { - for t in a_ty.parameters.iter() { - t.walk(f); - } - } - Ty::Projection(p_ty) => { - for t in p_ty.parameters.iter() { - t.walk(f); - } - } - Ty::UnselectedProjection(p_ty) => { - for t in p_ty.parameters.iter() { - t.walk(f); - } - } - Ty::Dyn(predicates) | Ty::Opaque(predicates) => { - for p in predicates.iter() { - p.walk(f); - } - } - Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} - } - f(self); - } - - fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { - match self { - Ty::Apply(a_ty) => { - a_ty.parameters.walk_mut(f); - } - Ty::Projection(p_ty) => { - p_ty.parameters.walk_mut(f); - } - Ty::UnselectedProjection(p_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(); - } - Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} - } - f(self); - } - - fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty { - self.walk_mut(&mut |ty_mut| { - let ty = mem::replace(ty_mut, Ty::Unknown); - *ty_mut = f(ty); - }); - self - } - pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { match self { Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { @@ -596,10 +524,53 @@ impl Ty { } } + /// Returns the type parameters of this type if it has some (i.e. is an ADT + /// or function); so if `self` is `Option`, this returns the `u32`. + pub fn substs(&self) -> Option { + match self { + Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), + _ => None, + } + } + + /// If this is an `impl Trait` or `dyn Trait`, returns that trait. + pub fn inherent_trait(&self) -> Option { + match self { + Ty::Dyn(predicates) | Ty::Opaque(predicates) => { + predicates.iter().find_map(|pred| match pred { + GenericPredicate::Implemented(tr) => Some(tr.trait_), + _ => None, + }) + } + _ => None, + } + } +} + +/// This allows walking structures that contain types to do something with those +/// types, similar to Chalk's `Fold` trait. +pub trait TypeWalk { + fn walk(&self, f: &mut impl FnMut(&Ty)); + fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)); + + fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self + where + Self: Sized, + { + self.walk_mut(&mut |ty_mut| { + let ty = mem::replace(ty_mut, Ty::Unknown); + *ty_mut = f(ty); + }); + self + } + /// Replaces type parameters in this type using the given `Substs`. (So e.g. /// if `self` is `&[T]`, where type parameter T has index 0, and the /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) - pub fn subst(self, substs: &Substs) -> Ty { + fn subst(self, substs: &Substs) -> Self + where + Self: Sized, + { self.fold(&mut |ty| match ty { Ty::Param { idx, name } => { substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) @@ -609,24 +580,21 @@ impl Ty { } /// Substitutes `Ty::Bound` vars (as opposed to type parameters). - pub fn subst_bound_vars(self, substs: &Substs) -> Ty { + fn subst_bound_vars(self, substs: &Substs) -> Self + where + Self: Sized, + { self.fold(&mut |ty| match ty { Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), ty => ty, }) } - /// Returns the type parameters of this type if it has some (i.e. is an ADT - /// or function); so if `self` is `Option`, this returns the `u32`. - pub fn substs(&self) -> Option { - match self { - Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), - _ => None, - } - } - /// Shifts up `Ty::Bound` vars by `n`. - pub fn shift_bound_vars(self, n: i32) -> Ty { + fn shift_bound_vars(self, n: i32) -> Self + where + Self: Sized, + { self.fold(&mut |ty| match ty { Ty::Bound(idx) => { assert!(idx as i32 >= -n); @@ -635,18 +603,57 @@ impl Ty { ty => ty, }) } +} - /// If this is an `impl Trait` or `dyn Trait`, returns that trait. - pub fn inherent_trait(&self) -> Option { +impl TypeWalk for Ty { + fn walk(&self, f: &mut impl FnMut(&Ty)) { match self { + Ty::Apply(a_ty) => { + for t in a_ty.parameters.iter() { + t.walk(f); + } + } + Ty::Projection(p_ty) => { + for t in p_ty.parameters.iter() { + t.walk(f); + } + } + Ty::UnselectedProjection(p_ty) => { + for t in p_ty.parameters.iter() { + t.walk(f); + } + } Ty::Dyn(predicates) | Ty::Opaque(predicates) => { - predicates.iter().find_map(|pred| match pred { - GenericPredicate::Implemented(tr) => Some(tr.trait_), - _ => None, - }) + for p in predicates.iter() { + p.walk(f); + } } - _ => None, + Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} + } + f(self); + } + + fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { + match self { + Ty::Apply(a_ty) => { + a_ty.parameters.walk_mut(f); + } + Ty::Projection(p_ty) => { + p_ty.parameters.walk_mut(f); + } + Ty::UnselectedProjection(p_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(); + } + Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } + f(self); } } diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 2535d4ae7..08f52a53b 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs @@ -7,7 +7,7 @@ use std::iter::successors; use log::{info, warn}; -use super::{traits::Solution, Canonical, Ty}; +use super::{traits::Solution, Canonical, Ty, TypeWalk}; use crate::{HasGenericParams, HirDatabase, Name, Resolver}; const AUTODEREF_RECURSION_LIMIT: usize = 10; diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index b89a40b4b..ec3b7ffef 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -30,7 +30,7 @@ use super::{ autoderef, lower, method_resolution, op, primitive, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, - Ty, TypableDef, TypeCtor, + Ty, TypableDef, TypeCtor, TypeWalk, }; use crate::{ adt::VariantDef, diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index e7e8825d1..9a0d2d8f9 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs @@ -3,7 +3,7 @@ use super::{InferenceContext, Obligation}; use crate::db::HirDatabase; use crate::ty::{ - Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, + Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk, }; impl<'a, D: HirDatabase> InferenceContext<'a, D> { diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 0011c06b4..f6f0137cf 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -10,6 +10,7 @@ use std::sync::Arc; use super::{ FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, + TypeWalk, }; use crate::{ adt::VariantDef, diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 25316bc02..6e0271a96 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs @@ -8,7 +8,7 @@ use ra_db::salsa; use ra_prof::profile; use rustc_hash::FxHashSet; -use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; +use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; use self::chalk::{from_chalk, ToChalk}; @@ -138,25 +138,13 @@ pub struct ProjectionPredicate { pub ty: Ty, } -impl ProjectionPredicate { - pub fn subst(mut self, substs: &super::Substs) -> ProjectionPredicate { - self.walk_mut(&mut |ty| match ty { - Ty::Param { idx, .. } => { - if let Some(t) = substs.get(*idx as usize).cloned() { - *ty = t; - } - } - _ => {} - }); - self - } - - pub fn walk(&self, f: &mut impl FnMut(&Ty)) { +impl TypeWalk for ProjectionPredicate { + fn walk(&self, f: &mut impl FnMut(&Ty)) { self.projection_ty.walk(f); self.ty.walk(f); } - pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { + fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { self.projection_ty.walk_mut(f); self.ty.walk_mut(f); } diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 3ab5b7cca..c201c5e50 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -19,6 +19,7 @@ use crate::{ ty::display::HirDisplay, ty::{ ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, + TypeWalk, }, Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias, }; diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index f19eec9b7..db7e8348e 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -1,5 +1,5 @@ //! This modules takes care of rendering various defenitions as completion items. -use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty}; +use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty, TypeWalk}; use join_to_string::join; use ra_syntax::ast::NameOwner; use test_utils::tested_by; -- cgit v1.2.3