Skip to content

Commit 4b07c1e

Browse files
committed
Add Type::walk method
1 parent 7ec0064 commit 4b07c1e

File tree

3 files changed

+132
-75
lines changed

3 files changed

+132
-75
lines changed

crates/ra_hir/src/code_model.rs

Lines changed: 59 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ use hir_ty::{
2626
autoderef,
2727
display::{HirDisplayError, HirFormatter},
2828
expr::ExprValidator,
29-
method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, OpaqueTyId,
30-
Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
29+
method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, TraitRef,
30+
Ty, TyDefId, TypeCtor,
3131
};
3232
use ra_db::{CrateId, CrateName, Edition, FileId};
3333
use ra_prof::profile;
@@ -1375,6 +1375,18 @@ impl Type {
13751375
Some(adt.into())
13761376
}
13771377

1378+
pub fn as_dyn_trait(&self) -> Option<Trait> {
1379+
self.ty.value.dyn_trait().map(Into::into)
1380+
}
1381+
1382+
pub fn as_impl_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
1383+
self.ty.value.impl_trait_ref(db).map(|it| it.trait_.into())
1384+
}
1385+
1386+
pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
1387+
self.ty.value.associated_type_parent_trait(db).map(Into::into)
1388+
}
1389+
13781390
// FIXME: provide required accessors such that it becomes implementable from outside.
13791391
pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
13801392
match (&self.ty.value, &other.ty.value) {
@@ -1397,96 +1409,72 @@ impl Type {
13971409
}
13981410
}
13991411

