diff options
Diffstat (limited to 'crates/hir_ty/src/diagnostics/expr.rs')
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 499 |
1 files changed, 91 insertions, 408 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index a2a4d61db..c480ed352 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -9,19 +9,13 @@ use hir_def::{ | |||
9 | }; | 9 | }; |
10 | use hir_expand::name; | 10 | use hir_expand::name; |
11 | use rustc_hash::FxHashSet; | 11 | use rustc_hash::FxHashSet; |
12 | use syntax::{ast, AstPtr}; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::HirDatabase, | 14 | db::HirDatabase, |
16 | diagnostics::{ | 15 | diagnostics::match_check::{ |
17 | match_check::{ | 16 | self, |
18 | self, | 17 | usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena}, |
19 | usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena}, | ||
20 | }, | ||
21 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | ||
22 | MissingPatFields, RemoveThisSemicolon, | ||
23 | }, | 18 | }, |
24 | diagnostics_sink::DiagnosticSink, | ||
25 | AdtId, InferenceResult, Interner, TyExt, TyKind, | 19 | AdtId, InferenceResult, Interner, TyExt, TyKind, |
26 | }; | 20 | }; |
27 | 21 | ||
@@ -31,38 +25,81 @@ pub(crate) use hir_def::{ | |||
31 | LocalFieldId, VariantId, | 25 | LocalFieldId, VariantId, |
32 | }; | 26 | }; |
33 | 27 | ||
34 | use super::ReplaceFilterMapNextWithFindMap; | 28 | pub enum BodyValidationDiagnostic { |
29 | RecordLiteralMissingFields { | ||
30 | record_expr: ExprId, | ||
31 | variant: VariantId, | ||
32 | missed_fields: Vec<LocalFieldId>, | ||
33 | }, | ||
34 | RecordPatMissingFields { | ||
35 | record_pat: PatId, | ||
36 | variant: VariantId, | ||
37 | missed_fields: Vec<LocalFieldId>, | ||
38 | }, | ||
39 | ReplaceFilterMapNextWithFindMap { | ||
40 | method_call_expr: ExprId, | ||
41 | }, | ||
42 | MismatchedArgCount { | ||
43 | call_expr: ExprId, | ||
44 | expected: usize, | ||
45 | found: usize, | ||
46 | }, | ||
47 | RemoveThisSemicolon { | ||
48 | expr: ExprId, | ||
49 | }, | ||
50 | MissingOkOrSomeInTailExpr { | ||
51 | expr: ExprId, | ||
52 | required: String, | ||
53 | }, | ||
54 | MissingMatchArms { | ||
55 | match_expr: ExprId, | ||
56 | }, | ||
57 | InternalBailedOut { | ||
58 | pat: PatId, | ||
59 | }, | ||
60 | } | ||
35 | 61 | ||
36 | pub(super) struct ExprValidator<'a, 'b: 'a> { | 62 | impl BodyValidationDiagnostic { |
63 | pub fn collect( | ||
64 | db: &dyn HirDatabase, | ||
65 | owner: DefWithBodyId, | ||
66 | internal_diagnostics: bool, | ||
67 | ) -> Vec<BodyValidationDiagnostic> { | ||
68 | let _p = profile::span("BodyValidationDiagnostic::collect"); | ||
69 | let infer = db.infer(owner); | ||
70 | let mut validator = ExprValidator::new(owner, infer.clone()); | ||
71 | validator.internal_diagnostics = internal_diagnostics; | ||
72 | validator.validate_body(db); | ||
73 | validator.diagnostics | ||
74 | } | ||
75 | } | ||
76 | |||
77 | struct ExprValidator { | ||
37 | owner: DefWithBodyId, | 78 | owner: DefWithBodyId, |
38 | infer: Arc<InferenceResult>, | 79 | infer: Arc<InferenceResult>, |
39 | sink: &'a mut DiagnosticSink<'b>, | 80 | pub(super) diagnostics: Vec<BodyValidationDiagnostic>, |
81 | internal_diagnostics: bool, | ||
40 | } | 82 | } |
41 | 83 | ||
42 | impl<'a, 'b> ExprValidator<'a, 'b> { | 84 | impl ExprValidator { |
43 | pub(super) fn new( | 85 | fn new(owner: DefWithBodyId, infer: Arc<InferenceResult>) -> ExprValidator { |
44 | owner: DefWithBodyId, | 86 | ExprValidator { owner, infer, diagnostics: Vec::new(), internal_diagnostics: false } |
45 | infer: Arc<InferenceResult>, | ||
46 | sink: &'a mut DiagnosticSink<'b>, | ||
47 | ) -> ExprValidator<'a, 'b> { | ||
48 | ExprValidator { owner, infer, sink } | ||
49 | } | 87 | } |
50 | 88 | ||
51 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { | 89 | fn validate_body(&mut self, db: &dyn HirDatabase) { |
52 | self.check_for_filter_map_next(db); | 90 | self.check_for_filter_map_next(db); |
53 | 91 | ||
54 | let body = db.body(self.owner); | 92 | let body = db.body(self.owner); |
55 | 93 | ||
56 | for (id, expr) in body.exprs.iter() { | 94 | for (id, expr) in body.exprs.iter() { |
57 | if let Some((variant_def, missed_fields, true)) = | 95 | if let Some((variant, missed_fields, true)) = |
58 | record_literal_missing_fields(db, &self.infer, id, expr) | 96 | record_literal_missing_fields(db, &self.infer, id, expr) |
59 | { | 97 | { |
60 | self.create_record_literal_missing_fields_diagnostic( | 98 | self.diagnostics.push(BodyValidationDiagnostic::RecordLiteralMissingFields { |
61 | id, | 99 | record_expr: id, |
62 | db, | 100 | variant, |
63 | variant_def, | ||
64 | missed_fields, | 101 | missed_fields, |
65 | ); | 102 | }); |
66 | } | 103 | } |
67 | 104 | ||
68 | match expr { | 105 | match expr { |
@@ -76,15 +113,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
76 | } | 113 | } |
77 | } | 114 | } |
78 | for (id, pat) in body.pats.iter() { | 115 | for (id, pat) in body.pats.iter() { |
79 | if let Some((variant_def, missed_fields, true)) = | 116 | if let Some((variant, missed_fields, true)) = |
80 | record_pattern_missing_fields(db, &self.infer, id, pat) | 117 | record_pattern_missing_fields(db, &self.infer, id, pat) |
81 | { | 118 | { |
82 | self.create_record_pattern_missing_fields_diagnostic( | 119 | self.diagnostics.push(BodyValidationDiagnostic::RecordPatMissingFields { |
83 | id, | 120 | record_pat: id, |
84 | db, | 121 | variant, |
85 | variant_def, | ||
86 | missed_fields, | 122 | missed_fields, |
87 | ); | 123 | }); |
88 | } | 124 | } |
89 | } | 125 | } |
90 | let body_expr = &body[body.body_expr]; | 126 | let body_expr = &body[body.body_expr]; |
@@ -92,71 +128,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
92 | if let Some(t) = tail { | 128 | if let Some(t) = tail { |
93 | self.validate_results_in_tail_expr(body.body_expr, *t, db); | 129 | self.validate_results_in_tail_expr(body.body_expr, *t, db); |
94 | } else if let Some(Statement::Expr { expr: id, .. }) = statements.last() { | 130 | } else if let Some(Statement::Expr { expr: id, .. }) = statements.last() { |
95 | self.validate_missing_tail_expr(body.body_expr, *id, db); | 131 | self.validate_missing_tail_expr(body.body_expr, *id); |
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | fn create_record_literal_missing_fields_diagnostic( | ||
101 | &mut self, | ||
102 | id: ExprId, | ||
103 | db: &dyn HirDatabase, | ||
104 | variant_def: VariantId, | ||
105 | missed_fields: Vec<LocalFieldId>, | ||
106 | ) { | ||
107 | // XXX: only look at source_map if we do have missing fields | ||
108 | let (_, source_map) = db.body_with_source_map(self.owner); | ||
109 | |||
110 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
111 | let root = source_ptr.file_syntax(db.upcast()); | ||
112 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { | ||
113 | if let Some(_) = record_expr.record_expr_field_list() { | ||
114 | let variant_data = variant_def.variant_data(db.upcast()); | ||
115 | let missed_fields = missed_fields | ||
116 | .into_iter() | ||
117 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
118 | .collect(); | ||
119 | self.sink.push(MissingFields { | ||
120 | file: source_ptr.file_id, | ||
121 | field_list_parent: AstPtr::new(&record_expr), | ||
122 | field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)), | ||
123 | missed_fields, | ||
124 | }) | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | |||
130 | fn create_record_pattern_missing_fields_diagnostic( | ||
131 | &mut self, | ||
132 | id: PatId, | ||
133 | db: &dyn HirDatabase, | ||
134 | variant_def: VariantId, | ||
135 | missed_fields: Vec<LocalFieldId>, | ||
136 | ) { | ||
137 | // XXX: only look at source_map if we do have missing fields | ||
138 | let (_, source_map) = db.body_with_source_map(self.owner); | ||
139 | |||
140 | if let Ok(source_ptr) = source_map.pat_syntax(id) { | ||
141 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
142 | let root = source_ptr.file_syntax(db.upcast()); | ||
143 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
144 | if let Some(_) = record_pat.record_pat_field_list() { | ||
145 | let variant_data = variant_def.variant_data(db.upcast()); | ||
146 | let missed_fields = missed_fields | ||
147 | .into_iter() | ||
148 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
149 | .collect(); | ||
150 | self.sink.push(MissingPatFields { | ||
151 | file: source_ptr.file_id, | ||
152 | field_list_parent: AstPtr::new(&record_pat), | ||
153 | field_list_parent_path: record_pat | ||
154 | .path() | ||
155 | .map(|path| AstPtr::new(&path)), | ||
156 | missed_fields, | ||
157 | }) | ||
158 | } | ||
159 | } | ||
160 | } | 132 | } |
161 | } | 133 | } |
162 | } | 134 | } |
@@ -199,13 +171,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
199 | if function_id == *next_function_id { | 171 | if function_id == *next_function_id { |
200 | if let Some(filter_map_id) = prev { | 172 | if let Some(filter_map_id) = prev { |
201 | if *receiver == filter_map_id { | 173 | if *receiver == filter_map_id { |
202 | let (_, source_map) = db.body_with_source_map(self.owner); | 174 | self.diagnostics.push( |
203 | if let Ok(next_source_ptr) = source_map.expr_syntax(id) { | 175 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { |
204 | self.sink.push(ReplaceFilterMapNextWithFindMap { | 176 | method_call_expr: id, |
205 | file: next_source_ptr.file_id, | 177 | }, |
206 | next_expr: next_source_ptr.value, | 178 | ); |
207 | }); | ||
208 | } | ||
209 | } | 179 | } |
210 | } | 180 | } |
211 | } | 181 | } |
@@ -266,19 +236,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
266 | let mut arg_count = args.len(); | 236 | let mut arg_count = args.len(); |
267 | 237 | ||
268 | if arg_count != param_count { | 238 | if arg_count != param_count { |
269 | let (_, source_map) = db.body_with_source_map(self.owner); | 239 | if is_method_call { |
270 | if let Ok(source_ptr) = source_map.expr_syntax(call_id) { | 240 | param_count -= 1; |
271 | if is_method_call { | 241 | arg_count -= 1; |
272 | param_count -= 1; | ||
273 | arg_count -= 1; | ||
274 | } | ||
275 | self.sink.push(MismatchedArgCount { | ||
276 | file: source_ptr.file_id, | ||
277 | call_expr: source_ptr.value, | ||
278 | expected: param_count, | ||
279 | found: arg_count, | ||
280 | }); | ||
281 | } | 242 | } |
243 | self.diagnostics.push(BodyValidationDiagnostic::MismatchedArgCount { | ||
244 | call_expr: call_id, | ||
245 | expected: param_count, | ||
246 | found: arg_count, | ||
247 | }); | ||
282 | } | 248 | } |
283 | } | 249 | } |
284 | 250 | ||
@@ -346,8 +312,9 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
346 | // fit the match expression, we skip this diagnostic. Skipping the entire | 312 | // fit the match expression, we skip this diagnostic. Skipping the entire |
347 | // diagnostic rather than just not including this match arm is preferred | 313 | // diagnostic rather than just not including this match arm is preferred |
348 | // to avoid the chance of false positives. | 314 | // to avoid the chance of false positives. |
349 | #[cfg(test)] | 315 | if self.internal_diagnostics { |
350 | match_check::tests::report_bail_out(db, self.owner, arm.pat, self.sink); | 316 | self.diagnostics.push(BodyValidationDiagnostic::InternalBailedOut { pat: arm.pat }) |
317 | } | ||
351 | return; | 318 | return; |
352 | } | 319 | } |
353 | 320 | ||
@@ -382,20 +349,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
382 | // FIXME Report witnesses | 349 | // FIXME Report witnesses |
383 | // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses); | 350 | // eprintln!("compute_match_usefulness(..) -> {:?}", &witnesses); |
384 | if !witnesses.is_empty() { | 351 | if !witnesses.is_empty() { |
385 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 352 | self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { match_expr: id }); |
386 | let root = source_ptr.file_syntax(db.upcast()); | ||
387 | if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) { | ||
388 | if let (Some(match_expr), Some(arms)) = | ||
389 | (match_expr.expr(), match_expr.match_arm_list()) | ||
390 | { | ||
391 | self.sink.push(MissingMatchArms { | ||
392 | file: source_ptr.file_id, | ||
393 | match_expr: AstPtr::new(&match_expr), | ||
394 | arms: AstPtr::new(&arms), | ||
395 | }) | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | } | 353 | } |
400 | } | 354 | } |
401 | 355 | ||
@@ -453,24 +407,12 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
453 | if params.len(&Interner) > 0 | 407 | if params.len(&Interner) > 0 |
454 | && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual) | 408 | && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual) |
455 | { | 409 | { |
456 | let (_, source_map) = db.body_with_source_map(self.owner); | 410 | self.diagnostics |
457 | 411 | .push(BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr: id, required }); | |
458 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
459 | self.sink.push(MissingOkOrSomeInTailExpr { | ||
460 | file: source_ptr.file_id, | ||
461 | expr: source_ptr.value, | ||
462 | required, | ||
463 | }); | ||
464 | } | ||
465 | } | 412 | } |
466 | } | 413 | } |
467 | 414 | ||
468 | fn validate_missing_tail_expr( | 415 | fn validate_missing_tail_expr(&mut self, body_id: ExprId, possible_tail_id: ExprId) { |
469 | &mut self, | ||
470 | body_id: ExprId, | ||
471 | possible_tail_id: ExprId, | ||
472 | db: &dyn HirDatabase, | ||
473 | ) { | ||
474 | let mismatch = match self.infer.type_mismatch_for_expr(body_id) { | 416 | let mismatch = match self.infer.type_mismatch_for_expr(body_id) { |
475 | Some(m) => m, | 417 | Some(m) => m, |
476 | None => return, | 418 | None => return, |
@@ -485,12 +427,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
485 | return; | 427 | return; |
486 | } | 428 | } |
487 | 429 | ||
488 | let (_, source_map) = db.body_with_source_map(self.owner); | 430 | self.diagnostics |
489 | 431 | .push(BodyValidationDiagnostic::RemoveThisSemicolon { expr: possible_tail_id }); | |
490 | if let Ok(source_ptr) = source_map.expr_syntax(possible_tail_id) { | ||
491 | self.sink | ||
492 | .push(RemoveThisSemicolon { file: source_ptr.file_id, expr: source_ptr.value }); | ||
493 | } | ||
494 | } | 432 | } |
495 | } | 433 | } |
496 | 434 | ||
@@ -568,258 +506,3 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul | |||
568 | walk(pat, body, infer, &mut has_type_mismatches); | 506 | walk(pat, body, infer, &mut has_type_mismatches); |
569 | !has_type_mismatches | 507 | !has_type_mismatches |
570 | } | 508 | } |
571 | |||
572 | #[cfg(test)] | ||
573 | mod tests { | ||
574 | use crate::diagnostics::tests::check_diagnostics; | ||
575 | |||
576 | #[test] | ||
577 | fn simple_free_fn_zero() { | ||
578 | check_diagnostics( | ||
579 | r#" | ||
580 | fn zero() {} | ||
581 | fn f() { zero(1); } | ||
582 | //^^^^^^^ Expected 0 arguments, found 1 | ||
583 | "#, | ||
584 | ); | ||
585 | |||
586 | check_diagnostics( | ||
587 | r#" | ||
588 | fn zero() {} | ||
589 | fn f() { zero(); } | ||
590 | "#, | ||
591 | ); | ||
592 | } | ||
593 | |||
594 | #[test] | ||
595 | fn simple_free_fn_one() { | ||
596 | check_diagnostics( | ||
597 | r#" | ||
598 | fn one(arg: u8) {} | ||
599 | fn f() { one(); } | ||
600 | //^^^^^ Expected 1 argument, found 0 | ||
601 | "#, | ||
602 | ); | ||
603 | |||
604 | check_diagnostics( | ||
605 | r#" | ||
606 | fn one(arg: u8) {} | ||
607 | fn f() { one(1); } | ||
608 | "#, | ||
609 | ); | ||
610 | } | ||
611 | |||
612 | #[test] | ||
613 | fn method_as_fn() { | ||
614 | check_diagnostics( | ||
615 | r#" | ||
616 | struct S; | ||
617 | impl S { fn method(&self) {} } | ||
618 | |||
619 | fn f() { | ||
620 | S::method(); | ||
621 | } //^^^^^^^^^^^ Expected 1 argument, found 0 | ||
622 | "#, | ||
623 | ); | ||
624 | |||
625 | check_diagnostics( | ||
626 | r#" | ||
627 | struct S; | ||
628 | impl S { fn method(&self) {} } | ||
629 | |||
630 | fn f() { | ||
631 | S::method(&S); | ||
632 | S.method(); | ||
633 | } | ||
634 | "#, | ||
635 | ); | ||
636 | } | ||
637 | |||
638 | #[test] | ||
639 | fn method_with_arg() { | ||
640 | check_diagnostics( | ||
641 | r#" | ||
642 | struct S; | ||
643 | impl S { fn method(&self, arg: u8) {} } | ||
644 | |||
645 | fn f() { | ||
646 | S.method(); | ||
647 | } //^^^^^^^^^^ Expected 1 argument, found 0 | ||
648 | "#, | ||
649 | ); | ||
650 | |||
651 | check_diagnostics( | ||
652 | r#" | ||
653 | struct S; | ||
654 | impl S { fn method(&self, arg: u8) {} } | ||
655 | |||
656 | fn f() { | ||
657 | S::method(&S, 0); | ||
658 | S.method(1); | ||
659 | } | ||
660 | "#, | ||
661 | ); | ||
662 | } | ||
663 | |||
664 | #[test] | ||
665 | fn method_unknown_receiver() { | ||
666 | // note: this is incorrect code, so there might be errors on this in the | ||
667 | // future, but we shouldn't emit an argument count diagnostic here | ||
668 | check_diagnostics( | ||
669 | r#" | ||
670 | trait Foo { fn method(&self, arg: usize) {} } | ||
671 | |||
672 | fn f() { | ||
673 | let x; | ||
674 | x.method(); | ||
675 | } | ||
676 | "#, | ||
677 | ); | ||
678 | } | ||
679 | |||
680 | #[test] | ||
681 | fn tuple_struct() { | ||
682 | check_diagnostics( | ||
683 | r#" | ||
684 | struct Tup(u8, u16); | ||
685 | fn f() { | ||
686 | Tup(0); | ||
687 | } //^^^^^^ Expected 2 arguments, found 1 | ||
688 | "#, | ||
689 | ) | ||
690 | } | ||
691 | |||
692 | #[test] | ||
693 | fn enum_variant() { | ||
694 | check_diagnostics( | ||
695 | r#" | ||
696 | enum En { Variant(u8, u16), } | ||
697 | fn f() { | ||
698 | En::Variant(0); | ||
699 | } //^^^^^^^^^^^^^^ Expected 2 arguments, found 1 | ||
700 | "#, | ||
701 | ) | ||
702 | } | ||
703 | |||
704 | #[test] | ||
705 | fn enum_variant_type_macro() { | ||
706 | check_diagnostics( | ||
707 | r#" | ||
708 | macro_rules! Type { | ||
709 | () => { u32 }; | ||
710 | } | ||
711 | enum Foo { | ||
712 | Bar(Type![]) | ||
713 | } | ||
714 | impl Foo { | ||
715 | fn new() { | ||
716 | Foo::Bar(0); | ||
717 | Foo::Bar(0, 1); | ||
718 | //^^^^^^^^^^^^^^ Expected 1 argument, found 2 | ||
719 | Foo::Bar(); | ||
720 | //^^^^^^^^^^ Expected 1 argument, found 0 | ||
721 | } | ||
722 | } | ||
723 | "#, | ||
724 | ); | ||
725 | } | ||
726 | |||
727 | #[test] | ||
728 | fn varargs() { | ||
729 | check_diagnostics( | ||
730 | r#" | ||
731 | extern "C" { | ||
732 | fn fixed(fixed: u8); | ||
733 | fn varargs(fixed: u8, ...); | ||
734 | fn varargs2(...); | ||
735 | } | ||
736 | |||
737 | fn f() { | ||
738 | unsafe { | ||
739 | fixed(0); | ||
740 | fixed(0, 1); | ||
741 | //^^^^^^^^^^^ Expected 1 argument, found 2 | ||
742 | varargs(0); | ||
743 | varargs(0, 1); | ||
744 | varargs2(); | ||
745 | varargs2(0); | ||
746 | varargs2(0, 1); | ||
747 | } | ||
748 | } | ||
749 | "#, | ||
750 | ) | ||
751 | } | ||
752 | |||
753 | #[test] | ||
754 | fn arg_count_lambda() { | ||
755 | check_diagnostics( | ||
756 | r#" | ||
757 | fn main() { | ||
758 | let f = |()| (); | ||
759 | f(); | ||
760 | //^^^ Expected 1 argument, found 0 | ||
761 | f(()); | ||
762 | f((), ()); | ||
763 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
764 | } | ||
765 | "#, | ||
766 | ) | ||
767 | } | ||
768 | |||
769 | #[test] | ||
770 | fn cfgd_out_call_arguments() { | ||
771 | check_diagnostics( | ||
772 | r#" | ||
773 | struct C(#[cfg(FALSE)] ()); | ||
774 | impl C { | ||
775 | fn new() -> Self { | ||
776 | Self( | ||
777 | #[cfg(FALSE)] | ||
778 | (), | ||
779 | ) | ||
780 | } | ||
781 | |||
782 | fn method(&self) {} | ||
783 | } | ||
784 | |||
785 | fn main() { | ||
786 | C::new().method(#[cfg(FALSE)] 0); | ||
787 | } | ||
788 | "#, | ||
789 | ); | ||
790 | } | ||
791 | |||
792 | #[test] | ||
793 | fn cfgd_out_fn_params() { | ||
794 | check_diagnostics( | ||
795 | r#" | ||
796 | fn foo(#[cfg(NEVER)] x: ()) {} | ||
797 | |||
798 | struct S; | ||
799 | |||
800 | impl S { | ||
801 | fn method(#[cfg(NEVER)] self) {} | ||
802 | fn method2(#[cfg(NEVER)] self, arg: u8) {} | ||
803 | fn method3(self, #[cfg(NEVER)] arg: u8) {} | ||
804 | } | ||
805 | |||
806 | extern "C" { | ||
807 | fn fixed(fixed: u8, #[cfg(NEVER)] ...); | ||
808 | fn varargs(#[cfg(not(NEVER))] ...); | ||
809 | } | ||
810 | |||
811 | fn main() { | ||
812 | foo(); | ||
813 | S::method(); | ||
814 | S::method2(0); | ||
815 | S::method3(S); | ||
816 | S.method3(); | ||
817 | unsafe { | ||
818 | fixed(0); | ||
819 | varargs(1, 2, 3); | ||
820 | } | ||
821 | } | ||
822 | "#, | ||
823 | ) | ||
824 | } | ||
825 | } | ||