Skip to content

Commit 4575c38

Browse files
bors[bot]vsrs
andauthored
Merge #4839
4839: `Go to Type Definition` hover action. r=matklad a=vsrs ![hover_actions_goto](https://user-images.githubusercontent.com/62505555/83335671-0122e380-a2b7-11ea-9922-fbdcfb11a7f3.gif) This implementation supports things like `dyn Trait<SomeType>`, `-> impl Trait`, etc. Co-authored-by: vsrs <vit@conrlab.com>
2 parents f6e250b + 022fbef commit 4575c38

File tree

11 files changed

+1360
-38
lines changed

11 files changed

+1360
-38
lines changed

crates/ra_hir/src/code_model.rs

Lines changed: 113 additions & 2 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, InEnvironment, Substs, TraitEnvironment, Ty,
30-
TyDefId, TypeCtor,
29+
method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs,
30+
TraitEnvironment, Ty, TyDefId, TypeCtor,
3131
};
3232
use ra_db::{CrateId, CrateName, Edition, FileId};
3333
use ra_prof::profile;
@@ -186,6 +186,22 @@ impl ModuleDef {
186186

187187
module.visibility_of(db, self)
188188
}
189+
190+
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
191+
match self {
192+
ModuleDef::Adt(it) => Some(it.name(db)),
193+
ModuleDef::Trait(it) => Some(it.name(db)),
194+
ModuleDef::Function(it) => Some(it.name(db)),
195+
ModuleDef::EnumVariant(it) => Some(it.name(db)),
196+
ModuleDef::TypeAlias(it) => Some(it.name(db)),
197+
198+
ModuleDef::Module(it) => it.name(db),
199+
ModuleDef::Const(it) => it.name(db),
200+
ModuleDef::Static(it) => it.name(db),
201+
202+
ModuleDef::BuiltinType(it) => Some(it.as_name()),
203+
}
204+
}
189205
}
190206

191207
pub use hir_def::{
@@ -1359,6 +1375,27 @@ impl Type {
13591375
Some(adt.into())
13601376
}
13611377

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_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
1383+
self.ty.value.impl_trait_bounds(db).map(|it| {
1384+
it.into_iter()
1385+
.filter_map(|pred| match pred {
1386+
hir_ty::GenericPredicate::Implemented(trait_ref) => {
1387+
Some(Trait::from(trait_ref.trait_))
1388+
}
1389+
_ => None,
1390+
})
1391+
.collect()
1392+
})
1393+
}
1394+
1395+
pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
1396+
self.ty.value.associated_type_parent_trait(db).map(Into::into)
1397+
}
1398+
13621399
// FIXME: provide required accessors such that it becomes implementable from outside.
13631400
pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
13641401
match (&self.ty.value, &other.ty.value) {
@@ -1380,6 +1417,80 @@ impl Type {
13801417
ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
13811418
}
13821419
}
1420+
1421+
pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
1422+
// TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
1423+
// We need a different order here.
1424+
1425+
fn walk_substs(
1426+
db: &dyn HirDatabase,
1427+
type_: &Type,
1428+
substs: &Substs,
1429+
cb: &mut impl FnMut(Type),
1430+
) {
1431+
for ty in substs.iter() {
1432+
walk_type(db, &type_.derived(ty.clone()), cb);
1433+
}
1434+
}
1435+
1436+
fn walk_bounds(
1437+
db: &dyn HirDatabase,
1438+
type_: &Type,
1439+
bounds: &[GenericPredicate],
1440+
cb: &mut impl FnMut(Type),
1441+
) {
1442+
for pred in bounds {
1443+
match pred {
1444+
GenericPredicate::Implemented(trait_ref) => {
1445+
cb(type_.clone());
1446+
walk_substs(db, type_, &trait_ref.substs, cb);
1447+
}
1448+
_ => (),
1449+
}
1450+
}
1451+
}
1452+
1453+
fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
1454+
let ty = type_.ty.value.strip_references();
1455+
match ty {
1456+
Ty::Apply(ApplicationTy { ctor, parameters }) => {
1457+
match ctor {
1458+
TypeCtor::Adt(_) => {
1459+
cb(type_.derived(ty.clone()));
1460+
}
1461+
TypeCtor::AssociatedType(_) => {
1462+
if let Some(_) = ty.associated_type_parent_trait(db) {
1463+
cb(type_.derived(ty.clone()));
1464+
}
1465+
}
1466+
_ => (),
1467+
}
1468+
1469+
// adt params, tuples, etc...
1470+
walk_substs(db, type_, parameters, cb);
1471+
}
1472+
Ty::Opaque(opaque_ty) => {
1473+
if let Some(bounds) = ty.impl_trait_bounds(db) {
1474+
walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1475+
}
1476+
1477+
walk_substs(db, type_, &opaque_ty.parameters, cb);
1478+
}
1479+
Ty::Placeholder(_) => {
1480+
if let Some(bounds) = ty.impl_trait_bounds(db) {
1481+
walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1482+
}
1483+
}
1484+
Ty::Dyn(bounds) => {
1485+
walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb);
1486+
}
1487+
1488+
_ => (),
1489+
}
1490+
}
1491+
1492+
walk_type(db, self, &mut cb);
1493+
}
13831494
}
13841495

