internal: Handle fields called as method calls as the fields they resolve to

This commit is contained in:
Lukas Wirth 2023-03-04 20:33:28 +01:00
parent b85e2af898
commit 5a91f015b4
4 changed files with 63 additions and 4 deletions

View File

@ -12,7 +12,7 @@ use hir_def::{
macro_id_to_def_id, macro_id_to_def_id,
resolver::{self, HasResolver, Resolver, TypeNs}, resolver::{self, HasResolver, Resolver, TypeNs},
type_ref::Mutability, type_ref::Mutability,
AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId, AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
}; };
use hir_expand::{ use hir_expand::{
db::AstDatabase, db::AstDatabase,
@ -366,6 +366,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.resolve_method_call(call).map(Function::from) self.imp.resolve_method_call(call).map(Function::from)
} }
/// Attempts to resolve this call expression as a method call falling back to resolving it as a field.
pub fn resolve_method_call_field_fallback(
&self,
call: &ast::MethodCallExpr,
) -> Option<Either<Function, Field>> {
self.imp
.resolve_method_call_fallback(call)
.map(|it| it.map_left(Function::from).map_right(Field::from))
}
pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> { pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
self.imp.resolve_await_to_poll(await_expr).map(Function::from) self.imp.resolve_await_to_poll(await_expr).map(Function::from)
} }
@ -1146,6 +1156,13 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(call.syntax())?.resolve_method_call(self.db, call) self.analyze(call.syntax())?.resolve_method_call(self.db, call)
} }
fn resolve_method_call_fallback(
&self,
call: &ast::MethodCallExpr,
) -> Option<Either<FunctionId, FieldId>> {
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
}
fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> { fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
} }

View File

@ -10,6 +10,7 @@ use std::{
sync::Arc, sync::Arc,
}; };
use either::Either;
use hir_def::{ use hir_def::{
body::{ body::{
self, self,
@ -266,6 +267,21 @@ impl SourceAnalyzer {
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)) Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
} }
pub(crate) fn resolve_method_call_fallback(
&self,
db: &dyn HirDatabase,
call: &ast::MethodCallExpr,
) -> Option<Either<FunctionId, FieldId>> {
let expr_id = self.expr_id(db, &call.clone().into())?;
let inference_result = self.infer.as_ref()?;
match inference_result.method_resolution(expr_id) {
Some((f_in_trait, substs)) => {
Some(Either::Left(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)))
}
None => inference_result.field_resolution(expr_id).map(Either::Right),
}
}
pub(crate) fn resolve_await_to_poll( pub(crate) fn resolve_await_to_poll(
&self, &self,
db: &dyn HirDatabase, db: &dyn HirDatabase,

View File

@ -469,9 +469,12 @@ impl NameRefClass {
match_ast! { match_ast! {
match parent { match parent {
ast::MethodCallExpr(method_call) => { ast::MethodCallExpr(method_call) => {
sema.resolve_method_call(&method_call) sema.resolve_method_call_field_fallback(&method_call)
.map(Definition::Function) .map(|it| {
.map(NameRefClass::Definition) it.map_left(Definition::Function)
.map_right(Definition::Field)
.either(NameRefClass::Definition, NameRefClass::Definition)
})
}, },
ast::FieldExpr(field_expr) => { ast::FieldExpr(field_expr) => {
sema.resolve_field(&field_expr) sema.resolve_field(&field_expr)

View File

@ -5797,3 +5797,26 @@ mod m {
"#]], "#]],
); );
} }
#[test]
fn field_as_method_call_fallback() {
check(
r#"
struct S { f: u32 }
fn test() {
S { f: 0 }.f$0();
}
"#,
expect![[r#"
*f*
```rust
test::S
```
```rust
f: u32 // size = 4, align = 4, offset = 0
```
"#]],
);
}