aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorvsrs <[email protected]>2020-06-11 18:17:32 +0100
committervsrs <[email protected]>2020-06-18 08:15:43 +0100
commit4b07c1e77515ae9198aae6275700aacd43181b50 (patch)
tree30fe7b19cfd23d384ba5de42b96c9eda2d389614 /crates
parent7ec0064409f90334f6b0dd61e572a65702702985 (diff)
Add Type::walk method
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/code_model.rs130
-rw-r--r--crates/ra_hir_ty/src/lib.rs52
-rw-r--r--crates/ra_ide/src/hover.rs25
3 files changed, 132 insertions, 75 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 5137a16e6..d0a8199a6 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -26,8 +26,8 @@ use hir_ty::{
26 autoderef, 26 autoderef,
27 display::{HirDisplayError, HirFormatter}, 27 display::{HirDisplayError, HirFormatter},
28 expr::ExprValidator, 28 expr::ExprValidator,
29 method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, OpaqueTyId, 29 method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, TraitRef,
30 Substs, TraitEnvironment, Ty, TyDefId, TypeCtor, 30 Ty, TyDefId, TypeCtor,
31}; 31};
32use ra_db::{CrateId, CrateName, Edition, FileId}; 32use ra_db::{CrateId, CrateName, Edition, FileId};
33use ra_prof::profile; 33use ra_prof::profile;
@@ -1375,6 +1375,18 @@ impl Type {
1375 Some(adt.into()) 1375 Some(adt.into())
1376 } 1376 }
1377 1377
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
1378 // FIXME: provide required accessors such that it becomes implementable from outside. 1390 // FIXME: provide required accessors such that it becomes implementable from outside.
1379 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { 1391 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1380 match (&self.ty.value, &other.ty.value) { 1392 match (&self.ty.value, &other.ty.value) {
@@ -1397,96 +1409,72 @@ impl Type {
1397 } 1409 }
1398 } 1410 }
1399 1411
1400 /// Returns a flattened list of all ADTs and Traits mentioned in the type 1412 pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
1401 pub fn flattened_type_items(&self, db: &dyn HirDatabase) -> Vec<ModuleDef> { 1413 // TypeWalk::walk does not preserve items order!
1402 fn push_new_item(item: ModuleDef, acc: &mut Vec<ModuleDef>) { 1414 fn walk_substs(db: &dyn HirDatabase, substs: &Substs, cb: &mut impl FnMut(Type)) {
1403 if !acc.contains(&item) { 1415 for ty in substs.iter() {
1404 acc.push(item); 1416 walk_ty(db, ty, cb);
1405 } 1417 }
1406 } 1418 }
1407 1419
1408 fn push_bounds( 1420 fn walk_trait(
1409 db: &dyn HirDatabase, 1421 db: &dyn HirDatabase,
1410 predicates: &[GenericPredicate], 1422 ty: Ty,
1411 acc: &mut Vec<ModuleDef>, 1423 trait_ref: &TraitRef,
1424 cb: &mut impl FnMut(Type),
1412 ) { 1425 ) {
1413 for p in predicates.iter() { 1426 let def_db: &dyn DefDatabase = db.upcast();
1414 match p { 1427 let resolver = trait_ref.trait_.resolver(def_db);
1415 GenericPredicate::Implemented(trait_ref) => { 1428 let krate = trait_ref.trait_.lookup(def_db).container.module(def_db).krate;
1416 push_new_item(Trait::from(trait_ref.trait_).into(), acc); 1429 cb(Type::new_with_resolver_inner(db, krate, &resolver, ty));
1417 walk_substs(db, &trait_ref.substs, acc); 1430 walk_substs(db, &trait_ref.substs, cb);
1418 }
1419 GenericPredicate::Projection(_) => {}
1420 GenericPredicate::Error => (),
1421 }
1422 }
1423 } 1431 }
1424 1432
1425 // TypeWalk::walk does not preserve items order! 1433 fn walk_ty(db: &dyn HirDatabase, ty: &Ty, cb: &mut impl FnMut(Type)) {
1426 fn walk_substs(db: &dyn HirDatabase, substs: &Substs, acc: &mut Vec<ModuleDef>) { 1434 let def_db: &dyn DefDatabase = db.upcast();
1427 for ty in substs.iter() { 1435 let ty = ty.strip_references();
1428 walk_type(db, ty, acc); 1436 match ty {
1429 } 1437 Ty::Apply(ApplicationTy { ctor, parameters }) => {
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, .. }) => {
1435 match ctor { 1438 match ctor {
1436 TypeCtor::Adt(adt_id) => push_new_item(Adt::from(*adt_id).into(), acc), 1439 TypeCtor::Adt(adt) => {
1437 TypeCtor::AssociatedType(type_alias_id) => { 1440 cb(Type::from_def(db, adt.module(def_db).krate, *adt));
1438 let trait_id = match type_alias_id.lookup(db.upcast()).container { 1441 }
1439 AssocContainerId::TraitId(it) => it, 1442 TypeCtor::AssociatedType(_) => {
1440 _ => panic!("not an associated type"), 1443 if let Some(trait_id) = ty.associated_type_parent_trait(db) {
1441 }; 1444 let resolver = trait_id.resolver(def_db);
1442 1445 let krate = trait_id.lookup(def_db).container.module(def_db).krate;
1443 push_new_item(Trait::from(trait_id).into(), acc); 1446 cb(Type::new_with_resolver_inner(db, krate, &resolver, ty.clone()));
1447 }
1444 } 1448 }
1445 _ => (), 1449 _ => (),
1446 } 1450 }
1451
1447 // adt params, tuples, etc... 1452 // adt params, tuples, etc...
1448 walk_substs(db, parameters, acc); 1453 walk_substs(db, parameters, cb);
1449 } 1454 }
1450 Ty::Dyn(predicates) => { 1455 Ty::Opaque(opaque_ty) => {
1451 push_bounds(db, predicates, acc); 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);
1452 } 1461 }
1453 Ty::Placeholder(id) => { 1462 Ty::Placeholder(_) => {
1454 let generic_params = db.generic_params(id.parent); 1463 if let Some(trait_ref) = ty.impl_trait_ref(db) {
1455 let param_data = &generic_params.types[id.local_id]; 1464 walk_trait(db, ty.clone(), &trait_ref, cb);
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 _ => (),
1466 } 1465 }
1467 } 1466 }
1468 Ty::Opaque(opaque_ty) => { 1467 Ty::Dyn(_) => {
1469 let bounds = match opaque_ty.opaque_ty_id { 1468 if let Some(trait_ref) = ty.dyn_trait_ref() {
1470 OpaqueTyId::ReturnTypeImplTrait(func, idx) => { 1469 walk_trait(db, ty.clone(), trait_ref, cb);
1471 let datas = db 1470 }
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);
1482 } 1471 }
1472
1483 _ => (), 1473 _ => (),
1484 } 1474 }
1485 } 1475 }
1486 1476
1487 let mut res: Vec<ModuleDef> = Vec::new(); // not a Set to preserve the order 1477 walk_ty(db, &self.ty.value, &mut cb);
1488 walk_type(db, &self.ty.value, &mut res);
1489 res
1490 } 1478 }
1491} 1479}
1492 1480
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 9d4d6aaa4..25ab9d872 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -877,6 +877,58 @@ impl Ty {
877 _ => None, 877 _ => None,
878 } 878 }
879 } 879 }
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 }
880} 932}
881 933
882/// This allows walking structures that contain types to do something with those 934/// This allows walking structures that contain types to do something with those
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 045713519..c2909e200 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -236,9 +236,26 @@ fn runnable_action(
236fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 236fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
237 match def { 237 match def {
238 Definition::Local(it) => { 238 Definition::Local(it) => {
239 let targets = it 239 let mut targets: Vec<ModuleDef> = Vec::new();
240 .ty(db) 240 let mut push_new_def = |item: ModuleDef| {
241 .flattened_type_items(db) 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
242 .into_iter() 259 .into_iter()
243 .filter_map(|it| { 260 .filter_map(|it| {
244 Some(HoverGotoTypeData { 261 Some(HoverGotoTypeData {
@@ -246,7 +263,7 @@ fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
246 nav: it.try_to_nav(db)?, 263 nav: it.try_to_nav(db)?,
247 }) 264 })
248 }) 265 })
249 .collect_vec(); 266 .collect();
250 267
251 Some(HoverAction::GoToType(targets)) 268 Some(HoverAction::GoToType(targets))
252 } 269 }