4900: Self variant enum res fix r=BGluth a=BGluth

Fixes #4789.

This is my first PR for this project, so it's probably worth giving it an extra close look.

A few things that I wasn't sure about:
- Is `resolve_path` really the best place to perform this check? It seemed like a natural place, but perhaps there's a better place?
- When handling the new variant `PathResolution::VariantDef`, I couldn't see an obvious variant of `TypeNs` to return in `in_type_ns` for Unions and Structs.

Co-authored-by: BGluth <gluthb@gmail.com>
This commit is contained in:
bors[bot] 2020-06-22 14:37:45 +00:00 committed by GitHub
commit 87615166af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 0 deletions

View File

@ -216,13 +216,43 @@ pub(crate) fn resolve_path(
if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
return Some(PathResolution::AssocItem(assoc.into()));
}
if let Some(VariantId::EnumVariantId(variant)) =
self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
{
return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
}
}
if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
let pat_id = self.pat_id(&path_pat.into())?;
if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
return Some(PathResolution::AssocItem(assoc.into()));
}
if let Some(VariantId::EnumVariantId(variant)) =
self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
{
return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
}
}
if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordLit::cast) {
let expr_id = self.expr_id(db, &rec_lit.into())?;
if let Some(VariantId::EnumVariantId(variant)) =
self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
{
return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
}
}
if let Some(rec_pat) = path.syntax().parent().and_then(ast::RecordPat::cast) {
let pat_id = self.pat_id(&rec_pat.into())?;
if let Some(VariantId::EnumVariantId(variant)) =
self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
{
return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
}
}
// This must be a normal source file rather than macro file.
let hir_path =
crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;

View File

@ -908,4 +908,84 @@ fn baz(foo: Foo) {
"x: i32|x",
);
}
#[test]
fn goto_def_for_enum_variant_self_pattern_const() {
check_goto(
"
//- /lib.rs
enum Foo {
Bar,
}
impl Foo {
fn baz(self) {
match self {
Self::Bar<|> => {}
}
}
}
",
"Bar ENUM_VARIANT FileId(1) 15..18 15..18",
"Bar|Bar",
);
}
#[test]
fn goto_def_for_enum_variant_self_pattern_record() {
check_goto(
"
//- /lib.rs
enum Foo {
Bar { val: i32 },
}
impl Foo {
fn baz(self) -> i32 {
match self {
Self::Bar<|> { val } => {}
}
}
}
",
"Bar ENUM_VARIANT FileId(1) 15..31 15..18",
"Bar { val: i32 }|Bar",
);
}
#[test]
fn goto_def_for_enum_variant_self_expr_const() {
check_goto(
"
//- /lib.rs
enum Foo {
Bar,
}
impl Foo {
fn baz(self) {
Self::Bar<|>;
}
}
",
"Bar ENUM_VARIANT FileId(1) 15..18 15..18",
"Bar|Bar",
);
}
#[test]
fn goto_def_for_enum_variant_self_expr_record() {
check_goto(
"
//- /lib.rs
enum Foo {
Bar { val: i32 },
}
impl Foo {
fn baz(self) {
Self::Bar<|> {val: 4};
}
}
",
"Bar ENUM_VARIANT FileId(1) 15..31 15..18",
"Bar { val: i32 }|Bar",
);
}
}