Skip to content

Commit 3c7a0aa

Browse files
committed
Diagnose call expression on non-callable things
1 parent 3ba876a commit 3c7a0aa

File tree

6 files changed

+83
-14
lines changed

6 files changed

+83
-14
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ pub enum InferenceDiagnostic {
170170
// FIXME: Make this proper
171171
BreakOutsideOfLoop { expr: ExprId, is_break: bool, bad_value_break: bool },
172172
MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
173+
ExpectedFunction { call_expr: ExprId, found: Ty },
173174
}
174175

175176
/// A mismatch between an expected and an inferred type.
@@ -505,6 +506,14 @@ impl<'a> InferenceContext<'a> {
505506
mismatch.expected = table.resolve_completely(mismatch.expected.clone());
506507
mismatch.actual = table.resolve_completely(mismatch.actual.clone());
507508
}
509+
for diagnostic in &mut result.diagnostics {
510+
match diagnostic {
511+
InferenceDiagnostic::ExpectedFunction { found, .. } => {
512+
*found = table.resolve_completely(found.clone())
513+
}
514+
_ => (),
515+
}
516+
}
508517
for (_, subst) in result.method_resolutions.values_mut() {
509518
*subst = table.resolve_completely(subst.clone());
510519
}

crates/hir-ty/src/infer/expr.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,13 @@ impl<'a> InferenceContext<'a> {
364364
}
365365
(params, ret_ty)
366366
}
367-
None => (Vec::new(), self.err_ty()), // FIXME diagnostic
367+
None => {
368+
self.result.diagnostics.push(InferenceDiagnostic::ExpectedFunction {
369+
call_expr: tgt_expr,
370+
found: callee_ty.clone(),
371+
});
372+
(Vec::new(), self.err_ty())
373+
}
368374
};
369375
let indices_to_skip = self.check_legacy_const_generics(derefed_callee, args);
370376
self.register_obligations_for_call(&callee_ty);

crates/hir/src/diagnostics.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ macro_rules! diagnostics {
3131

3232
diagnostics![
3333
BreakOutsideOfLoop,
34+
ExpectedFunction,
3435
InactiveCode,
3536
IncorrectCase,
3637
InvalidDeriveTarget,
@@ -130,6 +131,12 @@ pub struct PrivateAssocItem {
130131
pub item: AssocItem,
131132
}
132133

134+
#[derive(Debug)]
135+
pub struct ExpectedFunction {
136+
pub call: InFile<AstPtr<ast::Expr>>,
137+
pub found: Type,
138+
}
139+
133140
#[derive(Debug)]
134141
pub struct PrivateField {
135142
pub expr: InFile<AstPtr<ast::Expr>>,

crates/hir/src/lib.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ use crate::db::{DefDatabase, HirDatabase};
8484
pub use crate::{
8585
attrs::{HasAttrs, Namespace},
8686
diagnostics::{
87-
AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, InvalidDeriveTarget,
88-
MacroError, MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms,
89-
MissingUnsafe, NoSuchField, PrivateAssocItem, PrivateField,
87+
AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncorrectCase,
88+
InvalidDeriveTarget, MacroError, MalformedDerive, MismatchedArgCount, MissingFields,
89+
MissingMatchArms, MissingUnsafe, NoSuchField, PrivateAssocItem, PrivateField,
9090
ReplaceFilterMapNextWithFindMap, TypeMismatch, UnimplementedBuiltinMacro,
9191
UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
9292
UnresolvedProcMacro,
@@ -1377,8 +1377,8 @@ impl DefWithBody {
13771377
let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
13781378
for d in &infer.diagnostics {
13791379
match d {
1380-
hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
1381-
let field = source_map.field_syntax(*expr);
1380+
&hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
1381+
let field = source_map.field_syntax(expr);
13821382
acc.push(NoSuchField { field }.into())
13831383
}
13841384
&hir_ty::InferenceDiagnostic::BreakOutsideOfLoop {
@@ -1391,15 +1391,10 @@ impl DefWithBody {
13911391
.expect("break outside of loop in synthetic syntax");
13921392
acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into())
13931393
}
1394-
hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
1395-
match source_map.expr_syntax(*call_expr) {
1394+
&hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
1395+
match source_map.expr_syntax(call_expr) {
13961396
Ok(source_ptr) => acc.push(
1397-
MismatchedArgCount {
1398-
call_expr: source_ptr,
1399-
expected: *expected,
1400-
found: *found,
1401-
}
1402-
.into(),
1397+
MismatchedArgCount { call_expr: source_ptr, expected, found }.into(),
14031398
),
14041399
Err(SyntheticSyntax) => (),
14051400
}
@@ -1423,6 +1418,18 @@ impl DefWithBody {
14231418
let item = item.into();
14241419
acc.push(PrivateAssocItem { expr_or_pat, item }.into())
14251420
}
1421+
hir_ty::InferenceDiagnostic::ExpectedFunction { call_expr, found } => {
1422+
let call_expr =
1423+
source_map.expr_syntax(*call_expr).expect("unexpected synthetic");
1424+
1425+
acc.push(
1426+
ExpectedFunction {
1427+
call: call_expr,
1428+
found: Type::new(db, DefWithBodyId::from(self), found.clone()),
1429+
}
1430+
.into(),
1431+
)
1432+
}
14261433
}
14271434
}
14281435
for (pat_or_expr, mismatch) in infer.type_mismatches() {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use hir::HirDisplay;
2+
3+
use crate::{Diagnostic, DiagnosticsContext};
4+
5+
// Diagnostic: expected-function
6+
//
7+
// This diagnostic is triggered if a call is made on something that is not callable.
8+
pub(crate) fn expected_function(
9+
ctx: &DiagnosticsContext<'_>,
10+
d: &hir::ExpectedFunction,
11+
) -> Diagnostic {
12+
Diagnostic::new(
13+
"expected-function",
14+
format!("expected function, found {}", d.found.display(ctx.sema.db)),
15+
ctx.sema.diagnostics_display_range(d.call.clone().map(|it| it.into())).range,
16+
)
17+
}
18+
19+
#[cfg(test)]
20+
mod tests {
21+
use crate::tests::check_diagnostics;
22+
23+
#[test]
24+
fn smoke_test() {
25+
check_diagnostics(
26+
r#"
27+
fn foo() {
28+
let x = 3;
29+
x();
30+
// ^^^ error: expected function, found i32
31+
""();
32+
// ^^^^ error: expected function, found &str
33+
foo();
34+
}
35+
"#,
36+
);
37+
}
38+
}

crates/ide-diagnostics/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
mod handlers {
2929
pub(crate) mod break_outside_of_loop;
30+
pub(crate) mod expected_function;
3031
pub(crate) mod inactive_code;
3132
pub(crate) mod incorrect_case;
3233
pub(crate) mod invalid_derive_target;
@@ -248,6 +249,7 @@ pub fn diagnostics(
248249
#[rustfmt::skip]
249250
let d = match diag {
250251
AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
252+
AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),
251253
AnyDiagnostic::IncorrectCase(d) => handlers::incorrect_case::incorrect_case(&ctx, &d),
252254
AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
253255
AnyDiagnostic::MalformedDerive(d) => handlers::malformed_derive::malformed_derive(&ctx, &d),

0 commit comments

Comments
 (0)