mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 01:17:27 +00:00
Merge #1924
1924: Support inferring&completing `Self` type in enum/struct/union definitions r=ice1000 a=ice1000 Signed-off-by: ice1000 <ice1000kotlin@foxmail.com> An attempt to fix #1908. This code works, but I believe the implementation is ugly. Please give me suggestions! Co-authored-by: ice1000 <ice1000kotlin@foxmail.com>
This commit is contained in:
commit
92cf0eba93
8 changed files with 81 additions and 9 deletions
|
@ -24,7 +24,7 @@ use crate::{
|
|||
U8, USIZE,
|
||||
},
|
||||
nameres::{CrateModuleId, ImportId, ModuleScope, Namespace},
|
||||
resolve::{Resolver, TypeNs},
|
||||
resolve::{Resolver, Scope, TypeNs},
|
||||
traits::TraitData,
|
||||
ty::{
|
||||
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
|
||||
|
@ -465,7 +465,7 @@ impl Enum {
|
|||
// ...and add generic params, if present
|
||||
let p = self.generic_params(db);
|
||||
let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
|
||||
r
|
||||
r.push_scope(Scope::AdtScope(self.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,10 @@ pub(crate) enum Scope {
|
|||
ModuleScope(ModuleItemMap),
|
||||
/// Brings the generic parameters of an item into scope
|
||||
GenericParams(Arc<GenericParams>),
|
||||
/// Brings `Self` into scope
|
||||
/// Brings `Self` in `impl` block into scope
|
||||
ImplBlockScope(ImplBlock),
|
||||
/// Brings `Self` in enum, struct and union definitions into scope
|
||||
AdtScope(Adt),
|
||||
/// Local bindings
|
||||
ExprScope(ExprScope),
|
||||
}
|
||||
|
@ -54,6 +56,7 @@ pub enum TypeNs {
|
|||
SelfType(ImplBlock),
|
||||
GenericParam(u32),
|
||||
Adt(Adt),
|
||||
AdtSelfType(Adt),
|
||||
EnumVariant(EnumVariant),
|
||||
TypeAlias(TypeAlias),
|
||||
BuiltinType(BuiltinType),
|
||||
|
@ -151,6 +154,12 @@ impl Resolver {
|
|||
return Some((TypeNs::SelfType(*impl_), idx));
|
||||
}
|
||||
}
|
||||
Scope::AdtScope(adt) => {
|
||||
if first_name == &SELF_TYPE {
|
||||
let idx = if path.segments.len() == 1 { None } else { Some(1) };
|
||||
return Some((TypeNs::AdtSelfType(*adt), idx));
|
||||
}
|
||||
}
|
||||
Scope::ModuleScope(m) => {
|
||||
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
|
||||
let res = match module_def.take_types()? {
|
||||
|
@ -200,7 +209,10 @@ impl Resolver {
|
|||
let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
|
||||
for scope in self.scopes.iter().rev() {
|
||||
match scope {
|
||||
Scope::ExprScope(_) | Scope::GenericParams(_) | Scope::ImplBlockScope(_)
|
||||
Scope::AdtScope(_)
|
||||
| Scope::ExprScope(_)
|
||||
| Scope::GenericParams(_)
|
||||
| Scope::ImplBlockScope(_)
|
||||
if skip_to_mod =>
|
||||
{
|
||||
continue
|
||||
|
@ -233,7 +245,13 @@ impl Resolver {
|
|||
return Some(ResolveValueResult::Partial(ty, 1));
|
||||
}
|
||||
}
|
||||
Scope::ImplBlockScope(_) => continue,
|
||||
Scope::AdtScope(adt) if n_segments > 1 => {
|
||||
if first_name == &SELF_TYPE {
|
||||
let ty = TypeNs::AdtSelfType(*adt);
|
||||
return Some(ResolveValueResult::Partial(ty, 1));
|
||||
}
|
||||
}
|
||||
Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue,
|
||||
|
||||
Scope::ModuleScope(m) => {
|
||||
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
|
||||
|
@ -389,7 +407,8 @@ pub enum ScopeDef {
|
|||
ModuleDef(ModuleDef),
|
||||
MacroDef(MacroDef),
|
||||
GenericParam(u32),
|
||||
SelfType(ImplBlock),
|
||||
ImplSelfType(ImplBlock),
|
||||
AdtSelfType(Adt),
|
||||
LocalBinding(PatId),
|
||||
Unknown,
|
||||
}
|
||||
|
@ -437,7 +456,10 @@ impl Scope {
|
|||
}
|
||||
}
|
||||
Scope::ImplBlockScope(i) => {
|
||||
f(SELF_TYPE, ScopeDef::SelfType(*i));
|
||||
f(SELF_TYPE, ScopeDef::ImplSelfType(*i));
|
||||
}
|
||||
Scope::AdtScope(i) => {
|
||||
f(SELF_TYPE, ScopeDef::AdtSelfType(*i));
|
||||
}
|
||||
Scope::ExprScope(e) => {
|
||||
e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
|
||||
|
|
|
@ -216,7 +216,7 @@ impl SourceAnalyzer {
|
|||
let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty {
|
||||
TypeNs::SelfType(it) => PathResolution::SelfType(it),
|
||||
TypeNs::GenericParam(it) => PathResolution::GenericParam(it),
|
||||
TypeNs::Adt(it) => PathResolution::Def(it.into()),
|
||||
TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()),
|
||||
TypeNs::EnumVariant(it) => PathResolution::Def(it.into()),
|
||||
TypeNs::TypeAlias(it) => PathResolution::Def(it.into()),
|
||||
TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
|
||||
|
|
|
@ -559,6 +559,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
match resolver.resolve_path_in_type_ns_fully(self.db, &path) {
|
||||
Some(TypeNs::Adt(Adt::Struct(it))) => it.into(),
|
||||
Some(TypeNs::Adt(Adt::Union(it))) => it.into(),
|
||||
Some(TypeNs::AdtSelfType(adt)) => adt.into(),
|
||||
Some(TypeNs::EnumVariant(it)) => it.into(),
|
||||
Some(TypeNs::TypeAlias(it)) => it.into(),
|
||||
|
||||
|
|
|
@ -175,6 +175,7 @@ impl Ty {
|
|||
Ty::Param { idx, name }
|
||||
}
|
||||
TypeNs::SelfType(impl_block) => impl_block.target_ty(db),
|
||||
TypeNs::AdtSelfType(adt) => adt.ty(db),
|
||||
|
||||
TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()),
|
||||
TypeNs::BuiltinType(it) => {
|
||||
|
|
|
@ -134,6 +134,25 @@ mod boxed {
|
|||
assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_adt_self() {
|
||||
let (db, pos) = MockDatabase::with_position(
|
||||
r#"
|
||||
//- /main.rs
|
||||
enum Nat { Succ(Self), Demo(Nat), Zero }
|
||||
|
||||
fn test() {
|
||||
let foo: Nat = Nat::Zero;
|
||||
if let Nat::Succ(x) = foo {
|
||||
x<|>
|
||||
}
|
||||
}
|
||||
|
||||
"#,
|
||||
);
|
||||
assert_eq!("Nat", type_at_pos(&db, pos));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_try() {
|
||||
let (mut db, pos) = MockDatabase::with_position(
|
||||
|
|
|
@ -309,6 +309,35 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_self_in_enum() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
r"
|
||||
enum X {
|
||||
Y(<|>)
|
||||
}
|
||||
"
|
||||
),
|
||||
@r###"[
|
||||
CompletionItem {
|
||||
label: "Self",
|
||||
source_range: [48; 48),
|
||||
delete: [48; 48),
|
||||
insert: "Self",
|
||||
kind: TypeParam,
|
||||
},
|
||||
CompletionItem {
|
||||
label: "X",
|
||||
source_range: [48; 48),
|
||||
delete: [48; 48),
|
||||
insert: "X",
|
||||
kind: Enum,
|
||||
},
|
||||
]"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_module_items() {
|
||||
assert_debug_snapshot!(
|
||||
|
|
|
@ -72,7 +72,7 @@ impl Completions {
|
|||
}
|
||||
ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None),
|
||||
ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None),
|
||||
ScopeDef::SelfType(..) => (
|
||||
ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => (
|
||||
CompletionItemKind::TypeParam, // (does this need its own kind?)
|
||||
None,
|
||||
),
|
||||
|
|
Loading…
Reference in a new issue