Skip to content

Commit a492d9d

Browse files
rosefromthedeadVeykril
authored andcommitted
feat: add unresolved-ident diagnostic
1 parent d818b53 commit a492d9d

12 files changed

+113
-26
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ pub enum InferenceDiagnostic {
221221
UnresolvedAssocItem {
222222
id: ExprOrPatId,
223223
},
224+
UnresolvedIdent {
225+
expr: ExprId,
226+
},
224227
// FIXME: This should be emitted in body lowering
225228
BreakOutsideOfLoop {
226229
expr: ExprId,

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use hir_def::{
1313
ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
1414
},
1515
lang_item::{LangItem, LangItemTarget},
16-
path::{GenericArg, GenericArgs},
16+
path::{GenericArg, GenericArgs, Path},
1717
BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, TupleFieldId, TupleId,
1818
};
1919
use hir_expand::name::{name, Name};
@@ -439,7 +439,17 @@ impl InferenceContext<'_> {
439439
}
440440
Expr::Path(p) => {
441441
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
442-
let ty = self.infer_path(p, tgt_expr.into()).unwrap_or_else(|| self.err_ty());
442+
let ty = match self.infer_path(p, tgt_expr.into()) {
443+
Some(ty) => ty,
444+
None => {
445+
if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident()) {
446+
self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent {
447+
expr: tgt_expr,
448+
});
449+
}
450+
self.err_ty()
451+
}
452+
};
443453
self.resolver.reset_to_guard(g);
444454
ty
445455
}