1400-
/// Returns a flattened list of all ADTs and Traits mentioned in the type
1401-
pub fn flattened_type_items(&self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
1402-
fn push_new_item(item: ModuleDef, acc: &mut Vec<ModuleDef>) {
1403-
if !acc.contains(&item) {
1404-
acc.push(item);
1412+
pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
1413+
// TypeWalk::walk does not preserve items order!
1414+
fn walk_substs(db: &dyn HirDatabase, substs: &Substs, cb: &mut impl FnMut(Type)) {
1415+
for ty in substs.iter() {
1416+
walk_ty(db, ty, cb);
14051417
}
14061418
}
14071419

1408-
fn push_bounds(
1420+
fn walk_trait(
14091421
db: &dyn HirDatabase,
1410-
predicates: &[GenericPredicate],
1411-
acc: &mut Vec<ModuleDef>,
1422+
ty: Ty,
1423+
trait_ref: &TraitRef,
1424+
cb: &mut impl FnMut(Type),
14121425
) {
1413-
for p in predicates.iter() {
1414-
match p {
1415-
GenericPredicate::Implemented(trait_ref) => {
1416-
push_new_item(Trait::from(trait_ref.trait_).into(), acc);
1417-
walk_substs(db, &trait_ref.substs, acc);
1418-
}
1419-
GenericPredicate::Projection(_) => {}
1420-
GenericPredicate::Error => (),
1421-
}
1422-
}
1426+
let def_db: &dyn DefDatabase = db.upcast();
1427+
let resolver = trait_ref.trait_.resolver(def_db);
1428+
let krate = trait_ref.trait_.lookup(def_db).container.module(def_db).krate;
1429+
cb(Type::new_with_resolver_inner(db, krate, &resolver, ty));
1430+
walk_substs(db, &trait_ref.substs, cb);
14231431
}
14241432

1425-
// TypeWalk::walk does not preserve items order!
1426-
fn walk_substs(db: &dyn HirDatabase, substs: &Substs, acc: &mut Vec<ModuleDef>) {
1427-
for ty in substs.iter() {
1428-
walk_type(db, ty, acc);
1429-
}
1430-
}
1431-
1432-
fn walk_type(db: &dyn HirDatabase, ty: &Ty, acc: &mut Vec<ModuleDef>) {
1433-
match ty.strip_references() {
1434-
Ty::Apply(ApplicationTy { ctor, parameters, .. }) => {
1433+
fn walk_ty(db: &dyn HirDatabase, ty: &Ty, cb: &mut impl FnMut(Type)) {
1434+
let def_db: &dyn DefDatabase = db.upcast();
1435+
let ty = ty.strip_references();
1436+
match ty {
1437+
Ty::Apply(ApplicationTy { ctor, parameters }) => {
14351438
match ctor {
1436-
TypeCtor::Adt(adt_id) => push_new_item(Adt::from(*adt_id).into(), acc),
1437-
TypeCtor::AssociatedType(type_alias_id) => {
1438-
let trait_id = match type_alias_id.lookup(db.upcast()).container {
1439-
AssocContainerId::TraitId(it) => it,
1440-
_ => panic!("not an associated type"),
1441-
};
1442-
1443-
push_new_item(Trait::from(trait_id).into(), acc);
1439+
TypeCtor::Adt(adt) => {
1440+
cb(Type::from_def(db, adt.module(def_db).krate, *adt));
1441+
}
1442+
TypeCtor::AssociatedType(_) => {
1443+
if let Some(trait_id) = ty.associated_type_parent_trait(db) {
1444+
let resolver = trait_id.resolver(def_db);
1445+
let krate = trait_id.lookup(def_db).container.module(def_db).krate;
1446+
cb(Type::new_with_resolver_inner(db, krate, &resolver, ty.clone()));
1447+
}
14441448
}
14451449
_ => (),
14461450
}
1451+
14471452
// adt params, tuples, etc...
1448-
walk_substs(db, parameters, acc);
1453+
walk_substs(db, parameters, cb);
14491454
}
1450-
Ty::Dyn(predicates) => {
1451-
push_bounds(db, predicates, acc);
1455+
Ty::Opaque(opaque_ty) => {
1456+
if let Some(trait_ref) = ty.impl_trait_ref(db) {
1457+
walk_trait(db, ty.clone(), &trait_ref, cb);
1458+
}
1459+
1460+
walk_substs(db, &opaque_ty.parameters, cb);
14521461
}
1453-
Ty::Placeholder(id) => {
1454-
let generic_params = db.generic_params(id.parent);
1455-
let param_data = &generic_params.types[id.local_id];
1456-
match param_data.provenance {
1457-
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
1458-
let predicates: Vec<_> = db
1459-
.generic_predicates_for_param(*id)
1460-
.into_iter()
1461-
.map(|pred| pred.value.clone())
1462-
.collect();
1463-
push_bounds(db, &predicates, acc);
1464-
}
1465-
_ => (),
1462+
Ty::Placeholder(_) => {
1463+
if let Some(trait_ref) = ty.impl_trait_ref(db) {
1464+
walk_trait(db, ty.clone(), &trait_ref, cb);
14661465
}
14671466
}
1468-
Ty::Opaque(opaque_ty) => {
1469-
let bounds = match opaque_ty.opaque_ty_id {
1470-
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
1471-
let datas = db
1472-
.return_type_impl_traits(func)
1473-
.expect("impl trait id without data");
1474-
let data = (*datas)
1475-
.as_ref()
1476-
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
1477-
data.clone().subst(&opaque_ty.parameters)
1478-
}
1479-
};
1480-
push_bounds(db, &bounds.value, acc);
1481-
walk_substs(db, &opaque_ty.parameters, acc);
1467+
Ty::Dyn(_) => {
1468+
if let Some(trait_ref) = ty.dyn_trait_ref() {
1469+
walk_trait(db, ty.clone(), trait_ref, cb);
1470+
}
14821471
}
1472+
14831473
_ => (),
14841474
}
14851475
}
14861476

1487-
let mut res: Vec<ModuleDef> = Vec::new(); // not a Set to preserve the order
1488-
walk_type(db, &self.ty.value, &mut res);
1489-
res
1477+
walk_ty(db, &self.ty.value, &mut cb);
14901478
}
14911479
}
14921480

crates/ra_hir_ty/src/lib.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,58 @@ impl Ty {
877877
_ => None,
878878
}
879879
}
880+
881+
pub fn impl_trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
882+
match self {
883+
Ty::Opaque(opaque_ty) => {
884+
let predicates = match opaque_ty.opaque_ty_id {
885+
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
886+
db.return_type_impl_traits(func).map(|it| {
887+
let data = (*it)
888+
.as_ref()
889+
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
890+
data.clone().subst(&opaque_ty.parameters)
891+
})
892+
}
893+
};
894+
895+
predicates.and_then(|it| {
896+
it.value.iter().find_map(|pred| match pred {
897+
GenericPredicate::Implemented(tr) => Some(tr.clone()),
898+
_ => None,
899+
})
900+
})
901+
}
902+
Ty::Placeholder(id) => {
903+
let generic_params = db.generic_params(id.parent);
904+
let param_data = &generic_params.types[id.local_id];
905+
match param_data.provenance {
906+
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => db
907+
.generic_predicates_for_param(*id)
908+
.into_iter()
909+
.map(|pred| pred.value.clone())
910+
.find_map(|pred| match pred {
911+
GenericPredicate::Implemented(tr) => Some(tr.clone()),
912+
_ => None,
913+
}),
914+
_ => None,
915+
}
916+
}
917+
_ => None,
918+
}
919+
}
920+
921+
pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
922+
match self {
923+
Ty::Apply(ApplicationTy { ctor: TypeCtor::AssociatedType(type_alias_id), .. }) => {
924+
match type_alias_id.lookup(db.upcast()).container {
925+
AssocContainerId::TraitId(trait_id) => Some(trait_id),
926+
_ => None,
927+
}
928+
}
929+
_ => None,
930+
}
931+
}
880932
}
881933

882934
/// This allows walking structures that contain types to do something with those

crates/ra_ide/src/hover.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,17 +236,34 @@ fn runnable_action(
236236
fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
237237
match def {
238238
Definition::Local(it) => {
239-
let targets = it
240-
.ty(db)
241-
.flattened_type_items(db)
239+
let mut targets: Vec<ModuleDef> = Vec::new();
240+
let mut push_new_def = |item: ModuleDef| {
241+
if !targets.contains(&item) {
242+
targets.push(item);
243+
}
244+
};
245+
246+
it.ty(db).walk(db, |t| {
247+
if let Some(adt) = t.as_adt() {
248+
push_new_def(adt.into());
249+
} else if let Some(trait_) = t.as_dyn_trait() {
250+
push_new_def(trait_.into());
251+
} else if let Some(trait_) = t.as_impl_trait(db) {
252+
push_new_def(trait_.into());
253+
} else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
254+
push_new_def(trait_.into());
255+
}
256+
});
257+
258+
let targets = targets
242259
.into_iter()
243260
.filter_map(|it| {
244261
Some(HoverGotoTypeData {
245262
mod_path: mod_path(db, &it)?,
246263
nav: it.try_to_nav(db)?,
247264
})
248265
})
249-
.collect_vec();
266+
.collect();
250267

251268
Some(HoverAction::GoToType(targets))
252269
}

0 commit comments

Comments
 (0)