Skip to content

Commit e6ba791

Browse files
committed
Auto merge of rust-lang#14252 - Veykril:field-mcall-fallback, r=Veykril
internal: Handle fields called as method calls as the fields they resolve to Confusing PR title tbf but this makes it so `bar` in `foo.bar()` resolves to the field if it exists and no method with the same name exists. Improves UX slightly when incorrectly calling a field.
2 parents 94dc7a3 + 5a91f01 commit e6ba791

File tree

4 files changed

+63
-4
lines changed

4 files changed

+63
-4
lines changed

crates/hir/src/semantics.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use hir_def::{
1212
macro_id_to_def_id,
1313
resolver::{self, HasResolver, Resolver, TypeNs},
1414
type_ref::Mutability,
15-
AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
15+
AsMacroCall, DefWithBodyId, FieldId, FunctionId, MacroId, TraitId, VariantId,
1616
};
1717
use hir_expand::{
1818
db::AstDatabase,
@@ -366,6 +366,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
366366
self.imp.resolve_method_call(call).map(Function::from)
367367
}
368368

369+
/// Attempts to resolve this call expression as a method call falling back to resolving it as a field.
370+
pub fn resolve_method_call_field_fallback(
371+
&self,
372+
call: &ast::MethodCallExpr,
373+
) -> Option<Either<Function, Field>> {
374+
self.imp
375+
.resolve_method_call_fallback(call)
376+
.map(|it| it.map_left(Function::from).map_right(Field::from))
377+
}
378+
369379
pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
370380
self.imp.resolve_await_to_poll(await_expr).map(Function::from)
371381
}
@@ -1146,6 +1156,13 @@ impl<'db> SemanticsImpl<'db> {
11461156
self.analyze(call.syntax())?.resolve_method_call(self.db, call)
11471157
}
11481158

1159+
fn resolve_method_call_fallback(
1160+
&self,
1161+
call: &ast::MethodCallExpr,
1162+
) -> Option<Either<FunctionId, FieldId>> {
1163+
self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
1164+
}
1165+
11491166
fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
11501167
self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
11511168
}

crates/hir/src/source_analyzer.rs

+16
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::{
1010
sync::Arc,
1111
};
1212

13+
use either::Either;
1314
use hir_def::{
1415
body::{
1516
self,
@@ -266,6 +267,21 @@ impl SourceAnalyzer {
266267
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
267268
}
268269

270+
pub(crate) fn resolve_method_call_fallback(
271+
&self,
272+
db: &dyn HirDatabase,
273+
call: &ast::MethodCallExpr,
274+
) -> Option<Either<FunctionId, FieldId>> {
275+
let expr_id = self.expr_id(db, &call.clone().into())?;
276+
let inference_result = self.infer.as_ref()?;
277+
match inference_result.method_resolution(expr_id) {
278+
Some((f_in_trait, substs)) => {
279+
Some(Either::Left(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs)))
280+
}
281+
None => inference_result.field_resolution(expr_id).map(Either::Right),
282+
}
283+
}
284+
269285
pub(crate) fn resolve_await_to_poll(
270286
&self,
271287
db: &dyn HirDatabase,

crates/ide-db/src/defs.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -469,9 +469,12 @@ impl NameRefClass {
469469
match_ast! {
470470
match parent {
471471
ast::MethodCallExpr(method_call) => {
472-
sema.resolve_method_call(&method_call)
473-
.map(Definition::Function)
474-
.map(NameRefClass::Definition)
472+
sema.resolve_method_call_field_fallback(&method_call)
473+
.map(|it| {
474+
it.map_left(Definition::Function)
475+
.map_right(Definition::Field)
476+
.either(NameRefClass::Definition, NameRefClass::Definition)
477+
})
475478
},
476479
ast::FieldExpr(field_expr) => {
477480
sema.resolve_field(&field_expr)

crates/ide/src/hover/tests.rs

+23
Original file line numberDiff line numberDiff line change
@@ -5797,3 +5797,26 @@ mod m {
57975797
"#]],
57985798
);
57995799
}
5800+
5801+
#[test]
5802+
fn field_as_method_call_fallback() {
5803+
check(
5804+
r#"
5805+
struct S { f: u32 }
5806+
fn test() {
5807+
S { f: 0 }.f$0();
5808+
}
5809+
"#,
5810+
expect![[r#"
5811+
*f*
5812+
5813+
```rust
5814+
test::S
5815+
```
5816+
5817+
```rust
5818+
f: u32 // size = 4, align = 4, offset = 0
5819+
```
5820+
"#]],
5821+
);
5822+
}

0 commit comments

Comments
 (0)