mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 09:27:27 +00:00
Get substs for trait refs in impl blocks
This commit is contained in:
parent
23b876bc3b
commit
413c87f155
6 changed files with 85 additions and 44 deletions
|
@ -56,7 +56,11 @@ impl GenericParams {
|
|||
GenericDef::Function(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Trait(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::Trait(it) => {
|
||||
// traits get the Self type as an implicit first type parameter
|
||||
generics.params.push(GenericParam { idx: start, name: Name::self_type() });
|
||||
generics.fill(&*it.source(db).1, start + 1);
|
||||
}
|
||||
GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start),
|
||||
GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start),
|
||||
}
|
||||
|
|
|
@ -10,15 +10,13 @@ use ra_syntax::{
|
|||
use crate::{
|
||||
Const, TypeAlias, Function, HirFileId,
|
||||
HirDatabase, DefDatabase,
|
||||
ModuleDef, Trait, Resolution,
|
||||
type_ref::TypeRef,
|
||||
ids::LocationCtx,
|
||||
resolve::Resolver,
|
||||
ty::Ty, generics::GenericParams,
|
||||
TraitRef, code_model_api::{Module, ModuleSource}
|
||||
};
|
||||
|
||||
use crate::code_model_api::{Module, ModuleSource};
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub struct ImplSourceMap {
|
||||
map: ArenaMap<ImplId, AstPtr<ast::ImplBlock>>,
|
||||
|
@ -73,7 +71,7 @@ impl ImplBlock {
|
|||
self.module
|
||||
}
|
||||
|
||||
pub fn target_trait_ref(&self, db: &impl DefDatabase) -> Option<TypeRef> {
|
||||
pub fn target_trait(&self, db: &impl DefDatabase) -> Option<TypeRef> {
|
||||
db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned()
|
||||
}
|
||||
|
||||
|
@ -85,16 +83,8 @@ impl ImplBlock {
|
|||
Ty::from_hir(db, &self.resolver(db), &self.target_type(db))
|
||||
}
|
||||
|
||||
pub fn target_trait(&self, db: &impl HirDatabase) -> Option<Trait> {
|
||||
if let Some(TypeRef::Path(path)) = self.target_trait_ref(db) {
|
||||
let resolver = self.resolver(db);
|
||||
if let Some(Resolution::Def(ModuleDef::Trait(tr))) =
|
||||
resolver.resolve_path(db, &path).take_types()
|
||||
{
|
||||
return Some(tr);
|
||||
}
|
||||
}
|
||||
None
|
||||
pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> {
|
||||
TraitRef::from_hir(db, &self.resolver(db), &self.target_trait(db)?)
|
||||
}
|
||||
|
||||
pub fn items(&self, db: &impl DefDatabase) -> Vec<ImplItem> {
|
||||
|
|
|
@ -61,7 +61,7 @@ pub use self::{
|
|||
source_id::{AstIdMap, ErasedFileAstId},
|
||||
ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc},
|
||||
nameres::{PerNs, Namespace, ImportId},
|
||||
ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay, CallableDef},
|
||||
ty::{Ty, ApplicationTy, TypeCtor, TraitRef, Substs, display::HirDisplay, CallableDef},
|
||||
impl_block::{ImplBlock, ImplItem},
|
||||
docs::{Docs, Documentation},
|
||||
adt::AdtDef,
|
||||
|
|
|
@ -17,9 +17,9 @@ use crate::{
|
|||
resolve::{Resolver, Resolution},
|
||||
path::{ PathSegment, GenericArg},
|
||||
generics::GenericParams,
|
||||
adt::VariantDef,
|
||||
adt::VariantDef, Trait
|
||||
};
|
||||
use super::{Ty, primitive, FnSig, Substs, TypeCtor};
|
||||
use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef};
|
||||
|
||||
impl Ty {
|
||||
pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
|
||||
|
@ -115,7 +115,6 @@ impl Ty {
|
|||
segment: &PathSegment,
|
||||
resolved: TypableDef,
|
||||
) -> Substs {
|
||||
let mut substs = Vec::new();
|
||||
let def_generics = match resolved {
|
||||
TypableDef::Function(func) => func.generic_params(db),
|
||||
TypableDef::Struct(s) => s.generic_params(db),
|
||||
|
@ -124,28 +123,7 @@ impl Ty {
|
|||
TypableDef::TypeAlias(t) => t.generic_params(db),
|
||||
TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(),
|
||||
};
|
||||
let parent_param_count = def_generics.count_parent_params();
|
||||
substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
|
||||
if let Some(generic_args) = &segment.args_and_bindings {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
let param_count = def_generics.params.len();
|
||||
for arg in generic_args.args.iter().take(param_count) {
|
||||
match arg {
|
||||
GenericArg::Type(type_ref) => {
|
||||
let ty = Ty::from_hir(db, resolver, type_ref);
|
||||
substs.push(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// add placeholders for args that were not provided
|
||||
// FIXME: handle defaults
|
||||
let supplied_params = substs.len();
|
||||
for _ in supplied_params..def_generics.count_params_including_parent() {
|
||||
substs.push(Ty::Unknown);
|
||||
}
|
||||
assert_eq!(substs.len(), def_generics.count_params_including_parent());
|
||||
Substs(substs.into())
|
||||
substs_from_path_segment(db, resolver, segment, &def_generics, false)
|
||||
}
|
||||
|
||||
/// Collect generic arguments from a path into a `Substs`. See also
|
||||
|
@ -185,6 +163,73 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn substs_from_path_segment(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
segment: &PathSegment,
|
||||
def_generics: &GenericParams,
|
||||
add_self_param: bool,
|
||||
) -> Substs {
|
||||
let mut substs = Vec::new();
|
||||
let parent_param_count = def_generics.count_parent_params();
|
||||
substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
|
||||
if add_self_param {
|
||||
// FIXME this add_self_param argument is kind of a hack: Traits have the
|
||||
// Self type as an implicit first type parameter, but it can't be
|
||||
// actually provided in the type arguments
|
||||
substs.push(Ty::Unknown);
|
||||
}
|
||||
if let Some(generic_args) = &segment.args_and_bindings {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
let param_count = def_generics.params.len();
|
||||
for arg in generic_args.args.iter().take(param_count) {
|
||||
match arg {
|
||||
GenericArg::Type(type_ref) => {
|
||||
let ty = Ty::from_hir(db, resolver, type_ref);
|
||||
substs.push(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// add placeholders for args that were not provided
|
||||
// FIXME: handle defaults
|
||||
let supplied_params = substs.len();
|
||||
for _ in supplied_params..def_generics.count_params_including_parent() {
|
||||
substs.push(Ty::Unknown);
|
||||
}
|
||||
assert_eq!(substs.len(), def_generics.count_params_including_parent());
|
||||
Substs(substs.into())
|
||||
}
|
||||
|
||||
impl TraitRef {
|
||||
pub(crate) fn from_hir(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
type_ref: &TypeRef,
|
||||
) -> Option<Self> {
|
||||
let path = match type_ref {
|
||||
TypeRef::Path(path) => path,
|
||||
_ => return None,
|
||||
};
|
||||
let resolved = match resolver.resolve_path(db, &path).take_types()? {
|
||||
Resolution::Def(ModuleDef::Trait(tr)) => tr,
|
||||
_ => return None,
|
||||
};
|
||||
let substs = Self::substs_from_path(db, resolver, path, resolved);
|
||||
Some(TraitRef { trait_: resolved, substs })
|
||||
}
|
||||
|
||||
fn substs_from_path(
|
||||
db: &impl HirDatabase,
|
||||
resolver: &Resolver,
|
||||
path: &Path,
|
||||
resolved: Trait,
|
||||
) -> Substs {
|
||||
let segment = path.segments.last().expect("path should have at least one segment");
|
||||
substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true)
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the declared type of an item. This depends on the namespace; e.g. for
|
||||
/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
|
||||
/// the constructor function `(usize) -> Foo` which lives in the values
|
||||
|
|
|
@ -72,9 +72,9 @@ impl CrateImplBlocks {
|
|||
|
||||
let target_ty = impl_block.target_ty(db);
|
||||
|
||||
if let Some(tr) = impl_block.target_trait(db) {
|
||||
if let Some(tr) = impl_block.target_trait_ref(db) {
|
||||
self.impls_by_trait
|
||||
.entry(tr)
|
||||
.entry(tr.trait_)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((module.module_id, impl_id));
|
||||
} else {
|
||||
|
@ -185,6 +185,8 @@ impl Ty {
|
|||
// well (in fact, the 'implements' condition could just be considered a
|
||||
// 'where Self: Trait' clause)
|
||||
candidates.retain(|(t, _m)| {
|
||||
// FIXME construct substs of the correct length for the trait
|
||||
// - check in rustc whether it does anything smarter than putting variables for everything
|
||||
let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) };
|
||||
db.implements(trait_ref)
|
||||
});
|
||||
|
|
|
@ -104,7 +104,7 @@ pub(crate) fn reference_definition(
|
|||
}
|
||||
}
|
||||
hir::PathResolution::AssocItem(assoc) => {
|
||||
return Exact(NavigationTarget::from_impl_item(db, assoc))
|
||||
return Exact(NavigationTarget::from_impl_item(db, assoc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue