Skip to content

Commit e30ce42

Browse files
authored
Merge pull request #18707 from ChayimFriedman2/subst
feat: Show substitution where hovering over generic things
2 parents 633a10c + b5486ff commit e30ce42

29 files changed

+1015
-186
lines changed

crates/hir/src/lib.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3574,6 +3574,61 @@ impl GenericDef {
35743574
}
35753575
}
35763576

3577+
// We cannot call this `Substitution` unfortunately...
3578+
#[derive(Debug)]
3579+
pub struct GenericSubstitution {
3580+
def: GenericDefId,
3581+
subst: Substitution,
3582+
env: Arc<TraitEnvironment>,
3583+
}
3584+
3585+
impl GenericSubstitution {
3586+
fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self {
3587+
Self { def, subst, env }
3588+
}
3589+
3590+
pub fn types(&self, db: &dyn HirDatabase) -> Vec<(Symbol, Type)> {
3591+
let container = match self.def {
3592+
GenericDefId::ConstId(id) => Some(id.lookup(db.upcast()).container),
3593+
GenericDefId::FunctionId(id) => Some(id.lookup(db.upcast()).container),
3594+
GenericDefId::TypeAliasId(id) => Some(id.lookup(db.upcast()).container),
3595+
_ => None,
3596+
};
3597+
let container_type_params = container
3598+
.and_then(|container| match container {
3599+
ItemContainerId::ImplId(container) => Some(container.into()),
3600+
ItemContainerId::TraitId(container) => Some(container.into()),
3601+
_ => None,
3602+
})
3603+
.map(|container| {
3604+
db.generic_params(container)
3605+
.iter_type_or_consts()
3606+
.filter_map(|param| match param.1 {
3607+
TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()),
3608+
TypeOrConstParamData::ConstParamData(_) => None,
3609+
})
3610+
.collect::<Vec<_>>()
3611+
});
3612+
let generics = db.generic_params(self.def);
3613+
let type_params = generics.iter_type_or_consts().filter_map(|param| match param.1 {
3614+
TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()),
3615+
TypeOrConstParamData::ConstParamData(_) => None,
3616+
});
3617+
// The `Substitution` is first self then container, we want the reverse order.
3618+
let self_params = self.subst.type_parameters(Interner).zip(type_params);
3619+
let container_params = self.subst.as_slice(Interner)[generics.len()..]
3620+
.iter()
3621+
.filter_map(|param| param.ty(Interner).cloned())
3622+
.zip(container_type_params.into_iter().flatten());
3623+
container_params
3624+
.chain(self_params)
3625+
.filter_map(|(ty, name)| {
3626+
Some((name?.symbol().clone(), Type { ty, env: self.env.clone() }))
3627+
})
3628+
.collect()
3629+
}
3630+
}
3631+
35773632
/// A single local definition.
35783633
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
35793634
pub struct Local {

crates/hir/src/semantics.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ use crate::{
4949
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
5050
source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer},
5151
Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
52-
ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile,
53-
InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name,
54-
OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait, TraitAlias, TupleField,
55-
Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
52+
ConstParam, Crate, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource,
53+
HirFileId, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro,
54+
Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait,
55+
TraitAlias, TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
5656
};
5757

5858
const CONTINUE_NO_BREAKS: ControlFlow<Infallible, ()> = ControlFlow::Continue(());
@@ -1413,7 +1413,7 @@ impl<'db> SemanticsImpl<'db> {
14131413
pub fn resolve_method_call_fallback(
14141414
&self,
14151415
call: &ast::MethodCallExpr,
1416-
) -> Option<Either<Function, Field>> {
1416+
) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
14171417
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
14181418
}
14191419

@@ -1456,18 +1456,33 @@ impl<'db> SemanticsImpl<'db> {
14561456
pub fn resolve_field_fallback(
14571457
&self,
14581458
field: &ast::FieldExpr,
1459-
) -> Option<Either<Either<Field, TupleField>, Function>> {
1459+
) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
14601460
self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
14611461
}
14621462

14631463
pub fn resolve_record_field(
14641464
&self,
14651465
field: &ast::RecordExprField,
14661466
) -> Option<(Field, Option<Local>, Type)> {
1467+
self.resolve_record_field_with_substitution(field)
1468+
.map(|(field, local, ty, _)| (field, local, ty))
1469+
}
1470+
1471+
pub fn resolve_record_field_with_substitution(
1472+
&self,
1473+
field: &ast::RecordExprField,
1474+
) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
14671475
self.analyze(field.syntax())?.resolve_record_field(self.db, field)
14681476
}
14691477

14701478
pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
1479+
self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
1480+
}
1481+
1482+
pub fn resolve_record_pat_field_with_subst(
1483+
&self,
1484+
field: &ast::RecordPatField,
1485+
) -> Option<(Field, Type, GenericSubstitution)> {
14711486
self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
14721487
}
14731488

@@ -1523,6 +1538,13 @@ impl<'db> SemanticsImpl<'db> {
15231538
}
15241539

15251540
pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
1541+
self.resolve_path_with_subst(path).map(|(it, _)| it)
1542+
}
1543+
1544+
pub fn resolve_path_with_subst(
1545+
&self,
1546+
path: &ast::Path,
1547+
) -> Option<(PathResolution, Option<GenericSubstitution>)> {
15261548
self.analyze(path.syntax())?.resolve_path(self.db, path)
15271549
}
15281550

0 commit comments

Comments
 (0)