13851496
impl HirDisplay for Type {

crates/ra_hir_ty/src/lib.rs

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub use lower::{
7373
pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
7474

7575
pub use chalk_ir::{BoundVar, DebruijnIndex};
76+
use itertools::Itertools;
7677

7778
/// A type constructor or type name: this might be something like the primitive
7879
/// type `bool`, a struct like `Vec`, or things like function pointers or
@@ -815,6 +816,11 @@ impl Ty {
815816
}
816817
}
817818

819+
/// If this is a `dyn Trait`, returns that trait.
820+
pub fn dyn_trait(&self) -> Option<TraitId> {
821+
self.dyn_trait_ref().map(|it| it.trait_)
822+
}
823+
818824
fn builtin_deref(&self) -> Option<Ty> {
819825
match self {
820826
Ty::Apply(a_ty) => match a_ty.ctor {
@@ -867,13 +873,56 @@ impl Ty {
867873
}
868874
}
869875

870-
/// If this is a `dyn Trait`, returns that trait.
871-
pub fn dyn_trait(&self) -> Option<TraitId> {
876+
pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> {
872877
match self {
873-
Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred {
874-
GenericPredicate::Implemented(tr) => Some(tr.trait_),
875-
_ => None,
876-
}),
878+
Ty::Opaque(opaque_ty) => {
879+
let predicates = match opaque_ty.opaque_ty_id {
880+
OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
881+
db.return_type_impl_traits(func).map(|it| {
882+
let data = (*it)
883+
.as_ref()
884+
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
885+
data.clone().subst(&opaque_ty.parameters)
886+
})
887+
}
888+
};
889+
890+
predicates.map(|it| it.value)
891+
}
892+
Ty::Placeholder(id) => {
893+
let generic_params = db.generic_params(id.parent);
894+
let param_data = &generic_params.types[id.local_id];
895+
match param_data.provenance {
896+
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
897+
let predicates = db
898+
.generic_predicates_for_param(*id)
899+
.into_iter()
900+
.map(|pred| pred.value.clone())
901+
.collect_vec();
902+
903+
Some(predicates)
904+
}
905+
_ => None,
906+
}
907+
}
908+
_ => None,
909+
}
910+
}
911+
912+
pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
913+
match self {
914+
Ty::Apply(ApplicationTy { ctor: TypeCtor::AssociatedType(type_alias_id), .. }) => {
915+
match type_alias_id.lookup(db.upcast()).container {
916+
AssocContainerId::TraitId(trait_id) => Some(trait_id),
917+
_ => None,
918+
}
919+
}
920+
Ty::Projection(projection_ty) => {
921+
match projection_ty.associated_ty.lookup(db.upcast()).container {
922+
AssocContainerId::TraitId(trait_id) => Some(trait_id),
923+
_ => None,
924+
}
925+
}
877926
_ => None,
878927
}
879928
}
@@ -1057,5 +1106,5 @@ pub struct ReturnTypeImplTraits {
10571106

10581107
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
10591108
pub(crate) struct ReturnTypeImplTrait {
1060-
pub(crate) bounds: Binders<Vec<GenericPredicate>>,
1109+
pub bounds: Binders<Vec<GenericPredicate>>,
10611110
}

0 commit comments

Comments
 (0)