Skip to content

Commit caa651a

Browse files
authored
Merge pull request rust-lang#19148 from Veykril/push-ptnykrwnwwlu
Improve error recovery when method-calling a field
2 parents 537f4b2 + d9256ab commit caa651a

File tree

3 files changed

+152
-79
lines changed

3 files changed

+152
-79
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs

+126-78
Original file line numberDiff line numberDiff line change
@@ -489,78 +489,7 @@ impl InferenceContext<'_> {
489489

490490
ty
491491
}
492-
Expr::Call { callee, args, .. } => {
493-
let callee_ty = self.infer_expr(*callee, &Expectation::none(), ExprIsRead::Yes);
494-
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
495-
let (res, derefed_callee) = loop {
496-
let Some((callee_deref_ty, _)) = derefs.next() else {
497-
break (None, callee_ty.clone());
498-
};
499-
if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) {
500-
break (Some(res), callee_deref_ty);
501-
}
502-
};
503-
// if the function is unresolved, we use is_varargs=true to
504-
// suppress the arg count diagnostic here
505-
let is_varargs =
506-
derefed_callee.callable_sig(self.db).is_some_and(|sig| sig.is_varargs)
507-
|| res.is_none();
508-
let (param_tys, ret_ty) = match res {
509-
Some((func, params, ret_ty)) => {
510-
let mut adjustments = auto_deref_adjust_steps(&derefs);
511-
if let TyKind::Closure(c, _) =
512-
self.table.resolve_completely(callee_ty.clone()).kind(Interner)
513-
{
514-
if let Some(par) = self.current_closure {
515-
self.closure_dependencies.entry(par).or_default().push(*c);
516-
}
517-
self.deferred_closures.entry(*c).or_default().push((
518-
derefed_callee.clone(),
519-
callee_ty.clone(),
520-
params.clone(),
521-
tgt_expr,
522-
));
523-
}
524-
if let Some(fn_x) = func {
525-
self.write_fn_trait_method_resolution(
526-
fn_x,
527-
&derefed_callee,
528-
&mut adjustments,
529-
&callee_ty,
530-
&params,
531-
tgt_expr,
532-
);
533-
}
534-
self.write_expr_adj(*callee, adjustments);
535-
(params, ret_ty)
536-
}
537-
None => {
538-
self.push_diagnostic(InferenceDiagnostic::ExpectedFunction {
539-
call_expr: tgt_expr,
540-
found: callee_ty.clone(),
541-
});
542-
(Vec::new(), self.err_ty())
543-
}
544-
};
545-
let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
546-
self.register_obligations_for_call(&callee_ty);
547-
548-
let expected_inputs = self.expected_inputs_for_expected_output(
549-
expected,
550-
ret_ty.clone(),
551-
param_tys.clone(),
552-
);
553-
554-
self.check_call_arguments(
555-
tgt_expr,
556-
args,
557-
&expected_inputs,
558-
&param_tys,
559-
&indices_to_skip,
560-
is_varargs,
561-
);
562-
self.normalize_associated_types_in(ret_ty)
563-
}
492+
Expr::Call { callee, args, .. } => self.infer_call(tgt_expr, *callee, args, expected),
564493
Expr::MethodCall { receiver, args, method_name, generic_args } => self
565494
.infer_method_call(
566495
tgt_expr,
@@ -1872,6 +1801,107 @@ impl InferenceContext<'_> {
18721801
}
18731802
}
18741803

