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:
bors[bot] 2019-10-08 11:46:14 +00:00 committed by GitHub
commit 92cf0eba93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 81 additions and 9 deletions

View file

@ -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()))
}
}

View file

@ -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| {

View file

@ -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()),

View file

@ -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(),

View file

@ -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) => {

View file

@ -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(

View file

@ -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!(

View file

@ -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,
),