mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Complete assoc. items on type parameters
This commit is contained in:
parent
4ff3573e18
commit
8c2670026a
5 changed files with 408 additions and 69 deletions
|
@ -953,6 +953,16 @@ impl TypeParam {
|
||||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||||
self.id.parent.module(db.upcast()).into()
|
self.id.parent.module(db.upcast()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ty(self, db: &dyn HirDatabase) -> Type {
|
||||||
|
let resolver = self.id.parent.resolver(db.upcast());
|
||||||
|
let environment = TraitEnvironment::lower(db, &resolver);
|
||||||
|
let ty = Ty::Placeholder(self.id);
|
||||||
|
Type {
|
||||||
|
krate: self.id.parent.module(db.upcast()).krate,
|
||||||
|
ty: InEnvironment { value: ty, environment },
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: rename from `ImplDef` to `Impl`
|
// FIXME: rename from `ImplDef` to `Impl`
|
||||||
|
|
|
@ -9,6 +9,7 @@ use hir_def::{
|
||||||
AsMacroCall, TraitId,
|
AsMacroCall, TraitId,
|
||||||
};
|
};
|
||||||
use hir_expand::ExpansionInfo;
|
use hir_expand::ExpansionInfo;
|
||||||
|
use hir_ty::associated_types;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ra_db::{FileId, FileRange};
|
use ra_db::{FileId, FileRange};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
|
@ -24,8 +25,9 @@ use crate::{
|
||||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||||
AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef,
|
AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef,
|
||||||
Name, Origin, Path, ScopeDef, Trait, Type, TypeParam,
|
Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
|
||||||
};
|
};
|
||||||
|
use resolver::TypeNs;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum PathResolution {
|
pub enum PathResolution {
|
||||||
|
@ -40,6 +42,49 @@ pub enum PathResolution {
|
||||||
AssocItem(AssocItem),
|
AssocItem(AssocItem),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PathResolution {
|
||||||
|
fn in_type_ns(self) -> Option<TypeNs> {
|
||||||
|
match self {
|
||||||
|
PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId(adt.into())),
|
||||||
|
PathResolution::Def(ModuleDef::BuiltinType(builtin)) => {
|
||||||
|
Some(TypeNs::BuiltinType(builtin))
|
||||||
|
}
|
||||||
|
PathResolution::Def(ModuleDef::Const(_)) => None,
|
||||||
|
PathResolution::Def(ModuleDef::EnumVariant(_)) => None,
|
||||||
|
PathResolution::Def(ModuleDef::Function(_)) => None,
|
||||||
|
PathResolution::Def(ModuleDef::Module(_)) => None,
|
||||||
|
PathResolution::Def(ModuleDef::Static(_)) => None,
|
||||||
|
PathResolution::Def(ModuleDef::Trait(_)) => None,
|
||||||
|
PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
|
||||||
|
Some(TypeNs::TypeAliasId(alias.into()))
|
||||||
|
}
|
||||||
|
PathResolution::Local(_) => None,
|
||||||
|
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam(param.into())),
|
||||||
|
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType(impl_def.into())),
|
||||||
|
PathResolution::Macro(_) => None,
|
||||||
|
PathResolution::AssocItem(AssocItem::Const(_)) => None,
|
||||||
|
PathResolution::AssocItem(AssocItem::Function(_)) => None,
|
||||||
|
PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
|
||||||
|
Some(TypeNs::TypeAliasId(alias.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over associated types that may be specified after this path (using
|
||||||
|
/// `Ty::Assoc` syntax).
|
||||||
|
pub fn assoc_type_shorthand_candidates<R>(
|
||||||
|
&self,
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
mut cb: impl FnMut(TypeAlias) -> Option<R>,
|
||||||
|
) -> Option<R> {
|
||||||
|
if let Some(res) = self.clone().in_type_ns() {
|
||||||
|
associated_types(db, res, |_, _, id| cb(id.into()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Primary API to get semantic information, like types, from syntax trees.
|
/// Primary API to get semantic information, like types, from syntax trees.
|
||||||
pub struct Semantics<'db, DB> {
|
pub struct Semantics<'db, DB> {
|
||||||
pub db: &'db DB,
|
pub db: &'db DB,
|
||||||
|
|
|
@ -66,7 +66,8 @@ pub use autoderef::autoderef;
|
||||||
pub use infer::{InferTy, InferenceResult};
|
pub use infer::{InferTy, InferenceResult};
|
||||||
pub use lower::CallableDef;
|
pub use lower::CallableDef;
|
||||||
pub use lower::{
|
pub use lower::{
|
||||||
callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId,
|
associated_types, callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext,
|
||||||
|
ValueTyDefId,
|
||||||
};
|
};
|
||||||
pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
|
pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@ use hir_def::{
|
||||||
path::{GenericArg, Path, PathSegment, PathSegments},
|
path::{GenericArg, Path, PathSegment, PathSegments},
|
||||||
resolver::{HasResolver, Resolver, TypeNs},
|
resolver::{HasResolver, Resolver, TypeNs},
|
||||||
type_ref::{TypeBound, TypeRef},
|
type_ref::{TypeBound, TypeRef},
|
||||||
AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule,
|
AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId,
|
||||||
ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
|
HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
|
||||||
VariantId,
|
UnionId, VariantId,
|
||||||
};
|
};
|
||||||
use ra_arena::map::ArenaMap;
|
use ra_arena::map::ArenaMap;
|
||||||
use ra_db::CrateId;
|
use ra_db::CrateId;
|
||||||
|
@ -34,6 +34,7 @@ use crate::{
|
||||||
Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
|
Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
|
||||||
ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
|
ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
|
||||||
};
|
};
|
||||||
|
use hir_expand::name::Name;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TyLoweringContext<'a> {
|
pub struct TyLoweringContext<'a> {
|
||||||
|
@ -383,61 +384,37 @@ impl Ty {
|
||||||
res: Option<TypeNs>,
|
res: Option<TypeNs>,
|
||||||
segment: PathSegment<'_>,
|
segment: PathSegment<'_>,
|
||||||
) -> Ty {
|
) -> Ty {
|
||||||
let traits_from_env: Vec<_> = match res {
|
if let Some(res) = res {
|
||||||
Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) {
|
let ty = associated_types(ctx.db, res, move |name, t, associated_ty| {
|
||||||
None => return Ty::Unknown,
|
if name == segment.name {
|
||||||
Some(trait_ref) => vec![trait_ref.value],
|
let substs = match ctx.type_param_mode {
|
||||||
},
|
TypeParamLoweringMode::Placeholder => {
|
||||||
Some(TypeNs::GenericParam(param_id)) => {
|
// if we're lowering to placeholders, we have to put
|
||||||
let predicates = ctx.db.generic_predicates_for_param(param_id);
|
// them in now
|
||||||
let mut traits_: Vec<_> = predicates
|
let s = Substs::type_params(
|
||||||
.iter()
|
ctx.db,
|
||||||
.filter_map(|pred| match &pred.value {
|
ctx.resolver
|
||||||
GenericPredicate::Implemented(tr) => Some(tr.clone()),
|
.generic_def()
|
||||||
_ => None,
|
.expect("there should be generics if there's a generic param"),
|
||||||
})
|
);
|
||||||
.collect();
|
t.substs.clone().subst_bound_vars(&s)
|
||||||
// Handle `Self::Type` referring to own associated type in trait definitions
|
}
|
||||||
if let GenericDefId::TraitId(trait_id) = param_id.parent {
|
TypeParamLoweringMode::Variable => t.substs.clone(),
|
||||||
let generics = generics(ctx.db.upcast(), trait_id.into());
|
};
|
||||||
if generics.params.types[param_id.local_id].provenance
|
// FIXME handle type parameters on the segment
|
||||||
== TypeParamProvenance::TraitSelf
|
return Some(Ty::Projection(ProjectionTy {
|
||||||
{
|
associated_ty,
|
||||||
let trait_ref = TraitRef {
|
parameters: substs,
|
||||||
trait_: trait_id,
|
}));
|
||||||
substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
|
|
||||||
};
|
|
||||||
traits_.push(trait_ref);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
traits_
|
|
||||||
}
|
None
|
||||||
_ => return Ty::Unknown,
|
});
|
||||||
};
|
|
||||||
let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t));
|
ty.unwrap_or(Ty::Unknown)
|
||||||
for t in traits {
|
} else {
|
||||||
if let Some(associated_ty) =
|
Ty::Unknown
|
||||||
ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name)
|
|
||||||
{
|
|
||||||
let substs = match ctx.type_param_mode {
|
|
||||||
TypeParamLoweringMode::Placeholder => {
|
|
||||||
// if we're lowering to placeholders, we have to put
|
|
||||||
// them in now
|
|
||||||
let s = Substs::type_params(
|
|
||||||
ctx.db,
|
|
||||||
ctx.resolver
|
|
||||||
.generic_def()
|
|
||||||
.expect("there should be generics if there's a generic param"),
|
|
||||||
);
|
|
||||||
t.substs.subst_bound_vars(&s)
|
|
||||||
}
|
|
||||||
TypeParamLoweringMode::Variable => t.substs,
|
|
||||||
};
|
|
||||||
// FIXME handle (forbid) type parameters on the segment
|
|
||||||
return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ty::Unknown
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_hir_path_inner(
|
fn from_hir_path_inner(
|
||||||
|
@ -694,6 +671,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn associated_types<R>(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
|
res: TypeNs,
|
||||||
|
mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
|
||||||
|
) -> Option<R> {
|
||||||
|
let traits_from_env: Vec<_> = match res {
|
||||||
|
TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) {
|
||||||
|
None => vec![],
|
||||||
|
Some(trait_ref) => vec![trait_ref.value],
|
||||||
|
},
|
||||||
|
TypeNs::GenericParam(param_id) => {
|
||||||
|
let predicates = db.generic_predicates_for_param(param_id);
|
||||||
|
let mut traits_: Vec<_> = predicates
|
||||||
|
.iter()
|
||||||
|
.filter_map(|pred| match &pred.value {
|
||||||
|
GenericPredicate::Implemented(tr) => Some(tr.clone()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
// Handle `Self::Type` referring to own associated type in trait definitions
|
||||||
|
if let GenericDefId::TraitId(trait_id) = param_id.parent {
|
||||||
|
let generics = generics(db.upcast(), trait_id.into());
|
||||||
|
if generics.params.types[param_id.local_id].provenance
|
||||||
|
== TypeParamProvenance::TraitSelf
|
||||||
|
{
|
||||||
|
let trait_ref = TraitRef {
|
||||||
|
trait_: trait_id,
|
||||||
|
substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
|
||||||
|
};
|
||||||
|
traits_.push(trait_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
traits_
|
||||||
|
}
|
||||||
|
_ => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
|
||||||
|
let data = db.trait_data(t.trait_);
|
||||||
|
|
||||||
|
for (name, assoc_id) in &data.items {
|
||||||
|
match assoc_id {
|
||||||
|
AssocItemId::TypeAliasId(alias) => {
|
||||||
|
if let Some(result) = cb(name, &t, *alias) {
|
||||||
|
return Some(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Build the type of all specific fields of a struct or enum variant.
|
/// Build the type of all specific fields of a struct or enum variant.
|
||||||
pub(crate) fn field_types_query(
|
pub(crate) fn field_types_query(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
|
|
|
@ -5,19 +5,30 @@ use ra_syntax::AstNode;
|
||||||
use test_utils::tested_by;
|
use test_utils::tested_by;
|
||||||
|
|
||||||
use crate::completion::{CompletionContext, Completions};
|
use crate::completion::{CompletionContext, Completions};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
|
pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
let path = match &ctx.path_prefix {
|
let path = match &ctx.path_prefix {
|
||||||
Some(path) => path.clone(),
|
Some(path) => path.clone(),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
let def = match ctx.scope().resolve_hir_path(&path) {
|
let scope = ctx.scope();
|
||||||
Some(PathResolution::Def(def)) => def,
|
let context_module = scope.module();
|
||||||
_ => return,
|
|
||||||
|
let res = if let Some(res) = scope.resolve_hir_path(&path) {
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
let context_module = ctx.scope().module();
|
|
||||||
match def {
|
// Add associated types on type parameters and `Self`.
|
||||||
hir::ModuleDef::Module(module) => {
|
res.assoc_type_shorthand_candidates(ctx.db, |alias| {
|
||||||
|
acc.add_type_alias(ctx, alias);
|
||||||
|
None::<()>
|
||||||
|
});
|
||||||
|
|
||||||
|
match res {
|
||||||
|
PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
||||||
let module_scope = module.scope(ctx.db, context_module);
|
let module_scope = module.scope(ctx.db, context_module);
|
||||||
for (name, def) in module_scope {
|
for (name, def) in module_scope {
|
||||||
if ctx.use_item_syntax.is_some() {
|
if ctx.use_item_syntax.is_some() {
|
||||||
|
@ -35,7 +46,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
acc.add_resolution(ctx, name.to_string(), &def);
|
acc.add_resolution(ctx, name.to_string(), &def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => {
|
PathResolution::Def(def @ hir::ModuleDef::Adt(_))
|
||||||
|
| PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) => {
|
||||||
if let hir::ModuleDef::Adt(Adt::Enum(e)) = def {
|
if let hir::ModuleDef::Adt(Adt::Enum(e)) = def {
|
||||||
for variant in e.variants(ctx.db) {
|
for variant in e.variants(ctx.db) {
|
||||||
acc.add_enum_variant(ctx, variant, None);
|
acc.add_enum_variant(ctx, variant, None);
|
||||||
|
@ -46,8 +58,10 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
|
hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
// Iterate assoc types separately
|
|
||||||
// FIXME: complete T::AssocType
|
// XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
|
||||||
|
// (where AssocType is defined on a trait, not an inherent impl)
|
||||||
|
|
||||||
let krate = ctx.krate;
|
let krate = ctx.krate;
|
||||||
if let Some(krate) = krate {
|
if let Some(krate) = krate {
|
||||||
let traits_in_scope = ctx.scope().traits_in_scope();
|
let traits_in_scope = ctx.scope().traits_in_scope();
|
||||||
|
@ -65,6 +79,7 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
None::<()>
|
None::<()>
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Iterate assoc types separately
|
||||||
ty.iterate_impl_items(ctx.db, krate, |item| {
|
ty.iterate_impl_items(ctx.db, krate, |item| {
|
||||||
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
||||||
return None;
|
return None;
|
||||||
|
@ -77,7 +92,8 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ModuleDef::Trait(t) => {
|
PathResolution::Def(hir::ModuleDef::Trait(t)) => {
|
||||||
|
// Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
|
||||||
for item in t.items(ctx.db) {
|
for item in t.items(ctx.db) {
|
||||||
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -91,8 +107,38 @@ pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
PathResolution::TypeParam(_) | PathResolution::SelfType(_) => {
|
||||||
|
if let Some(krate) = ctx.krate {
|
||||||
|
let ty = match res {
|
||||||
|
PathResolution::TypeParam(param) => param.ty(ctx.db),
|
||||||
|
PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let traits_in_scope = ctx.scope().traits_in_scope();
|
||||||
|
let mut seen = FxHashSet::default();
|
||||||
|
ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
|
||||||
|
if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We might iterate candidates of a trait multiple times here, so deduplicate
|
||||||
|
// them.
|
||||||
|
if seen.insert(item) {
|
||||||
|
match item {
|
||||||
|
hir::AssocItem::Function(func) => {
|
||||||
|
acc.add_function(ctx, func, None);
|
||||||
|
}
|
||||||
|
hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
|
||||||
|
hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None::<()>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -843,6 +889,211 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_ty_param_assoc_ty() {
|
||||||
|
assert_debug_snapshot!(
|
||||||
|
do_reference_completion(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
trait Super {
|
||||||
|
type Ty;
|
||||||
|
const CONST: u8;
|
||||||
|
fn func() {}
|
||||||
|
fn method(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Sub: Super {
|
||||||
|
type SubTy;
|
||||||
|
const C2: ();
|
||||||
|
fn subfunc() {}
|
||||||
|
fn submethod(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<T: Sub>() {
|
||||||
|
T::<|>
|
||||||
|
}
|
||||||
|
"
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "C2",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "C2",
|
||||||
|
kind: Const,
|
||||||
|
detail: "const C2: ();",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "CONST",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "CONST",
|
||||||
|
kind: Const,
|
||||||
|
detail: "const CONST: u8;",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "SubTy",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "SubTy",
|
||||||
|
kind: TypeAlias,
|
||||||
|
detail: "type SubTy;",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "Ty",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "Ty",
|
||||||
|
kind: TypeAlias,
|
||||||
|
detail: "type Ty;",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "func()",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "func()$0",
|
||||||
|
kind: Function,
|
||||||
|
lookup: "func",
|
||||||
|
detail: "fn func()",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "method()",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "method()$0",
|
||||||
|
kind: Method,
|
||||||
|
lookup: "method",
|
||||||
|
detail: "fn method(&self)",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "subfunc()",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "subfunc()$0",
|
||||||
|
kind: Function,
|
||||||
|
lookup: "subfunc",
|
||||||
|
detail: "fn subfunc()",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "submethod()",
|
||||||
|
source_range: 219..219,
|
||||||
|
delete: 219..219,
|
||||||
|
insert: "submethod()$0",
|
||||||
|
kind: Method,
|
||||||
|
lookup: "submethod",
|
||||||
|
detail: "fn submethod(&self)",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completes_self_param_assoc_ty() {
|
||||||
|
assert_debug_snapshot!(
|
||||||
|
do_reference_completion(
|
||||||
|
"
|
||||||
|
//- /lib.rs
|
||||||
|
trait Super {
|
||||||
|
type Ty;
|
||||||
|
const CONST: u8 = 0;
|
||||||
|
fn func() {}
|
||||||
|
fn method(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Sub: Super {
|
||||||
|
type SubTy;
|
||||||
|
const C2: () = ();
|
||||||
|
fn subfunc() {}
|
||||||
|
fn submethod(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Wrap<T>(T);
|
||||||
|
impl<T> Super for Wrap<T> {}
|
||||||
|
impl<T> Sub for Wrap<T> {
|
||||||
|
fn subfunc() {
|
||||||
|
// Should be able to assume `Self: Sub + Super`
|
||||||
|
Self::<|>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "C2",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "C2",
|
||||||
|
kind: Const,
|
||||||
|
detail: "const C2: () = ();",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "CONST",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "CONST",
|
||||||
|
kind: Const,
|
||||||
|
detail: "const CONST: u8 = 0;",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "SubTy",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "SubTy",
|
||||||
|
kind: TypeAlias,
|
||||||
|
detail: "type SubTy;",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "Ty",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "Ty",
|
||||||
|
kind: TypeAlias,
|
||||||
|
detail: "type Ty;",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "func()",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "func()$0",
|
||||||
|
kind: Function,
|
||||||
|
lookup: "func",
|
||||||
|
detail: "fn func()",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "method()",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "method()$0",
|
||||||
|
kind: Method,
|
||||||
|
lookup: "method",
|
||||||
|
detail: "fn method(&self)",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "subfunc()",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "subfunc()$0",
|
||||||
|
kind: Function,
|
||||||
|
lookup: "subfunc",
|
||||||
|
detail: "fn subfunc()",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "submethod()",
|
||||||
|
source_range: 365..365,
|
||||||
|
delete: 365..365,
|
||||||
|
insert: "submethod()$0",
|
||||||
|
kind: Method,
|
||||||
|
lookup: "submethod",
|
||||||
|
detail: "fn submethod(&self)",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_type_alias() {
|
fn completes_type_alias() {
|
||||||
assert_debug_snapshot!(
|
assert_debug_snapshot!(
|
||||||
|
|
Loading…
Reference in a new issue