1804+
fn infer_call(
1805+
&mut self,
1806+
tgt_expr: ExprId,
1807+
callee: ExprId,
1808+
args: &[ExprId],
1809+
expected: &Expectation,
1810+
) -> Ty {
1811+
let callee_ty = self.infer_expr(callee, &Expectation::none(), ExprIsRead::Yes);
1812+
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
1813+
let (res, derefed_callee) = loop {
1814+
let Some((callee_deref_ty, _)) = derefs.next() else {
1815+
break (None, callee_ty.clone());
1816+
};
1817+
if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) {
1818+
break (Some(res), callee_deref_ty);
1819+
}
1820+
};
1821+
// if the function is unresolved, we use is_varargs=true to
1822+
// suppress the arg count diagnostic here
1823+
let is_varargs =
1824+
derefed_callee.callable_sig(self.db).is_some_and(|sig| sig.is_varargs) || res.is_none();
1825+
let (param_tys, ret_ty) = match res {
1826+
Some((func, params, ret_ty)) => {
1827+
let mut adjustments = auto_deref_adjust_steps(&derefs);
1828+
if let TyKind::Closure(c, _) =
1829+
self.table.resolve_completely(callee_ty.clone()).kind(Interner)
1830+
{
1831+
if let Some(par) = self.current_closure {
1832+
self.closure_dependencies.entry(par).or_default().push(*c);
1833+
}
1834+
self.deferred_closures.entry(*c).or_default().push((
1835+
derefed_callee.clone(),
1836+
callee_ty.clone(),
1837+
params.clone(),
1838+
tgt_expr,
1839+
));
1840+
}
1841+
if let Some(fn_x) = func {
1842+
self.write_fn_trait_method_resolution(
1843+
fn_x,
1844+
&derefed_callee,
1845+
&mut adjustments,
1846+
&callee_ty,
1847+
&params,
1848+
tgt_expr,
1849+
);
1850+
}
1851+
self.write_expr_adj(callee, adjustments);
1852+
(params, ret_ty)
1853+
}
1854+
None => {
1855+
self.push_diagnostic(InferenceDiagnostic::ExpectedFunction {
1856+
call_expr: tgt_expr,
1857+
found: callee_ty.clone(),
1858+
});
1859+
(Vec::new(), self.err_ty())
1860+
}
1861+
};
1862+
let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
1863+
self.check_call(
1864+
tgt_expr,
1865+
args,
1866+
callee_ty,
1867+
&param_tys,
1868+
ret_ty,
1869+
&indices_to_skip,
1870+
is_varargs,
1871+
expected,
1872+
)
1873+
}
1874+
1875+
fn check_call(
1876+
&mut self,
1877+
tgt_expr: ExprId,
1878+
args: &[ExprId],
1879+
callee_ty: Ty,
1880+
param_tys: &[Ty],
1881+
ret_ty: Ty,
1882+
indices_to_skip: &[u32],
1883+
is_varargs: bool,
1884+
expected: &Expectation,
1885+
) -> Ty {
1886+
self.register_obligations_for_call(&callee_ty);
1887+
1888+
let expected_inputs = self.expected_inputs_for_expected_output(
1889+
expected,
1890+
ret_ty.clone(),
1891+
param_tys.to_owned(),
1892+
);
1893+
1894+
self.check_call_arguments(
1895+
tgt_expr,
1896+
args,
1897+
&expected_inputs,
1898+
param_tys,
1899+
indices_to_skip,
1900+
is_varargs,
1901+
);
1902+
self.normalize_associated_types_in(ret_ty)
1903+
}
1904+
18751905
fn infer_method_call(
18761906
&mut self,
18771907
tgt_expr: ExprId,
@@ -1939,14 +1969,32 @@ impl InferenceContext<'_> {
19391969
expr: tgt_expr,
19401970
receiver: receiver_ty.clone(),
19411971
name: method_name.clone(),
1942-
field_with_same_name: field_with_same_name_exists,
1972+
field_with_same_name: field_with_same_name_exists.clone(),
19431973
assoc_func_with_same_name,
19441974
});
1945-
(
1946-
receiver_ty,
1947-
Binders::empty(Interner, self.err_ty()),
1948-
Substitution::empty(Interner),
1949-
)
1975+
1976+
return match field_with_same_name_exists {
1977+
Some(field_ty) => match field_ty.callable_sig(self.db) {
1978+
Some(sig) => self.check_call(
1979+
tgt_expr,
1980+
args,
1981+
field_ty,
1982+
sig.params(),
1983+
sig.ret().clone(),
1984+
&[],
1985+
true,
1986+
expected,
1987+
),
1988+
None => {
1989+
self.check_call_arguments(tgt_expr, args, &[], &[], &[], true);
1990+
field_ty
1991+
}
1992+
},
1993+
None => {
1994+
self.check_call_arguments(tgt_expr, args, &[], &[], &[], true);
1995+
self.err_ty()
1996+
}
1997+
};
19501998
}
19511999
};
19522000
self.check_method_call(tgt_expr, args, method_ty, substs, receiver_ty, expected)

src/tools/rust-analyzer/crates/hir-ty/src/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ fn check_impl(
117117
expected.trim_start_matches("adjustments:").trim().to_owned(),
118118
);
119119
} else {
120-
panic!("unexpected annotation: {expected}");
120+
panic!("unexpected annotation: {expected} @ {range:?}");
121121
}
122122
had_annotations = true;
123123
}

src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs

+25
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,28 @@ fn consume() -> Option<()> {
153153
"#,
154154
);
155155
}
156+
157+
#[test]
158+
fn method_call_on_field() {
159+
check(
160+
r#"
161+
struct S {
162+
field: fn() -> u32,
163+
field2: u32
164+
}
165+
166+
fn main() {
167+
let s = S { field: || 0, field2: 0 };
168+
s.field(0);
169+
// ^ type: i32
170+
// ^^^^^^^^^^ type: u32
171+
s.field2(0);
172+
// ^ type: i32
173+
// ^^^^^^^^^^^ type: u32
174+
s.not_a_field(0);
175+
// ^ type: i32
176+
// ^^^^^^^^^^^^^^^^ type: {unknown}
177+
}
178+
"#,
179+
);
180+
}

0 commit comments

Comments
 (0)