]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/diagnostics.rs
internal: refactor unresolved proc macro diagnostic
[rust.git] / crates / ide / src / diagnostics.rs
1 //! Collects diagnostics & fixits  for a single file.
2 //!
3 //! The tricky bit here is that diagnostics are produced by hir in terms of
4 //! macro-expanded files, but we need to present them to the users in terms of
5 //! original files. So we need to map the ranges.
6
7 mod unresolved_module;
8 mod unresolved_extern_crate;
9 mod unresolved_import;
10 mod unresolved_macro_call;
11 mod unresolved_proc_macro;
12 mod inactive_code;
13 mod missing_fields;
14
15 mod fixes;
16 mod field_shorthand;
17 mod unlinked_file;
18
19 use std::cell::RefCell;
20
21 use hir::{
22     diagnostics::{AnyDiagnostic, Diagnostic as _, DiagnosticCode, DiagnosticSinkBuilder},
23     Semantics,
24 };
25 use ide_assists::AssistResolveStrategy;
26 use ide_db::{base_db::SourceDatabase, RootDatabase};
27 use itertools::Itertools;
28 use rustc_hash::FxHashSet;
29 use syntax::{
30     ast::{self, AstNode},
31     SyntaxNode, SyntaxNodePtr, TextRange, TextSize,
32 };
33 use text_edit::TextEdit;
34 use unlinked_file::UnlinkedFile;
35
36 use crate::{Assist, AssistId, AssistKind, FileId, Label, SourceChange};
37
38 use self::fixes::DiagnosticWithFixes;
39
40 #[derive(Debug)]
41 pub struct Diagnostic {
42     // pub name: Option<String>,
43     pub message: String,
44     pub range: TextRange,
45     pub severity: Severity,
46     pub fixes: Option<Vec<Assist>>,
47     pub unused: bool,
48     pub code: Option<DiagnosticCode>,
49     pub experimental: bool,
50 }
51
52 impl Diagnostic {
53     fn new(code: &'static str, message: impl Into<String>, range: TextRange) -> Diagnostic {
54         let message = message.into();
55         let code = Some(DiagnosticCode(code));
56         Self {
57             message,
58             range,
59             severity: Severity::Error,
60             fixes: None,
61             unused: false,
62             code,
63             experimental: false,
64         }
65     }
66
67     fn experimental(mut self) -> Diagnostic {
68         self.experimental = true;
69         self
70     }
71
72     fn severity(mut self, severity: Severity) -> Diagnostic {
73         self.severity = severity;
74         self
75     }
76
77     fn error(range: TextRange, message: String) -> Self {
78         Self {
79             message,
80             range,
81             severity: Severity::Error,
82             fixes: None,
83             unused: false,
84             code: None,
85             experimental: false,
86         }
87     }
88
89     fn hint(range: TextRange, message: String) -> Self {
90         Self {
91             message,
92             range,
93             severity: Severity::WeakWarning,
94             fixes: None,
95             unused: false,
96             code: None,
97             experimental: false,
98         }
99     }
100
101     fn with_fixes(self, fixes: Option<Vec<Assist>>) -> Self {
102         Self { fixes, ..self }
103     }
104
105     fn with_unused(self, unused: bool) -> Self {
106         Self { unused, ..self }
107     }
108
109     fn with_code(self, code: Option<DiagnosticCode>) -> Self {
110         Self { code, ..self }
111     }
112 }
113
114 #[derive(Debug, Copy, Clone)]
115 pub enum Severity {
116     Error,
117     WeakWarning,
118 }
119
120 #[derive(Default, Debug, Clone)]
121 pub struct DiagnosticsConfig {
122     pub disable_experimental: bool,
123     pub disabled: FxHashSet<String>,
124 }
125
126 struct DiagnosticsContext<'a> {
127     config: &'a DiagnosticsConfig,
128     sema: Semantics<'a, RootDatabase>,
129     #[allow(unused)]
130     resolve: &'a AssistResolveStrategy,
131 }
132
133 pub(crate) fn diagnostics(
134     db: &RootDatabase,
135     config: &DiagnosticsConfig,
136     resolve: &AssistResolveStrategy,
137     file_id: FileId,
138 ) -> Vec<Diagnostic> {
139     let _p = profile::span("diagnostics");
140     let sema = Semantics::new(db);
141     let parse = db.parse(file_id);
142     let mut res = Vec::new();
143
144     // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
145     res.extend(
146         parse
147             .errors()
148             .iter()
149             .take(128)
150             .map(|err| Diagnostic::error(err.range(), format!("Syntax Error: {}", err))),
151     );
152
153     for node in parse.tree().syntax().descendants() {
154         check_unnecessary_braces_in_use_statement(&mut res, file_id, &node);
155         field_shorthand::check(&mut res, file_id, &node);
156     }
157     let res = RefCell::new(res);
158     let sink_builder = DiagnosticSinkBuilder::new()
159         .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| {
160             res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
161         })
162         .on::<hir::diagnostics::NoSuchField, _>(|d| {
163             res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
164         })
165         .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| {
166             res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
167         })
168         .on::<hir::diagnostics::IncorrectCase, _>(|d| {
169             res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
170         })
171         .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| {
172             res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
173         })
174         .on::<UnlinkedFile, _>(|d| {
175             // Limit diagnostic to the first few characters in the file. This matches how VS Code
176             // renders it with the full span, but on other editors, and is less invasive.
177             let range = sema.diagnostics_display_range(d.display_source()).range;
178             let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range);
179
180             // Override severity and mark as unused.
181             res.borrow_mut().push(
182                 Diagnostic::hint(range, d.message())
183                     .with_fixes(d.fixes(&sema, resolve))
184                     .with_code(Some(d.code())),
185             );
186         })
187         .on::<hir::diagnostics::UnimplementedBuiltinMacro, _>(|d| {
188             let display_range = sema.diagnostics_display_range(d.display_source()).range;
189             res.borrow_mut()
190                 .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code())));
191         })
192         // Only collect experimental diagnostics when they're enabled.
193         .filter(|diag| !(diag.is_experimental() && config.disable_experimental))
194         .filter(|diag| !config.disabled.contains(diag.code().as_str()));
195
196     // Finalize the `DiagnosticSink` building process.
197     let mut sink = sink_builder
198         // Diagnostics not handled above get no fix and default treatment.
199         .build(|d| {
200             res.borrow_mut().push(
201                 Diagnostic::error(
202                     sema.diagnostics_display_range(d.display_source()).range,
203                     d.message(),
204                 )
205                 .with_code(Some(d.code())),
206             );
207         });
208
209     let mut diags = Vec::new();
210     let internal_diagnostics = cfg!(test);
211     match sema.to_module_def(file_id) {
212         Some(m) => diags = m.diagnostics(db, &mut sink, internal_diagnostics),
213         None => {
214             sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(parse.tree().syntax()) });
215         }
216     }
217
218     drop(sink);
219
220     let mut res = res.into_inner();
221
222     let ctx = DiagnosticsContext { config, sema, resolve };
223     for diag in diags {
224         #[rustfmt::skip]
225         let d = match diag {
226             AnyDiagnostic::UnresolvedModule(d) => unresolved_module::unresolved_module(&ctx, &d),
227             AnyDiagnostic::UnresolvedExternCrate(d) => unresolved_extern_crate::unresolved_extern_crate(&ctx, &d),
228             AnyDiagnostic::UnresolvedImport(d) => unresolved_import::unresolved_import(&ctx, &d),
229             AnyDiagnostic::UnresolvedMacroCall(d) => unresolved_macro_call::unresolved_macro_call(&ctx, &d),
230             AnyDiagnostic::UnresolvedProcMacro(d) => unresolved_proc_macro::unresolved_proc_macro(&ctx, &d),
231             AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d),
232
233             AnyDiagnostic::InactiveCode(d) => match inactive_code::inactive_code(&ctx, &d) {
234                 Some(it) => it,
235                 None => continue,
236             }
237         };
238         if let Some(code) = d.code {
239             if ctx.config.disabled.contains(code.as_str()) {
240                 continue;
241             }
242         }
243         if ctx.config.disable_experimental && d.experimental {
244             continue;
245         }
246         res.push(d)
247     }
248
249     res
250 }
251
252 fn diagnostic_with_fix<D: DiagnosticWithFixes>(
253     d: &D,
254     sema: &Semantics<RootDatabase>,
255     resolve: &AssistResolveStrategy,
256 ) -> Diagnostic {
257     Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message())
258         .with_fixes(d.fixes(sema, resolve))
259         .with_code(Some(d.code()))
260 }
261
262 fn warning_with_fix<D: DiagnosticWithFixes>(
263     d: &D,
264     sema: &Semantics<RootDatabase>,
265     resolve: &AssistResolveStrategy,
266 ) -> Diagnostic {
267     Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message())
268         .with_fixes(d.fixes(sema, resolve))
269         .with_code(Some(d.code()))
270 }
271
272 fn check_unnecessary_braces_in_use_statement(
273     acc: &mut Vec<Diagnostic>,
274     file_id: FileId,
275     node: &SyntaxNode,
276 ) -> Option<()> {
277     let use_tree_list = ast::UseTreeList::cast(node.clone())?;
278     if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
279         // If there is a comment inside the bracketed `use`,
280         // assume it is a commented out module path and don't show diagnostic.
281         if use_tree_list.has_inner_comment() {
282             return Some(());
283         }
284
285         let use_range = use_tree_list.syntax().text_range();
286         let edit =
287             text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree)
288                 .unwrap_or_else(|| {
289                     let to_replace = single_use_tree.syntax().text().to_string();
290                     let mut edit_builder = TextEdit::builder();
291                     edit_builder.delete(use_range);
292                     edit_builder.insert(use_range.start(), to_replace);
293                     edit_builder.finish()
294                 });
295
296         acc.push(
297             Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string())
298                 .with_fixes(Some(vec![fix(
299                     "remove_braces",
300                     "Remove unnecessary braces",
301                     SourceChange::from_text_edit(file_id, edit),
302                     use_range,
303                 )])),
304         );
305     }
306
307     Some(())
308 }
309
310 fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
311     single_use_tree: &ast::UseTree,
312 ) -> Option<TextEdit> {
313     let use_tree_list_node = single_use_tree.syntax().parent()?;
314     if single_use_tree.path()?.segment()?.self_token().is_some() {
315         let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start();
316         let end = use_tree_list_node.text_range().end();
317         return Some(TextEdit::delete(TextRange::new(start, end)));
318     }
319     None
320 }
321
322 fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
323     let mut res = unresolved_fix(id, label, target);
324     res.source_change = Some(source_change);
325     res
326 }
327
328 fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
329     assert!(!id.contains(' '));
330     Assist {
331         id: AssistId(id, AssistKind::QuickFix),
332         label: Label::new(label),
333         group: None,
334         target,
335         source_change: None,
336     }
337 }
338
339 #[cfg(test)]
340 mod tests {
341     use expect_test::Expect;
342     use hir::diagnostics::DiagnosticCode;
343     use ide_assists::AssistResolveStrategy;
344     use stdx::trim_indent;
345     use test_utils::{assert_eq_text, extract_annotations};
346
347     use crate::{fixture, DiagnosticsConfig};
348
349     /// Takes a multi-file input fixture with annotated cursor positions,
350     /// and checks that:
351     ///  * a diagnostic is produced
352     ///  * the first diagnostic fix trigger range touches the input cursor position
353     ///  * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
354     #[track_caller]
355     pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) {
356         check_nth_fix(0, ra_fixture_before, ra_fixture_after);
357     }
358     /// Takes a multi-file input fixture with annotated cursor positions,
359     /// and checks that:
360     ///  * a diagnostic is produced
361     ///  * every diagnostic fixes trigger range touches the input cursor position
362     ///  * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied
363     pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) {
364         for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() {
365             check_nth_fix(i, ra_fixture_before, ra_fixture_after)
366         }
367     }
368
369     #[track_caller]
370     fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
371         let after = trim_indent(ra_fixture_after);
372
373         let (analysis, file_position) = fixture::position(ra_fixture_before);
374         let diagnostic = analysis
375             .diagnostics(
376                 &DiagnosticsConfig::default(),
377                 AssistResolveStrategy::All,
378                 file_position.file_id,
379             )
380             .unwrap()
381             .pop()
382             .unwrap();
383         let fix = &diagnostic.fixes.unwrap()[nth];
384         let actual = {
385             let source_change = fix.source_change.as_ref().unwrap();
386             let file_id = *source_change.source_file_edits.keys().next().unwrap();
387             let mut actual = analysis.file_text(file_id).unwrap().to_string();
388
389             for edit in source_change.source_file_edits.values() {
390                 edit.apply(&mut actual);
391             }
392             actual
393         };
394
395         assert_eq_text!(&after, &actual);
396         assert!(
397             fix.target.contains_inclusive(file_position.offset),
398             "diagnostic fix range {:?} does not touch cursor position {:?}",
399             fix.target,
400             file_position.offset
401         );
402     }
403     /// Checks that there's a diagnostic *without* fix at `$0`.
404     fn check_no_fix(ra_fixture: &str) {
405         let (analysis, file_position) = fixture::position(ra_fixture);
406         let diagnostic = analysis
407             .diagnostics(
408                 &DiagnosticsConfig::default(),
409                 AssistResolveStrategy::All,
410                 file_position.file_id,
411             )
412             .unwrap()
413             .pop()
414             .unwrap();
415         assert!(diagnostic.fixes.is_none(), "got a fix when none was expected: {:?}", diagnostic);
416     }
417
418     /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
419     /// apply to the file containing the cursor.
420     pub(crate) fn check_no_diagnostics(ra_fixture: &str) {
421         let (analysis, files) = fixture::files(ra_fixture);
422         let diagnostics = files
423             .into_iter()
424             .flat_map(|file_id| {
425                 analysis
426                     .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
427                     .unwrap()
428             })
429             .collect::<Vec<_>>();
430         assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics);
431     }
432
433     pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
434         let (analysis, file_id) = fixture::file(ra_fixture);
435         let diagnostics = analysis
436             .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
437             .unwrap();
438         expect.assert_debug_eq(&diagnostics)
439     }
440
441     #[track_caller]
442     pub(crate) fn check_diagnostics(ra_fixture: &str) {
443         check_diagnostics_with_inactive_code(ra_fixture, false)
444     }
445
446     #[track_caller]
447     pub(crate) fn check_diagnostics_with_inactive_code(ra_fixture: &str, with_inactive_code: bool) {
448         let (analysis, file_id) = fixture::file(ra_fixture);
449         let diagnostics = analysis
450             .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
451             .unwrap();
452
453         let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
454         let mut actual = diagnostics
455             .into_iter()
456             .filter(|d| d.code != Some(DiagnosticCode("inactive-code")) || with_inactive_code)
457             .map(|d| (d.range, d.message))
458             .collect::<Vec<_>>();
459         actual.sort_by_key(|(range, _)| range.start());
460         assert_eq!(expected, actual);
461     }
462
463     #[test]
464     fn range_mapping_out_of_macros() {
465         // FIXME: this is very wrong, but somewhat tricky to fix.
466         check_fix(
467             r#"
468 fn some() {}
469 fn items() {}
470 fn here() {}
471
472 macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
473
474 fn main() {
475     let _x = id![Foo { a: $042 }];
476 }
477
478 pub struct Foo { pub a: i32, pub b: i32 }
479 "#,
480             r#"
481 fn some(, b: () ) {}
482 fn items() {}
483 fn here() {}
484
485 macro_rules! id { ($($tt:tt)*) => { $($tt)*}; }
486
487 fn main() {
488     let _x = id![Foo { a: 42 }];
489 }
490
491 pub struct Foo { pub a: i32, pub b: i32 }
492 "#,
493         );
494     }
495
496     #[test]
497     fn test_check_unnecessary_braces_in_use_statement() {
498         check_no_diagnostics(
499             r#"
500 use a;
501 use a::{c, d::e};
502
503 mod a {
504     mod c {}
505     mod d {
506         mod e {}
507     }
508 }
509 "#,
510         );
511         check_no_diagnostics(
512             r#"
513 use a;
514 use a::{
515     c,
516     // d::e
517 };
518
519 mod a {
520     mod c {}
521     mod d {
522         mod e {}
523     }
524 }
525 "#,
526         );
527         check_fix(
528             r"
529             mod b {}
530             use {$0b};
531             ",
532             r"
533             mod b {}
534             use b;
535             ",
536         );
537         check_fix(
538             r"
539             mod b {}
540             use {b$0};
541             ",
542             r"
543             mod b {}
544             use b;
545             ",
546         );
547         check_fix(
548             r"
549             mod a { mod c {} }
550             use a::{c$0};
551             ",
552             r"
553             mod a { mod c {} }
554             use a::c;
555             ",
556         );
557         check_fix(
558             r"
559             mod a {}
560             use a::{self$0};
561             ",
562             r"
563             mod a {}
564             use a;
565             ",
566         );
567         check_fix(
568             r"
569             mod a { mod c {} mod d { mod e {} } }
570             use a::{c, d::{e$0}};
571             ",
572             r"
573             mod a { mod c {} mod d { mod e {} } }
574             use a::{c, d::e};
575             ",
576         );
577     }
578
579     #[test]
580     fn test_disabled_diagnostics() {
581         let mut config = DiagnosticsConfig::default();
582         config.disabled.insert("unresolved-module".into());
583
584         let (analysis, file_id) = fixture::file(r#"mod foo;"#);
585
586         let diagnostics =
587             analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap();
588         assert!(diagnostics.is_empty());
589
590         let diagnostics = analysis
591             .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id)
592             .unwrap();
593         assert!(!diagnostics.is_empty());
594     }
595
596     #[test]
597     fn unlinked_file_prepend_first_item() {
598         cov_mark::check!(unlinked_file_prepend_before_first_item);
599         // Only tests the first one for `pub mod` since the rest are the same
600         check_fixes(
601             r#"
602 //- /main.rs
603 fn f() {}
604 //- /foo.rs
605 $0
606 "#,
607             vec![
608                 r#"
609 mod foo;
610
611 fn f() {}
612 "#,
613                 r#"
614 pub mod foo;
615
616 fn f() {}
617 "#,
618             ],
619         );
620     }
621
622     #[test]
623     fn unlinked_file_append_mod() {
624         cov_mark::check!(unlinked_file_append_to_existing_mods);
625         check_fix(
626             r#"
627 //- /main.rs
628 //! Comment on top
629
630 mod preexisting;
631
632 mod preexisting2;
633
634 struct S;
635
636 mod preexisting_bottom;)
637 //- /foo.rs
638 $0
639 "#,
640             r#"
641 //! Comment on top
642
643 mod preexisting;
644
645 mod preexisting2;
646 mod foo;
647
648 struct S;
649
650 mod preexisting_bottom;)
651 "#,
652         );
653     }
654
655     #[test]
656     fn unlinked_file_insert_in_empty_file() {
657         cov_mark::check!(unlinked_file_empty_file);
658         check_fix(
659             r#"
660 //- /main.rs
661 //- /foo.rs
662 $0
663 "#,
664             r#"
665 mod foo;
666 "#,
667         );
668     }
669
670     #[test]
671     fn unlinked_file_old_style_modrs() {
672         check_fix(
673             r#"
674 //- /main.rs
675 mod submod;
676 //- /submod/mod.rs
677 // in mod.rs
678 //- /submod/foo.rs
679 $0
680 "#,
681             r#"
682 // in mod.rs
683 mod foo;
684 "#,
685         );
686     }
687
688     #[test]
689     fn unlinked_file_new_style_mod() {
690         check_fix(
691             r#"
692 //- /main.rs
693 mod submod;
694 //- /submod.rs
695 //- /submod/foo.rs
696 $0
697 "#,
698             r#"
699 mod foo;
700 "#,
701         );
702     }
703
704     #[test]
705     fn unlinked_file_with_cfg_off() {
706         cov_mark::check!(unlinked_file_skip_fix_when_mod_already_exists);
707         check_no_fix(
708             r#"
709 //- /main.rs
710 #[cfg(never)]
711 mod foo;
712
713 //- /foo.rs
714 $0
715 "#,
716         );
717     }
718
719     #[test]
720     fn unlinked_file_with_cfg_on() {
721         check_no_diagnostics(
722             r#"
723 //- /main.rs
724 #[cfg(not(never))]
725 mod foo;
726
727 //- /foo.rs
728 "#,
729         );
730     }
731
732     #[test]
733     fn break_outside_of_loop() {
734         check_diagnostics(
735             r#"
736 fn foo() { break; }
737          //^^^^^ break outside of loop
738 "#,
739         );
740     }
741
742     #[test]
743     fn no_such_field_diagnostics() {
744         check_diagnostics(
745             r#"
746 struct S { foo: i32, bar: () }
747 impl S {
748     fn new() -> S {
749         S {
750       //^ Missing structure fields:
751       //|    - bar
752             foo: 92,
753             baz: 62,
754           //^^^^^^^ no such field
755         }
756     }
757 }
758 "#,
759         );
760     }
761     #[test]
762     fn no_such_field_with_feature_flag_diagnostics() {
763         check_diagnostics(
764             r#"
765 //- /lib.rs crate:foo cfg:feature=foo
766 struct MyStruct {
767     my_val: usize,
768     #[cfg(feature = "foo")]
769     bar: bool,
770 }
771
772 impl MyStruct {
773     #[cfg(feature = "foo")]
774     pub(crate) fn new(my_val: usize, bar: bool) -> Self {
775         Self { my_val, bar }
776     }
777     #[cfg(not(feature = "foo"))]
778     pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
779         Self { my_val }
780     }
781 }
782 "#,
783         );
784     }
785
786     #[test]
787     fn no_such_field_enum_with_feature_flag_diagnostics() {
788         check_diagnostics(
789             r#"
790 //- /lib.rs crate:foo cfg:feature=foo
791 enum Foo {
792     #[cfg(not(feature = "foo"))]
793     Buz,
794     #[cfg(feature = "foo")]
795     Bar,
796     Baz
797 }
798
799 fn test_fn(f: Foo) {
800     match f {
801         Foo::Bar => {},
802         Foo::Baz => {},
803     }
804 }
805 "#,
806         );
807     }
808
809     #[test]
810     fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
811         check_diagnostics(
812             r#"
813 //- /lib.rs crate:foo cfg:feature=foo
814 struct S {
815     #[cfg(feature = "foo")]
816     foo: u32,
817     #[cfg(not(feature = "foo"))]
818     bar: u32,
819 }
820
821 impl S {
822     #[cfg(feature = "foo")]
823     fn new(foo: u32) -> Self {
824         Self { foo }
825     }
826     #[cfg(not(feature = "foo"))]
827     fn new(bar: u32) -> Self {
828         Self { bar }
829     }
830     fn new2(bar: u32) -> Self {
831         #[cfg(feature = "foo")]
832         { Self { foo: bar } }
833         #[cfg(not(feature = "foo"))]
834         { Self { bar } }
835     }
836     fn new2(val: u32) -> Self {
837         Self {
838             #[cfg(feature = "foo")]
839             foo: val,
840             #[cfg(not(feature = "foo"))]
841             bar: val,
842         }
843     }
844 }
845 "#,
846         );
847     }
848
849     #[test]
850     fn no_such_field_with_type_macro() {
851         check_diagnostics(
852             r#"
853 macro_rules! Type { () => { u32 }; }
854 struct Foo { bar: Type![] }
855
856 impl Foo {
857     fn new() -> Self {
858         Foo { bar: 0 }
859     }
860 }
861 "#,
862         );
863     }
864
865     #[test]
866     fn missing_unsafe_diagnostic_with_raw_ptr() {
867         check_diagnostics(
868             r#"
869 fn main() {
870     let x = &5 as *const usize;
871     unsafe { let y = *x; }
872     let z = *x;
873 }         //^^ This operation is unsafe and requires an unsafe function or block
874 "#,
875         )
876     }
877
878     #[test]
879     fn missing_unsafe_diagnostic_with_unsafe_call() {
880         check_diagnostics(
881             r#"
882 struct HasUnsafe;
883
884 impl HasUnsafe {
885     unsafe fn unsafe_fn(&self) {
886         let x = &5 as *const usize;
887         let y = *x;
888     }
889 }
890
891 unsafe fn unsafe_fn() {
892     let x = &5 as *const usize;
893     let y = *x;
894 }
895
896 fn main() {
897     unsafe_fn();
898   //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
899     HasUnsafe.unsafe_fn();
900   //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
901     unsafe {
902         unsafe_fn();
903         HasUnsafe.unsafe_fn();
904     }
905 }
906 "#,
907         );
908     }
909
910     #[test]
911     fn missing_unsafe_diagnostic_with_static_mut() {
912         check_diagnostics(
913             r#"
914 struct Ty {
915     a: u8,
916 }
917
918 static mut STATIC_MUT: Ty = Ty { a: 0 };
919
920 fn main() {
921     let x = STATIC_MUT.a;
922           //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
923     unsafe {
924         let x = STATIC_MUT.a;
925     }
926 }
927 "#,
928         );
929     }
930
931     #[test]
932     fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
933         check_diagnostics(
934             r#"
935 extern "rust-intrinsic" {
936     pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
937     pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
938 }
939
940 fn main() {
941     let _ = bitreverse(12);
942     let _ = floorf32(12.0);
943           //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
944 }
945 "#,
946         );
947     }
948
949     // Register the required standard library types to make the tests work
950     fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
951         let prefix = r#"
952         //- /main.rs crate:main deps:core
953         use core::iter::Iterator;
954         use core::option::Option::{self, Some, None};
955         "#;
956         let suffix = r#"
957         //- /core/lib.rs crate:core
958         pub mod option {
959             pub enum Option<T> { Some(T), None }
960         }
961         pub mod iter {
962             pub trait Iterator {
963                 type Item;
964                 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
965                 fn next(&mut self) -> Option<Self::Item>;
966             }
967             pub struct FilterMap {}
968             impl Iterator for FilterMap {
969                 type Item = i32;
970                 fn next(&mut self) -> i32 { 7 }
971             }
972         }
973         "#;
974         format!("{}{}{}", prefix, body, suffix)
975     }
976
977     #[test]
978     fn replace_filter_map_next_with_find_map2() {
979         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
980             r#"
981             fn foo() {
982                 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
983                       //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
984             }
985         "#,
986         ));
987     }
988
989     #[test]
990     fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
991         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
992             r#"
993             fn foo() {
994                 let m = [1, 2, 3]
995                     .iter()
996                     .filter_map(|x| if *x == 2 { Some (4) } else { None })
997                     .len();
998             }
999             "#,
1000         ));
1001     }
1002
1003     #[test]
1004     fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
1005         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
1006             r#"
1007             fn foo() {
1008                 let m = [1, 2, 3]
1009                     .iter()
1010                     .filter_map(|x| if *x == 2 { Some (4) } else { None })
1011                     .map(|x| x + 2)
1012                     .len();
1013             }
1014             "#,
1015         ));
1016     }
1017
1018     #[test]
1019     fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
1020         check_diagnostics(&add_filter_map_with_find_next_boilerplate(
1021             r#"
1022             fn foo() {
1023                 let m = [1, 2, 3]
1024                     .iter()
1025                     .filter_map(|x| if *x == 2 { Some (4) } else { None });
1026                 let n = m.next();
1027             }
1028             "#,
1029         ));
1030     }
1031
1032     #[test]
1033     fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
1034         check_diagnostics(
1035             r"
1036 struct S { foo: i32, bar: () }
1037 fn baz(s: S) -> i32 {
1038     match s {
1039         S { foo, .. } => foo,
1040     }
1041 }
1042 ",
1043         )
1044     }
1045
1046     #[test]
1047     fn missing_record_pat_field_box() {
1048         check_diagnostics(
1049             r"
1050 struct S { s: Box<u32> }
1051 fn x(a: S) {
1052     let S { box s } = a;
1053 }
1054 ",
1055         )
1056     }
1057
1058     #[test]
1059     fn missing_record_pat_field_ref() {
1060         check_diagnostics(
1061             r"
1062 struct S { s: u32 }
1063 fn x(a: S) {
1064     let S { ref s } = a;
1065 }
1066 ",
1067         )
1068     }
1069
1070     #[test]
1071     fn simple_free_fn_zero() {
1072         check_diagnostics(
1073             r#"
1074 fn zero() {}
1075 fn f() { zero(1); }
1076        //^^^^^^^ Expected 0 arguments, found 1
1077 "#,
1078         );
1079
1080         check_diagnostics(
1081             r#"
1082 fn zero() {}
1083 fn f() { zero(); }
1084 "#,
1085         );
1086     }
1087
1088     #[test]
1089     fn simple_free_fn_one() {
1090         check_diagnostics(
1091             r#"
1092 fn one(arg: u8) {}
1093 fn f() { one(); }
1094        //^^^^^ Expected 1 argument, found 0
1095 "#,
1096         );
1097
1098         check_diagnostics(
1099             r#"
1100 fn one(arg: u8) {}
1101 fn f() { one(1); }
1102 "#,
1103         );
1104     }
1105
1106     #[test]
1107     fn method_as_fn() {
1108         check_diagnostics(
1109             r#"
1110 struct S;
1111 impl S { fn method(&self) {} }
1112
1113 fn f() {
1114     S::method();
1115 } //^^^^^^^^^^^ Expected 1 argument, found 0
1116 "#,
1117         );
1118
1119         check_diagnostics(
1120             r#"
1121 struct S;
1122 impl S { fn method(&self) {} }
1123
1124 fn f() {
1125     S::method(&S);
1126     S.method();
1127 }
1128 "#,
1129         );
1130     }
1131
1132     #[test]
1133     fn method_with_arg() {
1134         check_diagnostics(
1135             r#"
1136 struct S;
1137 impl S { fn method(&self, arg: u8) {} }
1138
1139             fn f() {
1140                 S.method();
1141             } //^^^^^^^^^^ Expected 1 argument, found 0
1142             "#,
1143         );
1144
1145         check_diagnostics(
1146             r#"
1147 struct S;
1148 impl S { fn method(&self, arg: u8) {} }
1149
1150 fn f() {
1151     S::method(&S, 0);
1152     S.method(1);
1153 }
1154 "#,
1155         );
1156     }
1157
1158     #[test]
1159     fn method_unknown_receiver() {
1160         // note: this is incorrect code, so there might be errors on this in the
1161         // future, but we shouldn't emit an argument count diagnostic here
1162         check_diagnostics(
1163             r#"
1164 trait Foo { fn method(&self, arg: usize) {} }
1165
1166 fn f() {
1167     let x;
1168     x.method();
1169 }
1170 "#,
1171         );
1172     }
1173
1174     #[test]
1175     fn tuple_struct() {
1176         check_diagnostics(
1177             r#"
1178 struct Tup(u8, u16);
1179 fn f() {
1180     Tup(0);
1181 } //^^^^^^ Expected 2 arguments, found 1
1182 "#,
1183         )
1184     }
1185
1186     #[test]
1187     fn enum_variant() {
1188         check_diagnostics(
1189             r#"
1190 enum En { Variant(u8, u16), }
1191 fn f() {
1192     En::Variant(0);
1193 } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1
1194 "#,
1195         )
1196     }
1197
1198     #[test]
1199     fn enum_variant_type_macro() {
1200         check_diagnostics(
1201             r#"
1202 macro_rules! Type {
1203     () => { u32 };
1204 }
1205 enum Foo {
1206     Bar(Type![])
1207 }
1208 impl Foo {
1209     fn new() {
1210         Foo::Bar(0);
1211         Foo::Bar(0, 1);
1212       //^^^^^^^^^^^^^^ Expected 1 argument, found 2
1213         Foo::Bar();
1214       //^^^^^^^^^^ Expected 1 argument, found 0
1215     }
1216 }
1217         "#,
1218         );
1219     }
1220
1221     #[test]
1222     fn varargs() {
1223         check_diagnostics(
1224             r#"
1225 extern "C" {
1226     fn fixed(fixed: u8);
1227     fn varargs(fixed: u8, ...);
1228     fn varargs2(...);
1229 }
1230
1231 fn f() {
1232     unsafe {
1233         fixed(0);
1234         fixed(0, 1);
1235       //^^^^^^^^^^^ Expected 1 argument, found 2
1236         varargs(0);
1237         varargs(0, 1);
1238         varargs2();
1239         varargs2(0);
1240         varargs2(0, 1);
1241     }
1242 }
1243         "#,
1244         )
1245     }
1246
1247     #[test]
1248     fn arg_count_lambda() {
1249         check_diagnostics(
1250             r#"
1251 fn main() {
1252     let f = |()| ();
1253     f();
1254   //^^^ Expected 1 argument, found 0
1255     f(());
1256     f((), ());
1257   //^^^^^^^^^ Expected 1 argument, found 2
1258 }
1259 "#,
1260         )
1261     }
1262
1263     #[test]
1264     fn cfgd_out_call_arguments() {
1265         check_diagnostics(
1266             r#"
1267 struct C(#[cfg(FALSE)] ());
1268 impl C {
1269     fn new() -> Self {
1270         Self(
1271             #[cfg(FALSE)]
1272             (),
1273         )
1274     }
1275
1276     fn method(&self) {}
1277 }
1278
1279 fn main() {
1280     C::new().method(#[cfg(FALSE)] 0);
1281 }
1282             "#,
1283         );
1284     }
1285
1286     #[test]
1287     fn cfgd_out_fn_params() {
1288         check_diagnostics(
1289             r#"
1290 fn foo(#[cfg(NEVER)] x: ()) {}
1291
1292 struct S;
1293
1294 impl S {
1295     fn method(#[cfg(NEVER)] self) {}
1296     fn method2(#[cfg(NEVER)] self, arg: u8) {}
1297     fn method3(self, #[cfg(NEVER)] arg: u8) {}
1298 }
1299
1300 extern "C" {
1301     fn fixed(fixed: u8, #[cfg(NEVER)] ...);
1302     fn varargs(#[cfg(not(NEVER))] ...);
1303 }
1304
1305 fn main() {
1306     foo();
1307     S::method();
1308     S::method2(0);
1309     S::method3(S);
1310     S.method3();
1311     unsafe {
1312         fixed(0);
1313         varargs(1, 2, 3);
1314     }
1315 }
1316             "#,
1317         )
1318     }
1319
1320     #[test]
1321     fn missing_semicolon() {
1322         check_diagnostics(
1323             r#"
1324                 fn test() -> i32 { 123; }
1325                                  //^^^ Remove this semicolon
1326             "#,
1327         );
1328     }
1329
1330     #[test]
1331     fn import_extern_crate_clash_with_inner_item() {
1332         // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
1333
1334         check_diagnostics(
1335             r#"
1336 //- /lib.rs crate:lib deps:jwt
1337 mod permissions;
1338
1339 use permissions::jwt;
1340
1341 fn f() {
1342     fn inner() {}
1343     jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
1344 }
1345
1346 //- /permissions.rs
1347 pub mod jwt  {
1348     pub struct Claims {}
1349 }
1350
1351 //- /jwt/lib.rs crate:jwt
1352 pub struct Claims {
1353     field: u8,
1354 }
1355         "#,
1356         );
1357     }
1358 }
1359
1360 #[cfg(test)]
1361 pub(super) mod match_check_tests {
1362     use crate::diagnostics::tests::check_diagnostics;
1363
1364     #[test]
1365     fn empty_tuple() {
1366         check_diagnostics(
1367             r#"
1368 fn main() {
1369     match () { }
1370         //^^ Missing match arm
1371     match (()) { }
1372         //^^^^ Missing match arm
1373
1374     match () { _ => (), }
1375     match () { () => (), }
1376     match (()) { (()) => (), }
1377 }
1378 "#,
1379         );
1380     }
1381
1382     #[test]
1383     fn tuple_of_two_empty_tuple() {
1384         check_diagnostics(
1385             r#"
1386 fn main() {
1387     match ((), ()) { }
1388         //^^^^^^^^ Missing match arm
1389
1390     match ((), ()) { ((), ()) => (), }
1391 }
1392 "#,
1393         );
1394     }
1395
1396     #[test]
1397     fn boolean() {
1398         check_diagnostics(
1399             r#"
1400 fn test_main() {
1401     match false { }
1402         //^^^^^ Missing match arm
1403     match false { true => (), }
1404         //^^^^^ Missing match arm
1405     match (false, true) {}
1406         //^^^^^^^^^^^^^ Missing match arm
1407     match (false, true) { (true, true) => (), }
1408         //^^^^^^^^^^^^^ Missing match arm
1409     match (false, true) {
1410         //^^^^^^^^^^^^^ Missing match arm
1411         (false, true) => (),
1412         (false, false) => (),
1413         (true, false) => (),
1414     }
1415     match (false, true) { (true, _x) => (), }
1416         //^^^^^^^^^^^^^ Missing match arm
1417
1418     match false { true => (), false => (), }
1419     match (false, true) {
1420         (false, _) => (),
1421         (true, false) => (),
1422         (_, true) => (),
1423     }
1424     match (false, true) {
1425         (true, true) => (),
1426         (true, false) => (),
1427         (false, true) => (),
1428         (false, false) => (),
1429     }
1430     match (false, true) {
1431         (true, _x) => (),
1432         (false, true) => (),
1433         (false, false) => (),
1434     }
1435     match (false, true, false) {
1436         (false, ..) => (),
1437         (true, ..) => (),
1438     }
1439     match (false, true, false) {
1440         (.., false) => (),
1441         (.., true) => (),
1442     }
1443     match (false, true, false) { (..) => (), }
1444 }
1445 "#,
1446         );
1447     }
1448
1449     #[test]
1450     fn tuple_of_tuple_and_bools() {
1451         check_diagnostics(
1452             r#"
1453 fn main() {
1454     match (false, ((), false)) {}
1455         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1456     match (false, ((), false)) { (true, ((), true)) => (), }
1457         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1458     match (false, ((), false)) { (true, _) => (), }
1459         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1460
1461     match (false, ((), false)) {
1462         (true, ((), true)) => (),
1463         (true, ((), false)) => (),
1464         (false, ((), true)) => (),
1465         (false, ((), false)) => (),
1466     }
1467     match (false, ((), false)) {
1468         (true, ((), true)) => (),
1469         (true, ((), false)) => (),
1470         (false, _) => (),
1471     }
1472 }
1473 "#,
1474         );
1475     }
1476
1477     #[test]
1478     fn enums() {
1479         check_diagnostics(
1480             r#"
1481 enum Either { A, B, }
1482
1483 fn main() {
1484     match Either::A { }
1485         //^^^^^^^^^ Missing match arm
1486     match Either::B { Either::A => (), }
1487         //^^^^^^^^^ Missing match arm
1488
1489     match &Either::B {
1490         //^^^^^^^^^^ Missing match arm
1491         Either::A => (),
1492     }
1493
1494     match Either::B {
1495         Either::A => (), Either::B => (),
1496     }
1497     match &Either::B {
1498         Either::A => (), Either::B => (),
1499     }
1500 }
1501 "#,
1502         );
1503     }
1504
1505     #[test]
1506     fn enum_containing_bool() {
1507         check_diagnostics(
1508             r#"
1509 enum Either { A(bool), B }
1510
1511 fn main() {
1512     match Either::B { }
1513         //^^^^^^^^^ Missing match arm
1514     match Either::B {
1515         //^^^^^^^^^ Missing match arm
1516         Either::A(true) => (), Either::B => ()
1517     }
1518
1519     match Either::B {
1520         Either::A(true) => (),
1521         Either::A(false) => (),
1522         Either::B => (),
1523     }
1524     match Either::B {
1525         Either::B => (),
1526         _ => (),
1527     }
1528     match Either::B {
1529         Either::A(_) => (),
1530         Either::B => (),
1531     }
1532
1533 }
1534         "#,
1535         );
1536     }
1537
1538     #[test]
1539     fn enum_different_sizes() {
1540         check_diagnostics(
1541             r#"
1542 enum Either { A(bool), B(bool, bool) }
1543
1544 fn main() {
1545     match Either::A(false) {
1546         //^^^^^^^^^^^^^^^^ Missing match arm
1547         Either::A(_) => (),
1548         Either::B(false, _) => (),
1549     }
1550
1551     match Either::A(false) {
1552         Either::A(_) => (),
1553         Either::B(true, _) => (),
1554         Either::B(false, _) => (),
1555     }
1556     match Either::A(false) {
1557         Either::A(true) | Either::A(false) => (),
1558         Either::B(true, _) => (),
1559         Either::B(false, _) => (),
1560     }
1561 }
1562 "#,
1563         );
1564     }
1565
1566     #[test]
1567     fn tuple_of_enum_no_diagnostic() {
1568         check_diagnostics(
1569             r#"
1570 enum Either { A(bool), B(bool, bool) }
1571 enum Either2 { C, D }
1572
1573 fn main() {
1574     match (Either::A(false), Either2::C) {
1575         (Either::A(true), _) | (Either::A(false), _) => (),
1576         (Either::B(true, _), Either2::C) => (),
1577         (Either::B(false, _), Either2::C) => (),
1578         (Either::B(_, _), Either2::D) => (),
1579     }
1580 }
1581 "#,
1582         );
1583     }
1584
1585     #[test]
1586     fn or_pattern_no_diagnostic() {
1587         check_diagnostics(
1588             r#"
1589 enum Either {A, B}
1590
1591 fn main() {
1592     match (Either::A, Either::B) {
1593         (Either::A | Either::B, _) => (),
1594     }
1595 }"#,
1596         )
1597     }
1598
1599     #[test]
1600     fn mismatched_types() {
1601         // Match statements with arms that don't match the
1602         // expression pattern do not fire this diagnostic.
1603         check_diagnostics(
1604             r#"
1605 enum Either { A, B }
1606 enum Either2 { C, D }
1607
1608 fn main() {
1609     match Either::A {
1610         Either2::C => (),
1611     //  ^^^^^^^^^^ Internal: match check bailed out
1612         Either2::D => (),
1613     }
1614     match (true, false) {
1615         (true, false, true) => (),
1616     //  ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out
1617         (true) => (),
1618     }
1619     match (true, false) { (true,) => {} }
1620     //                    ^^^^^^^ Internal: match check bailed out
1621     match (0) { () => () }
1622             //  ^^ Internal: match check bailed out
1623     match Unresolved::Bar { Unresolved::Baz => () }
1624 }
1625         "#,
1626         );
1627     }
1628
1629     #[test]
1630     fn mismatched_types_in_or_patterns() {
1631         check_diagnostics(
1632             r#"
1633 fn main() {
1634     match false { true | () => {} }
1635     //            ^^^^^^^^^ Internal: match check bailed out
1636     match (false,) { (true | (),) => {} }
1637     //               ^^^^^^^^^^^^ Internal: match check bailed out
1638 }
1639 "#,
1640         );
1641     }
1642
1643     #[test]
1644     fn malformed_match_arm_tuple_enum_missing_pattern() {
1645         // We are testing to be sure we don't panic here when the match
1646         // arm `Either::B` is missing its pattern.
1647         check_diagnostics(
1648             r#"
1649 enum Either { A, B(u32) }
1650
1651 fn main() {
1652     match Either::A {
1653         Either::A => (),
1654         Either::B() => (),
1655     }
1656 }
1657 "#,
1658         );
1659     }
1660
1661     #[test]
1662     fn malformed_match_arm_extra_fields() {
1663         check_diagnostics(
1664             r#"
1665 enum A { B(isize, isize), C }
1666 fn main() {
1667     match A::B(1, 2) {
1668         A::B(_, _, _) => (),
1669     //  ^^^^^^^^^^^^^ Internal: match check bailed out
1670     }
1671     match A::B(1, 2) {
1672         A::C(_) => (),
1673     //  ^^^^^^^ Internal: match check bailed out
1674     }
1675 }
1676 "#,
1677         );
1678     }
1679
1680     #[test]
1681     fn expr_diverges() {
1682         check_diagnostics(
1683             r#"
1684 enum Either { A, B }
1685
1686 fn main() {
1687     match loop {} {
1688         Either::A => (),
1689     //  ^^^^^^^^^ Internal: match check bailed out
1690         Either::B => (),
1691     }
1692     match loop {} {
1693         Either::A => (),
1694     //  ^^^^^^^^^ Internal: match check bailed out
1695     }
1696     match loop { break Foo::A } {
1697         //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1698         Either::A => (),
1699     }
1700     match loop { break Foo::A } {
1701         Either::A => (),
1702         Either::B => (),
1703     }
1704 }
1705 "#,
1706         );
1707     }
1708
1709     #[test]
1710     fn expr_partially_diverges() {
1711         check_diagnostics(
1712             r#"
1713 enum Either<T> { A(T), B }
1714
1715 fn foo() -> Either<!> { Either::B }
1716 fn main() -> u32 {
1717     match foo() {
1718         Either::A(val) => val,
1719         Either::B => 0,
1720     }
1721 }
1722 "#,
1723         );
1724     }
1725
1726     #[test]
1727     fn enum_record() {
1728         check_diagnostics(
1729             r#"
1730 enum Either { A { foo: bool }, B }
1731
1732 fn main() {
1733     let a = Either::A { foo: true };
1734     match a { }
1735         //^ Missing match arm
1736     match a { Either::A { foo: true } => () }
1737         //^ Missing match arm
1738     match a {
1739         Either::A { } => (),
1740       //^^^^^^^^^ Missing structure fields:
1741       //        | - foo
1742         Either::B => (),
1743     }
1744     match a {
1745         //^ Missing match arm
1746         Either::A { } => (),
1747     } //^^^^^^^^^ Missing structure fields:
1748       //        | - foo
1749
1750     match a {
1751         Either::A { foo: true } => (),
1752         Either::A { foo: false } => (),
1753         Either::B => (),
1754     }
1755     match a {
1756         Either::A { foo: _ } => (),
1757         Either::B => (),
1758     }
1759 }
1760 "#,
1761         );
1762     }
1763
1764     #[test]
1765     fn enum_record_fields_out_of_order() {
1766         check_diagnostics(
1767             r#"
1768 enum Either {
1769     A { foo: bool, bar: () },
1770     B,
1771 }
1772
1773 fn main() {
1774     let a = Either::A { foo: true, bar: () };
1775     match a {
1776         //^ Missing match arm
1777         Either::A { bar: (), foo: false } => (),
1778         Either::A { foo: true, bar: () } => (),
1779     }
1780
1781     match a {
1782         Either::A { bar: (), foo: false } => (),
1783         Either::A { foo: true, bar: () } => (),
1784         Either::B => (),
1785     }
1786 }
1787 "#,
1788         );
1789     }
1790
1791     #[test]
1792     fn enum_record_ellipsis() {
1793         check_diagnostics(
1794             r#"
1795 enum Either {
1796     A { foo: bool, bar: bool },
1797     B,
1798 }
1799
1800 fn main() {
1801     let a = Either::B;
1802     match a {
1803         //^ Missing match arm
1804         Either::A { foo: true, .. } => (),
1805         Either::B => (),
1806     }
1807     match a {
1808         //^ Missing match arm
1809         Either::A { .. } => (),
1810     }
1811
1812     match a {
1813         Either::A { foo: true, .. } => (),
1814         Either::A { foo: false, .. } => (),
1815         Either::B => (),
1816     }
1817
1818     match a {
1819         Either::A { .. } => (),
1820         Either::B => (),
1821     }
1822 }
1823 "#,
1824         );
1825     }
1826
1827     #[test]
1828     fn enum_tuple_partial_ellipsis() {
1829         check_diagnostics(
1830             r#"
1831 enum Either {
1832     A(bool, bool, bool, bool),
1833     B,
1834 }
1835
1836 fn main() {
1837     match Either::B {
1838         //^^^^^^^^^ Missing match arm
1839         Either::A(true, .., true) => (),
1840         Either::A(true, .., false) => (),
1841         Either::A(false, .., false) => (),
1842         Either::B => (),
1843     }
1844     match Either::B {
1845         //^^^^^^^^^ Missing match arm
1846         Either::A(true, .., true) => (),
1847         Either::A(true, .., false) => (),
1848         Either::A(.., true) => (),
1849         Either::B => (),
1850     }
1851
1852     match Either::B {
1853         Either::A(true, .., true) => (),
1854         Either::A(true, .., false) => (),
1855         Either::A(false, .., true) => (),
1856         Either::A(false, .., false) => (),
1857         Either::B => (),
1858     }
1859     match Either::B {
1860         Either::A(true, .., true) => (),
1861         Either::A(true, .., false) => (),
1862         Either::A(.., true) => (),
1863         Either::A(.., false) => (),
1864         Either::B => (),
1865     }
1866 }
1867 "#,
1868         );
1869     }
1870
1871     #[test]
1872     fn never() {
1873         check_diagnostics(
1874             r#"
1875 enum Never {}
1876
1877 fn enum_(never: Never) {
1878     match never {}
1879 }
1880 fn enum_ref(never: &Never) {
1881     match never {}
1882         //^^^^^ Missing match arm
1883 }
1884 fn bang(never: !) {
1885     match never {}
1886 }
1887 "#,
1888         );
1889     }
1890
1891     #[test]
1892     fn unknown_type() {
1893         check_diagnostics(
1894             r#"
1895 enum Option<T> { Some(T), None }
1896
1897 fn main() {
1898     // `Never` is deliberately not defined so that it's an uninferred type.
1899     match Option::<Never>::None {
1900         None => (),
1901         Some(never) => match never {},
1902     //  ^^^^^^^^^^^ Internal: match check bailed out
1903     }
1904     match Option::<Never>::None {
1905         //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1906         Option::Some(_never) => {},
1907     }
1908 }
1909 "#,
1910         );
1911     }
1912
1913     #[test]
1914     fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
1915         check_diagnostics(
1916             r#"
1917 fn main() {
1918     match (false, true, false) {
1919         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1920         (false, ..) => (),
1921     }
1922 }"#,
1923         );
1924     }
1925
1926     #[test]
1927     fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
1928         check_diagnostics(
1929             r#"
1930 fn main() {
1931     match (false, true, false) {
1932         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1933         (.., false) => (),
1934     }
1935 }"#,
1936         );
1937     }
1938
1939     #[test]
1940     fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
1941         check_diagnostics(
1942             r#"
1943 fn main() {
1944     match (false, true, false) {
1945         //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1946         (true, .., false) => (),
1947     }
1948 }"#,
1949         );
1950     }
1951
1952     #[test]
1953     fn record_struct() {
1954         check_diagnostics(
1955             r#"struct Foo { a: bool }
1956 fn main(f: Foo) {
1957     match f {}
1958         //^ Missing match arm
1959     match f { Foo { a: true } => () }
1960         //^ Missing match arm
1961     match &f { Foo { a: true } => () }
1962         //^^ Missing match arm
1963     match f { Foo { a: _ } => () }
1964     match f {
1965         Foo { a: true } => (),
1966         Foo { a: false } => (),
1967     }
1968     match &f {
1969         Foo { a: true } => (),
1970         Foo { a: false } => (),
1971     }
1972 }
1973 "#,
1974         );
1975     }
1976
1977     #[test]
1978     fn tuple_struct() {
1979         check_diagnostics(
1980             r#"struct Foo(bool);
1981 fn main(f: Foo) {
1982     match f {}
1983         //^ Missing match arm
1984     match f { Foo(true) => () }
1985         //^ Missing match arm
1986     match f {
1987         Foo(true) => (),
1988         Foo(false) => (),
1989     }
1990 }
1991 "#,
1992         );
1993     }
1994
1995     #[test]
1996     fn unit_struct() {
1997         check_diagnostics(
1998             r#"struct Foo;
1999 fn main(f: Foo) {
2000     match f {}
2001         //^ Missing match arm
2002     match f { Foo => () }
2003 }
2004 "#,
2005         );
2006     }
2007
2008     #[test]
2009     fn record_struct_ellipsis() {
2010         check_diagnostics(
2011             r#"struct Foo { foo: bool, bar: bool }
2012 fn main(f: Foo) {
2013     match f { Foo { foo: true, .. } => () }
2014         //^ Missing match arm
2015     match f {
2016         //^ Missing match arm
2017         Foo { foo: true, .. } => (),
2018         Foo { bar: false, .. } => ()
2019     }
2020     match f { Foo { .. } => () }
2021     match f {
2022         Foo { foo: true, .. } => (),
2023         Foo { foo: false, .. } => ()
2024     }
2025 }
2026 "#,
2027         );
2028     }
2029
2030     #[test]
2031     fn internal_or() {
2032         check_diagnostics(
2033             r#"
2034 fn main() {
2035     enum Either { A(bool), B }
2036     match Either::B {
2037         //^^^^^^^^^ Missing match arm
2038         Either::A(true | false) => (),
2039     }
2040 }
2041 "#,
2042         );
2043     }
2044
2045     #[test]
2046     fn no_panic_at_unimplemented_subpattern_type() {
2047         check_diagnostics(
2048             r#"
2049 struct S { a: char}
2050 fn main(v: S) {
2051     match v { S{ a }      => {} }
2052     match v { S{ a: _x }  => {} }
2053     match v { S{ a: 'a' } => {} }
2054             //^^^^^^^^^^^ Internal: match check bailed out
2055     match v { S{..}       => {} }
2056     match v { _           => {} }
2057     match v { }
2058         //^ Missing match arm
2059 }
2060 "#,
2061         );
2062     }
2063
2064     #[test]
2065     fn binding() {
2066         check_diagnostics(
2067             r#"
2068 fn main() {
2069     match true {
2070         _x @ true => {}
2071         false     => {}
2072     }
2073     match true { _x @ true => {} }
2074         //^^^^ Missing match arm
2075 }
2076 "#,
2077         );
2078     }
2079
2080     #[test]
2081     fn binding_ref_has_correct_type() {
2082         // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
2083         // If that's not true match checking will panic with "incompatible constructors"
2084         // FIXME: make facilities to test this directly like `tests::check_infer(..)`
2085         check_diagnostics(
2086             r#"
2087 enum Foo { A }
2088 fn main() {
2089     // FIXME: this should not bail out but current behavior is such as the old algorithm.
2090     // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
2091     match Foo::A {
2092         ref _x => {}
2093     //  ^^^^^^ Internal: match check bailed out
2094         Foo::A => {}
2095     }
2096     match (true,) {
2097         (ref _x,) => {}
2098         (true,) => {}
2099     }
2100 }
2101 "#,
2102         );
2103     }
2104
2105     #[test]
2106     fn enum_non_exhaustive() {
2107         check_diagnostics(
2108             r#"
2109 //- /lib.rs crate:lib
2110 #[non_exhaustive]
2111 pub enum E { A, B }
2112 fn _local() {
2113     match E::A { _ => {} }
2114     match E::A {
2115         E::A => {}
2116         E::B => {}
2117     }
2118     match E::A {
2119         E::A | E::B => {}
2120     }
2121 }
2122
2123 //- /main.rs crate:main deps:lib
2124 use lib::E;
2125 fn main() {
2126     match E::A { _ => {} }
2127     match E::A {
2128         //^^^^ Missing match arm
2129         E::A => {}
2130         E::B => {}
2131     }
2132     match E::A {
2133         //^^^^ Missing match arm
2134         E::A | E::B => {}
2135     }
2136 }
2137 "#,
2138         );
2139     }
2140
2141     #[test]
2142     fn match_guard() {
2143         check_diagnostics(
2144             r#"
2145 fn main() {
2146     match true {
2147         true if false => {}
2148         true          => {}
2149         false         => {}
2150     }
2151     match true {
2152         //^^^^ Missing match arm
2153         true if false => {}
2154         false         => {}
2155     }
2156 }
2157 "#,
2158         );
2159     }
2160
2161     #[test]
2162     fn pattern_type_is_of_substitution() {
2163         cov_mark::check!(match_check_wildcard_expanded_to_substitutions);
2164         check_diagnostics(
2165             r#"
2166 struct Foo<T>(T);
2167 struct Bar;
2168 fn main() {
2169     match Foo(Bar) {
2170         _ | Foo(Bar) => {}
2171     }
2172 }
2173 "#,
2174         );
2175     }
2176
2177     #[test]
2178     fn record_struct_no_such_field() {
2179         check_diagnostics(
2180             r#"
2181 struct Foo { }
2182 fn main(f: Foo) {
2183     match f { Foo { bar } => () }
2184     //        ^^^^^^^^^^^ Internal: match check bailed out
2185 }
2186 "#,
2187         );
2188     }
2189
2190     #[test]
2191     fn match_ergonomics_issue_9095() {
2192         check_diagnostics(
2193             r#"
2194 enum Foo<T> { A(T) }
2195 fn main() {
2196     match &Foo::A(true) {
2197         _ => {}
2198         Foo::A(_) => {}
2199     }
2200 }
2201 "#,
2202         );
2203     }
2204
2205     mod false_negatives {
2206         //! The implementation of match checking here is a work in progress. As we roll this out, we
2207         //! prefer false negatives to false positives (ideally there would be no false positives). This
2208         //! test module should document known false negatives. Eventually we will have a complete
2209         //! implementation of match checking and this module will be empty.
2210         //!
2211         //! The reasons for documenting known false negatives:
2212         //!
2213         //!   1. It acts as a backlog of work that can be done to improve the behavior of the system.
2214         //!   2. It ensures the code doesn't panic when handling these cases.
2215         use super::*;
2216
2217         #[test]
2218         fn integers() {
2219             // We don't currently check integer exhaustiveness.
2220             check_diagnostics(
2221                 r#"
2222 fn main() {
2223     match 5 {
2224         10 => (),
2225     //  ^^ Internal: match check bailed out
2226         11..20 => (),
2227     }
2228 }
2229 "#,
2230             );
2231         }
2232
2233         #[test]
2234         fn reference_patterns_at_top_level() {
2235             check_diagnostics(
2236                 r#"
2237 fn main() {
2238     match &false {
2239         &true => {}
2240     //  ^^^^^ Internal: match check bailed out
2241     }
2242 }
2243             "#,
2244             );
2245         }
2246
2247         #[test]
2248         fn reference_patterns_in_fields() {
2249             check_diagnostics(
2250                 r#"
2251 fn main() {
2252     match (&false,) {
2253         (true,) => {}
2254     //  ^^^^^^^ Internal: match check bailed out
2255     }
2256     match (&false,) {
2257         (&true,) => {}
2258     //  ^^^^^^^^ Internal: match check bailed out
2259     }
2260 }
2261             "#,
2262             );
2263         }
2264     }
2265 }
2266
2267 #[cfg(test)]
2268 mod decl_check_tests {
2269     use crate::diagnostics::tests::check_diagnostics;
2270
2271     #[test]
2272     fn incorrect_function_name() {
2273         check_diagnostics(
2274             r#"
2275 fn NonSnakeCaseName() {}
2276 // ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
2277 "#,
2278         );
2279     }
2280
2281     #[test]
2282     fn incorrect_function_params() {
2283         check_diagnostics(
2284             r#"
2285 fn foo(SomeParam: u8) {}
2286     // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
2287
2288 fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
2289                      // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
2290 "#,
2291         );
2292     }
2293
2294     #[test]
2295     fn incorrect_variable_names() {
2296         check_diagnostics(
2297             r#"
2298 fn foo() {
2299     let SOME_VALUE = 10;
2300      // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
2301     let AnotherValue = 20;
2302      // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
2303 }
2304 "#,
2305         );
2306     }
2307
2308     #[test]
2309     fn incorrect_struct_names() {
2310         check_diagnostics(
2311             r#"
2312 struct non_camel_case_name {}
2313     // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
2314
2315 struct SCREAMING_CASE {}
2316     // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
2317 "#,
2318         );
2319     }
2320
2321     #[test]
2322     fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
2323         check_diagnostics(
2324             r#"
2325 struct AABB {}
2326 "#,
2327         );
2328     }
2329
2330     #[test]
2331     fn incorrect_struct_field() {
2332         check_diagnostics(
2333             r#"
2334 struct SomeStruct { SomeField: u8 }
2335                  // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
2336 "#,
2337         );
2338     }
2339
2340     #[test]
2341     fn incorrect_enum_names() {
2342         check_diagnostics(
2343             r#"
2344 enum some_enum { Val(u8) }
2345   // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
2346
2347 enum SOME_ENUM {}
2348   // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
2349 "#,
2350         );
2351     }
2352
2353     #[test]
2354     fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
2355         check_diagnostics(
2356             r#"
2357 enum AABB {}
2358 "#,
2359         );
2360     }
2361
2362     #[test]
2363     fn incorrect_enum_variant_name() {
2364         check_diagnostics(
2365             r#"
2366 enum SomeEnum { SOME_VARIANT(u8) }
2367              // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
2368 "#,
2369         );
2370     }
2371
2372     #[test]
2373     fn incorrect_const_name() {
2374         check_diagnostics(
2375             r#"
2376 const some_weird_const: u8 = 10;
2377    // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2378 "#,
2379         );
2380     }
2381
2382     #[test]
2383     fn incorrect_static_name() {
2384         check_diagnostics(
2385             r#"
2386 static some_weird_const: u8 = 10;
2387     // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2388 "#,
2389         );
2390     }
2391
2392     #[test]
2393     fn fn_inside_impl_struct() {
2394         check_diagnostics(
2395             r#"
2396 struct someStruct;
2397     // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
2398
2399 impl someStruct {
2400     fn SomeFunc(&self) {
2401     // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
2402         let WHY_VAR_IS_CAPS = 10;
2403          // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
2404     }
2405 }
2406 "#,
2407         );
2408     }
2409
2410     #[test]
2411     fn no_diagnostic_for_enum_varinats() {
2412         check_diagnostics(
2413             r#"
2414 enum Option { Some, None }
2415
2416 fn main() {
2417     match Option::None {
2418         None => (),
2419         Some => (),
2420     }
2421 }
2422 "#,
2423         );
2424     }
2425
2426     #[test]
2427     fn non_let_bind() {
2428         check_diagnostics(
2429             r#"
2430 enum Option { Some, None }
2431
2432 fn main() {
2433     match Option::None {
2434         SOME_VAR @ None => (),
2435      // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
2436         Some => (),
2437     }
2438 }
2439 "#,
2440         );
2441     }
2442
2443     #[test]
2444     fn allow_attributes() {
2445         check_diagnostics(
2446             r#"
2447 #[allow(non_snake_case)]
2448 fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
2449     // cov_flags generated output from elsewhere in this file
2450     extern "C" {
2451         #[no_mangle]
2452         static lower_case: u8;
2453     }
2454
2455     let OtherVar = SOME_VAR + 1;
2456     OtherVar
2457 }
2458
2459 #[allow(nonstandard_style)]
2460 mod CheckNonstandardStyle {
2461     fn HiImABadFnName() {}
2462 }
2463
2464 #[allow(bad_style)]
2465 mod CheckBadStyle {
2466     fn HiImABadFnName() {}
2467 }
2468
2469 mod F {
2470     #![allow(non_snake_case)]
2471     fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
2472 }
2473
2474 #[allow(non_snake_case, non_camel_case_types)]
2475 pub struct some_type {
2476     SOME_FIELD: u8,
2477     SomeField: u16,
2478 }
2479
2480 #[allow(non_upper_case_globals)]
2481 pub const some_const: u8 = 10;
2482
2483 #[allow(non_upper_case_globals)]
2484 pub static SomeStatic: u8 = 10;
2485     "#,
2486         );
2487     }
2488
2489     #[test]
2490     fn allow_attributes_crate_attr() {
2491         check_diagnostics(
2492             r#"
2493 #![allow(non_snake_case)]
2494
2495 mod F {
2496     fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
2497 }
2498     "#,
2499         );
2500     }
2501
2502     #[test]
2503     #[ignore]
2504     fn bug_trait_inside_fn() {
2505         // FIXME:
2506         // This is broken, and in fact, should not even be looked at by this
2507         // lint in the first place. There's weird stuff going on in the
2508         // collection phase.
2509         // It's currently being brought in by:
2510         // * validate_func on `a` recursing into modules
2511         // * then it finds the trait and then the function while iterating
2512         //   through modules
2513         // * then validate_func is called on Dirty
2514         // * ... which then proceeds to look at some unknown module taking no
2515         //   attrs from either the impl or the fn a, and then finally to the root
2516         //   module
2517         //
2518         // It should find the attribute on the trait, but it *doesn't even see
2519         // the trait* as far as I can tell.
2520
2521         check_diagnostics(
2522             r#"
2523 trait T { fn a(); }
2524 struct U {}
2525 impl T for U {
2526     fn a() {
2527         // this comes out of bitflags, mostly
2528         #[allow(non_snake_case)]
2529         trait __BitFlags {
2530             const HiImAlsoBad: u8 = 2;
2531             #[inline]
2532             fn Dirty(&self) -> bool {
2533                 false
2534             }
2535         }
2536
2537     }
2538 }
2539     "#,
2540         );
2541     }
2542
2543     #[test]
2544     #[ignore]
2545     fn bug_traits_arent_checked() {
2546         // FIXME: Traits and functions in traits aren't currently checked by
2547         // r-a, even though rustc will complain about them.
2548         check_diagnostics(
2549             r#"
2550 trait BAD_TRAIT {
2551     // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
2552     fn BAD_FUNCTION();
2553     // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
2554     fn BadFunction();
2555     // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
2556 }
2557     "#,
2558         );
2559     }
2560
2561     #[test]
2562     fn ignores_extern_items() {
2563         cov_mark::check!(extern_func_incorrect_case_ignored);
2564         cov_mark::check!(extern_static_incorrect_case_ignored);
2565         check_diagnostics(
2566             r#"
2567 extern {
2568     fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
2569     pub static SomeStatic: u8 = 10;
2570 }
2571             "#,
2572         );
2573     }
2574
2575     #[test]
2576     fn infinite_loop_inner_items() {
2577         check_diagnostics(
2578             r#"
2579 fn qualify() {
2580     mod foo {
2581         use super::*;
2582     }
2583 }
2584             "#,
2585         )
2586     }
2587
2588     #[test] // Issue #8809.
2589     fn parenthesized_parameter() {
2590         check_diagnostics(r#"fn f((O): _) {}"#)
2591     }
2592 }