Skip to content

Commit 7cc2e9a

Browse files
Show substitution where hovering over generic things
There are few things to note in the implementation: First, this is a best-effort implementation. Mainly, type aliases may not be shown (due to their eager nature it's harder) and partial pathes (aka. hovering over `Struct` in `Struct::method`) are not supported at all. Second, we only need to show substitutions in expression and pattern position, because in type position all generic arguments always have to be written explicitly.
1 parent 27e824f commit 7cc2e9a

30 files changed

+1014
-186
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,12 @@ impl InferenceResult {
539539
ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
540540
}
541541
}
542+
pub fn type_of_expr_including_adjust(&self, id: ExprId) -> Option<&Ty> {
543+
match self.expr_adjustments.get(&id).and_then(|adjustments| adjustments.last()) {
544+
Some(adjustment) => Some(&adjustment.target),
545+
None => self.type_of_expr.get(id),
546+
}
547+
}
542548
}
543549

544550
impl Index<ExprId> for InferenceResult {

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(());
@@ -1415,7 +1415,7 @@ impl<'db> SemanticsImpl<'db> {
14151415
pub fn resolve_method_call_fallback(
14161416
&self,
14171417
call: &ast::MethodCallExpr,
1418-
) -> Option<Either<Function, Field>> {
1418+
) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
14191419
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
14201420
}
14211421

@@ -1458,18 +1458,33 @@ impl<'db> SemanticsImpl<'db> {
14581458
pub fn resolve_field_fallback(
14591459
&self,
14601460
field: &ast::FieldExpr,
1461-
) -> Option<Either<Either<Field, TupleField>, Function>> {
1461+
) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
14621462
self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
14631463
}
14641464

14651465
pub fn resolve_record_field(
14661466
&self,
14671467
field: &ast::RecordExprField,
14681468
) -> Option<(Field, Option<Local>, Type)> {
1469+
self.resolve_record_field_with_substitution(field)
1470+
.map(|(field, local, ty, _)| (field, local, ty))
1471+
}
1472+
1473+
pub fn resolve_record_field_with_substitution(
1474+
&self,
1475+
field: &ast::RecordExprField,
1476+
) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
14691477
self.analyze(field.syntax())?.resolve_record_field(self.db, field)
14701478
}
14711479

14721480
pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
1481+
self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
1482+
}
1483+
1484+
pub fn resolve_record_pat_field_with_subst(
1485+
&self,
1486+
field: &ast::RecordPatField,
1487+
) -> Option<(Field, Type, GenericSubstitution)> {
14731488
self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
14741489
}
14751490

@@ -1525,6 +1540,13 @@ impl<'db> SemanticsImpl<'db> {
15251540
}
15261541

15271542
pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
1543+
self.resolve_path_with_subst(path).map(|(it, _)| it)
1544+
}
1545+
1546+
pub fn resolve_path_with_subst(
1547+
&self,
1548+
path: &ast::Path,
1549+
) -> Option<(PathResolution, Option<GenericSubstitution>)> {
15281550
self.analyze(path.syntax())?.resolve_path(self.db, path)
15291551
}
15301552

0 commit comments

Comments
 (0)