mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Merge #2413
2413: Remove another helper r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
6560e4ff2e
9 changed files with 156 additions and 124 deletions
|
@ -9,7 +9,7 @@ use hir_def::{
|
||||||
builtin_type::BuiltinType,
|
builtin_type::BuiltinType,
|
||||||
docs::Documentation,
|
docs::Documentation,
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
resolver::{HasResolver, TypeNs},
|
resolver::HasResolver,
|
||||||
type_ref::{Mutability, TypeRef},
|
type_ref::{Mutability, TypeRef},
|
||||||
AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId,
|
AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId,
|
||||||
HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId,
|
HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId,
|
||||||
|
@ -737,64 +737,7 @@ impl Trait {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> {
|
pub fn items(self, db: &impl DefDatabase) -> Vec<AssocItem> {
|
||||||
db.trait_data(self.id).items.iter().map(|it| (*it).into()).collect()
|
db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
|
||||||
}
|
|
||||||
|
|
||||||
fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
|
|
||||||
let resolver = self.id.resolver(db);
|
|
||||||
// returning the iterator directly doesn't easily work because of
|
|
||||||
// lifetime problems, but since there usually shouldn't be more than a
|
|
||||||
// few direct traits this should be fine (we could even use some kind of
|
|
||||||
// SmallVec if performance is a concern)
|
|
||||||
db.generic_params(self.id.into())
|
|
||||||
.where_predicates
|
|
||||||
.iter()
|
|
||||||
.filter_map(|pred| match &pred.type_ref {
|
|
||||||
TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
|
|
||||||
Some(TypeNs::TraitId(t)) => Some(t),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.map(Trait::from)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over the whole super trait hierarchy (including the
|
|
||||||
/// trait itself).
|
|
||||||
pub fn all_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
|
|
||||||
// we need to take care a bit here to avoid infinite loops in case of cycles
|
|
||||||
// (i.e. if we have `trait A: B; trait B: A;`)
|
|
||||||
let mut result = vec![self];
|
|
||||||
let mut i = 0;
|
|
||||||
while i < result.len() {
|
|
||||||
let t = result[i];
|
|
||||||
// yeah this is quadratic, but trait hierarchies should be flat
|
|
||||||
// enough that this doesn't matter
|
|
||||||
for tt in t.direct_super_traits(db) {
|
|
||||||
if !result.contains(&tt) {
|
|
||||||
result.push(tt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
|
|
||||||
let trait_data = db.trait_data(self.id);
|
|
||||||
let res =
|
|
||||||
trait_data.associated_types().map(TypeAlias::from).find(|t| &t.name(db) == name)?;
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn associated_type_by_name_including_super_traits(
|
|
||||||
self,
|
|
||||||
db: &impl HirDatabase,
|
|
||||||
name: &Name,
|
|
||||||
) -> Option<TypeAlias> {
|
|
||||||
self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef {
|
pub fn trait_ref(self, db: &impl HirDatabase) -> TraitRef {
|
||||||
|
|
|
@ -9,6 +9,7 @@ mod op;
|
||||||
mod lower;
|
mod lower;
|
||||||
mod infer;
|
mod infer;
|
||||||
pub(crate) mod display;
|
pub(crate) mod display;
|
||||||
|
pub(crate) mod utils;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use hir_expand::name;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use ra_db::CrateId;
|
use ra_db::CrateId;
|
||||||
|
|
||||||
use crate::{db::HirDatabase, Trait};
|
use crate::db::HirDatabase;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
traits::{InEnvironment, Solution},
|
traits::{InEnvironment, Solution},
|
||||||
|
@ -49,12 +49,12 @@ fn deref_by_trait(
|
||||||
ty: InEnvironment<&Canonical<Ty>>,
|
ty: InEnvironment<&Canonical<Ty>>,
|
||||||
) -> Option<Canonical<Ty>> {
|
) -> Option<Canonical<Ty>> {
|
||||||
let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
|
let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
|
||||||
LangItemTarget::TraitId(t) => Trait::from(t),
|
LangItemTarget::TraitId(it) => it,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
|
let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?;
|
||||||
|
|
||||||
let generic_params = db.generic_params(target.id.into());
|
let generic_params = db.generic_params(target.into());
|
||||||
if generic_params.count_params_including_parent() != 1 {
|
if generic_params.count_params_including_parent() != 1 {
|
||||||
// the Target type + Deref trait should only have one generic parameter,
|
// the Target type + Deref trait should only have one generic parameter,
|
||||||
// namely Deref's Self type
|
// namely Deref's Self type
|
||||||
|
@ -69,7 +69,7 @@ fn deref_by_trait(
|
||||||
|
|
||||||
let projection = super::traits::ProjectionPredicate {
|
let projection = super::traits::ProjectionPredicate {
|
||||||
ty: Ty::Bound(0),
|
ty: Ty::Bound(0),
|
||||||
projection_ty: super::ProjectionTy { associated_ty: target.id, parameters },
|
projection_ty: super::ProjectionTy { associated_ty: target, parameters },
|
||||||
};
|
};
|
||||||
|
|
||||||
let obligation = super::Obligation::Projection(projection);
|
let obligation = super::Obligation::Projection(projection);
|
||||||
|
|
|
@ -43,7 +43,7 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
expr::{BindingAnnotation, Body, ExprId, PatId},
|
expr::{BindingAnnotation, Body, ExprId, PatId},
|
||||||
ty::infer::diagnostics::InferenceDiagnostic,
|
ty::infer::diagnostics::InferenceDiagnostic,
|
||||||
Adt, AssocItem, DefWithBody, FloatTy, Function, IntTy, Path, StructField, Trait, VariantDef,
|
Adt, AssocItem, DefWithBody, FloatTy, Function, IntTy, Path, StructField, VariantDef,
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! ty_app {
|
macro_rules! ty_app {
|
||||||
|
@ -582,20 +582,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
|
fn resolve_into_iter_item(&self) -> Option<TypeAlias> {
|
||||||
let path = known::std_iter_into_iterator();
|
let path = known::std_iter_into_iterator();
|
||||||
let trait_: Trait = self.resolver.resolve_known_trait(self.db, &path)?.into();
|
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
|
||||||
trait_.associated_type_by_name(self.db, &name::ITEM_TYPE)
|
self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE).map(TypeAlias::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_ops_try_ok(&self) -> Option<TypeAlias> {
|
fn resolve_ops_try_ok(&self) -> Option<TypeAlias> {
|
||||||
let path = known::std_ops_try();
|
let path = known::std_ops_try();
|
||||||
let trait_: Trait = self.resolver.resolve_known_trait(self.db, &path)?.into();
|
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
|
||||||
trait_.associated_type_by_name(self.db, &name::OK_TYPE)
|
self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE).map(TypeAlias::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_future_future_output(&self) -> Option<TypeAlias> {
|
fn resolve_future_future_output(&self) -> Option<TypeAlias> {
|
||||||
let path = known::std_future_future();
|
let path = known::std_future_future();
|
||||||
let trait_: Trait = self.resolver.resolve_known_trait(self.db, &path)?.into();
|
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
|
||||||
trait_.associated_type_by_name(self.db, &name::OUTPUT_TYPE)
|
self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE).map(TypeAlias::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_boxed_box(&self) -> Option<AdtId> {
|
fn resolve_boxed_box(&self) -> Option<AdtId> {
|
||||||
|
|
|
@ -28,6 +28,7 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
ty::{
|
ty::{
|
||||||
primitive::{FloatTy, IntTy},
|
primitive::{FloatTy, IntTy},
|
||||||
|
utils::{all_super_traits, associated_type_by_name_including_super_traits},
|
||||||
Adt,
|
Adt,
|
||||||
},
|
},
|
||||||
util::make_mut_slice,
|
util::make_mut_slice,
|
||||||
|
@ -169,14 +170,16 @@ impl Ty {
|
||||||
);
|
);
|
||||||
return if remaining_segments.len() == 1 {
|
return if remaining_segments.len() == 1 {
|
||||||
let segment = &remaining_segments[0];
|
let segment = &remaining_segments[0];
|
||||||
match trait_ref
|
let associated_ty = associated_type_by_name_including_super_traits(
|
||||||
.trait_
|
db,
|
||||||
.associated_type_by_name_including_super_traits(db, &segment.name)
|
trait_ref.trait_.id,
|
||||||
{
|
&segment.name,
|
||||||
|
);
|
||||||
|
match associated_ty {
|
||||||
Some(associated_ty) => {
|
Some(associated_ty) => {
|
||||||
// FIXME handle type parameters on the segment
|
// FIXME handle type parameters on the segment
|
||||||
Ty::Projection(ProjectionTy {
|
Ty::Projection(ProjectionTy {
|
||||||
associated_ty: associated_ty.id,
|
associated_ty,
|
||||||
parameters: trait_ref.substs,
|
parameters: trait_ref.substs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -260,18 +263,16 @@ impl Ty {
|
||||||
GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_),
|
GenericPredicate::Implemented(tr) if tr.self_ty() == &self_ty => Some(tr.trait_),
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let traits = traits_from_env.flat_map(|t| t.all_super_traits(db));
|
let traits = traits_from_env.flat_map(|t| all_super_traits(db, t.id)).map(Trait::from);
|
||||||
for t in traits {
|
for t in traits {
|
||||||
if let Some(associated_ty) = t.associated_type_by_name(db, &segment.name) {
|
if let Some(associated_ty) = db.trait_data(t.id).associated_type_by_name(&segment.name)
|
||||||
|
{
|
||||||
let substs = Substs::build_for_def(db, t.id)
|
let substs = Substs::build_for_def(db, t.id)
|
||||||
.push(self_ty.clone())
|
.push(self_ty.clone())
|
||||||
.fill_with_unknown()
|
.fill_with_unknown()
|
||||||
.build();
|
.build();
|
||||||
// FIXME handle type parameters on the segment
|
// FIXME handle type parameters on the segment
|
||||||
return Ty::Projection(ProjectionTy {
|
return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
|
||||||
associated_ty: associated_ty.id,
|
|
||||||
parameters: substs,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ty::Unknown
|
Ty::Unknown
|
||||||
|
@ -509,10 +510,11 @@ fn assoc_type_bindings_from_type_bound<'a>(
|
||||||
.flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
|
.flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
|
||||||
.map(move |(name, type_ref)| {
|
.map(move |(name, type_ref)| {
|
||||||
let associated_ty =
|
let associated_ty =
|
||||||
match trait_ref.trait_.associated_type_by_name_including_super_traits(db, &name) {
|
associated_type_by_name_including_super_traits(db, trait_ref.trait_.id, &name);
|
||||||
None => return GenericPredicate::Error,
|
let associated_ty = match associated_ty {
|
||||||
Some(t) => t.id,
|
None => return GenericPredicate::Error,
|
||||||
};
|
Some(t) => t,
|
||||||
|
};
|
||||||
let projection_ty =
|
let projection_ty =
|
||||||
ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
|
ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
|
||||||
let ty = Ty::from_hir(db, resolver, type_ref);
|
let ty = Ty::from_hir(db, resolver, type_ref);
|
||||||
|
|
|
@ -16,7 +16,7 @@ use rustc_hash::FxHashMap;
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
ty::primitive::{FloatBitness, Uncertain},
|
ty::primitive::{FloatBitness, Uncertain},
|
||||||
ty::{Ty, TypeCtor},
|
ty::{utils::all_super_traits, Ty, TypeCtor},
|
||||||
AssocItem, Crate, Function, Mutability, Name, Trait,
|
AssocItem, Crate, Function, Mutability, Name, Trait,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -249,7 +249,8 @@ fn iterate_trait_method_candidates<T>(
|
||||||
let traits_from_env = env
|
let traits_from_env = env
|
||||||
.trait_predicates_for_self_ty(&ty.value)
|
.trait_predicates_for_self_ty(&ty.value)
|
||||||
.map(|tr| tr.trait_)
|
.map(|tr| tr.trait_)
|
||||||
.flat_map(|t| t.all_super_traits(db));
|
.flat_map(|t| all_super_traits(db, t.id))
|
||||||
|
.map(Trait::from);
|
||||||
let traits = inherent_trait
|
let traits = inherent_trait
|
||||||
.chain(traits_from_env)
|
.chain(traits_from_env)
|
||||||
.chain(resolver.traits_in_scope(db).into_iter().map(Trait::from));
|
.chain(resolver.traits_in_scope(db).into_iter().map(Trait::from));
|
||||||
|
@ -260,8 +261,8 @@ fn iterate_trait_method_candidates<T>(
|
||||||
// trait, but if we find out it doesn't, we'll skip the rest of the
|
// trait, but if we find out it doesn't, we'll skip the rest of the
|
||||||
// iteration
|
// iteration
|
||||||
let mut known_implemented = false;
|
let mut known_implemented = false;
|
||||||
for &item in data.items.iter() {
|
for (_name, item) in data.items.iter() {
|
||||||
if !is_valid_candidate(db, name, mode, item.into()) {
|
if !is_valid_candidate(db, name, mode, (*item).into()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !known_implemented {
|
if !known_implemented {
|
||||||
|
@ -271,7 +272,7 @@ fn iterate_trait_method_candidates<T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
known_implemented = true;
|
known_implemented = true;
|
||||||
if let Some(result) = callback(&ty.value, item.into()) {
|
if let Some(result) = callback(&ty.value, (*item).into()) {
|
||||||
return Some(result);
|
return Some(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use chalk_ir::{
|
||||||
};
|
};
|
||||||
use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
|
use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
|
||||||
|
|
||||||
use hir_def::{lang_item::LangItemTarget, ContainerId, GenericDefId, Lookup, TypeAliasId};
|
use hir_def::{lang_item::LangItemTarget, ContainerId, GenericDefId, Lookup, TraitId, TypeAliasId};
|
||||||
use hir_expand::name;
|
use hir_expand::name;
|
||||||
|
|
||||||
use ra_db::salsa::{InternId, InternKey};
|
use ra_db::salsa::{InternId, InternKey};
|
||||||
|
@ -459,7 +459,7 @@ where
|
||||||
[super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
|
[super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
|
||||||
{
|
{
|
||||||
if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
|
if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
|
||||||
if trait_ == actual_trait {
|
if trait_.id == actual_trait {
|
||||||
let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
|
let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
|
||||||
result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
|
result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
|
||||||
}
|
}
|
||||||
|
@ -661,6 +661,7 @@ fn impl_block_datum(
|
||||||
};
|
};
|
||||||
|
|
||||||
let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses };
|
let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses };
|
||||||
|
let trait_data = db.trait_data(trait_.id);
|
||||||
let associated_ty_value_ids = impl_block
|
let associated_ty_value_ids = impl_block
|
||||||
.items(db)
|
.items(db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -670,7 +671,7 @@ fn impl_block_datum(
|
||||||
})
|
})
|
||||||
.filter(|type_alias| {
|
.filter(|type_alias| {
|
||||||
// don't include associated types that don't exist in the trait
|
// don't include associated types that don't exist in the trait
|
||||||
trait_.associated_type_by_name(db, &type_alias.name(db)).is_some()
|
trait_data.associated_type_by_name(&type_alias.name(db)).is_some()
|
||||||
})
|
})
|
||||||
.map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db))
|
.map(|type_alias| AssocTyValue::TypeAlias(type_alias).to_chalk(db))
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -713,7 +714,7 @@ fn closure_fn_trait_impl_datum(
|
||||||
// and don't want to return a valid value only to find out later that FnOnce
|
// and don't want to return a valid value only to find out later that FnOnce
|
||||||
// is broken
|
// is broken
|
||||||
let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
|
let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
|
||||||
fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?;
|
let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?;
|
||||||
|
|
||||||
let num_args: u16 = match &db.body(data.def.into())[data.expr] {
|
let num_args: u16 = match &db.body(data.def.into())[data.expr] {
|
||||||
crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
|
crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
|
||||||
|
@ -735,8 +736,8 @@ fn closure_fn_trait_impl_datum(
|
||||||
let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
|
let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
|
||||||
|
|
||||||
let trait_ref = TraitRef {
|
let trait_ref = TraitRef {
|
||||||
trait_,
|
trait_: trait_.into(),
|
||||||
substs: Substs::build_for_def(db, trait_.id).push(self_ty).push(arg_ty).build(),
|
substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
|
let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
|
||||||
|
@ -783,10 +784,10 @@ fn type_alias_associated_ty_value(
|
||||||
.target_trait_ref(db)
|
.target_trait_ref(db)
|
||||||
.expect("assoc ty value should not exist") // we don't return any assoc ty values if the impl'd trait can't be resolved
|
.expect("assoc ty value should not exist") // we don't return any assoc ty values if the impl'd trait can't be resolved
|
||||||
.trait_;
|
.trait_;
|
||||||
let assoc_ty = trait_
|
let assoc_ty = db
|
||||||
.associated_type_by_name(db, &type_alias.name(db))
|
.trait_data(trait_.id)
|
||||||
.expect("assoc ty value should not exist") // validated when building the impl data as well
|
.associated_type_by_name(&type_alias.name(db))
|
||||||
.id;
|
.expect("assoc ty value should not exist"); // validated when building the impl data as well
|
||||||
let generic_params = db.generic_params(impl_block.id.into());
|
let generic_params = db.generic_params(impl_block.id.into());
|
||||||
let bound_vars = Substs::bound_vars(&generic_params);
|
let bound_vars = Substs::bound_vars(&generic_params);
|
||||||
let ty = db.type_for_def(type_alias.into(), crate::ty::Namespace::Types).subst(&bound_vars);
|
let ty = db.type_for_def(type_alias.into(), crate::ty::Namespace::Types).subst(&bound_vars);
|
||||||
|
@ -819,10 +820,10 @@ fn closure_fn_trait_output_assoc_ty_value(
|
||||||
let fn_once_trait =
|
let fn_once_trait =
|
||||||
get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
|
get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
|
||||||
|
|
||||||
let output_ty_id = fn_once_trait
|
let output_ty_id = db
|
||||||
.associated_type_by_name(db, &name::OUTPUT_TYPE)
|
.trait_data(fn_once_trait)
|
||||||
.expect("assoc ty value should not exist")
|
.associated_type_by_name(&name::OUTPUT_TYPE)
|
||||||
.id;
|
.expect("assoc ty value should not exist");
|
||||||
|
|
||||||
let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
|
let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
|
||||||
|
|
||||||
|
@ -834,10 +835,10 @@ fn closure_fn_trait_output_assoc_ty_value(
|
||||||
Arc::new(value)
|
Arc::new(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
|
fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<TraitId> {
|
||||||
let target = db.lang_item(krate.crate_id, fn_trait.lang_item_name().into())?;
|
let target = db.lang_item(krate.crate_id, fn_trait.lang_item_name().into())?;
|
||||||
match target {
|
match target {
|
||||||
LangItemTarget::TraitId(t) => Some(t.into()),
|
LangItemTarget::TraitId(t) => Some(t),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
63
crates/ra_hir/src/ty/utils.rs
Normal file
63
crates/ra_hir/src/ty/utils.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
//! Helper functions for working with def, which don't need to be a separate
|
||||||
|
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
|
||||||
|
|
||||||
|
use hir_def::{
|
||||||
|
db::DefDatabase,
|
||||||
|
resolver::{HasResolver, TypeNs},
|
||||||
|
type_ref::TypeRef,
|
||||||
|
TraitId, TypeAliasId,
|
||||||
|
};
|
||||||
|
use hir_expand::name::{self, Name};
|
||||||
|
|
||||||
|
// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
|
||||||
|
// We should return a `TraitREf` here.
|
||||||
|
fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
||||||
|
let resolver = trait_.resolver(db);
|
||||||
|
// returning the iterator directly doesn't easily work because of
|
||||||
|
// lifetime problems, but since there usually shouldn't be more than a
|
||||||
|
// few direct traits this should be fine (we could even use some kind of
|
||||||
|
// SmallVec if performance is a concern)
|
||||||
|
db.generic_params(trait_.into())
|
||||||
|
.where_predicates
|
||||||
|
.iter()
|
||||||
|
.filter_map(|pred| match &pred.type_ref {
|
||||||
|
TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
|
||||||
|
Some(TypeNs::TraitId(t)) => Some(t),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the whole super trait hierarchy (including the
|
||||||
|
/// trait itself).
|
||||||
|
pub(crate) fn all_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
|
||||||
|
// we need to take care a bit here to avoid infinite loops in case of cycles
|
||||||
|
// (i.e. if we have `trait A: B; trait B: A;`)
|
||||||
|
let mut result = vec![trait_];
|
||||||
|
let mut i = 0;
|
||||||
|
while i < result.len() {
|
||||||
|
let t = result[i];
|
||||||
|
// yeah this is quadratic, but trait hierarchies should be flat
|
||||||
|
// enough that this doesn't matter
|
||||||
|
for tt in direct_super_traits(db, t) {
|
||||||
|
if !result.contains(&tt) {
|
||||||
|
result.push(tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn associated_type_by_name_including_super_traits(
|
||||||
|
db: &impl DefDatabase,
|
||||||
|
trait_: TraitId,
|
||||||
|
name: &Name,
|
||||||
|
) -> Option<TypeAliasId> {
|
||||||
|
all_super_traits(db, trait_)
|
||||||
|
.into_iter()
|
||||||
|
.find_map(|t| db.trait_data(t).associated_type_by_name(name))
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ impl TypeAliasData {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct TraitData {
|
pub struct TraitData {
|
||||||
pub name: Option<Name>,
|
pub name: Option<Name>,
|
||||||
pub items: Vec<AssocItemId>,
|
pub items: Vec<(Name, AssocItemId)>,
|
||||||
pub auto: bool,
|
pub auto: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,28 +97,42 @@ impl TraitData {
|
||||||
let name = src.value.name().map(|n| n.as_name());
|
let name = src.value.name().map(|n| n.as_name());
|
||||||
let auto = src.value.is_auto();
|
let auto = src.value.is_auto();
|
||||||
let ast_id_map = db.ast_id_map(src.file_id);
|
let ast_id_map = db.ast_id_map(src.file_id);
|
||||||
|
|
||||||
|
let container = ContainerId::TraitId(tr);
|
||||||
let items = if let Some(item_list) = src.value.item_list() {
|
let items = if let Some(item_list) = src.value.item_list() {
|
||||||
item_list
|
item_list
|
||||||
.impl_items()
|
.impl_items()
|
||||||
.map(|item_node| match item_node {
|
.map(|item_node| match item_node {
|
||||||
ast::ImplItem::FnDef(it) => FunctionLoc {
|
ast::ImplItem::FnDef(it) => {
|
||||||
container: ContainerId::TraitId(tr),
|
let name = it.name().map(|it| it.as_name()).unwrap_or_else(Name::missing);
|
||||||
ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
|
let def = FunctionLoc {
|
||||||
|
container,
|
||||||
|
ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
|
||||||
|
}
|
||||||
|
.intern(db)
|
||||||
|
.into();
|
||||||
|
(name, def)
|
||||||
}
|
}
|
||||||
.intern(db)
|
ast::ImplItem::ConstDef(it) => {
|
||||||
.into(),
|
let name = it.name().map(|it| it.as_name()).unwrap_or_else(Name::missing);
|
||||||
ast::ImplItem::ConstDef(it) => ConstLoc {
|
let def = ConstLoc {
|
||||||
container: ContainerId::TraitId(tr),
|
container,
|
||||||
ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
|
ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
|
||||||
|
}
|
||||||
|
.intern(db)
|
||||||
|
.into();
|
||||||
|
(name, def)
|
||||||
}
|
}
|
||||||
.intern(db)
|
ast::ImplItem::TypeAliasDef(it) => {
|
||||||
.into(),
|
let name = it.name().map(|it| it.as_name()).unwrap_or_else(Name::missing);
|
||||||
ast::ImplItem::TypeAliasDef(it) => TypeAliasLoc {
|
let def = TypeAliasLoc {
|
||||||
container: ContainerId::TraitId(tr),
|
container,
|
||||||
ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
|
ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)),
|
||||||
|
}
|
||||||
|
.intern(db)
|
||||||
|
.into();
|
||||||
|
(name, def)
|
||||||
}
|
}
|
||||||
.intern(db)
|
|
||||||
.into(),
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
|
@ -128,11 +142,18 @@ impl TraitData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
|
pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
|
||||||
self.items.iter().filter_map(|item| match item {
|
self.items.iter().filter_map(|(_name, item)| match item {
|
||||||
AssocItemId::TypeAliasId(t) => Some(*t),
|
AssocItemId::TypeAliasId(t) => Some(*t),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn associated_type_by_name(&self, name: &Name) -> Option<TypeAliasId> {
|
||||||
|
self.items.iter().find_map(|(item_name, item)| match item {
|
||||||
|
AssocItemId::TypeAliasId(t) if item_name == name => Some(*t),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|
Loading…
Reference in a new issue