diff options
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 130 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 52 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 25 |
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 | }; |
32 | use ra_db::{CrateId, CrateName, Edition, FileId}; | 32 | use ra_db::{CrateId, CrateName, Edition, FileId}; |
33 | use ra_prof::profile; | 33 | use 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( | |||
236 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 236 | fn 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 | } |