Skip to content

Commit

Permalink
Merge pull request #18707 from ChayimFriedman2/subst
Browse files Browse the repository at this point in the history
feat: Show substitution where hovering over generic things
  • Loading branch information
Veykril authored Dec 24, 2024
2 parents eb80a6b + b80bb58 commit 8bfb2fe
Show file tree
Hide file tree
Showing 29 changed files with 1,015 additions and 186 deletions.
55 changes: 55 additions & 0 deletions src/tools/rust-analyzer/crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3574,6 +3574,61 @@ impl GenericDef {
}
}

// We cannot call this `Substitution` unfortunately...
#[derive(Debug)]
pub struct GenericSubstitution {
def: GenericDefId,
subst: Substitution,
env: Arc<TraitEnvironment>,
}

impl GenericSubstitution {
fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self {
Self { def, subst, env }
}

pub fn types(&self, db: &dyn HirDatabase) -> Vec<(Symbol, Type)> {
let container = match self.def {
GenericDefId::ConstId(id) => Some(id.lookup(db.upcast()).container),
GenericDefId::FunctionId(id) => Some(id.lookup(db.upcast()).container),
GenericDefId::TypeAliasId(id) => Some(id.lookup(db.upcast()).container),
_ => None,
};
let container_type_params = container
.and_then(|container| match container {
ItemContainerId::ImplId(container) => Some(container.into()),
ItemContainerId::TraitId(container) => Some(container.into()),
_ => None,
})
.map(|container| {
db.generic_params(container)
.iter_type_or_consts()
.filter_map(|param| match param.1 {
TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()),
TypeOrConstParamData::ConstParamData(_) => None,
})
.collect::<Vec<_>>()
});
let generics = db.generic_params(self.def);
let type_params = generics.iter_type_or_consts().filter_map(|param| match param.1 {
TypeOrConstParamData::TypeParamData(param) => Some(param.name.clone()),
TypeOrConstParamData::ConstParamData(_) => None,
});
// The `Substitution` is first self then container, we want the reverse order.
let self_params = self.subst.type_parameters(Interner).zip(type_params);
let container_params = self.subst.as_slice(Interner)[generics.len()..]
.iter()
.filter_map(|param| param.ty(Interner).cloned())
.zip(container_type_params.into_iter().flatten());
container_params
.chain(self_params)
.filter_map(|(ty, name)| {
Some((name?.symbol().clone(), Type { ty, env: self.env.clone() }))
})
.collect()
}
}

/// A single local definition.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Local {
Expand Down
34 changes: 28 additions & 6 deletions src/tools/rust-analyzer/crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ use crate::{
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer},
Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile,
InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name,
OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait, TraitAlias, TupleField,
Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
ConstParam, Crate, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource,
HirFileId, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro,
Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, Static, Struct, ToolModule, Trait,
TraitAlias, TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
};

const CONTINUE_NO_BREAKS: ControlFlow<Infallible, ()> = ControlFlow::Continue(());
Expand Down Expand Up @@ -1413,7 +1413,7 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_method_call_fallback(
&self,
call: &ast::MethodCallExpr,
) -> Option<Either<Function, Field>> {
) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
}

Expand Down Expand Up @@ -1456,18 +1456,33 @@ impl<'db> SemanticsImpl<'db> {
pub fn resolve_field_fallback(
&self,
field: &ast::FieldExpr,
) -> Option<Either<Either<Field, TupleField>, Function>> {
) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
self.analyze(field.syntax())?.resolve_field_fallback(self.db, field)
}

pub fn resolve_record_field(
&self,
field: &ast::RecordExprField,
) -> Option<(Field, Option<Local>, Type)> {
self.resolve_record_field_with_substitution(field)
.map(|(field, local, ty, _)| (field, local, ty))
}

pub fn resolve_record_field_with_substitution(
&self,
field: &ast::RecordExprField,
) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
self.analyze(field.syntax())?.resolve_record_field(self.db, field)
}

pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<(Field, Type)> {
self.resolve_record_pat_field_with_subst(field).map(|(field, ty, _)| (field, ty))
}

pub fn resolve_record_pat_field_with_subst(
&self,
field: &ast::RecordPatField,
) -> Option<(Field, Type, GenericSubstitution)> {
self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
}

Expand Down Expand Up @@ -1523,6 +1538,13 @@ impl<'db> SemanticsImpl<'db> {
}

pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
self.resolve_path_with_subst(path).map(|(it, _)| it)
}

pub fn resolve_path_with_subst(
&self,
path: &ast::Path,
) -> Option<(PathResolution, Option<GenericSubstitution>)> {
self.analyze(path.syntax())?.resolve_path(self.db, path)
}

Expand Down
Loading

0 comments on commit 8bfb2fe

Please sign in to comment.