crates/hir/src/diagnostics.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ diagnostics![
8787
UnresolvedMacroCall,
8888
UnresolvedMethodCall,
8989
UnresolvedModule,
90+
UnresolvedIdent,
9091
UnresolvedProcMacro,
9192
UnusedMut,
9293
UnusedVariable,
@@ -242,6 +243,11 @@ pub struct UnresolvedAssocItem {
242243
pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, Either<ast::Pat, ast::SelfParam>>>>,
243244
}
244245

246+
#[derive(Debug)]
247+
pub struct UnresolvedIdent {
248+
pub expr: InFile<AstPtr<ast::Expr>>,
249+
}
250+
245251
#[derive(Debug)]
246252
pub struct PrivateField {
247253
pub expr: InFile<AstPtr<ast::Expr>>,
@@ -588,6 +594,10 @@ impl AnyDiagnostic {
588594
};
589595
UnresolvedAssocItem { expr_or_pat }.into()
590596
}
597+
&InferenceDiagnostic::UnresolvedIdent { expr } => {
598+
let expr = expr_syntax(expr);
599+
UnresolvedIdent { expr }.into()
600+
}
591601
&InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
592602
let expr = expr_syntax(expr);
593603
BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()

crates/ide-diagnostics/src/handlers/inactive_code.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ fn f() {
6060
#[cfg(a)] let x = 0; // let statement
6161
//^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
6262
63+
fn abc() {}
6364
abc(#[cfg(a)] 0);
6465
//^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
6566
let x = Struct {

crates/ide-diagnostics/src/handlers/missing_fields.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,8 @@ struct TestStruct { one: i32, two: i64 }
634634
635635
fn test_fn() {
636636
let one = 1;
637-
let s = TestStruct{ ..a };
637+
let a = TestStruct{ one, two: 2 };
638+
let _ = TestStruct{ ..a };
638639
}
639640
"#,
640641
);

crates/ide-diagnostics/src/handlers/missing_match_arms.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ pub(crate) fn missing_match_arms(
1818
#[cfg(test)]
1919
mod tests {
2020
use crate::{
21-
tests::{check_diagnostics, check_diagnostics_with_config},
21+
tests::{
22+
check_diagnostics, check_diagnostics_with_config, check_diagnostics_with_disabled,
23+
},
2224
DiagnosticsConfig,
2325
};
2426

@@ -282,7 +284,7 @@ fn main() {
282284
cov_mark::check_count!(validate_match_bailed_out, 4);
283285
// Match statements with arms that don't match the
284286
// expression pattern do not fire this diagnostic.
285-
check_diagnostics(
287+
check_diagnostics_with_disabled(
286288
r#"
287289
enum Either { A, B }
288290
enum Either2 { C, D }
@@ -307,6 +309,7 @@ fn main() {
307309
match Unresolved::Bar { Unresolved::Baz => () }
308310
}
309311
"#,
312+
&["E0425"],
310313
);
311314
}
312315

@@ -397,11 +400,11 @@ fn main() {
397400
match loop {} {
398401
Either::A => (),
399402
}
400-
match loop { break Foo::A } {
401-
//^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
403+
match loop { break Either::A } {
404+
//^^^^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
402405
Either::A => (),
403406
}
404-
match loop { break Foo::A } {
407+
match loop { break Either::A } {
405408
Either::A => (),
406409
Either::B => (),
407410
}
@@ -977,7 +980,7 @@ fn f(ty: Enum) {
977980
#[test]
978981
fn unexpected_ty_fndef() {
979982
cov_mark::check!(validate_match_bailed_out);
980-
check_diagnostics(
983+
check_diagnostics_with_disabled(
981984
r"
982985
enum Exp {
983986
Tuple(()),
@@ -987,6 +990,7 @@ fn f() {
987990
Exp::Tuple => {}
988991
}
989992
}",
993+
&["E0425"],
990994
);
991995
}
992996

crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option<Vec<
9595

9696
#[cfg(test)]
9797
mod tests {
98-
use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix};
98+
use crate::tests::{check_diagnostics_with_disabled, check_fix};
9999

100100
#[test]
101101
fn remove_unnecessary_else_for_return() {
@@ -110,7 +110,7 @@ fn test() {
110110
}
111111
}
112112
"#,
113-
&["needless_return"],
113+
&["needless_return", "E0425"],
114114
);
115115
check_fix(
116116
r#"
@@ -148,7 +148,7 @@ fn test() {
148148
}
149149
}
150150
"#,
151-
&["needless_return"],
151+
&["needless_return", "E0425"],
152152
);
153153
check_fix(
154154
r#"
@@ -227,7 +227,7 @@ fn test() {
227227
}
228228
}
229229
"#,
230-
&["needless_return"],
230+
&["needless_return", "E0425"],
231231
);
232232
check_fix(
233233
r#"
@@ -293,7 +293,7 @@ fn test() {
293293

294294
#[test]
295295
fn remove_unnecessary_else_for_break() {
296-
check_diagnostics(
296+
check_diagnostics_with_disabled(
297297
r#"
298298
fn test() {
299299
loop {
@@ -306,6 +306,7 @@ fn test() {
306306
}
307307
}
308308
"#,
309+
&["E0425"],
309310
);
310311
check_fix(
311312
r#"
@@ -334,7 +335,7 @@ fn test() {
334335

335336
#[test]
336337
fn remove_unnecessary_else_for_continue() {
337-
check_diagnostics(
338+
check_diagnostics_with_disabled(
338339
r#"
339340
fn test() {
340341
loop {
@@ -347,6 +348,7 @@ fn test() {
347348
}
348349
}
349350
"#,
351+
&["E0425"],
350352
);
351353
check_fix(
352354
r#"
@@ -375,7 +377,7 @@ fn test() {
375377

376378
#[test]
377379
fn remove_unnecessary_else_for_never() {
378-
check_diagnostics(
380+
check_diagnostics_with_disabled(
379381
r#"
380382
fn test() {
381383
if foo {
@@ -390,6 +392,7 @@ fn never() -> ! {
390392
loop {}
391393
}
392394
"#,
395+
&["E0425"],
393396
);
394397
check_fix(
395398
r#"
@@ -422,7 +425,7 @@ fn never() -> ! {
422425

423426
#[test]
424427
fn no_diagnostic_if_no_else_branch() {
425-
check_diagnostics(
428+
check_diagnostics_with_disabled(
426429
r#"
427430
fn test() {
428431
if foo {
@@ -432,12 +435,13 @@ fn test() {
432435
do_something_else();
433436
}
434437
"#,
438+
&["E0425"],
435439
);
436440
}
437441

438442
#[test]
439443
fn no_diagnostic_if_no_divergence() {
440-
check_diagnostics(
444+
check_diagnostics_with_disabled(
441445
r#"
442446
fn test() {
443447
if foo {
@@ -447,6 +451,7 @@ fn test() {
447451
}
448452
}
449453
"#,
454+
&["E0425"],
450455
);
451456
}
452457

@@ -462,7 +467,7 @@ fn test() {
462467
}
463468
}
464469
"#,
465-
&["needless_return"],
470+
&["needless_return", "E0425"],
466471
);
467472
}
468473

crates/ide-diagnostics/src/handlers/undeclared_label.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ fn foo() {
3838
fn while_let_loop_with_label_in_condition() {
3939
check_diagnostics(
4040
r#"
41+
//- minicore: option
42+
4143
fn foo() {
4244
let mut optional = Some(0);
4345
44-
'my_label: while let Some(a) = match optional {
46+
'my_label: while let Some(_) = match optional {
4547
None => break 'my_label,
4648
Some(val) => Some(val),
4749
} {
@@ -59,8 +61,8 @@ fn foo() {
5961
r#"
6062
//- minicore: iterator
6163
fn foo() {
62-
'xxx: for _ in unknown {
63-
'yyy: for _ in unknown {
64+
'xxx: for _ in [] {
65+
'yyy: for _ in [] {
6466
break 'xxx;
6567
continue 'yyy;
6668
break 'zzz;

crates/ide-diagnostics/src/handlers/unresolved_field.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ fn method_fix(
7878
#[cfg(test)]
7979
mod tests {
8080
use crate::{
81-
tests::{check_diagnostics, check_diagnostics_with_config},
81+
tests::{
82+
check_diagnostics, check_diagnostics_with_config, check_diagnostics_with_disabled,
83+
},
8284
DiagnosticsConfig,
8385
};
8486

@@ -148,14 +150,15 @@ fn foo() {
148150

149151
#[test]
150152
fn no_diagnostic_on_unknown() {
151-
check_diagnostics(
153+
check_diagnostics_with_disabled(
152154
r#"
153155
fn foo() {
154156
x.foo;
155157
(&x).foo;
156158
(&((x,),),).foo;
157159
}
158160
"#,
161+
&["E0425"],
159162
);
160163
}
161164

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
2+
3+
// Diagnostic: unresolved-ident
4+
//
5+
// This diagnostic is triggered if an expr-position ident is invalid.
6+
pub(crate) fn unresolved_ident(
7+
ctx: &DiagnosticsContext<'_>,
8+
d: &hir::UnresolvedIdent,
9+
) -> Diagnostic {
10+
Diagnostic::new_with_syntax_node_ptr(
11+
ctx,
12+
DiagnosticCode::RustcHardError("E0425"),
13+
"no such value in this scope",
14+
d.expr.map(Into::into),
15+
)
16+
.experimental()
17+
}
18+
19+
#[cfg(test)]
20+
mod tests {
21+
use crate::tests::check_diagnostics;
22+
23+
#[test]
24+
fn missing() {
25+
check_diagnostics(
26+
r#"
27+
fn main() {
28+
let _ = x;
29+
//^ error: no such value in this scope
30+
}
31+
"#,
32+
);
33+
}
34+
35+
#[test]
36+
fn present() {
37+
check_diagnostics(
38+
r#"
39+
fn main() {
40+
let x = 5;
41+
let _ = x;
42+
}
43+
"#,
44+
);
45+
}
46+
}

crates/ide-diagnostics/src/handlers/unresolved_method.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,8 @@ fn main() {
335335
r#"
336336
struct Foo { bar: i32 }
337337
fn foo() {
338-
Foo { bar: i32 }.bar();
339-
// ^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists
338+
Foo { bar: 0 }.bar();
339+
// ^^^ error: no method `bar` on type `Foo`, but a field with a similar name exists
340340
}
341341
"#,
342342
);

0 commit comments

Comments
 (0)