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