aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock13
-rw-r--r--crates/base_db/src/lib.rs2
-rw-r--r--crates/hir/Cargo.toml1
-rw-r--r--crates/hir/src/diagnostics.rs372
-rw-r--r--crates/hir/src/diagnostics_sink.rs (renamed from crates/hir_ty/src/diagnostics_sink.rs)0
-rw-r--r--crates/hir/src/lib.rs236
-rw-r--r--crates/hir_def/Cargo.toml2
-rw-r--r--crates/hir_def/src/attr.rs22
-rw-r--r--crates/hir_ty/Cargo.toml2
-rw-r--r--crates/hir_ty/src/diagnostics.rs769
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs357
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs499
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs957
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs1
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs151
-rw-r--r--crates/hir_ty/src/infer.rs94
-rw-r--r--crates/hir_ty/src/infer/expr.rs7
-rw-r--r--crates/hir_ty/src/lib.rs3
-rw-r--r--crates/hir_ty/src/tests.rs98
-rw-r--r--crates/hir_ty/src/tests/coercion.rs43
-rw-r--r--crates/hir_ty/src/tests/patterns.rs57
-rw-r--r--crates/ide/Cargo.toml3
-rw-r--r--crates/ide/src/diagnostics.rs1885
-rw-r--r--crates/ide/src/goto_implementation.rs4
-rw-r--r--crates/ide/src/hover.rs2
-rw-r--r--crates/ide/src/references/rename.rs165
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html4
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs4
-rw-r--r--crates/ide_assists/Cargo.toml2
-rw-r--r--crates/ide_assists/src/handlers/change_visibility.rs11
-rw-r--r--crates/ide_completion/Cargo.toml2
-rw-r--r--crates/ide_completion/src/completions.rs10
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs18
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs34
-rw-r--r--crates/ide_completion/src/patterns.rs7
-rw-r--r--crates/ide_completion/src/render.rs18
-rw-r--r--crates/ide_completion/src/render/function.rs26
-rw-r--r--crates/ide_completion/src/render/type_alias.rs23
-rw-r--r--crates/ide_db/Cargo.toml2
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/search.rs47
-rw-r--r--crates/ide_ssr/Cargo.toml2
-rw-r--r--crates/mbe/Cargo.toml2
-rw-r--r--crates/mbe/src/tests/expand.rs42
-rw-r--r--crates/parser/src/grammar/attributes.rs3
-rw-r--r--crates/parser/src/syntax_kind/generated.rs2
-rw-r--r--crates/profile/src/memory_usage.rs35
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs31
-rw-r--r--crates/syntax/src/ast/node_ext.rs19
-rw-r--r--crates/syntax/test_data/parser/err/0005_attribute_recover.rast66
-rw-r--r--crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast68
-rw-r--r--crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast18
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast25
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast25
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast51
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast125
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast34
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast45
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast18
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast23
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast9
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast17
-rw-r--r--crates/syntax/test_data/parser/ok/0006_inner_attributes.rast258
-rw-r--r--crates/syntax/test_data/parser/ok/0008_mod_item.rast9
-rw-r--r--crates/syntax/test_data/parser/ok/0011_outer_attribute.rast45
-rw-r--r--crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast19
-rw-r--r--crates/syntax/test_data/parser/ok/0035_weird_exprs.rast87
-rw-r--r--crates/syntax/test_data/parser/ok/0044_let_attrs.rast25
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_attrs.rast102
-rw-r--r--crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast17
-rw-r--r--crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast135
-rw-r--r--crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast9
-rw-r--r--crates/syntax/test_data/parser/ok/0062_macro_2.0.rast9
-rw-r--r--crates/syntax/test_data/parser/ok/0063_variadic_fun.rast17
-rw-r--r--xtask/Cargo.toml2
-rw-r--r--xtask/src/ast_src.rs2
86 files changed, 3969 insertions, 3499 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ea2c1aed7..e47b87964 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -245,9 +245,9 @@ dependencies = [
245 245
246[[package]] 246[[package]]
247name = "cov-mark" 247name = "cov-mark"
248version = "1.1.0" 248version = "2.0.0-pre.1"
249source = "registry+https://github.com/rust-lang/crates.io-index" 249source = "registry+https://github.com/rust-lang/crates.io-index"
250checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3" 250checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a"
251 251
252[[package]] 252[[package]]
253name = "crc32fast" 253name = "crc32fast"
@@ -482,6 +482,7 @@ dependencies = [
482 "hir_ty", 482 "hir_ty",
483 "itertools", 483 "itertools",
484 "log", 484 "log",
485 "once_cell",
485 "profile", 486 "profile",
486 "rustc-hash", 487 "rustc-hash",
487 "smallvec", 488 "smallvec",
@@ -765,9 +766,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
765 766
766[[package]] 767[[package]]
767name = "libc" 768name = "libc"
768version = "0.2.95" 769version = "0.2.97"
769source = "registry+https://github.com/rust-lang/crates.io-index" 770source = "registry+https://github.com/rust-lang/crates.io-index"
770checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" 771checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
771 772
772[[package]] 773[[package]]
773name = "libloading" 774name = "libloading"
@@ -1802,9 +1803,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
1802 1803
1803[[package]] 1804[[package]]
1804name = "ungrammar" 1805name = "ungrammar"
1805version = "1.13.0" 1806version = "1.14.0"
1806source = "registry+https://github.com/rust-lang/crates.io-index" 1807source = "registry+https://github.com/rust-lang/crates.io-index"
1807checksum = "76760314176cc2b94047af2f921b92c39f11a34dc05c43a3c2b0fc91cb22959f" 1808checksum = "50ef6d7335c77ec3e4a7c4be74c2b9e4642569e94a4004c836f8cca71fede3a7"
1808 1809
1809[[package]] 1810[[package]]
1810name = "unicase" 1811name = "unicase"
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index 54baa3a63..d26f8f180 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -42,7 +42,7 @@ pub struct FilePosition {
42 pub offset: TextSize, 42 pub offset: TextSize,
43} 43}
44 44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)] 45#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
46pub struct FileRange { 46pub struct FileRange {
47 pub file_id: FileId, 47 pub file_id: FileId,
48 pub range: TextRange, 48 pub range: TextRange,
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index 560b15238..7c148fd40 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -16,6 +16,7 @@ either = "1.5.3"
16arrayvec = "0.7" 16arrayvec = "0.7"
17itertools = "0.10.0" 17itertools = "0.10.0"
18smallvec = "1.4.0" 18smallvec = "1.4.0"
19once_cell = "1"
19 20
20stdx = { path = "../stdx", version = "0.0.0" } 21stdx = { path = "../stdx", version = "0.0.0" }
21syntax = { path = "../syntax", version = "0.0.0" } 22syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 2cdbd172a..8a7c3a4fd 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -7,17 +7,12 @@ use std::any::Any;
7 7
8use cfg::{CfgExpr, CfgOptions, DnfExpr}; 8use cfg::{CfgExpr, CfgOptions, DnfExpr};
9use hir_def::path::ModPath; 9use hir_def::path::ModPath;
10use hir_expand::{HirFileId, InFile}; 10use hir_expand::{name::Name, HirFileId, InFile};
11use stdx::format_to; 11use stdx::format_to;
12use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; 12use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
13 13
14pub use hir_ty::{ 14pub use crate::diagnostics_sink::{
15 diagnostics::{ 15 Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder,
16 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms,
17 MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon,
18 ReplaceFilterMapNextWithFindMap,
19 },
20 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder},
21}; 16};
22 17
23// Diagnostic: unresolved-module 18// Diagnostic: unresolved-module
@@ -251,3 +246,364 @@ impl Diagnostic for UnimplementedBuiltinMacro {
251 self 246 self
252 } 247 }
253} 248}
249
250// Diagnostic: no-such-field
251//
252// This diagnostic is triggered if created structure does not have field provided in record.
253#[derive(Debug)]
254pub struct NoSuchField {
255 pub file: HirFileId,
256 pub field: AstPtr<ast::RecordExprField>,
257}
258
259impl Diagnostic for NoSuchField {
260 fn code(&self) -> DiagnosticCode {
261 DiagnosticCode("no-such-field")
262 }
263
264 fn message(&self) -> String {
265 "no such field".to_string()
266 }
267
268 fn display_source(&self) -> InFile<SyntaxNodePtr> {
269 InFile::new(self.file, self.field.clone().into())
270 }
271
272 fn as_any(&self) -> &(dyn Any + Send + 'static) {
273 self
274 }
275}
276
277// Diagnostic: break-outside-of-loop
278//
279// This diagnostic is triggered if the `break` keyword is used outside of a loop.
280#[derive(Debug)]
281pub struct BreakOutsideOfLoop {
282 pub file: HirFileId,
283 pub expr: AstPtr<ast::Expr>,
284}
285
286impl Diagnostic for BreakOutsideOfLoop {
287 fn code(&self) -> DiagnosticCode {
288 DiagnosticCode("break-outside-of-loop")
289 }
290 fn message(&self) -> String {
291 "break outside of loop".to_string()
292 }
293 fn display_source(&self) -> InFile<SyntaxNodePtr> {
294 InFile { file_id: self.file, value: self.expr.clone().into() }
295 }
296 fn as_any(&self) -> &(dyn Any + Send + 'static) {
297 self
298 }
299}
300
301// Diagnostic: missing-unsafe
302//
303// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
304#[derive(Debug)]
305pub struct MissingUnsafe {
306 pub file: HirFileId,
307 pub expr: AstPtr<ast::Expr>,
308}
309
310impl Diagnostic for MissingUnsafe {
311 fn code(&self) -> DiagnosticCode {
312 DiagnosticCode("missing-unsafe")
313 }
314 fn message(&self) -> String {
315 format!("This operation is unsafe and requires an unsafe function or block")
316 }
317 fn display_source(&self) -> InFile<SyntaxNodePtr> {
318 InFile { file_id: self.file, value: self.expr.clone().into() }
319 }
320 fn as_any(&self) -> &(dyn Any + Send + 'static) {
321 self
322 }
323}
324
325// Diagnostic: missing-structure-fields
326//
327// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
328//
329// Example:
330//
331// ```rust
332// struct A { a: u8, b: u8 }
333//
334// let a = A { a: 10 };
335// ```
336#[derive(Debug)]
337pub struct MissingFields {
338 pub file: HirFileId,
339 pub field_list_parent: AstPtr<ast::RecordExpr>,
340 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
341 pub missed_fields: Vec<Name>,
342}
343
344impl Diagnostic for MissingFields {
345 fn code(&self) -> DiagnosticCode {
346 DiagnosticCode("missing-structure-fields")
347 }
348 fn message(&self) -> String {
349 let mut buf = String::from("Missing structure fields:\n");
350 for field in &self.missed_fields {
351 format_to!(buf, "- {}\n", field);
352 }
353 buf
354 }
355
356 fn display_source(&self) -> InFile<SyntaxNodePtr> {
357 InFile {
358 file_id: self.file,
359 value: self
360 .field_list_parent_path
361 .clone()
362 .map(SyntaxNodePtr::from)
363 .unwrap_or_else(|| self.field_list_parent.clone().into()),
364 }
365 }
366
367 fn as_any(&self) -> &(dyn Any + Send + 'static) {
368 self
369 }
370}
371
372// Diagnostic: missing-pat-fields
373//
374// This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure.
375//
376// Example:
377//
378// ```rust
379// struct A { a: u8, b: u8 }
380//
381// let a = A { a: 10, b: 20 };
382//
383// if let A { a } = a {
384// // ...
385// }
386// ```
387#[derive(Debug)]
388pub struct MissingPatFields {
389 pub file: HirFileId,
390 pub field_list_parent: AstPtr<ast::RecordPat>,
391 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
392 pub missed_fields: Vec<Name>,
393}
394
395impl Diagnostic for MissingPatFields {
396 fn code(&self) -> DiagnosticCode {
397 DiagnosticCode("missing-pat-fields")
398 }
399 fn message(&self) -> String {
400 let mut buf = String::from("Missing structure fields:\n");
401 for field in &self.missed_fields {
402 format_to!(buf, "- {}\n", field);
403 }
404 buf
405 }
406 fn display_source(&self) -> InFile<SyntaxNodePtr> {
407 InFile {
408 file_id: self.file,
409 value: self
410 .field_list_parent_path
411 .clone()
412 .map(SyntaxNodePtr::from)
413 .unwrap_or_else(|| self.field_list_parent.clone().into()),
414 }
415 }
416 fn as_any(&self) -> &(dyn Any + Send + 'static) {
417 self
418 }
419}
420
421// Diagnostic: replace-filter-map-next-with-find-map
422//
423// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
424#[derive(Debug)]
425pub struct ReplaceFilterMapNextWithFindMap {
426 pub file: HirFileId,
427 /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
428 pub next_expr: AstPtr<ast::Expr>,
429}
430
431impl Diagnostic for ReplaceFilterMapNextWithFindMap {
432 fn code(&self) -> DiagnosticCode {
433 DiagnosticCode("replace-filter-map-next-with-find-map")
434 }
435 fn message(&self) -> String {
436 "replace filter_map(..).next() with find_map(..)".to_string()
437 }
438 fn display_source(&self) -> InFile<SyntaxNodePtr> {
439 InFile { file_id: self.file, value: self.next_expr.clone().into() }
440 }
441 fn as_any(&self) -> &(dyn Any + Send + 'static) {
442 self
443 }
444}
445
446// Diagnostic: mismatched-arg-count
447//
448// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
449#[derive(Debug)]
450pub struct MismatchedArgCount {
451 pub file: HirFileId,
452 pub call_expr: AstPtr<ast::Expr>,
453 pub expected: usize,
454 pub found: usize,
455}
456
457impl Diagnostic for MismatchedArgCount {
458 fn code(&self) -> DiagnosticCode {
459 DiagnosticCode("mismatched-arg-count")
460 }
461 fn message(&self) -> String {
462 let s = if self.expected == 1 { "" } else { "s" };
463 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
464 }
465 fn display_source(&self) -> InFile<SyntaxNodePtr> {
466 InFile { file_id: self.file, value: self.call_expr.clone().into() }
467 }
468 fn as_any(&self) -> &(dyn Any + Send + 'static) {
469 self
470 }
471 fn is_experimental(&self) -> bool {
472 true
473 }
474}
475
476#[derive(Debug)]
477pub struct RemoveThisSemicolon {
478 pub file: HirFileId,
479 pub expr: AstPtr<ast::Expr>,
480}
481
482impl Diagnostic for RemoveThisSemicolon {
483 fn code(&self) -> DiagnosticCode {
484 DiagnosticCode("remove-this-semicolon")
485 }
486
487 fn message(&self) -> String {
488 "Remove this semicolon".to_string()
489 }
490
491 fn display_source(&self) -> InFile<SyntaxNodePtr> {
492 InFile { file_id: self.file, value: self.expr.clone().into() }
493 }
494
495 fn as_any(&self) -> &(dyn Any + Send + 'static) {
496 self
497 }
498}
499
500// Diagnostic: missing-ok-or-some-in-tail-expr
501//
502// This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`,
503// or if a block that should return `Option` returns a value not wrapped in `Some`.
504//
505// Example:
506//
507// ```rust
508// fn foo() -> Result<u8, ()> {
509// 10
510// }
511// ```
512#[derive(Debug)]
513pub struct MissingOkOrSomeInTailExpr {
514 pub file: HirFileId,
515 pub expr: AstPtr<ast::Expr>,
516 // `Some` or `Ok` depending on whether the return type is Result or Option
517 pub required: String,
518}
519
520impl Diagnostic for MissingOkOrSomeInTailExpr {
521 fn code(&self) -> DiagnosticCode {
522 DiagnosticCode("missing-ok-or-some-in-tail-expr")
523 }
524 fn message(&self) -> String {
525 format!("wrap return expression in {}", self.required)
526 }
527 fn display_source(&self) -> InFile<SyntaxNodePtr> {
528 InFile { file_id: self.file, value: self.expr.clone().into() }
529 }
530 fn as_any(&self) -> &(dyn Any + Send + 'static) {
531 self
532 }
533}
534
535// Diagnostic: missing-match-arm
536//
537// This diagnostic is triggered if `match` block is missing one or more match arms.
538#[derive(Debug)]
539pub struct MissingMatchArms {
540 pub file: HirFileId,
541 pub match_expr: AstPtr<ast::Expr>,
542 pub arms: AstPtr<ast::MatchArmList>,
543}
544
545impl Diagnostic for MissingMatchArms {
546 fn code(&self) -> DiagnosticCode {
547 DiagnosticCode("missing-match-arm")
548 }
549 fn message(&self) -> String {
550 String::from("Missing match arm")
551 }
552 fn display_source(&self) -> InFile<SyntaxNodePtr> {
553 InFile { file_id: self.file, value: self.match_expr.clone().into() }
554 }
555 fn as_any(&self) -> &(dyn Any + Send + 'static) {
556 self
557 }
558}
559
560#[derive(Debug)]
561pub struct InternalBailedOut {
562 pub file: HirFileId,
563 pub pat_syntax_ptr: SyntaxNodePtr,
564}
565
566impl Diagnostic for InternalBailedOut {
567 fn code(&self) -> DiagnosticCode {
568 DiagnosticCode("internal:match-check-bailed-out")
569 }
570 fn message(&self) -> String {
571 format!("Internal: match check bailed out")
572 }
573 fn display_source(&self) -> InFile<SyntaxNodePtr> {
574 InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() }
575 }
576 fn as_any(&self) -> &(dyn Any + Send + 'static) {
577 self
578 }
579}
580
581pub use hir_ty::diagnostics::IncorrectCase;
582
583impl Diagnostic for IncorrectCase {
584 fn code(&self) -> DiagnosticCode {
585 DiagnosticCode("incorrect-ident-case")
586 }
587
588 fn message(&self) -> String {
589 format!(
590 "{} `{}` should have {} name, e.g. `{}`",
591 self.ident_type,
592 self.ident_text,
593 self.expected_case.to_string(),
594 self.suggested_text
595 )
596 }
597
598 fn display_source(&self) -> InFile<SyntaxNodePtr> {
599 InFile::new(self.file, self.ident.clone().into())
600 }
601
602 fn as_any(&self) -> &(dyn Any + Send + 'static) {
603 self
604 }
605
606 fn is_experimental(&self) -> bool {
607 true
608 }
609}
diff --git a/crates/hir_ty/src/diagnostics_sink.rs b/crates/hir/src/diagnostics_sink.rs
index 084fa8b06..084fa8b06 100644
--- a/crates/hir_ty/src/diagnostics_sink.rs
+++ b/crates/hir/src/diagnostics_sink.rs
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b9c1dc44d..2468c0dc6 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -27,6 +27,7 @@ mod attrs;
27mod has_source; 27mod has_source;
28 28
29pub mod diagnostics; 29pub mod diagnostics;
30pub mod diagnostics_sink;
30pub mod db; 31pub mod db;
31 32
32mod display; 33mod display;
@@ -35,14 +36,10 @@ use std::{iter, sync::Arc};
35 36
36use arrayvec::ArrayVec; 37use arrayvec::ArrayVec;
37use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 38use base_db::{CrateDisplayName, CrateId, Edition, FileId};
38use diagnostics::{
39 InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
40 UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
41};
42use either::Either; 39use either::Either;
43use hir_def::{ 40use hir_def::{
44 adt::{ReprKind, VariantData}, 41 adt::{ReprKind, VariantData},
45 body::BodyDiagnostic, 42 body::{BodyDiagnostic, SyntheticSyntax},
46 expr::{BindingAnnotation, LabelId, Pat, PatId}, 43 expr::{BindingAnnotation, LabelId, Pat, PatId},
47 item_tree::ItemTreeNode, 44 item_tree::ItemTreeNode,
48 lang_item::LangItemTarget, 45 lang_item::LangItemTarget,
@@ -60,8 +57,8 @@ use hir_ty::{
60 autoderef, 57 autoderef,
61 consteval::ConstExt, 58 consteval::ConstExt,
62 could_unify, 59 could_unify,
63 diagnostics_sink::DiagnosticSink, 60 diagnostics::BodyValidationDiagnostic,
64 method_resolution::{self, def_crates, TyFingerprint}, 61 method_resolution::{self, TyFingerprint},
65 primitive::UintTy, 62 primitive::UintTy,
66 subst_prefix, 63 subst_prefix,
67 traits::FnTrait, 64 traits::FnTrait,
@@ -72,6 +69,7 @@ use hir_ty::{
72}; 69};
73use itertools::Itertools; 70use itertools::Itertools;
74use nameres::diagnostics::DefDiagnosticKind; 71use nameres::diagnostics::DefDiagnosticKind;
72use once_cell::unsync::Lazy;
75use rustc_hash::FxHashSet; 73use rustc_hash::FxHashSet;
76use stdx::{format_to, impl_from}; 74use stdx::{format_to, impl_from};
77use syntax::{ 75use syntax::{
@@ -80,7 +78,17 @@ use syntax::{
80}; 78};
81use tt::{Ident, Leaf, Literal, TokenTree}; 79use tt::{Ident, Leaf, Literal, TokenTree};
82 80
83use crate::db::{DefDatabase, HirDatabase}; 81use crate::{
82 db::{DefDatabase, HirDatabase},
83 diagnostics::{
84 BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount,
85 MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, MissingPatFields,
86 MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap,
87 UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall,
88 UnresolvedModule, UnresolvedProcMacro,
89 },
90 diagnostics_sink::DiagnosticSink,
91};
84 92
85pub use crate::{ 93pub use crate::{
86 attrs::{HasAttrs, Namespace}, 94 attrs::{HasAttrs, Namespace},
@@ -353,7 +361,9 @@ impl ModuleDef {
353 None => return, 361 None => return,
354 }; 362 };
355 363
356 hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) 364 for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) {
365 sink.push(diag)
366 }
357 } 367 }
358} 368}
359 369
@@ -445,7 +455,12 @@ impl Module {
445 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) 455 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into())
446 } 456 }
447 457
448 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 458 pub fn diagnostics(
459 self,
460 db: &dyn HirDatabase,
461 sink: &mut DiagnosticSink,
462 internal_diagnostics: bool,
463 ) {
449 let _p = profile::span("Module::diagnostics").detail(|| { 464 let _p = profile::span("Module::diagnostics").detail(|| {
450 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) 465 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
451 }); 466 });
@@ -591,11 +606,11 @@ impl Module {
591 } 606 }
592 for decl in self.declarations(db) { 607 for decl in self.declarations(db) {
593 match decl { 608 match decl {
594 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 609 crate::ModuleDef::Function(f) => f.diagnostics(db, sink, internal_diagnostics),
595 crate::ModuleDef::Module(m) => { 610 crate::ModuleDef::Module(m) => {
596 // Only add diagnostics from inline modules 611 // Only add diagnostics from inline modules
597 if def_map[m.id.local_id].origin.is_inline() { 612 if def_map[m.id.local_id].origin.is_inline() {
598 m.diagnostics(db, sink) 613 m.diagnostics(db, sink, internal_diagnostics)
599 } 614 }
600 } 615 }
601 _ => { 616 _ => {
@@ -607,7 +622,7 @@ impl Module {
607 for impl_def in self.impl_defs(db) { 622 for impl_def in self.impl_defs(db) {
608 for item in impl_def.items(db) { 623 for item in impl_def.items(db) {
609 if let AssocItem::Function(f) = item { 624 if let AssocItem::Function(f) = item {
610 f.diagnostics(db, sink); 625 f.diagnostics(db, sink, internal_diagnostics);
611 } 626 }
612 } 627 }
613 } 628 }
@@ -1009,7 +1024,12 @@ impl Function {
1009 db.function_data(self.id).is_async() 1024 db.function_data(self.id).is_async()
1010 } 1025 }
1011 1026
1012 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 1027 pub fn diagnostics(
1028 self,
1029 db: &dyn HirDatabase,
1030 sink: &mut DiagnosticSink,
1031 internal_diagnostics: bool,
1032 ) {
1013 let krate = self.module(db).id.krate(); 1033 let krate = self.module(db).id.krate();
1014 1034
1015 let source_map = db.body_with_source_map(self.id.into()).1; 1035 let source_map = db.body_with_source_map(self.id.into()).1;
@@ -1042,8 +1062,174 @@ impl Function {
1042 } 1062 }
1043 } 1063 }
1044 1064
1045 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); 1065 let infer = db.infer(self.id.into());
1046 hir_ty::diagnostics::validate_body(db, self.id.into(), sink); 1066 let source_map = Lazy::new(|| db.body_with_source_map(self.id.into()).1);
1067 for d in &infer.diagnostics {
1068 match d {
1069 hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
1070 let field = source_map.field_syntax(*expr);
1071 sink.push(NoSuchField { file: field.file_id, field: field.value })
1072 }
1073 hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
1074 let ptr = source_map
1075 .expr_syntax(*expr)
1076 .expect("break outside of loop in synthetic syntax");
1077 sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
1078 }
1079 }
1080 }
1081
1082 for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) {
1083 match source_map.expr_syntax(expr) {
1084 Ok(in_file) => {
1085 sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value })
1086 }
1087 Err(SyntheticSyntax) => {
1088 // FIXME: Here and eslwhere in this file, the `expr` was
1089 // desugared, report or assert that this doesn't happen.
1090 }
1091 }
1092 }
1093
1094 for diagnostic in
1095 BodyValidationDiagnostic::collect(db, self.id.into(), internal_diagnostics)
1096 {
1097 match diagnostic {
1098 BodyValidationDiagnostic::RecordLiteralMissingFields {
1099 record_expr,
1100 variant,
1101 missed_fields,
1102 } => match source_map.expr_syntax(record_expr) {
1103 Ok(source_ptr) => {
1104 let root = source_ptr.file_syntax(db.upcast());
1105 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root)
1106 {
1107 if let Some(_) = record_expr.record_expr_field_list() {
1108 let variant_data = variant.variant_data(db.upcast());
1109 let missed_fields = missed_fields
1110 .into_iter()
1111 .map(|idx| variant_data.fields()[idx].name.clone())
1112 .collect();
1113 sink.push(MissingFields {
1114 file: source_ptr.file_id,
1115 field_list_parent: AstPtr::new(&record_expr),
1116 field_list_parent_path: record_expr
1117 .path()
1118 .map(|path| AstPtr::new(&path)),
1119 missed_fields,
1120 })
1121 }
1122 }
1123 }
1124 Err(SyntheticSyntax) => (),
1125 },
1126 BodyValidationDiagnostic::RecordPatMissingFields {
1127 record_pat,
1128 variant,
1129 missed_fields,
1130 } => match source_map.pat_syntax(record_pat) {
1131 Ok(source_ptr) => {
1132 if let Some(expr) = source_ptr.value.as_ref().left() {
1133 let root = source_ptr.file_syntax(db.upcast());
1134 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
1135 if let Some(_) = record_pat.record_pat_field_list() {
1136 let variant_data = variant.variant_data(db.upcast());
1137 let missed_fields = missed_fields
1138 .into_iter()
1139 .map(|idx| variant_data.fields()[idx].name.clone())
1140 .collect();
1141 sink.push(MissingPatFields {
1142 file: source_ptr.file_id,
1143 field_list_parent: AstPtr::new(&record_pat),
1144 field_list_parent_path: record_pat
1145 .path()
1146 .map(|path| AstPtr::new(&path)),
1147 missed_fields,
1148 })
1149 }
1150 }
1151 }
1152 }
1153 Err(SyntheticSyntax) => (),
1154 },
1155
1156 BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
1157 if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) {
1158 sink.push(ReplaceFilterMapNextWithFindMap {
1159 file: next_source_ptr.file_id,
1160 next_expr: next_source_ptr.value,
1161 });
1162 }
1163 }
1164 BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
1165 match source_map.expr_syntax(call_expr) {
1166 Ok(source_ptr) => sink.push(MismatchedArgCount {
1167 file: source_ptr.file_id,
1168 call_expr: source_ptr.value,
1169 expected,
1170 found,
1171 }),
1172 Err(SyntheticSyntax) => (),
1173 }
1174 }
1175 BodyValidationDiagnostic::RemoveThisSemicolon { expr } => {
1176 match source_map.expr_syntax(expr) {
1177 Ok(source_ptr) => sink.push(RemoveThisSemicolon {
1178 file: source_ptr.file_id,
1179 expr: source_ptr.value,
1180 }),
1181 Err(SyntheticSyntax) => (),
1182 }
1183 }
1184 BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => {
1185 match source_map.expr_syntax(expr) {
1186 Ok(source_ptr) => sink.push(MissingOkOrSomeInTailExpr {
1187 file: source_ptr.file_id,
1188 expr: source_ptr.value,
1189 required,
1190 }),
1191 Err(SyntheticSyntax) => (),
1192 }
1193 }
1194 BodyValidationDiagnostic::MissingMatchArms { match_expr } => {
1195 match source_map.expr_syntax(match_expr) {
1196 Ok(source_ptr) => {
1197 let root = source_ptr.file_syntax(db.upcast());
1198 if let ast::Expr::MatchExpr(match_expr) =
1199 &source_ptr.value.to_node(&root)
1200 {
1201 if let (Some(match_expr), Some(arms)) =
1202 (match_expr.expr(), match_expr.match_arm_list())
1203 {
1204 sink.push(MissingMatchArms {
1205 file: source_ptr.file_id,
1206 match_expr: AstPtr::new(&match_expr),
1207 arms: AstPtr::new(&arms),
1208 })
1209 }
1210 }
1211 }
1212 Err(SyntheticSyntax) => (),
1213 }
1214 }
1215 BodyValidationDiagnostic::InternalBailedOut { pat } => {
1216 match source_map.pat_syntax(pat) {
1217 Ok(source_ptr) => {
1218 let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into);
1219 sink.push(InternalBailedOut {
1220 file: source_ptr.file_id,
1221 pat_syntax_ptr,
1222 });
1223 }
1224 Err(SyntheticSyntax) => (),
1225 }
1226 }
1227 }
1228 }
1229
1230 for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) {
1231 sink.push(diag)
1232 }
1047 } 1233 }
1048 1234
1049 /// Whether this function declaration has a definition. 1235 /// Whether this function declaration has a definition.
@@ -1451,6 +1637,20 @@ impl AssocItem {
1451 _ => None, 1637 _ => None,
1452 } 1638 }
1453 } 1639 }
1640
1641 pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
1642 match self.container(db) {
1643 AssocItemContainer::Impl(i) => i.trait_(db),
1644 _ => None,
1645 }
1646 }
1647
1648 pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
1649 match self.container(db) {
1650 AssocItemContainer::Trait(t) => Some(t),
1651 AssocItemContainer::Impl(i) => i.trait_(db),
1652 }
1653 }
1454} 1654}
1455 1655
1456impl HasVisibility for AssocItem { 1656impl HasVisibility for AssocItem {
@@ -1748,7 +1948,7 @@ impl Impl {
1748 } 1948 }
1749 1949
1750 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { 1950 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> {
1751 let def_crates = match def_crates(db, &ty, krate) { 1951 let def_crates = match method_resolution::def_crates(db, &ty, krate) {
1752 Some(def_crates) => def_crates, 1952 Some(def_crates) => def_crates,
1753 None => return Vec::new(), 1953 None => return Vec::new(),
1754 }; 1954 };
@@ -2154,7 +2354,7 @@ impl Type {
2154 krate: Crate, 2354 krate: Crate,
2155 mut callback: impl FnMut(AssocItem) -> Option<T>, 2355 mut callback: impl FnMut(AssocItem) -> Option<T>,
2156 ) -> Option<T> { 2356 ) -> Option<T> {
2157 for krate in def_crates(db, &self.ty, krate.id)? { 2357 for krate in method_resolution::def_crates(db, &self.ty, krate.id)? {
2158 let impls = db.inherent_impls_in_crate(krate); 2358 let impls = db.inherent_impls_in_crate(krate);
2159 2359
2160 for impl_def in impls.for_self_ty(&self.ty) { 2360 for impl_def in impls.for_self_ty(&self.ty) {
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 43324d8d9..bb86f6a73 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14dashmap = { version = "4.0.2", features = ["raw-api"] } 14dashmap = { version = "4.0.2", features = ["raw-api"] }
15log = "0.4.8" 15log = "0.4.8"
16once_cell = "1.3.1" 16once_cell = "1.3.1"
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 3886b6c04..d9f9fadc1 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -106,7 +106,9 @@ impl RawAttrs {
106 ) -> Self { 106 ) -> Self {
107 let entries = collect_attrs(owner) 107 let entries = collect_attrs(owner)
108 .flat_map(|(id, attr)| match attr { 108 .flat_map(|(id, attr)| match attr {
109 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), 109 Either::Left(attr) => {
110 attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id))
111 }
110 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 112 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
111 id, 113 id,
112 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), 114 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
@@ -172,10 +174,9 @@ impl RawAttrs {
172 let index = attr.id; 174 let index = attr.id;
173 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { 175 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
174 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; 176 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
175 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
176 // FIXME hygiene 177 // FIXME hygiene
177 let hygiene = Hygiene::new_unhygienic(); 178 let hygiene = Hygiene::new_unhygienic();
178 Attr::from_src(db, attr, &hygiene, index) 179 Attr::from_tt(db, &tree, &hygiene, index)
179 }); 180 });
180 181
181 let cfg_options = &crate_graph[krate].cfg_options; 182 let cfg_options = &crate_graph[krate].cfg_options;
@@ -664,7 +665,7 @@ impl fmt::Display for AttrInput {
664impl Attr { 665impl Attr {
665 fn from_src( 666 fn from_src(
666 db: &dyn DefDatabase, 667 db: &dyn DefDatabase,
667 ast: ast::Attr, 668 ast: ast::Meta,
668 hygiene: &Hygiene, 669 hygiene: &Hygiene,
669 id: AttrId, 670 id: AttrId,
670 ) -> Option<Attr> { 671 ) -> Option<Attr> {
@@ -683,6 +684,19 @@ impl Attr {
683 Some(Attr { id, path, input }) 684 Some(Attr { id, path, input })
684 } 685 }
685 686
687 fn from_tt(
688 db: &dyn DefDatabase,
689 tt: &tt::Subtree,
690 hygiene: &Hygiene,
691 id: AttrId,
692 ) -> Option<Attr> {
693 let (parse, _) =
694 mbe::token_tree_to_syntax_node(tt, hir_expand::FragmentKind::MetaItem).ok()?;
695 let ast = ast::Meta::cast(parse.syntax_node())?;
696
697 Self::from_src(db, ast, hygiene, id)
698 }
699
686 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 700 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
687 /// to derive macros. 701 /// to derive macros.
688 /// 702 ///
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 4b714c6d8..a1894e8d8 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14itertools = "0.10.0" 14itertools = "0.10.0"
15arrayvec = "0.7" 15arrayvec = "0.7"
16smallvec = "1.2.0" 16smallvec = "1.2.0"
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 283894704..407273943 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -4,325 +4,31 @@ mod match_check;
4mod unsafe_check; 4mod unsafe_check;
5mod decl_check; 5mod decl_check;
6 6
7use std::{any::Any, fmt}; 7use std::fmt;
8 8
9use base_db::CrateId; 9use base_db::CrateId;
10use hir_def::{DefWithBodyId, ModuleDefId}; 10use hir_def::ModuleDefId;
11use hir_expand::{name::Name, HirFileId, InFile}; 11use hir_expand::HirFileId;
12use stdx::format_to; 12use syntax::{ast, AstPtr};
13use syntax::{ast, AstPtr, SyntaxNodePtr};
14 13
15use crate::{ 14use crate::db::HirDatabase;
16 db::HirDatabase,
17 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink},
18};
19 15
20pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; 16pub use crate::diagnostics::{
17 expr::{
18 record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
19 },
20 unsafe_check::missing_unsafe,
21};
21 22
22pub fn validate_module_item( 23pub fn validate_module_item(
23 db: &dyn HirDatabase, 24 db: &dyn HirDatabase,
24 krate: CrateId, 25 krate: CrateId,
25 owner: ModuleDefId, 26 owner: ModuleDefId,
26 sink: &mut DiagnosticSink<'_>, 27) -> Vec<IncorrectCase> {
27) {
28 let _p = profile::span("validate_module_item"); 28 let _p = profile::span("validate_module_item");
29 let mut validator = decl_check::DeclValidator::new(db, krate, sink); 29 let mut validator = decl_check::DeclValidator::new(db, krate);
30 validator.validate_item(owner); 30 validator.validate_item(owner);
31} 31 validator.sink
32
33pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
34 let _p = profile::span("validate_body");
35 let infer = db.infer(owner);
36 infer.add_diagnostics(db, owner, sink);
37 let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink);
38 validator.validate_body(db);
39 let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink);
40 validator.validate_body(db);
41}
42
43// Diagnostic: no-such-field
44//
45// This diagnostic is triggered if created structure does not have field provided in record.
46#[derive(Debug)]
47pub struct NoSuchField {
48 pub file: HirFileId,
49 pub field: AstPtr<ast::RecordExprField>,
50}
51
52impl Diagnostic for NoSuchField {
53 fn code(&self) -> DiagnosticCode {
54 DiagnosticCode("no-such-field")
55 }
56
57 fn message(&self) -> String {
58 "no such field".to_string()
59 }
60
61 fn display_source(&self) -> InFile<SyntaxNodePtr> {
62 InFile::new(self.file, self.field.clone().into())
63 }
64
65 fn as_any(&self) -> &(dyn Any + Send + 'static) {
66 self
67 }
68}
69
70// Diagnostic: missing-structure-fields
71//
72// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
73//
74// Example:
75//
76// ```rust
77// struct A { a: u8, b: u8 }
78//
79// let a = A { a: 10 };
80// ```
81#[derive(Debug)]
82pub struct MissingFields {
83 pub file: HirFileId,
84 pub field_list_parent: AstPtr<ast::RecordExpr>,
85 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
86 pub missed_fields: Vec<Name>,
87}
88
89impl Diagnostic for MissingFields {
90 fn code(&self) -> DiagnosticCode {
91 DiagnosticCode("missing-structure-fields")
92 }
93 fn message(&self) -> String {
94 let mut buf = String::from("Missing structure fields:\n");
95 for field in &self.missed_fields {
96 format_to!(buf, "- {}\n", field);
97 }
98 buf
99 }
100
101 fn display_source(&self) -> InFile<SyntaxNodePtr> {
102 InFile {
103 file_id: self.file,
104 value: self
105 .field_list_parent_path
106 .clone()
107 .map(SyntaxNodePtr::from)
108 .unwrap_or_else(|| self.field_list_parent.clone().into()),
109 }
110 }
111
112 fn as_any(&self) -> &(dyn Any + Send + 'static) {
113 self
114 }
115}
116
117// Diagnostic: missing-pat-fields
118//
119// This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure.
120//
121// Example:
122//
123// ```rust
124// struct A { a: u8, b: u8 }
125//
126// let a = A { a: 10, b: 20 };
127//
128// if let A { a } = a {
129// // ...
130// }
131// ```
132#[derive(Debug)]
133pub struct MissingPatFields {
134 pub file: HirFileId,
135 pub field_list_parent: AstPtr<ast::RecordPat>,
136 pub field_list_parent_path: Option<AstPtr<ast::Path>>,
137 pub missed_fields: Vec<Name>,
138}
139
140impl Diagnostic for MissingPatFields {
141 fn code(&self) -> DiagnosticCode {
142 DiagnosticCode("missing-pat-fields")
143 }
144 fn message(&self) -> String {
145 let mut buf = String::from("Missing structure fields:\n");
146 for field in &self.missed_fields {
147 format_to!(buf, "- {}\n", field);
148 }
149 buf
150 }
151 fn display_source(&self) -> InFile<SyntaxNodePtr> {
152 InFile {
153 file_id: self.file,
154 value: self
155 .field_list_parent_path
156 .clone()
157 .map(SyntaxNodePtr::from)
158 .unwrap_or_else(|| self.field_list_parent.clone().into()),
159 }
160 }
161 fn as_any(&self) -> &(dyn Any + Send + 'static) {
162 self
163 }
164}
165
166// Diagnostic: missing-match-arm
167//
168// This diagnostic is triggered if `match` block is missing one or more match arms.
169#[derive(Debug)]
170pub struct MissingMatchArms {
171 pub file: HirFileId,
172 pub match_expr: AstPtr<ast::Expr>,
173 pub arms: AstPtr<ast::MatchArmList>,
174}
175
176impl Diagnostic for MissingMatchArms {
177 fn code(&self) -> DiagnosticCode {
178 DiagnosticCode("missing-match-arm")
179 }
180 fn message(&self) -> String {
181 String::from("Missing match arm")
182 }
183 fn display_source(&self) -> InFile<SyntaxNodePtr> {
184 InFile { file_id: self.file, value: self.match_expr.clone().into() }
185 }
186 fn as_any(&self) -> &(dyn Any + Send + 'static) {
187 self
188 }
189}
190
191// Diagnostic: missing-ok-or-some-in-tail-expr
192//
193// This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`,
194// or if a block that should return `Option` returns a value not wrapped in `Some`.
195//
196// Example:
197//
198// ```rust
199// fn foo() -> Result<u8, ()> {
200// 10
201// }
202// ```
203#[derive(Debug)]
204pub struct MissingOkOrSomeInTailExpr {
205 pub file: HirFileId,
206 pub expr: AstPtr<ast::Expr>,
207 // `Some` or `Ok` depending on whether the return type is Result or Option
208 pub required: String,
209}
210
211impl Diagnostic for MissingOkOrSomeInTailExpr {
212 fn code(&self) -> DiagnosticCode {
213 DiagnosticCode("missing-ok-or-some-in-tail-expr")
214 }
215 fn message(&self) -> String {
216 format!("wrap return expression in {}", self.required)
217 }
218 fn display_source(&self) -> InFile<SyntaxNodePtr> {
219 InFile { file_id: self.file, value: self.expr.clone().into() }
220 }
221 fn as_any(&self) -> &(dyn Any + Send + 'static) {
222 self
223 }
224}
225
226#[derive(Debug)]
227pub struct RemoveThisSemicolon {
228 pub file: HirFileId,
229 pub expr: AstPtr<ast::Expr>,
230}
231
232impl Diagnostic for RemoveThisSemicolon {
233 fn code(&self) -> DiagnosticCode {
234 DiagnosticCode("remove-this-semicolon")
235 }
236
237 fn message(&self) -> String {
238 "Remove this semicolon".to_string()
239 }
240
241 fn display_source(&self) -> InFile<SyntaxNodePtr> {
242 InFile { file_id: self.file, value: self.expr.clone().into() }
243 }
244
245 fn as_any(&self) -> &(dyn Any + Send + 'static) {
246 self
247 }
248}
249
250// Diagnostic: break-outside-of-loop
251//
252// This diagnostic is triggered if the `break` keyword is used outside of a loop.
253#[derive(Debug)]
254pub struct BreakOutsideOfLoop {
255 pub file: HirFileId,
256 pub expr: AstPtr<ast::Expr>,
257}
258
259impl Diagnostic for BreakOutsideOfLoop {
260 fn code(&self) -> DiagnosticCode {
261 DiagnosticCode("break-outside-of-loop")
262 }
263 fn message(&self) -> String {
264 "break outside of loop".to_string()
265 }
266 fn display_source(&self) -> InFile<SyntaxNodePtr> {
267 InFile { file_id: self.file, value: self.expr.clone().into() }
268 }
269 fn as_any(&self) -> &(dyn Any + Send + 'static) {
270 self
271 }
272}
273
274// Diagnostic: missing-unsafe
275//
276// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
277#[derive(Debug)]
278pub struct MissingUnsafe {
279 pub file: HirFileId,
280 pub expr: AstPtr<ast::Expr>,
281}
282
283impl Diagnostic for MissingUnsafe {
284 fn code(&self) -> DiagnosticCode {
285 DiagnosticCode("missing-unsafe")
286 }
287 fn message(&self) -> String {
288 format!("This operation is unsafe and requires an unsafe function or block")
289 }
290 fn display_source(&self) -> InFile<SyntaxNodePtr> {
291 InFile { file_id: self.file, value: self.expr.clone().into() }
292 }
293 fn as_any(&self) -> &(dyn Any + Send + 'static) {
294 self
295 }
296}
297
298// Diagnostic: mismatched-arg-count
299//
300// This diagnostic is triggered if a function is invoked with an incorrect amount of arguments.
301#[derive(Debug)]
302pub struct MismatchedArgCount {
303 pub file: HirFileId,
304 pub call_expr: AstPtr<ast::Expr>,
305 pub expected: usize,
306 pub found: usize,
307}
308
309impl Diagnostic for MismatchedArgCount {
310 fn code(&self) -> DiagnosticCode {
311 DiagnosticCode("mismatched-arg-count")
312 }
313 fn message(&self) -> String {
314 let s = if self.expected == 1 { "" } else { "s" };
315 format!("Expected {} argument{}, found {}", self.expected, s, self.found)
316 }
317 fn display_source(&self) -> InFile<SyntaxNodePtr> {
318 InFile { file_id: self.file, value: self.call_expr.clone().into() }
319 }
320 fn as_any(&self) -> &(dyn Any + Send + 'static) {
321 self
322 }
323 fn is_experimental(&self) -> bool {
324 true
325 }
326} 32}
327 33
328#[derive(Debug)] 34#[derive(Debug)]
@@ -390,450 +96,3 @@ pub struct IncorrectCase {
390 pub ident_text: String, 96 pub ident_text: String,
391 pub suggested_text: String, 97 pub suggested_text: String,
392} 98}
393
394impl Diagnostic for IncorrectCase {
395 fn code(&self) -> DiagnosticCode {
396 DiagnosticCode("incorrect-ident-case")
397 }
398
399 fn message(&self) -> String {
400 format!(
401 "{} `{}` should have {} name, e.g. `{}`",
402 self.ident_type,
403 self.ident_text,
404 self.expected_case.to_string(),
405 self.suggested_text
406 )
407 }
408
409 fn display_source(&self) -> InFile<SyntaxNodePtr> {
410 InFile::new(self.file, self.ident.clone().into())
411 }
412
413 fn as_any(&self) -> &(dyn Any + Send + 'static) {
414 self
415 }
416
417 fn is_experimental(&self) -> bool {
418 true
419 }
420}
421
422// Diagnostic: replace-filter-map-next-with-find-map
423//
424// This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`.
425#[derive(Debug)]
426pub struct ReplaceFilterMapNextWithFindMap {
427 pub file: HirFileId,
428 /// This expression is the whole method chain up to and including `.filter_map(..).next()`.
429 pub next_expr: AstPtr<ast::Expr>,
430}
431
432impl Diagnostic for ReplaceFilterMapNextWithFindMap {
433 fn code(&self) -> DiagnosticCode {
434 DiagnosticCode("replace-filter-map-next-with-find-map")
435 }
436 fn message(&self) -> String {
437 "replace filter_map(..).next() with find_map(..)".to_string()
438 }
439 fn display_source(&self) -> InFile<SyntaxNodePtr> {
440 InFile { file_id: self.file, value: self.next_expr.clone().into() }
441 }
442 fn as_any(&self) -> &(dyn Any + Send + 'static) {
443 self
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use base_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
450 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
451 use hir_expand::db::AstDatabase;
452 use rustc_hash::FxHashMap;
453 use syntax::{TextRange, TextSize};
454
455 use crate::{
456 diagnostics::{validate_body, validate_module_item},
457 diagnostics_sink::{Diagnostic, DiagnosticSinkBuilder},
458 test_db::TestDB,
459 };
460
461 impl TestDB {
462 fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
463 let crate_graph = self.crate_graph();
464 for krate in crate_graph.iter() {
465 let crate_def_map = self.crate_def_map(krate);
466
467 let mut fns = Vec::new();
468 for (module_id, _) in crate_def_map.modules() {
469 for decl in crate_def_map[module_id].scope.declarations() {
470 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
471 validate_module_item(self, krate, decl, &mut sink);
472
473 if let ModuleDefId::FunctionId(f) = decl {
474 fns.push(f)
475 }
476 }
477
478 for impl_id in crate_def_map[module_id].scope.impls() {
479 let impl_data = self.impl_data(impl_id);
480 for item in impl_data.items.iter() {
481 if let AssocItemId::FunctionId(f) = item {
482 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
483 validate_module_item(
484 self,
485 krate,
486 ModuleDefId::FunctionId(*f),
487 &mut sink,
488 );
489 fns.push(*f)
490 }
491 }
492 }
493 }
494
495 for f in fns {
496 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
497 validate_body(self, f.into(), &mut sink);
498 }
499 }
500 }
501 }
502
503 pub(crate) fn check_diagnostics(ra_fixture: &str) {
504 let db = TestDB::with_files(ra_fixture);
505 let annotations = db.extract_annotations();
506
507 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
508 db.diagnostics(|d| {
509 let src = d.display_source();
510 let root = db.parse_or_expand(src.file_id).unwrap();
511 // FIXME: macros...
512 let file_id = src.file_id.original_file(&db);
513 let range = src.value.to_node(&root).text_range();
514 let message = d.message();
515 actual.entry(file_id).or_default().push((range, message));
516 });
517
518 for (file_id, diags) in actual.iter_mut() {
519 diags.sort_by_key(|it| it.0.start());
520 let text = db.file_text(*file_id);
521 // For multiline spans, place them on line start
522 for (range, content) in diags {
523 if text[*range].contains('\n') {
524 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
525 *content = format!("... {}", content);
526 }
527 }
528 }
529
530 assert_eq!(annotations, actual);
531 }
532
533 #[test]
534 fn no_such_field_diagnostics() {
535 check_diagnostics(
536 r#"
537struct S { foo: i32, bar: () }
538impl S {
539 fn new() -> S {
540 S {
541 //^ Missing structure fields:
542 //| - bar
543 foo: 92,
544 baz: 62,
545 //^^^^^^^ no such field
546 }
547 }
548}
549"#,
550 );
551 }
552 #[test]
553 fn no_such_field_with_feature_flag_diagnostics() {
554 check_diagnostics(
555 r#"
556//- /lib.rs crate:foo cfg:feature=foo
557struct MyStruct {
558 my_val: usize,
559 #[cfg(feature = "foo")]
560 bar: bool,
561}
562
563impl MyStruct {
564 #[cfg(feature = "foo")]
565 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
566 Self { my_val, bar }
567 }
568 #[cfg(not(feature = "foo"))]
569 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
570 Self { my_val }
571 }
572}
573"#,
574 );
575 }
576
577 #[test]
578 fn no_such_field_enum_with_feature_flag_diagnostics() {
579 check_diagnostics(
580 r#"
581//- /lib.rs crate:foo cfg:feature=foo
582enum Foo {
583 #[cfg(not(feature = "foo"))]
584 Buz,
585 #[cfg(feature = "foo")]
586 Bar,
587 Baz
588}
589
590fn test_fn(f: Foo) {
591 match f {
592 Foo::Bar => {},
593 Foo::Baz => {},
594 }
595}
596"#,
597 );
598 }
599
600 #[test]
601 fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
602 check_diagnostics(
603 r#"
604//- /lib.rs crate:foo cfg:feature=foo
605struct S {
606 #[cfg(feature = "foo")]
607 foo: u32,
608 #[cfg(not(feature = "foo"))]
609 bar: u32,
610}
611
612impl S {
613 #[cfg(feature = "foo")]
614 fn new(foo: u32) -> Self {
615 Self { foo }
616 }
617 #[cfg(not(feature = "foo"))]
618 fn new(bar: u32) -> Self {
619 Self { bar }
620 }
621 fn new2(bar: u32) -> Self {
622 #[cfg(feature = "foo")]
623 { Self { foo: bar } }
624 #[cfg(not(feature = "foo"))]
625 { Self { bar } }
626 }
627 fn new2(val: u32) -> Self {
628 Self {
629 #[cfg(feature = "foo")]
630 foo: val,
631 #[cfg(not(feature = "foo"))]
632 bar: val,
633 }
634 }
635}
636"#,
637 );
638 }
639
640 #[test]
641 fn no_such_field_with_type_macro() {
642 check_diagnostics(
643 r#"
644macro_rules! Type { () => { u32 }; }
645struct Foo { bar: Type![] }
646
647impl Foo {
648 fn new() -> Self {
649 Foo { bar: 0 }
650 }
651}
652"#,
653 );
654 }
655
656 #[test]
657 fn missing_record_pat_field_diagnostic() {
658 check_diagnostics(
659 r#"
660struct S { foo: i32, bar: () }
661fn baz(s: S) {
662 let S { foo: _ } = s;
663 //^ Missing structure fields:
664 //| - bar
665}
666"#,
667 );
668 }
669
670 #[test]
671 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
672 check_diagnostics(
673 r"
674struct S { foo: i32, bar: () }
675fn baz(s: S) -> i32 {
676 match s {
677 S { foo, .. } => foo,
678 }
679}
680",
681 )
682 }
683
684 #[test]
685 fn missing_record_pat_field_box() {
686 check_diagnostics(
687 r"
688struct S { s: Box<u32> }
689fn x(a: S) {
690 let S { box s } = a;
691}
692",
693 )
694 }
695
696 #[test]
697 fn missing_record_pat_field_ref() {
698 check_diagnostics(
699 r"
700struct S { s: u32 }
701fn x(a: S) {
702 let S { ref s } = a;
703}
704",
705 )
706 }
707
708 #[test]
709 fn import_extern_crate_clash_with_inner_item() {
710 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
711
712 check_diagnostics(
713 r#"
714//- /lib.rs crate:lib deps:jwt
715mod permissions;
716
717use permissions::jwt;
718
719fn f() {
720 fn inner() {}
721 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
722}
723
724//- /permissions.rs
725pub mod jwt {
726 pub struct Claims {}
727}
728
729//- /jwt/lib.rs crate:jwt
730pub struct Claims {
731 field: u8,
732}
733 "#,
734 );
735 }
736
737 #[test]
738 fn break_outside_of_loop() {
739 check_diagnostics(
740 r#"
741fn foo() { break; }
742 //^^^^^ break outside of loop
743"#,
744 );
745 }
746
747 #[test]
748 fn missing_semicolon() {
749 check_diagnostics(
750 r#"
751 fn test() -> i32 { 123; }
752 //^^^ Remove this semicolon
753 "#,
754 );
755 }
756
757 // Register the required standard library types to make the tests work
758 fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
759 let prefix = r#"
760 //- /main.rs crate:main deps:core
761 use core::iter::Iterator;
762 use core::option::Option::{self, Some, None};
763 "#;
764 let suffix = r#"
765 //- /core/lib.rs crate:core
766 pub mod option {
767 pub enum Option<T> { Some(T), None }
768 }
769 pub mod iter {
770 pub trait Iterator {
771 type Item;
772 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
773 fn next(&mut self) -> Option<Self::Item>;
774 }
775 pub struct FilterMap {}
776 impl Iterator for FilterMap {
777 type Item = i32;
778 fn next(&mut self) -> i32 { 7 }
779 }
780 }
781 "#;
782 format!("{}{}{}", prefix, body, suffix)
783 }
784
785 #[test]
786 fn replace_filter_map_next_with_find_map2() {
787 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
788 r#"
789 fn foo() {
790 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
791 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
792 }
793 "#,
794 ));
795 }
796
797 #[test]
798 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
799 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
800 r#"
801 fn foo() {
802 let m = [1, 2, 3]
803 .iter()
804 .filter_map(|x| if *x == 2 { Some (4) } else { None })
805 .len();
806 }
807 "#,
808 ));
809 }
810
811 #[test]
812 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
813 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
814 r#"
815 fn foo() {
816 let m = [1, 2, 3]
817 .iter()
818 .filter_map(|x| if *x == 2 { Some (4) } else { None })
819 .map(|x| x + 2)
820 .len();
821 }
822 "#,
823 ));
824 }
825
826 #[test]
827 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
828 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
829 r#"
830 fn foo() {
831 let m = [1, 2, 3]
832 .iter()
833 .filter_map(|x| if *x == 2 { Some (4) } else { None });
834 let n = m.next();
835 }
836 "#,
837 ));
838 }
839}
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index cfb5d7320..f26150b77 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -29,7 +29,6 @@ use syntax::{
29use crate::{ 29use crate::{
30 db::HirDatabase, 30 db::HirDatabase,
31 diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase}, 31 diagnostics::{decl_check::case_conv::*, CaseType, IdentType, IncorrectCase},
32 diagnostics_sink::DiagnosticSink,
33}; 32};
34 33
35mod allow { 34mod allow {
@@ -40,10 +39,10 @@ mod allow {
40 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; 39 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
41} 40}
42 41
43pub(super) struct DeclValidator<'a, 'b> { 42pub(super) struct DeclValidator<'a> {
44 db: &'a dyn HirDatabase, 43 db: &'a dyn HirDatabase,
45 krate: CrateId, 44 krate: CrateId,
46 sink: &'a mut DiagnosticSink<'b>, 45 pub(super) sink: Vec<IncorrectCase>,
47} 46}
48 47
49#[derive(Debug)] 48#[derive(Debug)]
@@ -53,13 +52,9 @@ struct Replacement {
53 expected_case: CaseType, 52 expected_case: CaseType,
54} 53}
55 54
56impl<'a, 'b> DeclValidator<'a, 'b> { 55impl<'a> DeclValidator<'a> {
57 pub(super) fn new( 56 pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> {
58 db: &'a dyn HirDatabase, 57 DeclValidator { db, krate, sink: Vec::new() }
59 krate: CrateId,
60 sink: &'a mut DiagnosticSink<'b>,
61 ) -> DeclValidator<'a, 'b> {
62 DeclValidator { db, krate, sink }
63 } 58 }
64 59
65 pub(super) fn validate_item(&mut self, item: ModuleDefId) { 60 pub(super) fn validate_item(&mut self, item: ModuleDefId) {
@@ -131,7 +126,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
131 for (_, block_def_map) in body.blocks(self.db.upcast()) { 126 for (_, block_def_map) in body.blocks(self.db.upcast()) {
132 for (_, module) in block_def_map.modules() { 127 for (_, module) in block_def_map.modules() {
133 for def_id in module.scope.declarations() { 128 for def_id in module.scope.declarations() {
134 let mut validator = DeclValidator::new(self.db, self.krate, self.sink); 129 let mut validator = DeclValidator::new(self.db, self.krate);
135 validator.validate_item(def_id); 130 validator.validate_item(def_id);
136 } 131 }
137 } 132 }
@@ -623,343 +618,3 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
623 self.sink.push(diagnostic); 618 self.sink.push(diagnostic);
624 } 619 }
625} 620}
626
627#[cfg(test)]
628mod tests {
629 use crate::diagnostics::tests::check_diagnostics;
630
631 #[test]
632 fn incorrect_function_name() {
633 check_diagnostics(
634 r#"
635fn NonSnakeCaseName() {}
636// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
637"#,
638 );
639 }
640
641 #[test]
642 fn incorrect_function_params() {
643 check_diagnostics(
644 r#"
645fn foo(SomeParam: u8) {}
646 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
647
648fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
649 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
650"#,
651 );
652 }
653
654 #[test]
655 fn incorrect_variable_names() {
656 check_diagnostics(
657 r#"
658fn foo() {
659 let SOME_VALUE = 10;
660 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
661 let AnotherValue = 20;
662 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
663}
664"#,
665 );
666 }
667
668 #[test]
669 fn incorrect_struct_names() {
670 check_diagnostics(
671 r#"
672struct non_camel_case_name {}
673 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
674
675struct SCREAMING_CASE {}
676 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
677"#,
678 );
679 }
680
681 #[test]
682 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
683 check_diagnostics(
684 r#"
685struct AABB {}
686"#,
687 );
688 }
689
690 #[test]
691 fn incorrect_struct_field() {
692 check_diagnostics(
693 r#"
694struct SomeStruct { SomeField: u8 }
695 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
696"#,
697 );
698 }
699
700 #[test]
701 fn incorrect_enum_names() {
702 check_diagnostics(
703 r#"
704enum some_enum { Val(u8) }
705 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
706
707enum SOME_ENUM
708 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
709"#,
710 );
711 }
712
713 #[test]
714 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
715 check_diagnostics(
716 r#"
717enum AABB {}
718"#,
719 );
720 }
721
722 #[test]
723 fn incorrect_enum_variant_name() {
724 check_diagnostics(
725 r#"
726enum SomeEnum { SOME_VARIANT(u8) }
727 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
728"#,
729 );
730 }
731
732 #[test]
733 fn incorrect_const_name() {
734 check_diagnostics(
735 r#"
736const some_weird_const: u8 = 10;
737 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
738
739fn func() {
740 const someConstInFunc: &str = "hi there";
741 // ^^^^^^^^^^^^^^^ Constant `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
742
743}
744"#,
745 );
746 }
747
748 #[test]
749 fn incorrect_static_name() {
750 check_diagnostics(
751 r#"
752static some_weird_const: u8 = 10;
753 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
754
755fn func() {
756 static someConstInFunc: &str = "hi there";
757 // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
758}
759"#,
760 );
761 }
762
763 #[test]
764 fn fn_inside_impl_struct() {
765 check_diagnostics(
766 r#"
767struct someStruct;
768 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
769
770impl someStruct {
771 fn SomeFunc(&self) {
772 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
773 static someConstInFunc: &str = "hi there";
774 // ^^^^^^^^^^^^^^^ Static variable `someConstInFunc` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST_IN_FUNC`
775 let WHY_VAR_IS_CAPS = 10;
776 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
777 }
778}
779"#,
780 );
781 }
782
783 #[test]
784 fn no_diagnostic_for_enum_varinats() {
785 check_diagnostics(
786 r#"
787enum Option { Some, None }
788
789fn main() {
790 match Option::None {
791 None => (),
792 Some => (),
793 }
794}
795"#,
796 );
797 }
798
799 #[test]
800 fn non_let_bind() {
801 check_diagnostics(
802 r#"
803enum Option { Some, None }
804
805fn main() {
806 match Option::None {
807 SOME_VAR @ None => (),
808 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
809 Some => (),
810 }
811}
812"#,
813 );
814 }
815
816 #[test]
817 fn allow_attributes() {
818 check_diagnostics(
819 r#"
820#[allow(non_snake_case)]
821fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
822 // cov_flags generated output from elsewhere in this file
823 extern "C" {
824 #[no_mangle]
825 static lower_case: u8;
826 }
827
828 let OtherVar = SOME_VAR + 1;
829 OtherVar
830}
831
832#[allow(nonstandard_style)]
833mod CheckNonstandardStyle {
834 fn HiImABadFnName() {}
835}
836
837#[allow(bad_style)]
838mod CheckBadStyle {
839 fn HiImABadFnName() {}
840}
841
842mod F {
843 #![allow(non_snake_case)]
844 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
845}
846
847#[allow(non_snake_case, non_camel_case_types)]
848pub struct some_type {
849 SOME_FIELD: u8,
850 SomeField: u16,
851}
852
853#[allow(non_upper_case_globals)]
854pub const some_const: u8 = 10;
855
856#[allow(non_upper_case_globals)]
857pub static SomeStatic: u8 = 10;
858 "#,
859 );
860 }
861
862 #[test]
863 fn allow_attributes_crate_attr() {
864 check_diagnostics(
865 r#"
866#![allow(non_snake_case)]
867
868mod F {
869 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
870}
871 "#,
872 );
873 }
874
875 #[test]
876 #[ignore]
877 fn bug_trait_inside_fn() {
878 // FIXME:
879 // This is broken, and in fact, should not even be looked at by this
880 // lint in the first place. There's weird stuff going on in the
881 // collection phase.
882 // It's currently being brought in by:
883 // * validate_func on `a` recursing into modules
884 // * then it finds the trait and then the function while iterating
885 // through modules
886 // * then validate_func is called on Dirty
887 // * ... which then proceeds to look at some unknown module taking no
888 // attrs from either the impl or the fn a, and then finally to the root
889 // module
890 //
891 // It should find the attribute on the trait, but it *doesn't even see
892 // the trait* as far as I can tell.
893
894 check_diagnostics(
895 r#"
896trait T { fn a(); }
897struct U {}
898impl T for U {
899 fn a() {
900 // this comes out of bitflags, mostly
901 #[allow(non_snake_case)]
902 trait __BitFlags {
903 const HiImAlsoBad: u8 = 2;
904 #[inline]
905 fn Dirty(&self) -> bool {
906 false
907 }
908 }
909
910 }
911}
912 "#,
913 );
914 }
915
916 #[test]
917 #[ignore]
918 fn bug_traits_arent_checked() {
919 // FIXME: Traits and functions in traits aren't currently checked by
920 // r-a, even though rustc will complain about them.
921 check_diagnostics(
922 r#"
923trait BAD_TRAIT {
924 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
925 fn BAD_FUNCTION();
926 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
927 fn BadFunction();
928 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
929}
930 "#,
931 );
932 }
933
934 #[test]
935 fn ignores_extern_items() {
936 cov_mark::check!(extern_func_incorrect_case_ignored);
937 cov_mark::check!(extern_static_incorrect_case_ignored);
938 check_diagnostics(
939 r#"
940extern {
941 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
942 pub static SomeStatic: u8 = 10;
943}
944 "#,
945 );
946 }
947
948 #[test]
949 fn infinite_loop_inner_items() {
950 check_diagnostics(
951 r#"
952fn qualify() {
953 mod foo {
954 use super::*;
955 }
956}
957 "#,
958 )
959 }
960
961 #[test] // Issue #8809.
962 fn parenthesized_parameter() {
963 check_diagnostics(r#"fn f((O): _) {}"#)
964 }
965}
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};
10use hir_expand::name; 10use hir_expand::name;
11use rustc_hash::FxHashSet; 11use rustc_hash::FxHashSet;
12use syntax::{ast, AstPtr};
13 12
14use crate::{ 13use 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
34use super::ReplaceFilterMapNextWithFindMap; 28pub 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
36pub(super) struct ExprValidator<'a, 'b: 'a> { 62impl 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
77struct 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
42impl<'a, 'b> ExprValidator<'a, 'b> { 84impl 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)]
573mod tests {
574 use crate::diagnostics::tests::check_diagnostics;
575
576 #[test]
577 fn simple_free_fn_zero() {
578 check_diagnostics(
579 r#"
580fn zero() {}
581fn f() { zero(1); }
582 //^^^^^^^ Expected 0 arguments, found 1
583"#,
584 );
585
586 check_diagnostics(
587 r#"
588fn zero() {}
589fn f() { zero(); }
590"#,
591 );
592 }
593
594 #[test]
595 fn simple_free_fn_one() {
596 check_diagnostics(
597 r#"
598fn one(arg: u8) {}
599fn f() { one(); }
600 //^^^^^ Expected 1 argument, found 0
601"#,
602 );
603
604 check_diagnostics(
605 r#"
606fn one(arg: u8) {}
607fn f() { one(1); }
608"#,
609 );
610 }
611
612 #[test]
613 fn method_as_fn() {
614 check_diagnostics(
615 r#"
616struct S;
617impl S { fn method(&self) {} }
618
619fn f() {
620 S::method();
621} //^^^^^^^^^^^ Expected 1 argument, found 0
622"#,
623 );
624
625 check_diagnostics(
626 r#"
627struct S;
628impl S { fn method(&self) {} }
629
630fn 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#"
642struct S;
643impl 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#"
653struct S;
654impl S { fn method(&self, arg: u8) {} }
655
656fn 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#"
670trait Foo { fn method(&self, arg: usize) {} }
671
672fn f() {
673 let x;
674 x.method();
675}
676"#,
677 );
678 }
679
680 #[test]
681 fn tuple_struct() {
682 check_diagnostics(
683 r#"
684struct Tup(u8, u16);
685fn 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#"
696enum En { Variant(u8, u16), }
697fn 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#"
708macro_rules! Type {
709 () => { u32 };
710}
711enum Foo {
712 Bar(Type![])
713}
714impl 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#"
731extern "C" {
732 fn fixed(fixed: u8);
733 fn varargs(fixed: u8, ...);
734 fn varargs2(...);
735}
736
737fn 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#"
757fn 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#"
773struct C(#[cfg(FALSE)] ());
774impl C {
775 fn new() -> Self {
776 Self(
777 #[cfg(FALSE)]
778 (),
779 )
780 }
781
782 fn method(&self) {}
783}
784
785fn 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#"
796fn foo(#[cfg(NEVER)] x: ()) {}
797
798struct S;
799
800impl 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
806extern "C" {
807 fn fixed(fixed: u8, #[cfg(NEVER)] ...);
808 fn varargs(#[cfg(not(NEVER))] ...);
809}
810
811fn 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}
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index c8e1b23de..a30e42699 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -364,960 +364,3 @@ impl PatternFoldable for PatKind {
364 } 364 }
365 } 365 }
366} 366}
367
368#[cfg(test)]
369pub(super) mod tests {
370 mod report {
371 use std::any::Any;
372
373 use hir_def::{expr::PatId, DefWithBodyId};
374 use hir_expand::{HirFileId, InFile};
375 use syntax::SyntaxNodePtr;
376
377 use crate::{
378 db::HirDatabase,
379 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink},
380 };
381
382 /// In tests, match check bails out loudly.
383 /// This helps to catch incorrect tests that pass due to false negatives.
384 pub(crate) fn report_bail_out(
385 db: &dyn HirDatabase,
386 def: DefWithBodyId,
387 pat: PatId,
388 sink: &mut DiagnosticSink,
389 ) {
390 let (_, source_map) = db.body_with_source_map(def);
391 if let Ok(source_ptr) = source_map.pat_syntax(pat) {
392 let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into);
393 sink.push(BailedOut { file: source_ptr.file_id, pat_syntax_ptr });
394 }
395 }
396
397 #[derive(Debug)]
398 struct BailedOut {
399 file: HirFileId,
400 pat_syntax_ptr: SyntaxNodePtr,
401 }
402
403 impl Diagnostic for BailedOut {
404 fn code(&self) -> DiagnosticCode {
405 DiagnosticCode("internal:match-check-bailed-out")
406 }
407 fn message(&self) -> String {
408 format!("Internal: match check bailed out")
409 }
410 fn display_source(&self) -> InFile<SyntaxNodePtr> {
411 InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() }
412 }
413 fn as_any(&self) -> &(dyn Any + Send + 'static) {
414 self
415 }
416 }
417 }
418
419 use crate::diagnostics::tests::check_diagnostics;
420
421 pub(crate) use self::report::report_bail_out;
422
423 #[test]
424 fn empty_tuple() {
425 check_diagnostics(
426 r#"
427fn main() {
428 match () { }
429 //^^ Missing match arm
430 match (()) { }
431 //^^^^ Missing match arm
432
433 match () { _ => (), }
434 match () { () => (), }
435 match (()) { (()) => (), }
436}
437"#,
438 );
439 }
440
441 #[test]
442 fn tuple_of_two_empty_tuple() {
443 check_diagnostics(
444 r#"
445fn main() {
446 match ((), ()) { }
447 //^^^^^^^^ Missing match arm
448
449 match ((), ()) { ((), ()) => (), }
450}
451"#,
452 );
453 }
454
455 #[test]
456 fn boolean() {
457 check_diagnostics(
458 r#"
459fn test_main() {
460 match false { }
461 //^^^^^ Missing match arm
462 match false { true => (), }
463 //^^^^^ Missing match arm
464 match (false, true) {}
465 //^^^^^^^^^^^^^ Missing match arm
466 match (false, true) { (true, true) => (), }
467 //^^^^^^^^^^^^^ Missing match arm
468 match (false, true) {
469 //^^^^^^^^^^^^^ Missing match arm
470 (false, true) => (),
471 (false, false) => (),
472 (true, false) => (),
473 }
474 match (false, true) { (true, _x) => (), }
475 //^^^^^^^^^^^^^ Missing match arm
476
477 match false { true => (), false => (), }
478 match (false, true) {
479 (false, _) => (),
480 (true, false) => (),
481 (_, true) => (),
482 }
483 match (false, true) {
484 (true, true) => (),
485 (true, false) => (),
486 (false, true) => (),
487 (false, false) => (),
488 }
489 match (false, true) {
490 (true, _x) => (),
491 (false, true) => (),
492 (false, false) => (),
493 }
494 match (false, true, false) {
495 (false, ..) => (),
496 (true, ..) => (),
497 }
498 match (false, true, false) {
499 (.., false) => (),
500 (.., true) => (),
501 }
502 match (false, true, false) { (..) => (), }
503}
504"#,
505 );
506 }
507
508 #[test]
509 fn tuple_of_tuple_and_bools() {
510 check_diagnostics(
511 r#"
512fn main() {
513 match (false, ((), false)) {}
514 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
515 match (false, ((), false)) { (true, ((), true)) => (), }
516 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
517 match (false, ((), false)) { (true, _) => (), }
518 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
519
520 match (false, ((), false)) {
521 (true, ((), true)) => (),
522 (true, ((), false)) => (),
523 (false, ((), true)) => (),
524 (false, ((), false)) => (),
525 }
526 match (false, ((), false)) {
527 (true, ((), true)) => (),
528 (true, ((), false)) => (),
529 (false, _) => (),
530 }
531}
532"#,
533 );
534 }
535
536 #[test]
537 fn enums() {
538 check_diagnostics(
539 r#"
540enum Either { A, B, }
541
542fn main() {
543 match Either::A { }
544 //^^^^^^^^^ Missing match arm
545 match Either::B { Either::A => (), }
546 //^^^^^^^^^ Missing match arm
547
548 match &Either::B {
549 //^^^^^^^^^^ Missing match arm
550 Either::A => (),
551 }
552
553 match Either::B {
554 Either::A => (), Either::B => (),
555 }
556 match &Either::B {
557 Either::A => (), Either::B => (),
558 }
559}
560"#,
561 );
562 }
563
564 #[test]
565 fn enum_containing_bool() {
566 check_diagnostics(
567 r#"
568enum Either { A(bool), B }
569
570fn main() {
571 match Either::B { }
572 //^^^^^^^^^ Missing match arm
573 match Either::B {
574 //^^^^^^^^^ Missing match arm
575 Either::A(true) => (), Either::B => ()
576 }
577
578 match Either::B {
579 Either::A(true) => (),
580 Either::A(false) => (),
581 Either::B => (),
582 }
583 match Either::B {
584 Either::B => (),
585 _ => (),
586 }
587 match Either::B {
588 Either::A(_) => (),
589 Either::B => (),
590 }
591
592}
593 "#,
594 );
595 }
596
597 #[test]
598 fn enum_different_sizes() {
599 check_diagnostics(
600 r#"
601enum Either { A(bool), B(bool, bool) }
602
603fn main() {
604 match Either::A(false) {
605 //^^^^^^^^^^^^^^^^ Missing match arm
606 Either::A(_) => (),
607 Either::B(false, _) => (),
608 }
609
610 match Either::A(false) {
611 Either::A(_) => (),
612 Either::B(true, _) => (),
613 Either::B(false, _) => (),
614 }
615 match Either::A(false) {
616 Either::A(true) | Either::A(false) => (),
617 Either::B(true, _) => (),
618 Either::B(false, _) => (),
619 }
620}
621"#,
622 );
623 }
624
625 #[test]
626 fn tuple_of_enum_no_diagnostic() {
627 check_diagnostics(
628 r#"
629enum Either { A(bool), B(bool, bool) }
630enum Either2 { C, D }
631
632fn main() {
633 match (Either::A(false), Either2::C) {
634 (Either::A(true), _) | (Either::A(false), _) => (),
635 (Either::B(true, _), Either2::C) => (),
636 (Either::B(false, _), Either2::C) => (),
637 (Either::B(_, _), Either2::D) => (),
638 }
639}
640"#,
641 );
642 }
643
644 #[test]
645 fn or_pattern_no_diagnostic() {
646 check_diagnostics(
647 r#"
648enum Either {A, B}
649
650fn main() {
651 match (Either::A, Either::B) {
652 (Either::A | Either::B, _) => (),
653 }
654}"#,
655 )
656 }
657
658 #[test]
659 fn mismatched_types() {
660 // Match statements with arms that don't match the
661 // expression pattern do not fire this diagnostic.
662 check_diagnostics(
663 r#"
664enum Either { A, B }
665enum Either2 { C, D }
666
667fn main() {
668 match Either::A {
669 Either2::C => (),
670 // ^^^^^^^^^^ Internal: match check bailed out
671 Either2::D => (),
672 }
673 match (true, false) {
674 (true, false, true) => (),
675 // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out
676 (true) => (),
677 }
678 match (true, false) { (true,) => {} }
679 // ^^^^^^^ Internal: match check bailed out
680 match (0) { () => () }
681 // ^^ Internal: match check bailed out
682 match Unresolved::Bar { Unresolved::Baz => () }
683}
684 "#,
685 );
686 }
687
688 #[test]
689 fn mismatched_types_in_or_patterns() {
690 check_diagnostics(
691 r#"
692fn main() {
693 match false { true | () => {} }
694 // ^^^^^^^^^ Internal: match check bailed out
695 match (false,) { (true | (),) => {} }
696 // ^^^^^^^^^^^^ Internal: match check bailed out
697}
698"#,
699 );
700 }
701
702 #[test]
703 fn malformed_match_arm_tuple_enum_missing_pattern() {
704 // We are testing to be sure we don't panic here when the match
705 // arm `Either::B` is missing its pattern.
706 check_diagnostics(
707 r#"
708enum Either { A, B(u32) }
709
710fn main() {
711 match Either::A {
712 Either::A => (),
713 Either::B() => (),
714 }
715}
716"#,
717 );
718 }
719
720 #[test]
721 fn malformed_match_arm_extra_fields() {
722 check_diagnostics(
723 r#"
724enum A { B(isize, isize), C }
725fn main() {
726 match A::B(1, 2) {
727 A::B(_, _, _) => (),
728 // ^^^^^^^^^^^^^ Internal: match check bailed out
729 }
730 match A::B(1, 2) {
731 A::C(_) => (),
732 // ^^^^^^^ Internal: match check bailed out
733 }
734}
735"#,
736 );
737 }
738
739 #[test]
740 fn expr_diverges() {
741 check_diagnostics(
742 r#"
743enum Either { A, B }
744
745fn main() {
746 match loop {} {
747 Either::A => (),
748 // ^^^^^^^^^ Internal: match check bailed out
749 Either::B => (),
750 }
751 match loop {} {
752 Either::A => (),
753 // ^^^^^^^^^ Internal: match check bailed out
754 }
755 match loop { break Foo::A } {
756 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
757 Either::A => (),
758 }
759 match loop { break Foo::A } {
760 Either::A => (),
761 Either::B => (),
762 }
763}
764"#,
765 );
766 }
767
768 #[test]
769 fn expr_partially_diverges() {
770 check_diagnostics(
771 r#"
772enum Either<T> { A(T), B }
773
774fn foo() -> Either<!> { Either::B }
775fn main() -> u32 {
776 match foo() {
777 Either::A(val) => val,
778 Either::B => 0,
779 }
780}
781"#,
782 );
783 }
784
785 #[test]
786 fn enum_record() {
787 check_diagnostics(
788 r#"
789enum Either { A { foo: bool }, B }
790
791fn main() {
792 let a = Either::A { foo: true };
793 match a { }
794 //^ Missing match arm
795 match a { Either::A { foo: true } => () }
796 //^ Missing match arm
797 match a {
798 Either::A { } => (),
799 //^^^^^^^^^ Missing structure fields:
800 // | - foo
801 Either::B => (),
802 }
803 match a {
804 //^ Missing match arm
805 Either::A { } => (),
806 } //^^^^^^^^^ Missing structure fields:
807 // | - foo
808
809 match a {
810 Either::A { foo: true } => (),
811 Either::A { foo: false } => (),
812 Either::B => (),
813 }
814 match a {
815 Either::A { foo: _ } => (),
816 Either::B => (),
817 }
818}
819"#,
820 );
821 }
822
823 #[test]
824 fn enum_record_fields_out_of_order() {
825 check_diagnostics(
826 r#"
827enum Either {
828 A { foo: bool, bar: () },
829 B,
830}
831
832fn main() {
833 let a = Either::A { foo: true, bar: () };
834 match a {
835 //^ Missing match arm
836 Either::A { bar: (), foo: false } => (),
837 Either::A { foo: true, bar: () } => (),
838 }
839
840 match a {
841 Either::A { bar: (), foo: false } => (),
842 Either::A { foo: true, bar: () } => (),
843 Either::B => (),
844 }
845}
846"#,
847 );
848 }
849
850 #[test]
851 fn enum_record_ellipsis() {
852 check_diagnostics(
853 r#"
854enum Either {
855 A { foo: bool, bar: bool },
856 B,
857}
858
859fn main() {
860 let a = Either::B;
861 match a {
862 //^ Missing match arm
863 Either::A { foo: true, .. } => (),
864 Either::B => (),
865 }
866 match a {
867 //^ Missing match arm
868 Either::A { .. } => (),
869 }
870
871 match a {
872 Either::A { foo: true, .. } => (),
873 Either::A { foo: false, .. } => (),
874 Either::B => (),
875 }
876
877 match a {
878 Either::A { .. } => (),
879 Either::B => (),
880 }
881}
882"#,
883 );
884 }
885
886 #[test]
887 fn enum_tuple_partial_ellipsis() {
888 check_diagnostics(
889 r#"
890enum Either {
891 A(bool, bool, bool, bool),
892 B,
893}
894
895fn main() {
896 match Either::B {
897 //^^^^^^^^^ Missing match arm
898 Either::A(true, .., true) => (),
899 Either::A(true, .., false) => (),
900 Either::A(false, .., false) => (),
901 Either::B => (),
902 }
903 match Either::B {
904 //^^^^^^^^^ Missing match arm
905 Either::A(true, .., true) => (),
906 Either::A(true, .., false) => (),
907 Either::A(.., true) => (),
908 Either::B => (),
909 }
910
911 match Either::B {
912 Either::A(true, .., true) => (),
913 Either::A(true, .., false) => (),
914 Either::A(false, .., true) => (),
915 Either::A(false, .., false) => (),
916 Either::B => (),
917 }
918 match Either::B {
919 Either::A(true, .., true) => (),
920 Either::A(true, .., false) => (),
921 Either::A(.., true) => (),
922 Either::A(.., false) => (),
923 Either::B => (),
924 }
925}
926"#,
927 );
928 }
929
930 #[test]
931 fn never() {
932 check_diagnostics(
933 r#"
934enum Never {}
935
936fn enum_(never: Never) {
937 match never {}
938}
939fn enum_ref(never: &Never) {
940 match never {}
941 //^^^^^ Missing match arm
942}
943fn bang(never: !) {
944 match never {}
945}
946"#,
947 );
948 }
949
950 #[test]
951 fn unknown_type() {
952 check_diagnostics(
953 r#"
954enum Option<T> { Some(T), None }
955
956fn main() {
957 // `Never` is deliberately not defined so that it's an uninferred type.
958 match Option::<Never>::None {
959 None => (),
960 Some(never) => match never {},
961 // ^^^^^^^^^^^ Internal: match check bailed out
962 }
963 match Option::<Never>::None {
964 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
965 Option::Some(_never) => {},
966 }
967}
968"#,
969 );
970 }
971
972 #[test]
973 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
974 check_diagnostics(
975 r#"
976fn main() {
977 match (false, true, false) {
978 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
979 (false, ..) => (),
980 }
981}"#,
982 );
983 }
984
985 #[test]
986 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
987 check_diagnostics(
988 r#"
989fn main() {
990 match (false, true, false) {
991 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
992 (.., false) => (),
993 }
994}"#,
995 );
996 }
997
998 #[test]
999 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
1000 check_diagnostics(
1001 r#"
1002fn main() {
1003 match (false, true, false) {
1004 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1005 (true, .., false) => (),
1006 }
1007}"#,
1008 );
1009 }
1010
1011 #[test]
1012 fn record_struct() {
1013 check_diagnostics(
1014 r#"struct Foo { a: bool }
1015fn main(f: Foo) {
1016 match f {}
1017 //^ Missing match arm
1018 match f { Foo { a: true } => () }
1019 //^ Missing match arm
1020 match &f { Foo { a: true } => () }
1021 //^^ Missing match arm
1022 match f { Foo { a: _ } => () }
1023 match f {
1024 Foo { a: true } => (),
1025 Foo { a: false } => (),
1026 }
1027 match &f {
1028 Foo { a: true } => (),
1029 Foo { a: false } => (),
1030 }
1031}
1032"#,
1033 );
1034 }
1035
1036 #[test]
1037 fn tuple_struct() {
1038 check_diagnostics(
1039 r#"struct Foo(bool);
1040fn main(f: Foo) {
1041 match f {}
1042 //^ Missing match arm
1043 match f { Foo(true) => () }
1044 //^ Missing match arm
1045 match f {
1046 Foo(true) => (),
1047 Foo(false) => (),
1048 }
1049}
1050"#,
1051 );
1052 }
1053
1054 #[test]
1055 fn unit_struct() {
1056 check_diagnostics(
1057 r#"struct Foo;
1058fn main(f: Foo) {
1059 match f {}
1060 //^ Missing match arm
1061 match f { Foo => () }
1062}
1063"#,
1064 );
1065 }
1066
1067 #[test]
1068 fn record_struct_ellipsis() {
1069 check_diagnostics(
1070 r#"struct Foo { foo: bool, bar: bool }
1071fn main(f: Foo) {
1072 match f { Foo { foo: true, .. } => () }
1073 //^ Missing match arm
1074 match f {
1075 //^ Missing match arm
1076 Foo { foo: true, .. } => (),
1077 Foo { bar: false, .. } => ()
1078 }
1079 match f { Foo { .. } => () }
1080 match f {
1081 Foo { foo: true, .. } => (),
1082 Foo { foo: false, .. } => ()
1083 }
1084}
1085"#,
1086 );
1087 }
1088
1089 #[test]
1090 fn internal_or() {
1091 check_diagnostics(
1092 r#"
1093fn main() {
1094 enum Either { A(bool), B }
1095 match Either::B {
1096 //^^^^^^^^^ Missing match arm
1097 Either::A(true | false) => (),
1098 }
1099}
1100"#,
1101 );
1102 }
1103
1104 #[test]
1105 fn no_panic_at_unimplemented_subpattern_type() {
1106 check_diagnostics(
1107 r#"
1108struct S { a: char}
1109fn main(v: S) {
1110 match v { S{ a } => {} }
1111 match v { S{ a: _x } => {} }
1112 match v { S{ a: 'a' } => {} }
1113 //^^^^^^^^^^^ Internal: match check bailed out
1114 match v { S{..} => {} }
1115 match v { _ => {} }
1116 match v { }
1117 //^ Missing match arm
1118}
1119"#,
1120 );
1121 }
1122
1123 #[test]
1124 fn binding() {
1125 check_diagnostics(
1126 r#"
1127fn main() {
1128 match true {
1129 _x @ true => {}
1130 false => {}
1131 }
1132 match true { _x @ true => {} }
1133 //^^^^ Missing match arm
1134}
1135"#,
1136 );
1137 }
1138
1139 #[test]
1140 fn binding_ref_has_correct_type() {
1141 // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
1142 // If that's not true match checking will panic with "incompatible constructors"
1143 // FIXME: make facilities to test this directly like `tests::check_infer(..)`
1144 check_diagnostics(
1145 r#"
1146enum Foo { A }
1147fn main() {
1148 // FIXME: this should not bail out but current behavior is such as the old algorithm.
1149 // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
1150 match Foo::A {
1151 ref _x => {}
1152 // ^^^^^^ Internal: match check bailed out
1153 Foo::A => {}
1154 }
1155 match (true,) {
1156 (ref _x,) => {}
1157 (true,) => {}
1158 }
1159}
1160"#,
1161 );
1162 }
1163
1164 #[test]
1165 fn enum_non_exhaustive() {
1166 check_diagnostics(
1167 r#"
1168//- /lib.rs crate:lib
1169#[non_exhaustive]
1170pub enum E { A, B }
1171fn _local() {
1172 match E::A { _ => {} }
1173 match E::A {
1174 E::A => {}
1175 E::B => {}
1176 }
1177 match E::A {
1178 E::A | E::B => {}
1179 }
1180}
1181
1182//- /main.rs crate:main deps:lib
1183use lib::E;
1184fn main() {
1185 match E::A { _ => {} }
1186 match E::A {
1187 //^^^^ Missing match arm
1188 E::A => {}
1189 E::B => {}
1190 }
1191 match E::A {
1192 //^^^^ Missing match arm
1193 E::A | E::B => {}
1194 }
1195}
1196"#,
1197 );
1198 }
1199
1200 #[test]
1201 fn match_guard() {
1202 check_diagnostics(
1203 r#"
1204fn main() {
1205 match true {
1206 true if false => {}
1207 true => {}
1208 false => {}
1209 }
1210 match true {
1211 //^^^^ Missing match arm
1212 true if false => {}
1213 false => {}
1214}
1215"#,
1216 );
1217 }
1218
1219 #[test]
1220 fn pattern_type_is_of_substitution() {
1221 cov_mark::check!(match_check_wildcard_expanded_to_substitutions);
1222 check_diagnostics(
1223 r#"
1224struct Foo<T>(T);
1225struct Bar;
1226fn main() {
1227 match Foo(Bar) {
1228 _ | Foo(Bar) => {}
1229 }
1230}
1231"#,
1232 );
1233 }
1234
1235 #[test]
1236 fn record_struct_no_such_field() {
1237 check_diagnostics(
1238 r#"
1239struct Foo { }
1240fn main(f: Foo) {
1241 match f { Foo { bar } => () }
1242 // ^^^^^^^^^^^ Internal: match check bailed out
1243}
1244"#,
1245 );
1246 }
1247
1248 #[test]
1249 fn match_ergonomics_issue_9095() {
1250 check_diagnostics(
1251 r#"
1252enum Foo<T> { A(T) }
1253fn main() {
1254 match &Foo::A(true) {
1255 _ => {}
1256 Foo::A(_) => {}
1257 }
1258}
1259"#,
1260 );
1261 }
1262
1263 mod false_negatives {
1264 //! The implementation of match checking here is a work in progress. As we roll this out, we
1265 //! prefer false negatives to false positives (ideally there would be no false positives). This
1266 //! test module should document known false negatives. Eventually we will have a complete
1267 //! implementation of match checking and this module will be empty.
1268 //!
1269 //! The reasons for documenting known false negatives:
1270 //!
1271 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
1272 //! 2. It ensures the code doesn't panic when handling these cases.
1273 use super::*;
1274
1275 #[test]
1276 fn integers() {
1277 // We don't currently check integer exhaustiveness.
1278 check_diagnostics(
1279 r#"
1280fn main() {
1281 match 5 {
1282 10 => (),
1283 // ^^ Internal: match check bailed out
1284 11..20 => (),
1285 }
1286}
1287"#,
1288 );
1289 }
1290
1291 #[test]
1292 fn reference_patterns_at_top_level() {
1293 check_diagnostics(
1294 r#"
1295fn main() {
1296 match &false {
1297 &true => {}
1298 // ^^^^^ Internal: match check bailed out
1299 }
1300}
1301 "#,
1302 );
1303 }
1304
1305 #[test]
1306 fn reference_patterns_in_fields() {
1307 check_diagnostics(
1308 r#"
1309fn main() {
1310 match (&false,) {
1311 (true,) => {}
1312 // ^^^^^^^ Internal: match check bailed out
1313 }
1314 match (&false,) {
1315 (&true,) => {}
1316 // ^^^^^^^^ Internal: match check bailed out
1317 }
1318}
1319 "#,
1320 );
1321 }
1322 }
1323}
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
index 1f4219b42..222141bd6 100644
--- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -664,7 +664,6 @@ impl Fields {
664 let is_non_exhaustive = 664 let is_non_exhaustive =
665 is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local; 665 is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local;
666 666
667 cov_mark::hit!(match_check_wildcard_expanded_to_substitutions);
668 let field_ty_data = cx.db.field_types(variant_id); 667 let field_ty_data = cx.db.field_types(variant_id);
669 let field_tys = || { 668 let field_tys = || {
670 field_ty_data 669 field_ty_data
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index c3c483425..777f347b8 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -1,8 +1,6 @@
1//! Provides validations for unsafe code. Currently checks if unsafe functions are missing 1//! Provides validations for unsafe code. Currently checks if unsafe functions are missing
2//! unsafe blocks. 2//! unsafe blocks.
3 3
4use std::sync::Arc;
5
6use hir_def::{ 4use hir_def::{
7 body::Body, 5 body::Body,
8 expr::{Expr, ExprId, UnaryOp}, 6 expr::{Expr, ExprId, UnaryOp},
@@ -10,60 +8,32 @@ use hir_def::{
10 DefWithBodyId, 8 DefWithBodyId,
11}; 9};
12 10
13use crate::{ 11use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind};
14 db::HirDatabase, diagnostics::MissingUnsafe, diagnostics_sink::DiagnosticSink, InferenceResult,
15 Interner, TyExt, TyKind,
16};
17 12
18pub(super) struct UnsafeValidator<'a, 'b: 'a> { 13pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
19 owner: DefWithBodyId, 14 let infer = db.infer(def);
20 infer: Arc<InferenceResult>,
21 sink: &'a mut DiagnosticSink<'b>,
22}
23 15
24impl<'a, 'b> UnsafeValidator<'a, 'b> { 16 let is_unsafe = match def {
25 pub(super) fn new( 17 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
26 owner: DefWithBodyId, 18 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
27 infer: Arc<InferenceResult>, 19 };
28 sink: &'a mut DiagnosticSink<'b>, 20 if is_unsafe {
29 ) -> UnsafeValidator<'a, 'b> { 21 return Vec::new();
30 UnsafeValidator { owner, infer, sink }
31 } 22 }
32 23
33 pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { 24 unsafe_expressions(db, &infer, def)
34 let def = self.owner; 25 .into_iter()
35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); 26 .filter(|it| !it.inside_unsafe_block)
36 let is_unsafe = match self.owner { 27 .map(|it| it.expr)
37 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), 28 .collect()
38 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
39 };
40 if is_unsafe
41 || unsafe_expressions
42 .iter()
43 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block)
44 .count()
45 == 0
46 {
47 return;
48 }
49
50 let (_, body_source) = db.body_with_source_map(def);
51 for unsafe_expr in unsafe_expressions {
52 if !unsafe_expr.inside_unsafe_block {
53 if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) {
54 self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value })
55 }
56 }
57 }
58 }
59} 29}
60 30
61pub(crate) struct UnsafeExpr { 31struct UnsafeExpr {
62 pub(crate) expr: ExprId, 32 pub(crate) expr: ExprId,
63 pub(crate) inside_unsafe_block: bool, 33 pub(crate) inside_unsafe_block: bool,
64} 34}
65 35
66pub(crate) fn unsafe_expressions( 36fn unsafe_expressions(
67 db: &dyn HirDatabase, 37 db: &dyn HirDatabase,
68 infer: &InferenceResult, 38 infer: &InferenceResult,
69 def: DefWithBodyId, 39 def: DefWithBodyId,
@@ -126,92 +96,3 @@ fn walk_unsafe(
126 walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); 96 walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
127 }); 97 });
128} 98}
129
130#[cfg(test)]
131mod tests {
132 use crate::diagnostics::tests::check_diagnostics;
133
134 #[test]
135 fn missing_unsafe_diagnostic_with_raw_ptr() {
136 check_diagnostics(
137 r#"
138fn main() {
139 let x = &5 as *const usize;
140 unsafe { let y = *x; }
141 let z = *x;
142} //^^ This operation is unsafe and requires an unsafe function or block
143"#,
144 )
145 }
146
147 #[test]
148 fn missing_unsafe_diagnostic_with_unsafe_call() {
149 check_diagnostics(
150 r#"
151struct HasUnsafe;
152
153impl HasUnsafe {
154 unsafe fn unsafe_fn(&self) {
155 let x = &5 as *const usize;
156 let y = *x;
157 }
158}
159
160unsafe fn unsafe_fn() {
161 let x = &5 as *const usize;
162 let y = *x;
163}
164
165fn main() {
166 unsafe_fn();
167 //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
168 HasUnsafe.unsafe_fn();
169 //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
170 unsafe {
171 unsafe_fn();
172 HasUnsafe.unsafe_fn();
173 }
174}
175"#,
176 );
177 }
178
179 #[test]
180 fn missing_unsafe_diagnostic_with_static_mut() {
181 check_diagnostics(
182 r#"
183struct Ty {
184 a: u8,
185}
186
187static mut STATIC_MUT: Ty = Ty { a: 0 };
188
189fn main() {
190 let x = STATIC_MUT.a;
191 //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
192 unsafe {
193 let x = STATIC_MUT.a;
194 }
195}
196"#,
197 );
198 }
199
200 #[test]
201 fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
202 check_diagnostics(
203 r#"
204extern "rust-intrinsic" {
205 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
206 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
207}
208
209fn main() {
210 let _ = bitreverse(12);
211 let _ = floorf32(12.0);
212 //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
213}
214"#,
215 );
216 }
217}
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 0e9f777da..f023c1fb7 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -35,11 +35,9 @@ use stdx::impl_from;
35use syntax::SmolStr; 35use syntax::SmolStr;
36 36
37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; 37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
38use crate::diagnostics_sink::DiagnosticSink;
39use crate::{ 38use crate::{
40 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, 39 db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy,
41 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution, 40 Goal, Interner, Substitution, TyBuilder, TyExt, TyKind,
42 TyBuilder, TyExt, TyKind,
43}; 41};
44 42
45// This lint has a false positive here. See the link below for details. 43// This lint has a false positive here. See the link below for details.
@@ -111,6 +109,12 @@ pub(crate) struct InferOk {
111pub(crate) struct TypeError; 109pub(crate) struct TypeError;
112pub(crate) type InferResult = Result<InferOk, TypeError>; 110pub(crate) type InferResult = Result<InferOk, TypeError>;
113 111
112#[derive(Debug, PartialEq, Eq, Clone)]
113pub enum InferenceDiagnostic {
114 NoSuchField { expr: ExprId },
115 BreakOutsideOfLoop { expr: ExprId },
116}
117
114/// A mismatch between an expected and an inferred type. 118/// A mismatch between an expected and an inferred type.
115#[derive(Clone, PartialEq, Eq, Debug, Hash)] 119#[derive(Clone, PartialEq, Eq, Debug, Hash)]
116pub struct TypeMismatch { 120pub struct TypeMismatch {
@@ -140,7 +144,7 @@ pub struct InferenceResult {
140 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, 144 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
141 /// For each associated item record what it resolves to 145 /// For each associated item record what it resolves to
142 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, 146 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
143 diagnostics: Vec<InferenceDiagnostic>, 147 pub diagnostics: Vec<InferenceDiagnostic>,
144 pub type_of_expr: ArenaMap<ExprId, Ty>, 148 pub type_of_expr: ArenaMap<ExprId, Ty>,
145 /// For each pattern record the type it resolves to. 149 /// For each pattern record the type it resolves to.
146 /// 150 ///
@@ -191,14 +195,6 @@ impl InferenceResult {
191 _ => None, 195 _ => None,
192 }) 196 })
193 } 197 }
194 pub fn add_diagnostics(
195 &self,
196 db: &dyn HirDatabase,
197 owner: DefWithBodyId,
198 sink: &mut DiagnosticSink,
199 ) {
200 self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
201 }
202} 198}
203 199
204impl Index<ExprId> for InferenceResult { 200impl Index<ExprId> for InferenceResult {
@@ -765,6 +761,38 @@ impl Expectation {
765 Expectation::RValueLikeUnsized(_) | Expectation::None => None, 761 Expectation::RValueLikeUnsized(_) | Expectation::None => None,
766 } 762 }
767 } 763 }
764
765 /// Comment copied from rustc:
766 /// Disregard "castable to" expectations because they
767 /// can lead us astray. Consider for example `if cond
768 /// {22} else {c} as u8` -- if we propagate the
769 /// "castable to u8" constraint to 22, it will pick the
770 /// type 22u8, which is overly constrained (c might not
771 /// be a u8). In effect, the problem is that the
772 /// "castable to" expectation is not the tightest thing
773 /// we can say, so we want to drop it in this case.
774 /// The tightest thing we can say is "must unify with
775 /// else branch". Note that in the case of a "has type"
776 /// constraint, this limitation does not hold.
777 ///
778 /// If the expected type is just a type variable, then don't use
779 /// an expected type. Otherwise, we might write parts of the type
780 /// when checking the 'then' block which are incompatible with the
781 /// 'else' branch.
782 fn adjust_for_branches(&self, table: &mut unify::InferenceTable) -> Expectation {
783 match self {
784 Expectation::HasType(ety) => {
785 let ety = table.resolve_ty_shallow(&ety);
786 if !ety.is_ty_var() {
787 Expectation::HasType(ety)
788 } else {
789 Expectation::None
790 }
791 }
792 Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety.clone()),
793 _ => Expectation::None,
794 }
795 }
768} 796}
769 797
770#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 798#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -804,43 +832,3 @@ impl std::ops::BitOrAssign for Diverges {
804 *self = *self | other; 832 *self = *self | other;
805 } 833 }
806} 834}
807
808mod diagnostics {
809 use hir_def::{expr::ExprId, DefWithBodyId};
810
811 use crate::{
812 db::HirDatabase,
813 diagnostics::{BreakOutsideOfLoop, NoSuchField},
814 diagnostics_sink::DiagnosticSink,
815 };
816
817 #[derive(Debug, PartialEq, Eq, Clone)]
818 pub(super) enum InferenceDiagnostic {
819 NoSuchField { expr: ExprId },
820 BreakOutsideOfLoop { expr: ExprId },
821 }
822
823 impl InferenceDiagnostic {
824 pub(super) fn add_to(
825 &self,
826 db: &dyn HirDatabase,
827 owner: DefWithBodyId,
828 sink: &mut DiagnosticSink,
829 ) {
830 match self {
831 InferenceDiagnostic::NoSuchField { expr } => {
832 let (_, source_map) = db.body_with_source_map(owner);
833 let field = source_map.field_syntax(*expr);
834 sink.push(NoSuchField { file: field.file_id, field: field.value })
835 }
836 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
837 let (_, source_map) = db.body_with_source_map(owner);
838 let ptr = source_map
839 .expr_syntax(*expr)
840 .expect("break outside of loop in synthetic syntax");
841 sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
842 }
843 }
844 }
845 }
846}
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index f73bf43b2..e34f194ff 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -337,10 +337,15 @@ impl<'a> InferenceContext<'a> {
337 Expr::Match { expr, arms } => { 337 Expr::Match { expr, arms } => {
338 let input_ty = self.infer_expr(*expr, &Expectation::none()); 338 let input_ty = self.infer_expr(*expr, &Expectation::none());
339 339
340 let expected = expected.adjust_for_branches(&mut self.table);
341
340 let mut result_ty = if arms.is_empty() { 342 let mut result_ty = if arms.is_empty() {
341 TyKind::Never.intern(&Interner) 343 TyKind::Never.intern(&Interner)
342 } else { 344 } else {
343 self.table.new_type_var() 345 match &expected {
346 Expectation::HasType(ty) => ty.clone(),
347 _ => self.table.new_type_var(),
348 }
344 }; 349 };
345 350
346 let matchee_diverges = self.diverges; 351 let matchee_diverges = self.diverges;
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 50e0d6333..128cae830 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -21,7 +21,6 @@ mod utils;
21mod walk; 21mod walk;
22pub mod db; 22pub mod db;
23pub mod diagnostics; 23pub mod diagnostics;
24pub mod diagnostics_sink;
25pub mod display; 24pub mod display;
26pub mod method_resolution; 25pub mod method_resolution;
27pub mod primitive; 26pub mod primitive;
@@ -50,7 +49,7 @@ use crate::{db::HirDatabase, utils::generics};
50pub use autoderef::autoderef; 49pub use autoderef::autoderef;
51pub use builder::TyBuilder; 50pub use builder::TyBuilder;
52pub use chalk_ext::*; 51pub use chalk_ext::*;
53pub use infer::{could_unify, InferenceResult}; 52pub use infer::{could_unify, InferenceDiagnostic, InferenceResult};
54pub use interner::Interner; 53pub use interner::Interner;
55pub use lower::{ 54pub use lower::{
56 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 55 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 9d726b024..b873585c4 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -9,7 +9,7 @@ mod macros;
9mod display_source_code; 9mod display_source_code;
10mod incremental; 10mod incremental;
11 11
12use std::{env, sync::Arc}; 12use std::{collections::HashMap, env, sync::Arc};
13 13
14use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; 14use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
15use expect_test::Expect; 15use expect_test::Expect;
@@ -83,9 +83,105 @@ fn check_types_impl(ra_fixture: &str, display_source: bool) {
83 checked_one = true; 83 checked_one = true;
84 } 84 }
85 } 85 }
86
86 assert!(checked_one, "no `//^` annotations found"); 87 assert!(checked_one, "no `//^` annotations found");
87} 88}
88 89
90fn check_no_mismatches(ra_fixture: &str) {
91 check_mismatches_impl(ra_fixture, true)
92}
93
94#[allow(unused)]
95fn check_mismatches(ra_fixture: &str) {
96 check_mismatches_impl(ra_fixture, false)
97}
98
99fn check_mismatches_impl(ra_fixture: &str, allow_none: bool) {
100 let _tracing = setup_tracing();
101 let (db, file_id) = TestDB::with_single_file(ra_fixture);
102 let module = db.module_for_file(file_id);
103 let def_map = module.def_map(&db);
104
105 let mut defs: Vec<DefWithBodyId> = Vec::new();
106 visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
107 defs.sort_by_key(|def| match def {
108 DefWithBodyId::FunctionId(it) => {
109 let loc = it.lookup(&db);
110 loc.source(&db).value.syntax().text_range().start()
111 }
112 DefWithBodyId::ConstId(it) => {
113 let loc = it.lookup(&db);
114 loc.source(&db).value.syntax().text_range().start()
115 }
116 DefWithBodyId::StaticId(it) => {
117 let loc = it.lookup(&db);
118 loc.source(&db).value.syntax().text_range().start()
119 }
120 });
121 let mut mismatches = HashMap::new();
122 let mut push_mismatch = |src_ptr: InFile<SyntaxNode>, mismatch: TypeMismatch| {
123 let range = src_ptr.value.text_range();
124 if src_ptr.file_id.call_node(&db).is_some() {
125 panic!("type mismatch in macro expansion");
126 }
127 let file_range = FileRange { file_id: src_ptr.file_id.original_file(&db), range };
128 let actual = format!(
129 "expected {}, got {}",
130 mismatch.expected.display_test(&db),
131 mismatch.actual.display_test(&db)
132 );
133 mismatches.insert(file_range, actual);
134 };
135 for def in defs {
136 let (_body, body_source_map) = db.body_with_source_map(def);
137 let inference_result = db.infer(def);
138 for (pat, mismatch) in inference_result.pat_type_mismatches() {
139 let syntax_ptr = match body_source_map.pat_syntax(pat) {
140 Ok(sp) => {
141 let root = db.parse_or_expand(sp.file_id).unwrap();
142 sp.map(|ptr| {
143 ptr.either(
144 |it| it.to_node(&root).syntax().clone(),
145 |it| it.to_node(&root).syntax().clone(),
146 )
147 })
148 }
149 Err(SyntheticSyntax) => continue,
150 };
151 push_mismatch(syntax_ptr, mismatch.clone());
152 }
153 for (expr, mismatch) in inference_result.expr_type_mismatches() {
154 let node = match body_source_map.expr_syntax(expr) {
155 Ok(sp) => {
156 let root = db.parse_or_expand(sp.file_id).unwrap();
157 sp.map(|ptr| ptr.to_node(&root).syntax().clone())
158 }
159 Err(SyntheticSyntax) => continue,
160 };
161 push_mismatch(node, mismatch.clone());
162 }
163 }
164 let mut checked_one = false;
165 for (file_id, annotations) in db.extract_annotations() {
166 for (range, expected) in annotations {
167 let file_range = FileRange { file_id, range };
168 if let Some(mismatch) = mismatches.remove(&file_range) {
169 assert_eq!(mismatch, expected);
170 } else {
171 assert!(false, "Expected mismatch not encountered: {}\n", expected);
172 }
173 checked_one = true;
174 }
175 }
176 let mut buf = String::new();
177 for (range, mismatch) in mismatches {
178 format_to!(buf, "{:?}: {}\n", range.range, mismatch,);
179 }
180 assert!(buf.is_empty(), "Unexpected type mismatches:\n{}", buf);
181
182 assert!(checked_one || allow_none, "no `//^` annotations found");
183}
184
89fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { 185fn type_at_range(db: &TestDB, pos: FileRange) -> Ty {
90 let file = db.parse(pos.file_id).ok().unwrap(); 186 let file = db.parse(pos.file_id).ok().unwrap();
91 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap(); 187 let expr = algo::find_node_at_range::<ast::Expr>(file.syntax(), pos.range).unwrap();
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 6dac7e103..71047703d 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches, check_types}; 3use super::{check_infer, check_infer_with_mismatches, check_no_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_block_expr_type_mismatch() { 6fn infer_block_expr_type_mismatch() {
@@ -963,7 +963,7 @@ fn test() -> i32 {
963 963
964#[test] 964#[test]
965fn panic_macro() { 965fn panic_macro() {
966 check_infer_with_mismatches( 966 check_no_mismatches(
967 r#" 967 r#"
968mod panic { 968mod panic {
969 #[macro_export] 969 #[macro_export]
@@ -991,15 +991,34 @@ fn main() {
991 panic!() 991 panic!()
992} 992}
993 "#, 993 "#,
994 expect![[r#" 994 );
995 174..185 '{ loop {} }': ! 995}
996 176..183 'loop {}': ! 996
997 181..183 '{}': () 997#[test]
998 !0..24 '$crate...:panic': fn panic() -> ! 998fn coerce_unsize_expected_type() {
999 !0..26 '$crate...anic()': ! 999 check_no_mismatches(
1000 !0..26 '$crate...anic()': ! 1000 r#"
1001 !0..28 '$crate...015!()': ! 1001#[lang = "sized"]
1002 454..470 '{ ...c!() }': () 1002pub trait Sized {}
1003 "#]], 1003#[lang = "unsize"]
1004pub trait Unsize<T> {}
1005#[lang = "coerce_unsized"]
1006pub trait CoerceUnsized<T> {}
1007
1008impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
1009
1010fn main() {
1011 let foo: &[u32] = &[1, 2];
1012 let foo: &[u32] = match true {
1013 true => &[1, 2],
1014 false => &[1, 2, 3],
1015 };
1016 let foo: &[u32] = if true {
1017 &[1, 2]
1018 } else {
1019 &[1, 2, 3]
1020 };
1021}
1022 "#,
1004 ); 1023 );
1005} 1024}
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 7d00cee9b..aa513c56d 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches, check_types}; 3use super::{check_infer, check_infer_with_mismatches, check_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_pattern() { 6fn infer_pattern() {
@@ -518,47 +518,24 @@ fn infer_generics_in_patterns() {
518 518
519#[test] 519#[test]
520fn infer_const_pattern() { 520fn infer_const_pattern() {
521 check_infer_with_mismatches( 521 check_mismatches(
522 r#" 522 r#"
523 enum Option<T> { None } 523enum Option<T> { None }
524 use Option::None; 524use Option::None;
525 struct Foo; 525struct Foo;
526 const Bar: usize = 1; 526const Bar: usize = 1;
527 527
528 fn test() { 528fn test() {
529 let a: Option<u32> = None; 529 let a: Option<u32> = None;
530 let b: Option<i64> = match a { 530 let b: Option<i64> = match a {
531 None => None, 531 None => None,
532 }; 532 };
533 let _: () = match () { Foo => Foo }; // Expected mismatch 533 let _: () = match () { Foo => () };
534 let _: () = match () { Bar => Bar }; // Expected mismatch 534 // ^^^ expected (), got Foo
535 } 535 let _: () = match () { Bar => () };
536 // ^^^ expected (), got usize
537}
536 "#, 538 "#,
537 expect![[r#"
538 73..74 '1': usize
539 87..309 '{ ...atch }': ()
540 97..98 'a': Option<u32>
541 114..118 'None': Option<u32>
542 128..129 'b': Option<i64>
543 145..182 'match ... }': Option<i64>
544 151..152 'a': Option<u32>
545 163..167 'None': Option<u32>
546 171..175 'None': Option<i64>
547 192..193 '_': ()
548 200..223 'match ... Foo }': Foo
549 206..208 '()': ()
550 211..214 'Foo': Foo
551 218..221 'Foo': Foo
552 254..255 '_': ()
553 262..285 'match ... Bar }': usize
554 268..270 '()': ()
555 273..276 'Bar': usize
556 280..283 'Bar': usize
557 200..223: expected (), got Foo
558 211..214: expected (), got Foo
559 262..285: expected (), got usize
560 273..276: expected (), got usize
561 "#]],
562 ); 539 );
563} 540}
564 541
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 88f3d09d3..f12928225 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14either = "1.5.3" 14either = "1.5.3"
15indexmap = "1.4.0" 15indexmap = "1.4.0"
16itertools = "0.10.0" 16itertools = "0.10.0"
@@ -39,4 +39,3 @@ hir = { path = "../hir", version = "0.0.0" }
39[dev-dependencies] 39[dev-dependencies]
40test_utils = { path = "../test_utils" } 40test_utils = { path = "../test_utils" }
41expect-test = "1.1" 41expect-test = "1.1"
42cov-mark = "1.1.0"
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index d5c954b8b..4193aabf5 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -204,8 +204,9 @@ pub(crate) fn diagnostics(
204 ); 204 );
205 }); 205 });
206 206
207 let internal_diagnostics = cfg!(test);
207 match sema.to_module_def(file_id) { 208 match sema.to_module_def(file_id) {
208 Some(m) => m.diagnostics(db, &mut sink), 209 Some(m) => m.diagnostics(db, &mut sink, internal_diagnostics),
209 None => { 210 None => {
210 sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(&parse.tree().syntax()) }); 211 sink.push(UnlinkedFile { file_id, node: SyntaxNodePtr::new(&parse.tree().syntax()) });
211 } 212 }
@@ -305,6 +306,7 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
305#[cfg(test)] 306#[cfg(test)]
306mod tests { 307mod tests {
307 use expect_test::Expect; 308 use expect_test::Expect;
309 use hir::diagnostics::DiagnosticCode;
308 use ide_assists::AssistResolveStrategy; 310 use ide_assists::AssistResolveStrategy;
309 use stdx::trim_indent; 311 use stdx::trim_indent;
310 use test_utils::{assert_eq_text, extract_annotations}; 312 use test_utils::{assert_eq_text, extract_annotations};
@@ -410,7 +412,12 @@ mod tests {
410 .unwrap(); 412 .unwrap();
411 413
412 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); 414 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
413 let actual = diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>(); 415 let mut actual = diagnostics
416 .into_iter()
417 .filter(|d| d.code != Some(DiagnosticCode("inactive-code")))
418 .map(|d| (d.range, d.message))
419 .collect::<Vec<_>>();
420 actual.sort_by_key(|(range, _)| range.start());
414 assert_eq!(expected, actual); 421 assert_eq!(expected, actual);
415 } 422 }
416 423
@@ -719,4 +726,1878 @@ mod foo;
719"#, 726"#,
720 ); 727 );
721 } 728 }
729
730 #[test]
731 fn break_outside_of_loop() {
732 check_diagnostics(
733 r#"
734fn foo() { break; }
735 //^^^^^ break outside of loop
736"#,
737 );
738 }
739
740 #[test]
741 fn no_such_field_diagnostics() {
742 check_diagnostics(
743 r#"
744struct S { foo: i32, bar: () }
745impl S {
746 fn new() -> S {
747 S {
748 //^ Missing structure fields:
749 //| - bar
750 foo: 92,
751 baz: 62,
752 //^^^^^^^ no such field
753 }
754 }
755}
756"#,
757 );
758 }
759 #[test]
760 fn no_such_field_with_feature_flag_diagnostics() {
761 check_diagnostics(
762 r#"
763//- /lib.rs crate:foo cfg:feature=foo
764struct MyStruct {
765 my_val: usize,
766 #[cfg(feature = "foo")]
767 bar: bool,
768}
769
770impl MyStruct {
771 #[cfg(feature = "foo")]
772 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
773 Self { my_val, bar }
774 }
775 #[cfg(not(feature = "foo"))]
776 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
777 Self { my_val }
778 }
779}
780"#,
781 );
782 }
783
784 #[test]
785 fn no_such_field_enum_with_feature_flag_diagnostics() {
786 check_diagnostics(
787 r#"
788//- /lib.rs crate:foo cfg:feature=foo
789enum Foo {
790 #[cfg(not(feature = "foo"))]
791 Buz,
792 #[cfg(feature = "foo")]
793 Bar,
794 Baz
795}
796
797fn test_fn(f: Foo) {
798 match f {
799 Foo::Bar => {},
800 Foo::Baz => {},
801 }
802}
803"#,
804 );
805 }
806
807 #[test]
808 fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
809 check_diagnostics(
810 r#"
811//- /lib.rs crate:foo cfg:feature=foo
812struct S {
813 #[cfg(feature = "foo")]
814 foo: u32,
815 #[cfg(not(feature = "foo"))]
816 bar: u32,
817}
818
819impl S {
820 #[cfg(feature = "foo")]
821 fn new(foo: u32) -> Self {
822 Self { foo }
823 }
824 #[cfg(not(feature = "foo"))]
825 fn new(bar: u32) -> Self {
826 Self { bar }
827 }
828 fn new2(bar: u32) -> Self {
829 #[cfg(feature = "foo")]
830 { Self { foo: bar } }
831 #[cfg(not(feature = "foo"))]
832 { Self { bar } }
833 }
834 fn new2(val: u32) -> Self {
835 Self {
836 #[cfg(feature = "foo")]
837 foo: val,
838 #[cfg(not(feature = "foo"))]
839 bar: val,
840 }
841 }
842}
843"#,
844 );
845 }
846
847 #[test]
848 fn no_such_field_with_type_macro() {
849 check_diagnostics(
850 r#"
851macro_rules! Type { () => { u32 }; }
852struct Foo { bar: Type![] }
853
854impl Foo {
855 fn new() -> Self {
856 Foo { bar: 0 }
857 }
858}
859"#,
860 );
861 }
862
863 #[test]
864 fn missing_unsafe_diagnostic_with_raw_ptr() {
865 check_diagnostics(
866 r#"
867fn main() {
868 let x = &5 as *const usize;
869 unsafe { let y = *x; }
870 let z = *x;
871} //^^ This operation is unsafe and requires an unsafe function or block
872"#,
873 )
874 }
875
876 #[test]
877 fn missing_unsafe_diagnostic_with_unsafe_call() {
878 check_diagnostics(
879 r#"
880struct HasUnsafe;
881
882impl HasUnsafe {
883 unsafe fn unsafe_fn(&self) {
884 let x = &5 as *const usize;
885 let y = *x;
886 }
887}
888
889unsafe fn unsafe_fn() {
890 let x = &5 as *const usize;
891 let y = *x;
892}
893
894fn main() {
895 unsafe_fn();
896 //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
897 HasUnsafe.unsafe_fn();
898 //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
899 unsafe {
900 unsafe_fn();
901 HasUnsafe.unsafe_fn();
902 }
903}
904"#,
905 );
906 }
907
908 #[test]
909 fn missing_unsafe_diagnostic_with_static_mut() {
910 check_diagnostics(
911 r#"
912struct Ty {
913 a: u8,
914}
915
916static mut STATIC_MUT: Ty = Ty { a: 0 };
917
918fn main() {
919 let x = STATIC_MUT.a;
920 //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
921 unsafe {
922 let x = STATIC_MUT.a;
923 }
924}
925"#,
926 );
927 }
928
929 #[test]
930 fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
931 check_diagnostics(
932 r#"
933extern "rust-intrinsic" {
934 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
935 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
936}
937
938fn main() {
939 let _ = bitreverse(12);
940 let _ = floorf32(12.0);
941 //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
942}
943"#,
944 );
945 }
946
947 // Register the required standard library types to make the tests work
948 fn add_filter_map_with_find_next_boilerplate(body: &str) -> String {
949 let prefix = r#"
950 //- /main.rs crate:main deps:core
951 use core::iter::Iterator;
952 use core::option::Option::{self, Some, None};
953 "#;
954 let suffix = r#"
955 //- /core/lib.rs crate:core
956 pub mod option {
957 pub enum Option<T> { Some(T), None }
958 }
959 pub mod iter {
960 pub trait Iterator {
961 type Item;
962 fn filter_map<B, F>(self, f: F) -> FilterMap where F: FnMut(Self::Item) -> Option<B> { FilterMap }
963 fn next(&mut self) -> Option<Self::Item>;
964 }
965 pub struct FilterMap {}
966 impl Iterator for FilterMap {
967 type Item = i32;
968 fn next(&mut self) -> i32 { 7 }
969 }
970 }
971 "#;
972 format!("{}{}{}", prefix, body, suffix)
973 }
974
975 #[test]
976 fn replace_filter_map_next_with_find_map2() {
977 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
978 r#"
979 fn foo() {
980 let m = [1, 2, 3].iter().filter_map(|x| if *x == 2 { Some (4) } else { None }).next();
981 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace filter_map(..).next() with find_map(..)
982 }
983 "#,
984 ));
985 }
986
987 #[test]
988 fn replace_filter_map_next_with_find_map_no_diagnostic_without_next() {
989 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
990 r#"
991 fn foo() {
992 let m = [1, 2, 3]
993 .iter()
994 .filter_map(|x| if *x == 2 { Some (4) } else { None })
995 .len();
996 }
997 "#,
998 ));
999 }
1000
1001 #[test]
1002 fn replace_filter_map_next_with_find_map_no_diagnostic_with_intervening_methods() {
1003 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
1004 r#"
1005 fn foo() {
1006 let m = [1, 2, 3]
1007 .iter()
1008 .filter_map(|x| if *x == 2 { Some (4) } else { None })
1009 .map(|x| x + 2)
1010 .len();
1011 }
1012 "#,
1013 ));
1014 }
1015
1016 #[test]
1017 fn replace_filter_map_next_with_find_map_no_diagnostic_if_not_in_chain() {
1018 check_diagnostics(&add_filter_map_with_find_next_boilerplate(
1019 r#"
1020 fn foo() {
1021 let m = [1, 2, 3]
1022 .iter()
1023 .filter_map(|x| if *x == 2 { Some (4) } else { None });
1024 let n = m.next();
1025 }
1026 "#,
1027 ));
1028 }
1029
1030 #[test]
1031 fn missing_record_pat_field_diagnostic() {
1032 check_diagnostics(
1033 r#"
1034struct S { foo: i32, bar: () }
1035fn baz(s: S) {
1036 let S { foo: _ } = s;
1037 //^ Missing structure fields:
1038 //| - bar
1039}
1040"#,
1041 );
1042 }
1043
1044 #[test]
1045 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
1046 check_diagnostics(
1047 r"
1048struct S { foo: i32, bar: () }
1049fn baz(s: S) -> i32 {
1050 match s {
1051 S { foo, .. } => foo,
1052 }
1053}
1054",
1055 )
1056 }
1057
1058 #[test]
1059 fn missing_record_pat_field_box() {
1060 check_diagnostics(
1061 r"
1062struct S { s: Box<u32> }
1063fn x(a: S) {
1064 let S { box s } = a;
1065}
1066",
1067 )
1068 }
1069
1070 #[test]
1071 fn missing_record_pat_field_ref() {
1072 check_diagnostics(
1073 r"
1074struct S { s: u32 }
1075fn x(a: S) {
1076 let S { ref s } = a;
1077}
1078",
1079 )
1080 }
1081
1082 #[test]
1083 fn simple_free_fn_zero() {
1084 check_diagnostics(
1085 r#"
1086fn zero() {}
1087fn f() { zero(1); }
1088 //^^^^^^^ Expected 0 arguments, found 1
1089"#,
1090 );
1091
1092 check_diagnostics(
1093 r#"
1094fn zero() {}
1095fn f() { zero(); }
1096"#,
1097 );
1098 }
1099
1100 #[test]
1101 fn simple_free_fn_one() {
1102 check_diagnostics(
1103 r#"
1104fn one(arg: u8) {}
1105fn f() { one(); }
1106 //^^^^^ Expected 1 argument, found 0
1107"#,
1108 );
1109
1110 check_diagnostics(
1111 r#"
1112fn one(arg: u8) {}
1113fn f() { one(1); }
1114"#,
1115 );
1116 }
1117
1118 #[test]
1119 fn method_as_fn() {
1120 check_diagnostics(
1121 r#"
1122struct S;
1123impl S { fn method(&self) {} }
1124
1125fn f() {
1126 S::method();
1127} //^^^^^^^^^^^ Expected 1 argument, found 0
1128"#,
1129 );
1130
1131 check_diagnostics(
1132 r#"
1133struct S;
1134impl S { fn method(&self) {} }
1135
1136fn f() {
1137 S::method(&S);
1138 S.method();
1139}
1140"#,
1141 );
1142 }
1143
1144 #[test]
1145 fn method_with_arg() {
1146 check_diagnostics(
1147 r#"
1148struct S;
1149impl S { fn method(&self, arg: u8) {} }
1150
1151 fn f() {
1152 S.method();
1153 } //^^^^^^^^^^ Expected 1 argument, found 0
1154 "#,
1155 );
1156
1157 check_diagnostics(
1158 r#"
1159struct S;
1160impl S { fn method(&self, arg: u8) {} }
1161
1162fn f() {
1163 S::method(&S, 0);
1164 S.method(1);
1165}
1166"#,
1167 );
1168 }
1169
1170 #[test]
1171 fn method_unknown_receiver() {
1172 // note: this is incorrect code, so there might be errors on this in the
1173 // future, but we shouldn't emit an argument count diagnostic here
1174 check_diagnostics(
1175 r#"
1176trait Foo { fn method(&self, arg: usize) {} }
1177
1178fn f() {
1179 let x;
1180 x.method();
1181}
1182"#,
1183 );
1184 }
1185
1186 #[test]
1187 fn tuple_struct() {
1188 check_diagnostics(
1189 r#"
1190struct Tup(u8, u16);
1191fn f() {
1192 Tup(0);
1193} //^^^^^^ Expected 2 arguments, found 1
1194"#,
1195 )
1196 }
1197
1198 #[test]
1199 fn enum_variant() {
1200 check_diagnostics(
1201 r#"
1202enum En { Variant(u8, u16), }
1203fn f() {
1204 En::Variant(0);
1205} //^^^^^^^^^^^^^^ Expected 2 arguments, found 1
1206"#,
1207 )
1208 }
1209
1210 #[test]
1211 fn enum_variant_type_macro() {
1212 check_diagnostics(
1213 r#"
1214macro_rules! Type {
1215 () => { u32 };
1216}
1217enum Foo {
1218 Bar(Type![])
1219}
1220impl Foo {
1221 fn new() {
1222 Foo::Bar(0);
1223 Foo::Bar(0, 1);
1224 //^^^^^^^^^^^^^^ Expected 1 argument, found 2
1225 Foo::Bar();
1226 //^^^^^^^^^^ Expected 1 argument, found 0
1227 }
1228}
1229 "#,
1230 );
1231 }
1232
1233 #[test]
1234 fn varargs() {
1235 check_diagnostics(
1236 r#"
1237extern "C" {
1238 fn fixed(fixed: u8);
1239 fn varargs(fixed: u8, ...);
1240 fn varargs2(...);
1241}
1242
1243fn f() {
1244 unsafe {
1245 fixed(0);
1246 fixed(0, 1);
1247 //^^^^^^^^^^^ Expected 1 argument, found 2
1248 varargs(0);
1249 varargs(0, 1);
1250 varargs2();
1251 varargs2(0);
1252 varargs2(0, 1);
1253 }
1254}
1255 "#,
1256 )
1257 }
1258
1259 #[test]
1260 fn arg_count_lambda() {
1261 check_diagnostics(
1262 r#"
1263fn main() {
1264 let f = |()| ();
1265 f();
1266 //^^^ Expected 1 argument, found 0
1267 f(());
1268 f((), ());
1269 //^^^^^^^^^ Expected 1 argument, found 2
1270}
1271"#,
1272 )
1273 }
1274
1275 #[test]
1276 fn cfgd_out_call_arguments() {
1277 check_diagnostics(
1278 r#"
1279struct C(#[cfg(FALSE)] ());
1280impl C {
1281 fn new() -> Self {
1282 Self(
1283 #[cfg(FALSE)]
1284 (),
1285 )
1286 }
1287
1288 fn method(&self) {}
1289}
1290
1291fn main() {
1292 C::new().method(#[cfg(FALSE)] 0);
1293}
1294 "#,
1295 );
1296 }
1297
1298 #[test]
1299 fn cfgd_out_fn_params() {
1300 check_diagnostics(
1301 r#"
1302fn foo(#[cfg(NEVER)] x: ()) {}
1303
1304struct S;
1305
1306impl S {
1307 fn method(#[cfg(NEVER)] self) {}
1308 fn method2(#[cfg(NEVER)] self, arg: u8) {}
1309 fn method3(self, #[cfg(NEVER)] arg: u8) {}
1310}
1311
1312extern "C" {
1313 fn fixed(fixed: u8, #[cfg(NEVER)] ...);
1314 fn varargs(#[cfg(not(NEVER))] ...);
1315}
1316
1317fn main() {
1318 foo();
1319 S::method();
1320 S::method2(0);
1321 S::method3(S);
1322 S.method3();
1323 unsafe {
1324 fixed(0);
1325 varargs(1, 2, 3);
1326 }
1327}
1328 "#,
1329 )
1330 }
1331
1332 #[test]
1333 fn missing_semicolon() {
1334 check_diagnostics(
1335 r#"
1336 fn test() -> i32 { 123; }
1337 //^^^ Remove this semicolon
1338 "#,
1339 );
1340 }
1341
1342 #[test]
1343 fn import_extern_crate_clash_with_inner_item() {
1344 // This is more of a resolver test, but doesn't really work with the hir_def testsuite.
1345
1346 check_diagnostics(
1347 r#"
1348//- /lib.rs crate:lib deps:jwt
1349mod permissions;
1350
1351use permissions::jwt;
1352
1353fn f() {
1354 fn inner() {}
1355 jwt::Claims {}; // should resolve to the local one with 0 fields, and not get a diagnostic
1356}
1357
1358//- /permissions.rs
1359pub mod jwt {
1360 pub struct Claims {}
1361}
1362
1363//- /jwt/lib.rs crate:jwt
1364pub struct Claims {
1365 field: u8,
1366}
1367 "#,
1368 );
1369 }
1370}
1371
1372#[cfg(test)]
1373pub(super) mod match_check_tests {
1374 use crate::diagnostics::tests::check_diagnostics;
1375
1376 #[test]
1377 fn empty_tuple() {
1378 check_diagnostics(
1379 r#"
1380fn main() {
1381 match () { }
1382 //^^ Missing match arm
1383 match (()) { }
1384 //^^^^ Missing match arm
1385
1386 match () { _ => (), }
1387 match () { () => (), }
1388 match (()) { (()) => (), }
1389}
1390"#,
1391 );
1392 }
1393
1394 #[test]
1395 fn tuple_of_two_empty_tuple() {
1396 check_diagnostics(
1397 r#"
1398fn main() {
1399 match ((), ()) { }
1400 //^^^^^^^^ Missing match arm
1401
1402 match ((), ()) { ((), ()) => (), }
1403}
1404"#,
1405 );
1406 }
1407
1408 #[test]
1409 fn boolean() {
1410 check_diagnostics(
1411 r#"
1412fn test_main() {
1413 match false { }
1414 //^^^^^ Missing match arm
1415 match false { true => (), }
1416 //^^^^^ Missing match arm
1417 match (false, true) {}
1418 //^^^^^^^^^^^^^ Missing match arm
1419 match (false, true) { (true, true) => (), }
1420 //^^^^^^^^^^^^^ Missing match arm
1421 match (false, true) {
1422 //^^^^^^^^^^^^^ Missing match arm
1423 (false, true) => (),
1424 (false, false) => (),
1425 (true, false) => (),
1426 }
1427 match (false, true) { (true, _x) => (), }
1428 //^^^^^^^^^^^^^ Missing match arm
1429
1430 match false { true => (), false => (), }
1431 match (false, true) {
1432 (false, _) => (),
1433 (true, false) => (),
1434 (_, true) => (),
1435 }
1436 match (false, true) {
1437 (true, true) => (),
1438 (true, false) => (),
1439 (false, true) => (),
1440 (false, false) => (),
1441 }
1442 match (false, true) {
1443 (true, _x) => (),
1444 (false, true) => (),
1445 (false, false) => (),
1446 }
1447 match (false, true, false) {
1448 (false, ..) => (),
1449 (true, ..) => (),
1450 }
1451 match (false, true, false) {
1452 (.., false) => (),
1453 (.., true) => (),
1454 }
1455 match (false, true, false) { (..) => (), }
1456}
1457"#,
1458 );
1459 }
1460
1461 #[test]
1462 fn tuple_of_tuple_and_bools() {
1463 check_diagnostics(
1464 r#"
1465fn main() {
1466 match (false, ((), false)) {}
1467 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1468 match (false, ((), false)) { (true, ((), true)) => (), }
1469 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1470 match (false, ((), false)) { (true, _) => (), }
1471 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1472
1473 match (false, ((), false)) {
1474 (true, ((), true)) => (),
1475 (true, ((), false)) => (),
1476 (false, ((), true)) => (),
1477 (false, ((), false)) => (),
1478 }
1479 match (false, ((), false)) {
1480 (true, ((), true)) => (),
1481 (true, ((), false)) => (),
1482 (false, _) => (),
1483 }
1484}
1485"#,
1486 );
1487 }
1488
1489 #[test]
1490 fn enums() {
1491 check_diagnostics(
1492 r#"
1493enum Either { A, B, }
1494
1495fn main() {
1496 match Either::A { }
1497 //^^^^^^^^^ Missing match arm
1498 match Either::B { Either::A => (), }
1499 //^^^^^^^^^ Missing match arm
1500
1501 match &Either::B {
1502 //^^^^^^^^^^ Missing match arm
1503 Either::A => (),
1504 }
1505
1506 match Either::B {
1507 Either::A => (), Either::B => (),
1508 }
1509 match &Either::B {
1510 Either::A => (), Either::B => (),
1511 }
1512}
1513"#,
1514 );
1515 }
1516
1517 #[test]
1518 fn enum_containing_bool() {
1519 check_diagnostics(
1520 r#"
1521enum Either { A(bool), B }
1522
1523fn main() {
1524 match Either::B { }
1525 //^^^^^^^^^ Missing match arm
1526 match Either::B {
1527 //^^^^^^^^^ Missing match arm
1528 Either::A(true) => (), Either::B => ()
1529 }
1530
1531 match Either::B {
1532 Either::A(true) => (),
1533 Either::A(false) => (),
1534 Either::B => (),
1535 }
1536 match Either::B {
1537 Either::B => (),
1538 _ => (),
1539 }
1540 match Either::B {
1541 Either::A(_) => (),
1542 Either::B => (),
1543 }
1544
1545}
1546 "#,
1547 );
1548 }
1549
1550 #[test]
1551 fn enum_different_sizes() {
1552 check_diagnostics(
1553 r#"
1554enum Either { A(bool), B(bool, bool) }
1555
1556fn main() {
1557 match Either::A(false) {
1558 //^^^^^^^^^^^^^^^^ Missing match arm
1559 Either::A(_) => (),
1560 Either::B(false, _) => (),
1561 }
1562
1563 match Either::A(false) {
1564 Either::A(_) => (),
1565 Either::B(true, _) => (),
1566 Either::B(false, _) => (),
1567 }
1568 match Either::A(false) {
1569 Either::A(true) | Either::A(false) => (),
1570 Either::B(true, _) => (),
1571 Either::B(false, _) => (),
1572 }
1573}
1574"#,
1575 );
1576 }
1577
1578 #[test]
1579 fn tuple_of_enum_no_diagnostic() {
1580 check_diagnostics(
1581 r#"
1582enum Either { A(bool), B(bool, bool) }
1583enum Either2 { C, D }
1584
1585fn main() {
1586 match (Either::A(false), Either2::C) {
1587 (Either::A(true), _) | (Either::A(false), _) => (),
1588 (Either::B(true, _), Either2::C) => (),
1589 (Either::B(false, _), Either2::C) => (),
1590 (Either::B(_, _), Either2::D) => (),
1591 }
1592}
1593"#,
1594 );
1595 }
1596
1597 #[test]
1598 fn or_pattern_no_diagnostic() {
1599 check_diagnostics(
1600 r#"
1601enum Either {A, B}
1602
1603fn main() {
1604 match (Either::A, Either::B) {
1605 (Either::A | Either::B, _) => (),
1606 }
1607}"#,
1608 )
1609 }
1610
1611 #[test]
1612 fn mismatched_types() {
1613 // Match statements with arms that don't match the
1614 // expression pattern do not fire this diagnostic.
1615 check_diagnostics(
1616 r#"
1617enum Either { A, B }
1618enum Either2 { C, D }
1619
1620fn main() {
1621 match Either::A {
1622 Either2::C => (),
1623 // ^^^^^^^^^^ Internal: match check bailed out
1624 Either2::D => (),
1625 }
1626 match (true, false) {
1627 (true, false, true) => (),
1628 // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out
1629 (true) => (),
1630 }
1631 match (true, false) { (true,) => {} }
1632 // ^^^^^^^ Internal: match check bailed out
1633 match (0) { () => () }
1634 // ^^ Internal: match check bailed out
1635 match Unresolved::Bar { Unresolved::Baz => () }
1636}
1637 "#,
1638 );
1639 }
1640
1641 #[test]
1642 fn mismatched_types_in_or_patterns() {
1643 check_diagnostics(
1644 r#"
1645fn main() {
1646 match false { true | () => {} }
1647 // ^^^^^^^^^ Internal: match check bailed out
1648 match (false,) { (true | (),) => {} }
1649 // ^^^^^^^^^^^^ Internal: match check bailed out
1650}
1651"#,
1652 );
1653 }
1654
1655 #[test]
1656 fn malformed_match_arm_tuple_enum_missing_pattern() {
1657 // We are testing to be sure we don't panic here when the match
1658 // arm `Either::B` is missing its pattern.
1659 check_diagnostics(
1660 r#"
1661enum Either { A, B(u32) }
1662
1663fn main() {
1664 match Either::A {
1665 Either::A => (),
1666 Either::B() => (),
1667 }
1668}
1669"#,
1670 );
1671 }
1672
1673 #[test]
1674 fn malformed_match_arm_extra_fields() {
1675 check_diagnostics(
1676 r#"
1677enum A { B(isize, isize), C }
1678fn main() {
1679 match A::B(1, 2) {
1680 A::B(_, _, _) => (),
1681 // ^^^^^^^^^^^^^ Internal: match check bailed out
1682 }
1683 match A::B(1, 2) {
1684 A::C(_) => (),
1685 // ^^^^^^^ Internal: match check bailed out
1686 }
1687}
1688"#,
1689 );
1690 }
1691
1692 #[test]
1693 fn expr_diverges() {
1694 check_diagnostics(
1695 r#"
1696enum Either { A, B }
1697
1698fn main() {
1699 match loop {} {
1700 Either::A => (),
1701 // ^^^^^^^^^ Internal: match check bailed out
1702 Either::B => (),
1703 }
1704 match loop {} {
1705 Either::A => (),
1706 // ^^^^^^^^^ Internal: match check bailed out
1707 }
1708 match loop { break Foo::A } {
1709 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1710 Either::A => (),
1711 }
1712 match loop { break Foo::A } {
1713 Either::A => (),
1714 Either::B => (),
1715 }
1716}
1717"#,
1718 );
1719 }
1720
1721 #[test]
1722 fn expr_partially_diverges() {
1723 check_diagnostics(
1724 r#"
1725enum Either<T> { A(T), B }
1726
1727fn foo() -> Either<!> { Either::B }
1728fn main() -> u32 {
1729 match foo() {
1730 Either::A(val) => val,
1731 Either::B => 0,
1732 }
1733}
1734"#,
1735 );
1736 }
1737
1738 #[test]
1739 fn enum_record() {
1740 check_diagnostics(
1741 r#"
1742enum Either { A { foo: bool }, B }
1743
1744fn main() {
1745 let a = Either::A { foo: true };
1746 match a { }
1747 //^ Missing match arm
1748 match a { Either::A { foo: true } => () }
1749 //^ Missing match arm
1750 match a {
1751 Either::A { } => (),
1752 //^^^^^^^^^ Missing structure fields:
1753 // | - foo
1754 Either::B => (),
1755 }
1756 match a {
1757 //^ Missing match arm
1758 Either::A { } => (),
1759 } //^^^^^^^^^ Missing structure fields:
1760 // | - foo
1761
1762 match a {
1763 Either::A { foo: true } => (),
1764 Either::A { foo: false } => (),
1765 Either::B => (),
1766 }
1767 match a {
1768 Either::A { foo: _ } => (),
1769 Either::B => (),
1770 }
1771}
1772"#,
1773 );
1774 }
1775
1776 #[test]
1777 fn enum_record_fields_out_of_order() {
1778 check_diagnostics(
1779 r#"
1780enum Either {
1781 A { foo: bool, bar: () },
1782 B,
1783}
1784
1785fn main() {
1786 let a = Either::A { foo: true, bar: () };
1787 match a {
1788 //^ Missing match arm
1789 Either::A { bar: (), foo: false } => (),
1790 Either::A { foo: true, bar: () } => (),
1791 }
1792
1793 match a {
1794 Either::A { bar: (), foo: false } => (),
1795 Either::A { foo: true, bar: () } => (),
1796 Either::B => (),
1797 }
1798}
1799"#,
1800 );
1801 }
1802
1803 #[test]
1804 fn enum_record_ellipsis() {
1805 check_diagnostics(
1806 r#"
1807enum Either {
1808 A { foo: bool, bar: bool },
1809 B,
1810}
1811
1812fn main() {
1813 let a = Either::B;
1814 match a {
1815 //^ Missing match arm
1816 Either::A { foo: true, .. } => (),
1817 Either::B => (),
1818 }
1819 match a {
1820 //^ Missing match arm
1821 Either::A { .. } => (),
1822 }
1823
1824 match a {
1825 Either::A { foo: true, .. } => (),
1826 Either::A { foo: false, .. } => (),
1827 Either::B => (),
1828 }
1829
1830 match a {
1831 Either::A { .. } => (),
1832 Either::B => (),
1833 }
1834}
1835"#,
1836 );
1837 }
1838
1839 #[test]
1840 fn enum_tuple_partial_ellipsis() {
1841 check_diagnostics(
1842 r#"
1843enum Either {
1844 A(bool, bool, bool, bool),
1845 B,
1846}
1847
1848fn main() {
1849 match Either::B {
1850 //^^^^^^^^^ Missing match arm
1851 Either::A(true, .., true) => (),
1852 Either::A(true, .., false) => (),
1853 Either::A(false, .., false) => (),
1854 Either::B => (),
1855 }
1856 match Either::B {
1857 //^^^^^^^^^ Missing match arm
1858 Either::A(true, .., true) => (),
1859 Either::A(true, .., false) => (),
1860 Either::A(.., true) => (),
1861 Either::B => (),
1862 }
1863
1864 match Either::B {
1865 Either::A(true, .., true) => (),
1866 Either::A(true, .., false) => (),
1867 Either::A(false, .., true) => (),
1868 Either::A(false, .., false) => (),
1869 Either::B => (),
1870 }
1871 match Either::B {
1872 Either::A(true, .., true) => (),
1873 Either::A(true, .., false) => (),
1874 Either::A(.., true) => (),
1875 Either::A(.., false) => (),
1876 Either::B => (),
1877 }
1878}
1879"#,
1880 );
1881 }
1882
1883 #[test]
1884 fn never() {
1885 check_diagnostics(
1886 r#"
1887enum Never {}
1888
1889fn enum_(never: Never) {
1890 match never {}
1891}
1892fn enum_ref(never: &Never) {
1893 match never {}
1894 //^^^^^ Missing match arm
1895}
1896fn bang(never: !) {
1897 match never {}
1898}
1899"#,
1900 );
1901 }
1902
1903 #[test]
1904 fn unknown_type() {
1905 check_diagnostics(
1906 r#"
1907enum Option<T> { Some(T), None }
1908
1909fn main() {
1910 // `Never` is deliberately not defined so that it's an uninferred type.
1911 match Option::<Never>::None {
1912 None => (),
1913 Some(never) => match never {},
1914 // ^^^^^^^^^^^ Internal: match check bailed out
1915 }
1916 match Option::<Never>::None {
1917 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
1918 Option::Some(_never) => {},
1919 }
1920}
1921"#,
1922 );
1923 }
1924
1925 #[test]
1926 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
1927 check_diagnostics(
1928 r#"
1929fn main() {
1930 match (false, true, false) {
1931 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1932 (false, ..) => (),
1933 }
1934}"#,
1935 );
1936 }
1937
1938 #[test]
1939 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
1940 check_diagnostics(
1941 r#"
1942fn main() {
1943 match (false, true, false) {
1944 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1945 (.., false) => (),
1946 }
1947}"#,
1948 );
1949 }
1950
1951 #[test]
1952 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
1953 check_diagnostics(
1954 r#"
1955fn main() {
1956 match (false, true, false) {
1957 //^^^^^^^^^^^^^^^^^^^^ Missing match arm
1958 (true, .., false) => (),
1959 }
1960}"#,
1961 );
1962 }
1963
1964 #[test]
1965 fn record_struct() {
1966 check_diagnostics(
1967 r#"struct Foo { a: bool }
1968fn main(f: Foo) {
1969 match f {}
1970 //^ Missing match arm
1971 match f { Foo { a: true } => () }
1972 //^ Missing match arm
1973 match &f { Foo { a: true } => () }
1974 //^^ Missing match arm
1975 match f { Foo { a: _ } => () }
1976 match f {
1977 Foo { a: true } => (),
1978 Foo { a: false } => (),
1979 }
1980 match &f {
1981 Foo { a: true } => (),
1982 Foo { a: false } => (),
1983 }
1984}
1985"#,
1986 );
1987 }
1988
1989 #[test]
1990 fn tuple_struct() {
1991 check_diagnostics(
1992 r#"struct Foo(bool);
1993fn main(f: Foo) {
1994 match f {}
1995 //^ Missing match arm
1996 match f { Foo(true) => () }
1997 //^ Missing match arm
1998 match f {
1999 Foo(true) => (),
2000 Foo(false) => (),
2001 }
2002}
2003"#,
2004 );
2005 }
2006
2007 #[test]
2008 fn unit_struct() {
2009 check_diagnostics(
2010 r#"struct Foo;
2011fn main(f: Foo) {
2012 match f {}
2013 //^ Missing match arm
2014 match f { Foo => () }
2015}
2016"#,
2017 );
2018 }
2019
2020 #[test]
2021 fn record_struct_ellipsis() {
2022 check_diagnostics(
2023 r#"struct Foo { foo: bool, bar: bool }
2024fn main(f: Foo) {
2025 match f { Foo { foo: true, .. } => () }
2026 //^ Missing match arm
2027 match f {
2028 //^ Missing match arm
2029 Foo { foo: true, .. } => (),
2030 Foo { bar: false, .. } => ()
2031 }
2032 match f { Foo { .. } => () }
2033 match f {
2034 Foo { foo: true, .. } => (),
2035 Foo { foo: false, .. } => ()
2036 }
2037}
2038"#,
2039 );
2040 }
2041
2042 #[test]
2043 fn internal_or() {
2044 check_diagnostics(
2045 r#"
2046fn main() {
2047 enum Either { A(bool), B }
2048 match Either::B {
2049 //^^^^^^^^^ Missing match arm
2050 Either::A(true | false) => (),
2051 }
2052}
2053"#,
2054 );
2055 }
2056
2057 #[test]
2058 fn no_panic_at_unimplemented_subpattern_type() {
2059 check_diagnostics(
2060 r#"
2061struct S { a: char}
2062fn main(v: S) {
2063 match v { S{ a } => {} }
2064 match v { S{ a: _x } => {} }
2065 match v { S{ a: 'a' } => {} }
2066 //^^^^^^^^^^^ Internal: match check bailed out
2067 match v { S{..} => {} }
2068 match v { _ => {} }
2069 match v { }
2070 //^ Missing match arm
2071}
2072"#,
2073 );
2074 }
2075
2076 #[test]
2077 fn binding() {
2078 check_diagnostics(
2079 r#"
2080fn main() {
2081 match true {
2082 _x @ true => {}
2083 false => {}
2084 }
2085 match true { _x @ true => {} }
2086 //^^^^ Missing match arm
2087}
2088"#,
2089 );
2090 }
2091
2092 #[test]
2093 fn binding_ref_has_correct_type() {
2094 // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
2095 // If that's not true match checking will panic with "incompatible constructors"
2096 // FIXME: make facilities to test this directly like `tests::check_infer(..)`
2097 check_diagnostics(
2098 r#"
2099enum Foo { A }
2100fn main() {
2101 // FIXME: this should not bail out but current behavior is such as the old algorithm.
2102 // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
2103 match Foo::A {
2104 ref _x => {}
2105 // ^^^^^^ Internal: match check bailed out
2106 Foo::A => {}
2107 }
2108 match (true,) {
2109 (ref _x,) => {}
2110 (true,) => {}
2111 }
2112}
2113"#,
2114 );
2115 }
2116
2117 #[test]
2118 fn enum_non_exhaustive() {
2119 check_diagnostics(
2120 r#"
2121//- /lib.rs crate:lib
2122#[non_exhaustive]
2123pub enum E { A, B }
2124fn _local() {
2125 match E::A { _ => {} }
2126 match E::A {
2127 E::A => {}
2128 E::B => {}
2129 }
2130 match E::A {
2131 E::A | E::B => {}
2132 }
2133}
2134
2135//- /main.rs crate:main deps:lib
2136use lib::E;
2137fn main() {
2138 match E::A { _ => {} }
2139 match E::A {
2140 //^^^^ Missing match arm
2141 E::A => {}
2142 E::B => {}
2143 }
2144 match E::A {
2145 //^^^^ Missing match arm
2146 E::A | E::B => {}
2147 }
2148}
2149"#,
2150 );
2151 }
2152
2153 #[test]
2154 fn match_guard() {
2155 check_diagnostics(
2156 r#"
2157fn main() {
2158 match true {
2159 true if false => {}
2160 true => {}
2161 false => {}
2162 }
2163 match true {
2164 //^^^^ Missing match arm
2165 true if false => {}
2166 false => {}
2167 }
2168}
2169"#,
2170 );
2171 }
2172
2173 #[test]
2174 fn pattern_type_is_of_substitution() {
2175 check_diagnostics(
2176 r#"
2177struct Foo<T>(T);
2178struct Bar;
2179fn main() {
2180 match Foo(Bar) {
2181 _ | Foo(Bar) => {}
2182 }
2183}
2184"#,
2185 );
2186 }
2187
2188 #[test]
2189 fn record_struct_no_such_field() {
2190 check_diagnostics(
2191 r#"
2192struct Foo { }
2193fn main(f: Foo) {
2194 match f { Foo { bar } => () }
2195 // ^^^^^^^^^^^ Internal: match check bailed out
2196}
2197"#,
2198 );
2199 }
2200
2201 #[test]
2202 fn match_ergonomics_issue_9095() {
2203 check_diagnostics(
2204 r#"
2205enum Foo<T> { A(T) }
2206fn main() {
2207 match &Foo::A(true) {
2208 _ => {}
2209 Foo::A(_) => {}
2210 }
2211}
2212"#,
2213 );
2214 }
2215
2216 mod false_negatives {
2217 //! The implementation of match checking here is a work in progress. As we roll this out, we
2218 //! prefer false negatives to false positives (ideally there would be no false positives). This
2219 //! test module should document known false negatives. Eventually we will have a complete
2220 //! implementation of match checking and this module will be empty.
2221 //!
2222 //! The reasons for documenting known false negatives:
2223 //!
2224 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
2225 //! 2. It ensures the code doesn't panic when handling these cases.
2226 use super::*;
2227
2228 #[test]
2229 fn integers() {
2230 // We don't currently check integer exhaustiveness.
2231 check_diagnostics(
2232 r#"
2233fn main() {
2234 match 5 {
2235 10 => (),
2236 // ^^ Internal: match check bailed out
2237 11..20 => (),
2238 }
2239}
2240"#,
2241 );
2242 }
2243
2244 #[test]
2245 fn reference_patterns_at_top_level() {
2246 check_diagnostics(
2247 r#"
2248fn main() {
2249 match &false {
2250 &true => {}
2251 // ^^^^^ Internal: match check bailed out
2252 }
2253}
2254 "#,
2255 );
2256 }
2257
2258 #[test]
2259 fn reference_patterns_in_fields() {
2260 check_diagnostics(
2261 r#"
2262fn main() {
2263 match (&false,) {
2264 (true,) => {}
2265 // ^^^^^^^ Internal: match check bailed out
2266 }
2267 match (&false,) {
2268 (&true,) => {}
2269 // ^^^^^^^^ Internal: match check bailed out
2270 }
2271}
2272 "#,
2273 );
2274 }
2275 }
2276}
2277
2278#[cfg(test)]
2279mod decl_check_tests {
2280 use crate::diagnostics::tests::check_diagnostics;
2281
2282 #[test]
2283 fn incorrect_function_name() {
2284 check_diagnostics(
2285 r#"
2286fn NonSnakeCaseName() {}
2287// ^^^^^^^^^^^^^^^^ Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name`
2288"#,
2289 );
2290 }
2291
2292 #[test]
2293 fn incorrect_function_params() {
2294 check_diagnostics(
2295 r#"
2296fn foo(SomeParam: u8) {}
2297 // ^^^^^^^^^ Parameter `SomeParam` should have snake_case name, e.g. `some_param`
2298
2299fn foo2(ok_param: &str, CAPS_PARAM: u8) {}
2300 // ^^^^^^^^^^ Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param`
2301"#,
2302 );
2303 }
2304
2305 #[test]
2306 fn incorrect_variable_names() {
2307 check_diagnostics(
2308 r#"
2309fn foo() {
2310 let SOME_VALUE = 10;
2311 // ^^^^^^^^^^ Variable `SOME_VALUE` should have snake_case name, e.g. `some_value`
2312 let AnotherValue = 20;
2313 // ^^^^^^^^^^^^ Variable `AnotherValue` should have snake_case name, e.g. `another_value`
2314}
2315"#,
2316 );
2317 }
2318
2319 #[test]
2320 fn incorrect_struct_names() {
2321 check_diagnostics(
2322 r#"
2323struct non_camel_case_name {}
2324 // ^^^^^^^^^^^^^^^^^^^ Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName`
2325
2326struct SCREAMING_CASE {}
2327 // ^^^^^^^^^^^^^^ Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase`
2328"#,
2329 );
2330 }
2331
2332 #[test]
2333 fn no_diagnostic_for_camel_cased_acronyms_in_struct_name() {
2334 check_diagnostics(
2335 r#"
2336struct AABB {}
2337"#,
2338 );
2339 }
2340
2341 #[test]
2342 fn incorrect_struct_field() {
2343 check_diagnostics(
2344 r#"
2345struct SomeStruct { SomeField: u8 }
2346 // ^^^^^^^^^ Field `SomeField` should have snake_case name, e.g. `some_field`
2347"#,
2348 );
2349 }
2350
2351 #[test]
2352 fn incorrect_enum_names() {
2353 check_diagnostics(
2354 r#"
2355enum some_enum { Val(u8) }
2356 // ^^^^^^^^^ Enum `some_enum` should have CamelCase name, e.g. `SomeEnum`
2357
2358enum SOME_ENUM {}
2359 // ^^^^^^^^^ Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum`
2360"#,
2361 );
2362 }
2363
2364 #[test]
2365 fn no_diagnostic_for_camel_cased_acronyms_in_enum_name() {
2366 check_diagnostics(
2367 r#"
2368enum AABB {}
2369"#,
2370 );
2371 }
2372
2373 #[test]
2374 fn incorrect_enum_variant_name() {
2375 check_diagnostics(
2376 r#"
2377enum SomeEnum { SOME_VARIANT(u8) }
2378 // ^^^^^^^^^^^^ Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant`
2379"#,
2380 );
2381 }
2382
2383 #[test]
2384 fn incorrect_const_name() {
2385 check_diagnostics(
2386 r#"
2387const some_weird_const: u8 = 10;
2388 // ^^^^^^^^^^^^^^^^ Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2389"#,
2390 );
2391 }
2392
2393 #[test]
2394 fn incorrect_static_name() {
2395 check_diagnostics(
2396 r#"
2397static some_weird_const: u8 = 10;
2398 // ^^^^^^^^^^^^^^^^ Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST`
2399"#,
2400 );
2401 }
2402
2403 #[test]
2404 fn fn_inside_impl_struct() {
2405 check_diagnostics(
2406 r#"
2407struct someStruct;
2408 // ^^^^^^^^^^ Structure `someStruct` should have CamelCase name, e.g. `SomeStruct`
2409
2410impl someStruct {
2411 fn SomeFunc(&self) {
2412 // ^^^^^^^^ Function `SomeFunc` should have snake_case name, e.g. `some_func`
2413 let WHY_VAR_IS_CAPS = 10;
2414 // ^^^^^^^^^^^^^^^ Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps`
2415 }
2416}
2417"#,
2418 );
2419 }
2420
2421 #[test]
2422 fn no_diagnostic_for_enum_varinats() {
2423 check_diagnostics(
2424 r#"
2425enum Option { Some, None }
2426
2427fn main() {
2428 match Option::None {
2429 None => (),
2430 Some => (),
2431 }
2432}
2433"#,
2434 );
2435 }
2436
2437 #[test]
2438 fn non_let_bind() {
2439 check_diagnostics(
2440 r#"
2441enum Option { Some, None }
2442
2443fn main() {
2444 match Option::None {
2445 SOME_VAR @ None => (),
2446 // ^^^^^^^^ Variable `SOME_VAR` should have snake_case name, e.g. `some_var`
2447 Some => (),
2448 }
2449}
2450"#,
2451 );
2452 }
2453
2454 #[test]
2455 fn allow_attributes() {
2456 check_diagnostics(
2457 r#"
2458#[allow(non_snake_case)]
2459fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
2460 // cov_flags generated output from elsewhere in this file
2461 extern "C" {
2462 #[no_mangle]
2463 static lower_case: u8;
2464 }
2465
2466 let OtherVar = SOME_VAR + 1;
2467 OtherVar
2468}
2469
2470#[allow(nonstandard_style)]
2471mod CheckNonstandardStyle {
2472 fn HiImABadFnName() {}
2473}
2474
2475#[allow(bad_style)]
2476mod CheckBadStyle {
2477 fn HiImABadFnName() {}
2478}
2479
2480mod F {
2481 #![allow(non_snake_case)]
2482 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
2483}
2484
2485#[allow(non_snake_case, non_camel_case_types)]
2486pub struct some_type {
2487 SOME_FIELD: u8,
2488 SomeField: u16,
2489}
2490
2491#[allow(non_upper_case_globals)]
2492pub const some_const: u8 = 10;
2493
2494#[allow(non_upper_case_globals)]
2495pub static SomeStatic: u8 = 10;
2496 "#,
2497 );
2498 }
2499
2500 #[test]
2501 fn allow_attributes_crate_attr() {
2502 check_diagnostics(
2503 r#"
2504#![allow(non_snake_case)]
2505
2506mod F {
2507 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
2508}
2509 "#,
2510 );
2511 }
2512
2513 #[test]
2514 #[ignore]
2515 fn bug_trait_inside_fn() {
2516 // FIXME:
2517 // This is broken, and in fact, should not even be looked at by this
2518 // lint in the first place. There's weird stuff going on in the
2519 // collection phase.
2520 // It's currently being brought in by:
2521 // * validate_func on `a` recursing into modules
2522 // * then it finds the trait and then the function while iterating
2523 // through modules
2524 // * then validate_func is called on Dirty
2525 // * ... which then proceeds to look at some unknown module taking no
2526 // attrs from either the impl or the fn a, and then finally to the root
2527 // module
2528 //
2529 // It should find the attribute on the trait, but it *doesn't even see
2530 // the trait* as far as I can tell.
2531
2532 check_diagnostics(
2533 r#"
2534trait T { fn a(); }
2535struct U {}
2536impl T for U {
2537 fn a() {
2538 // this comes out of bitflags, mostly
2539 #[allow(non_snake_case)]
2540 trait __BitFlags {
2541 const HiImAlsoBad: u8 = 2;
2542 #[inline]
2543 fn Dirty(&self) -> bool {
2544 false
2545 }
2546 }
2547
2548 }
2549}
2550 "#,
2551 );
2552 }
2553
2554 #[test]
2555 #[ignore]
2556 fn bug_traits_arent_checked() {
2557 // FIXME: Traits and functions in traits aren't currently checked by
2558 // r-a, even though rustc will complain about them.
2559 check_diagnostics(
2560 r#"
2561trait BAD_TRAIT {
2562 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
2563 fn BAD_FUNCTION();
2564 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
2565 fn BadFunction();
2566 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
2567}
2568 "#,
2569 );
2570 }
2571
2572 #[test]
2573 fn ignores_extern_items() {
2574 cov_mark::check!(extern_func_incorrect_case_ignored);
2575 cov_mark::check!(extern_static_incorrect_case_ignored);
2576 check_diagnostics(
2577 r#"
2578extern {
2579 fn NonSnakeCaseName(SOME_VAR: u8) -> u8;
2580 pub static SomeStatic: u8 = 10;
2581}
2582 "#,
2583 );
2584 }
2585
2586 #[test]
2587 fn infinite_loop_inner_items() {
2588 check_diagnostics(
2589 r#"
2590fn qualify() {
2591 mod foo {
2592 use super::*;
2593 }
2594}
2595 "#,
2596 )
2597 }
2598
2599 #[test] // Issue #8809.
2600 fn parenthesized_parameter() {
2601 check_diagnostics(r#"fn f((O): _) {}"#)
2602 }
722} 2603}
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 43356a94e..95fd39850 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -52,13 +52,13 @@ pub(crate) fn goto_implementation(
52 hir::ModuleDef::Function(f) => { 52 hir::ModuleDef::Function(f) => {
53 let assoc = f.as_assoc_item(sema.db)?; 53 let assoc = f.as_assoc_item(sema.db)?;
54 let name = assoc.name(sema.db)?; 54 let name = assoc.name(sema.db)?;
55 let trait_ = assoc.containing_trait(sema.db)?; 55 let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
56 impls_for_trait_item(&sema, trait_, name) 56 impls_for_trait_item(&sema, trait_, name)
57 } 57 }
58 hir::ModuleDef::Const(c) => { 58 hir::ModuleDef::Const(c) => {
59 let assoc = c.as_assoc_item(sema.db)?; 59 let assoc = c.as_assoc_item(sema.db)?;
60 let name = assoc.name(sema.db)?; 60 let name = assoc.name(sema.db)?;
61 let trait_ = assoc.containing_trait(sema.db)?; 61 let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
62 impls_for_trait_item(&sema, trait_, name) 62 impls_for_trait_item(&sema, trait_, name)
63 } 63 }
64 _ => return None, 64 _ => return None,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index ed4f18e1f..1c6d36939 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -208,7 +208,7 @@ pub(crate) fn hover(
208} 208}
209 209
210fn try_hover_for_attribute(token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> { 210fn try_hover_for_attribute(token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> {
211 let attr = token.ancestors().nth(1).and_then(ast::Attr::cast)?; 211 let attr = token.ancestors().find_map(ast::Attr::cast)?;
212 let (path, tt) = attr.as_simple_call()?; 212 let (path, tt) = attr.as_simple_call()?;
213 if !tt.syntax().text_range().contains(token.text_range().start()) { 213 if !tt.syntax().text_range().contains(token.text_range().start()) {
214 return None; 214 return None;
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 2a4a1c3c8..7dfc5043e 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -239,7 +239,7 @@ fn rename_mod(
239 239
240fn rename_reference( 240fn rename_reference(
241 sema: &Semantics<RootDatabase>, 241 sema: &Semantics<RootDatabase>,
242 def: Definition, 242 mut def: Definition,
243 new_name: &str, 243 new_name: &str,
244) -> RenameResult<SourceChange> { 244) -> RenameResult<SourceChange> {
245 let ident_kind = check_identifier(new_name)?; 245 let ident_kind = check_identifier(new_name)?;
@@ -285,7 +285,38 @@ fn rename_reference(
285 } 285 }
286 } 286 }
287 287
288 def = match def {
289 // HACK: resolve trait impl items to the item def of the trait definition
290 // so that we properly resolve all trait item references
291 Definition::ModuleDef(mod_def) => mod_def
292 .as_assoc_item(sema.db)
293 .and_then(|it| it.containing_trait_impl(sema.db))
294 .and_then(|it| {
295 it.items(sema.db).into_iter().find_map(|it| match (it, mod_def) {
296 (hir::AssocItem::Function(trait_func), ModuleDef::Function(func))
297 if trait_func.name(sema.db) == func.name(sema.db) =>
298 {
299 Some(Definition::ModuleDef(ModuleDef::Function(trait_func)))
300 }
301 (hir::AssocItem::Const(trait_konst), ModuleDef::Const(konst))
302 if trait_konst.name(sema.db) == konst.name(sema.db) =>
303 {
304 Some(Definition::ModuleDef(ModuleDef::Const(trait_konst)))
305 }
306 (
307 hir::AssocItem::TypeAlias(trait_type_alias),
308 ModuleDef::TypeAlias(type_alias),
309 ) if trait_type_alias.name(sema.db) == type_alias.name(sema.db) => {
310 Some(Definition::ModuleDef(ModuleDef::TypeAlias(trait_type_alias)))
311 }
312 _ => None,
313 })
314 })
315 .unwrap_or(def),
316 _ => def,
317 };
288 let usages = def.usages(sema).all(); 318 let usages = def.usages(sema).all();
319
289 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { 320 if !usages.is_empty() && ident_kind == IdentifierKind::Underscore {
290 cov_mark::hit!(rename_underscore_multiple); 321 cov_mark::hit!(rename_underscore_multiple);
291 bail!("Cannot rename reference to `_` as it is being referenced multiple times"); 322 bail!("Cannot rename reference to `_` as it is being referenced multiple times");
@@ -1938,4 +1969,136 @@ use Bar$0;
1938 "error: Renaming aliases is currently unsupported", 1969 "error: Renaming aliases is currently unsupported",
1939 ); 1970 );
1940 } 1971 }
1972
1973 #[test]
1974 fn test_rename_trait_method() {
1975 let res = r"
1976trait Foo {
1977 fn foo(&self) {
1978 self.foo();
1979 }
1980}
1981
1982impl Foo for () {
1983 fn foo(&self) {
1984 self.foo();
1985 }
1986}";
1987 check(
1988 "foo",
1989 r#"
1990trait Foo {
1991 fn bar$0(&self) {
1992 self.bar();
1993 }
1994}
1995
1996impl Foo for () {
1997 fn bar(&self) {
1998 self.bar();
1999 }
2000}"#,
2001 res,
2002 );
2003 check(
2004 "foo",
2005 r#"
2006trait Foo {
2007 fn bar(&self) {
2008 self.bar$0();
2009 }
2010}
2011
2012impl Foo for () {
2013 fn bar(&self) {
2014 self.bar();
2015 }
2016}"#,
2017 res,
2018 );
2019 check(
2020 "foo",
2021 r#"
2022trait Foo {
2023 fn bar(&self) {
2024 self.bar();
2025 }
2026}
2027
2028impl Foo for () {
2029 fn bar$0(&self) {
2030 self.bar();
2031 }
2032}"#,
2033 res,
2034 );
2035 check(
2036 "foo",
2037 r#"
2038trait Foo {
2039 fn bar(&self) {
2040 self.bar();
2041 }
2042}
2043
2044impl Foo for () {
2045 fn bar(&self) {
2046 self.bar$0();
2047 }
2048}"#,
2049 res,
2050 );
2051 }
2052
2053 #[test]
2054 fn test_rename_trait_const() {
2055 let res = r"
2056trait Foo {
2057 const FOO: ();
2058}
2059
2060impl Foo for () {
2061 const FOO: ();
2062}
2063fn f() { <()>::FOO; }";
2064 check(
2065 "FOO",
2066 r#"
2067trait Foo {
2068 const BAR$0: ();
2069}
2070
2071impl Foo for () {
2072 const BAR: ();
2073}
2074fn f() { <()>::BAR; }"#,
2075 res,
2076 );
2077 check(
2078 "FOO",
2079 r#"
2080trait Foo {
2081 const BAR: ();
2082}
2083
2084impl Foo for () {
2085 const BAR$0: ();
2086}
2087fn f() { <()>::BAR; }"#,
2088 res,
2089 );
2090 check(
2091 "FOO",
2092 r#"
2093trait Foo {
2094 const BAR: ();
2095}
2096
2097impl Foo for () {
2098 const BAR: ();
2099}
2100fn f() { <()>::BAR$0; }"#,
2101 res,
2102 );
2103 }
1941} 2104}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 9503c936d..84012227d 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -131,6 +131,9 @@ pub(super) fn element(
131 } 131 }
132 STRING | BYTE_STRING => HlTag::StringLiteral.into(), 132 STRING | BYTE_STRING => HlTag::StringLiteral.into(),
133 ATTR => HlTag::Attribute.into(), 133 ATTR => HlTag::Attribute.into(),
134 INT_NUMBER if element.ancestors().nth(1).map_or(false, |it| it.kind() == FIELD_EXPR) => {
135 SymbolKind::Field.into()
136 }
134 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), 137 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
135 BYTE => HlTag::ByteLiteral.into(), 138 BYTE => HlTag::ByteLiteral.into(),
136 CHAR => HlTag::CharLiteral.into(), 139 CHAR => HlTag::CharLiteral.into(),
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index a7b5c3b89..59f1e8e4c 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -215,8 +215,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
215 <span class="keyword">let</span> <span class="variable callable declaration">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span> 215 <span class="keyword">let</span> <span class="variable callable declaration">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="semicolon">;</span>
216 <span class="keyword">let</span> <span class="variable callable declaration">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span> 216 <span class="keyword">let</span> <span class="variable callable declaration">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function associated">baz</span><span class="semicolon">;</span>
217 217
218 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> 218 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="comma">,</span><span class="parenthesis">)</span><span class="semicolon">;</span>
219 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> 219 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="operator">.</span><span class="field">0</span><span class="semicolon">;</span>
220 220
221 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> 221 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
222 222
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 6ad2a362a..f7d8334a0 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -189,8 +189,8 @@ fn main() {
189 let a = |x| x; 189 let a = |x| x;
190 let bar = Foo::baz; 190 let bar = Foo::baz;
191 191
192 let baz = -42; 192 let baz = (-42,);
193 let baz = -baz; 193 let baz = -baz.0;
194 194
195 let _ = !true; 195 let _ = !true;
196 196
diff --git a/crates/ide_assists/Cargo.toml b/crates/ide_assists/Cargo.toml
index a83acb191..0d0d1605e 100644
--- a/crates/ide_assists/Cargo.toml
+++ b/crates/ide_assists/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15itertools = "0.10.0" 15itertools = "0.10.0"
16either = "1.6.1" 16either = "1.6.1"
diff --git a/crates/ide_assists/src/handlers/change_visibility.rs b/crates/ide_assists/src/handlers/change_visibility.rs
index d7e39b2ae..ed936667f 100644
--- a/crates/ide_assists/src/handlers/change_visibility.rs
+++ b/crates/ide_assists/src/handlers/change_visibility.rs
@@ -1,7 +1,9 @@
1use syntax::{ 1use syntax::{
2 ast::{self, NameOwner, VisibilityOwner}, 2 ast::{self, NameOwner, VisibilityOwner},
3 AstNode, 3 AstNode,
4 SyntaxKind::{CONST, ENUM, FN, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, VISIBILITY}, 4 SyntaxKind::{
5 CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY,
6 },
5 T, 7 T,
6}; 8};
7 9
@@ -37,12 +39,15 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
37 | T![enum] 39 | T![enum]
38 | T![trait] 40 | T![trait]
39 | T![type] 41 | T![type]
42 | T![use]
43 | T![macro]
40 ) 44 )
41 }); 45 });
42 46
43 let (offset, target) = if let Some(keyword) = item_keyword { 47 let (offset, target) = if let Some(keyword) = item_keyword {
44 let parent = keyword.parent()?; 48 let parent = keyword.parent()?;
45 let def_kws = vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT]; 49 let def_kws =
50 vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
46 // Parent is not a definition, can't add visibility 51 // Parent is not a definition, can't add visibility
47 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 52 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
48 return None; 53 return None;
@@ -122,6 +127,8 @@ mod tests {
122 check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}"); 127 check_assist(change_visibility, "$0trait Foo {}", "pub(crate) trait Foo {}");
123 check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}"); 128 check_assist(change_visibility, "m$0od {}", "pub(crate) mod {}");
124 check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}"); 129 check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}");
130 check_assist(change_visibility, "$0macro foo() {}", "pub(crate) macro foo() {}");
131 check_assist(change_visibility, "$0use foo;", "pub(crate) use foo;");
125 } 132 }
126 133
127 #[test] 134 #[test]
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index ba81c9e04..3c45fe1cb 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14itertools = "0.10.0" 14itertools = "0.10.0"
15log = "0.4.8" 15log = "0.4.8"
16rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index fbd499900..bd90cefb2 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -29,7 +29,7 @@ use crate::{
29 macro_::render_macro, 29 macro_::render_macro,
30 pattern::{render_struct_pat, render_variant_pat}, 30 pattern::{render_struct_pat, render_variant_pat},
31 render_field, render_resolution, render_tuple_field, 31 render_field, render_resolution, render_tuple_field,
32 type_alias::render_type_alias, 32 type_alias::{render_type_alias, render_type_alias_with_eq},
33 RenderContext, 33 RenderContext,
34 }, 34 },
35 CompletionContext, CompletionItem, CompletionItemKind, 35 CompletionContext, CompletionItem, CompletionItemKind,
@@ -188,6 +188,14 @@ impl Completions {
188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); 188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias));
189 } 189 }
190 190
191 pub(crate) fn add_type_alias_with_eq(
192 &mut self,
193 ctx: &CompletionContext,
194 type_alias: hir::TypeAlias,
195 ) {
196 self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
197 }
198
191 pub(crate) fn add_qualified_enum_variant( 199 pub(crate) fn add_qualified_enum_variant(
192 &mut self, 200 &mut self,
193 ctx: &CompletionContext, 201 ctx: &CompletionContext,
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index c010cbbca..30b8d44bd 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -1,10 +1,10 @@
1//! Feature: completion with imports-on-the-fly 1//! Feature: completion with imports-on-the-fly
2//! 2//!
3//! When completing names in the current scope, proposes additional imports from other modules or crates, 3//! When completing names in the current scope, proposes additional imports from other modules or crates,
4//! if they can be qualified in the scope and their name contains all symbols from the completion input. 4//! if they can be qualified in the scope, and their name contains all symbols from the completion input.
5//! 5//!
6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. 6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively. 7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively.
8//! 8//!
9//! ``` 9//! ```
10//! fn main() { 10//! fn main() {
@@ -23,8 +23,8 @@
23//! ``` 23//! ```
24//! 24//!
25//! Also completes associated items, that require trait imports. 25//! Also completes associated items, that require trait imports.
26//! If any unresolved and/or partially-qualified path predeces the input, it will be taken into account. 26//! If any unresolved and/or partially-qualified path precedes the input, it will be taken into account.
27//! Currently, only the imports with their import path ending with the whole qialifier will be proposed 27//! Currently, only the imports with their import path ending with the whole qualifier will be proposed
28//! (no fuzzy matching for qualifier). 28//! (no fuzzy matching for qualifier).
29//! 29//!
30//! ``` 30//! ```
@@ -61,14 +61,14 @@
61//! } 61//! }
62//! ``` 62//! ```
63//! 63//!
64//! NOTE: currently, if an assoc item comes from a trait that's not currently imported and it also has an unresolved and/or partially-qualified path, 64//! NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
65//! no imports will be proposed. 65//! no imports will be proposed.
66//! 66//!
67//! .Fuzzy search details 67//! .Fuzzy search details
68//! 68//!
69//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only 69//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
70//! (i.e. in `HashMap` in the `std::collections::HashMap` path). 70//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
71//! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols 71//! For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
72//! (but shows all associated items for any input length). 72//! (but shows all associated items for any input length).
73//! 73//!
74//! .Import configuration 74//! .Import configuration
@@ -79,15 +79,15 @@
79//! .LSP and performance implications 79//! .LSP and performance implications
80//! 80//!
81//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` 81//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
82//! (case sensitive) resolve client capability in its client capabilities. 82//! (case-sensitive) resolve client capability in its client capabilities.
83//! This way the server is able to defer the costly computations, doing them for a selected completion item only. 83//! This way the server is able to defer the costly computations, doing them for a selected completion item only.
84//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, 84//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
85//! which might be slow ergo the feature is automatically disabled. 85//! which might be slow ergo the feature is automatically disabled.
86//! 86//!
87//! .Feature toggle 87//! .Feature toggle
88//! 88//!
89//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. 89//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
91//! capability enabled. 91//! capability enabled.
92 92
93use ide_db::helpers::{ 93use ide_db::helpers::{
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index b1e6b2b77..952f052a1 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -1,8 +1,9 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use hir::ScopeDef; 3use hir::ScopeDef;
4use syntax::{ast, AstNode};
4 5
5use crate::{CompletionContext, Completions}; 6use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
6 7
7pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
8 if ctx.is_path_disallowed() || !ctx.is_trivial_path() { 9 if ctx.is_path_disallowed() || !ctx.is_trivial_path() {
@@ -43,6 +44,20 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
43 }); 44 });
44 } 45 }
45 46
47 if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location {
48 if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) {
49 if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) =
50 ctx.sema.resolve_path(&path_seg.parent_path())
51 {
52 trait_.items(ctx.sema.db).into_iter().for_each(|it| {
53 if let hir::AssocItem::TypeAlias(alias) = it {
54 acc.add_type_alias_with_eq(ctx, alias)
55 }
56 });
57 }
58 }
59 }
60
46 ctx.scope.process_all_names(&mut |name, res| { 61 ctx.scope.process_all_names(&mut |name, res| {
47 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { 62 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
48 cov_mark::hit!(skip_lifetime_completion); 63 cov_mark::hit!(skip_lifetime_completion);
@@ -777,4 +792,21 @@ $0
777 "#]], 792 "#]],
778 ) 793 )
779 } 794 }
795
796 #[test]
797 fn completes_assoc_types_in_dynimpl_trait() {
798 check(
799 r#"
800trait Foo {
801 type Bar;
802}
803
804fn foo(_: impl Foo<B$0>) {}
805"#,
806 expect![[r#"
807 ta Bar = type Bar;
808 tt Foo
809 "#]],
810 );
811 }
780} 812}
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index ee87bf461..81d7a1a1d 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -47,6 +47,9 @@ pub(crate) enum ImmediateLocation {
47 receiver_is_ambiguous_float_literal: bool, 47 receiver_is_ambiguous_float_literal: bool,
48 }, 48 },
49 // Original file ast node 49 // Original file ast node
50 // Only set from a type arg
51 GenericArgList(ast::GenericArgList),
52 // Original file ast node
50 /// The record expr of the field name we are completing 53 /// The record expr of the field name we are completing
51 RecordExpr(ast::RecordExpr), 54 RecordExpr(ast::RecordExpr),
52 // Original file ast node 55 // Original file ast node
@@ -159,7 +162,6 @@ pub(crate) fn determine_location(
159 } 162 }
160 } 163 }
161 }; 164 };
162
163 let res = match_ast! { 165 let res = match_ast! {
164 match parent { 166 match parent {
165 ast::IdentPat(_it) => ImmediateLocation::IdentPat, 167 ast::IdentPat(_it) => ImmediateLocation::IdentPat,
@@ -174,6 +176,9 @@ pub(crate) fn determine_location(
174 Some(TRAIT) => ImmediateLocation::Trait, 176 Some(TRAIT) => ImmediateLocation::Trait,
175 _ => return None, 177 _ => return None,
176 }, 178 },
179 ast::GenericArgList(_it) => sema
180 .find_node_at_offset_with_macros(original_file, offset)
181 .map(ImmediateLocation::GenericArgList)?,
177 ast::Module(it) => { 182 ast::Module(it) => {
178 if it.item_list().is_none() { 183 if it.item_list().is_none() {
179 ImmediateLocation::ModDeclaration(it) 184 ImmediateLocation::ModDeclaration(it)
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 902df46ca..d3db55c35 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -111,7 +111,10 @@ impl<'a> RenderContext<'a> {
111 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), 111 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
112 }; 112 };
113 is_assoc_deprecated 113 is_assoc_deprecated
114 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) 114 || assoc
115 .containing_trait_or_trait_impl(db)
116 .map(|trait_| self.is_deprecated(trait_))
117 .unwrap_or(false)
115 } 118 }
116 119
117 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> { 120 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
@@ -132,16 +135,17 @@ fn render_field_(
132 ctx.source_range(), 135 ctx.source_range(),
133 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), 136 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
134 ); 137 );
135 item.kind(SymbolKind::Field)
136 .detail(ty.display(ctx.db()).to_string())
137 .set_documentation(field.docs(ctx.db()))
138 .set_deprecated(is_deprecated);
139 138
140 item.set_relevance(CompletionRelevance { 139 item.set_relevance(CompletionRelevance {
141 type_match: compute_type_match(ctx.completion, ty), 140 type_match: compute_type_match(ctx.completion, ty),
142 exact_name_match: compute_exact_name_match(ctx.completion, &name), 141 exact_name_match: compute_exact_name_match(ctx.completion, &name),
143 ..CompletionRelevance::default() 142 ..CompletionRelevance::default()
144 }); 143 });
144 item.kind(SymbolKind::Field)
145 .detail(ty.display(ctx.db()).to_string())
146 .set_documentation(field.docs(ctx.db()))
147 .set_deprecated(is_deprecated)
148 .lookup_by(name);
145 149
146 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { 150 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
147 // FIXME 151 // FIXME
@@ -164,7 +168,9 @@ fn render_tuple_field_(
164 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), 168 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
165 ); 169 );
166 170
167 item.kind(SymbolKind::Field).detail(ty.display(ctx.db()).to_string()); 171 item.kind(SymbolKind::Field)
172 .detail(ty.display(ctx.db()).to_string())
173 .lookup_by(field.to_string());
168 174
169 item.build() 175 item.build()
170} 176}
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 1abeed96d..1357b9f4a 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -58,29 +58,29 @@ impl<'a> FunctionRender<'a> {
58 Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method }) 58 Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method })
59 } 59 }
60 60
61 fn render(mut self, import_to_add: Option<ImportEdit>) -> CompletionItem { 61 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
62 let params = self.params(); 62 let params = self.params();
63 if let Some(receiver) = &self.receiver { 63 let call = if let Some(receiver) = &self.receiver {
64 self.name = format!("{}.{}", receiver, &self.name) 64 format!("{}.{}", receiver, &self.name)
65 } 65 } else {
66 let mut item = CompletionItem::new( 66 self.name.clone()
67 CompletionKind::Reference, 67 };
68 self.ctx.source_range(), 68 let mut item =
69 self.name.clone(), 69 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), call.clone());
70 );
71 item.kind(self.kind()) 70 item.kind(self.kind())
72 .set_documentation(self.ctx.docs(self.func)) 71 .set_documentation(self.ctx.docs(self.func))
73 .set_deprecated( 72 .set_deprecated(
74 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), 73 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
75 ) 74 )
76 .detail(self.detail()) 75 .detail(self.detail())
77 .add_call_parens(self.ctx.completion, self.name.clone(), params) 76 .add_call_parens(self.ctx.completion, call.clone(), params)
78 .add_import(import_to_add); 77 .add_import(import_to_add)
78 .lookup_by(self.name);
79 79
80 let ret_type = self.func.ret_type(self.ctx.db()); 80 let ret_type = self.func.ret_type(self.ctx.db());
81 item.set_relevance(CompletionRelevance { 81 item.set_relevance(CompletionRelevance {
82 type_match: compute_type_match(self.ctx.completion, &ret_type), 82 type_match: compute_type_match(self.ctx.completion, &ret_type),
83 exact_name_match: compute_exact_name_match(self.ctx.completion, &self.name), 83 exact_name_match: compute_exact_name_match(self.ctx.completion, &call),
84 ..CompletionRelevance::default() 84 ..CompletionRelevance::default()
85 }); 85 });
86 86
@@ -263,7 +263,7 @@ fn bar(s: &S) {
263 ); 263 );
264 264
265 check_edit( 265 check_edit(
266 "self.foo", 266 "foo",
267 r#" 267 r#"
268struct S {} 268struct S {}
269impl S { 269impl S {
diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs
index e47b4c745..e0234171a 100644
--- a/crates/ide_completion/src/render/type_alias.rs
+++ b/crates/ide_completion/src/render/type_alias.rs
@@ -16,7 +16,14 @@ pub(crate) fn render_type_alias<'a>(
16 ctx: RenderContext<'a>, 16 ctx: RenderContext<'a>,
17 type_alias: hir::TypeAlias, 17 type_alias: hir::TypeAlias,
18) -> Option<CompletionItem> { 18) -> Option<CompletionItem> {
19 TypeAliasRender::new(ctx, type_alias)?.render() 19 TypeAliasRender::new(ctx, type_alias)?.render(false)
20}
21
22pub(crate) fn render_type_alias_with_eq<'a>(
23 ctx: RenderContext<'a>,
24 type_alias: hir::TypeAlias,
25) -> Option<CompletionItem> {
26 TypeAliasRender::new(ctx, type_alias)?.render(true)
20} 27}
21 28
22#[derive(Debug)] 29#[derive(Debug)]
@@ -32,8 +39,14 @@ impl<'a> TypeAliasRender<'a> {
32 Some(TypeAliasRender { ctx, type_alias, ast_node }) 39 Some(TypeAliasRender { ctx, type_alias, ast_node })
33 } 40 }
34 41
35 fn render(self) -> Option<CompletionItem> { 42 fn render(self, with_eq: bool) -> Option<CompletionItem> {
36 let name = self.name()?; 43 let name = self.ast_node.name().map(|name| {
44 if with_eq {
45 format!("{} = ", name.text())
46 } else {
47 name.text().to_string()
48 }
49 })?;
37 let detail = self.detail(); 50 let detail = self.detail();
38 51
39 let mut item = 52 let mut item =
@@ -49,10 +62,6 @@ impl<'a> TypeAliasRender<'a> {
49 Some(item.build()) 62 Some(item.build())
50 } 63 }
51 64
52 fn name(&self) -> Option<String> {
53 self.ast_node.name().map(|name| name.text().to_string())
54 }
55
56 fn detail(&self) -> String { 65 fn detail(&self) -> String {
57 type_label(&self.ast_node) 66 type_label(&self.ast_node)
58 } 67 }
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 6229996ec..e219c577a 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14log = "0.4.8" 14log = "0.4.8"
15rayon = "1.5.0" 15rayon = "1.5.0"
16fst = { version = "0.4", default-features = false } 16fst = { version = "0.4", default-features = false }
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 1b69d72f9..a54f2c323 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -369,7 +369,7 @@ impl NameRefClass {
369 } 369 }
370 370
371 if let Some(resolved) = sema.resolve_path(&path) { 371 if let Some(resolved) = sema.resolve_path(&path) {
372 if path.syntax().parent().and_then(ast::Attr::cast).is_some() { 372 if path.syntax().ancestors().find_map(ast::Attr::cast).is_some() {
373 if let PathResolution::Def(ModuleDef::Function(func)) = resolved { 373 if let PathResolution::Def(ModuleDef::Function(func)) = resolved {
374 if func.attrs(sema.db).by_key("proc_macro_attribute").exists() { 374 if func.attrs(sema.db).by_key("proc_macro_attribute").exists() {
375 return Some(NameRefClass::Definition(resolved.into())); 375 return Some(NameRefClass::Definition(resolved.into()));
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 67840602b..8152630f5 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -8,7 +8,8 @@ use std::{convert::TryInto, mem};
8 8
9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; 9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
10use hir::{ 10use hir::{
11 DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics, Visibility, 11 AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleDef, ModuleSource, Semantics,
12 Visibility,
12}; 13};
13use once_cell::unsync::Lazy; 14use once_cell::unsync::Lazy;
14use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
@@ -303,13 +304,13 @@ impl Definition {
303 } 304 }
304 } 305 }
305 306
306 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { 307 pub fn usages<'a>(self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
307 FindUsages { def: self, sema, scope: None, include_self_kw_refs: None } 308 FindUsages { def: self, sema, scope: None, include_self_kw_refs: None }
308 } 309 }
309} 310}
310 311
311pub struct FindUsages<'a> { 312pub struct FindUsages<'a> {
312 def: &'a Definition, 313 def: Definition,
313 sema: &'a Semantics<'a, RootDatabase>, 314 sema: &'a Semantics<'a, RootDatabase>,
314 scope: Option<SearchScope>, 315 scope: Option<SearchScope>,
315 include_self_kw_refs: Option<hir::Type>, 316 include_self_kw_refs: Option<hir::Type>,
@@ -318,7 +319,7 @@ pub struct FindUsages<'a> {
318impl<'a> FindUsages<'a> { 319impl<'a> FindUsages<'a> {
319 /// Enable searching for `Self` when the definition is a type. 320 /// Enable searching for `Self` when the definition is a type.
320 pub fn include_self_refs(mut self) -> FindUsages<'a> { 321 pub fn include_self_refs(mut self) -> FindUsages<'a> {
321 self.include_self_kw_refs = def_to_ty(self.sema, self.def); 322 self.include_self_kw_refs = def_to_ty(self.sema, &self.def);
322 self 323 self
323 } 324 }
324 325
@@ -445,7 +446,7 @@ impl<'a> FindUsages<'a> {
445 sink: &mut dyn FnMut(FileId, FileReference) -> bool, 446 sink: &mut dyn FnMut(FileId, FileReference) -> bool,
446 ) -> bool { 447 ) -> bool {
447 match NameRefClass::classify_lifetime(self.sema, lifetime) { 448 match NameRefClass::classify_lifetime(self.sema, lifetime) {
448 Some(NameRefClass::Definition(def)) if &def == self.def => { 449 Some(NameRefClass::Definition(def)) if def == self.def => {
449 let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); 450 let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax());
450 let reference = FileReference { 451 let reference = FileReference {
451 range, 452 range,
@@ -464,7 +465,7 @@ impl<'a> FindUsages<'a> {
464 sink: &mut dyn FnMut(FileId, FileReference) -> bool, 465 sink: &mut dyn FnMut(FileId, FileReference) -> bool,
465 ) -> bool { 466 ) -> bool {
466 match NameRefClass::classify(self.sema, &name_ref) { 467 match NameRefClass::classify(self.sema, &name_ref) {
467 Some(NameRefClass::Definition(def)) if &def == self.def => { 468 Some(NameRefClass::Definition(def)) if def == self.def => {
468 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); 469 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
469 let reference = FileReference { 470 let reference = FileReference {
470 range, 471 range,
@@ -489,10 +490,10 @@ impl<'a> FindUsages<'a> {
489 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => { 490 Some(NameRefClass::FieldShorthand { local_ref: local, field_ref: field }) => {
490 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); 491 let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
491 let access = match self.def { 492 let access = match self.def {
492 Definition::Field(_) if &field == self.def => { 493 Definition::Field(_) if field == self.def => {
493 reference_access(&field, &name_ref) 494 reference_access(&field, &name_ref)
494 } 495 }
495 Definition::Local(l) if &local == l => { 496 Definition::Local(l) if local == l => {
496 reference_access(&Definition::Local(local), &name_ref) 497 reference_access(&Definition::Local(local), &name_ref)
497 } 498 }
498 _ => return false, 499 _ => return false,
@@ -513,7 +514,7 @@ impl<'a> FindUsages<'a> {
513 match NameClass::classify(self.sema, name) { 514 match NameClass::classify(self.sema, name) {
514 Some(NameClass::PatFieldShorthand { local_def: _, field_ref }) 515 Some(NameClass::PatFieldShorthand { local_def: _, field_ref })
515 if matches!( 516 if matches!(
516 self.def, Definition::Field(_) if &field_ref == self.def 517 self.def, Definition::Field(_) if field_ref == self.def
517 ) => 518 ) =>
518 { 519 {
519 let FileRange { file_id, range } = self.sema.original_range(name.syntax()); 520 let FileRange { file_id, range } = self.sema.original_range(name.syntax());
@@ -525,12 +526,38 @@ impl<'a> FindUsages<'a> {
525 }; 526 };
526 sink(file_id, reference) 527 sink(file_id, reference)
527 } 528 }
528 Some(NameClass::ConstReference(def)) if *self.def == def => { 529 Some(NameClass::ConstReference(def)) if self.def == def => {
529 let FileRange { file_id, range } = self.sema.original_range(name.syntax()); 530 let FileRange { file_id, range } = self.sema.original_range(name.syntax());
530 let reference = 531 let reference =
531 FileReference { range, name: ast::NameLike::Name(name.clone()), access: None }; 532 FileReference { range, name: ast::NameLike::Name(name.clone()), access: None };
532 sink(file_id, reference) 533 sink(file_id, reference)
533 } 534 }
535 // Resolve trait impl function definitions to the trait definition's version if self.def is the trait definition's
536 Some(NameClass::Definition(Definition::ModuleDef(mod_def))) => {
537 /* poor man's try block */
538 (|| {
539 let this = match self.def {
540 Definition::ModuleDef(this) if this != mod_def => this,
541 _ => return None,
542 };
543 let this_trait = this
544 .as_assoc_item(self.sema.db)?
545 .containing_trait_or_trait_impl(self.sema.db)?;
546 let trait_ = mod_def
547 .as_assoc_item(self.sema.db)?
548 .containing_trait_or_trait_impl(self.sema.db)?;
549 (trait_ == this_trait).then(|| {
550 let FileRange { file_id, range } = self.sema.original_range(name.syntax());
551 let reference = FileReference {
552 range,
553 name: ast::NameLike::Name(name.clone()),
554 access: None,
555 };
556 sink(file_id, reference)
557 })
558 })()
559 .unwrap_or(false)
560 }
534 _ => false, 561 _ => false,
535 } 562 }
536 } 563 }
diff --git a/crates/ide_ssr/Cargo.toml b/crates/ide_ssr/Cargo.toml
index 5d2221ebc..727d17bac 100644
--- a/crates/ide_ssr/Cargo.toml
+++ b/crates/ide_ssr/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2018"
11doctest = false 11doctest = false
12 12
13[dependencies] 13[dependencies]
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = "2.0.0-pre.1"
15rustc-hash = "1.1.0" 15rustc-hash = "1.1.0"
16itertools = "0.10.0" 16itertools = "0.10.0"
17 17
diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml
index 8856787c0..f3092d9aa 100644
--- a/crates/mbe/Cargo.toml
+++ b/crates/mbe/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15smallvec = "1.2.0" 15smallvec = "1.2.0"
16log = "0.4.8" 16log = "0.4.8"
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
index 5f173f513..75c88687c 100644
--- a/crates/mbe/src/tests/expand.rs
+++ b/crates/mbe/src/tests/expand.rs
@@ -1846,16 +1846,17 @@ fn test_no_space_after_semi_colon() {
1846 [email protected] 1846 [email protected]
1847 [email protected] "#" 1847 [email protected] "#"
1848 [email protected] "[" 1848 [email protected] "["
1849 [email protected] 1849 [email protected]
1850 [email protected] 1850 [email protected]
1851 [email protected] 1851 [email protected]
1852 [email protected] "cfg" 1852 [email protected]
1853 [email protected] 1853 [email protected] "cfg"
1854 [email protected] "(" 1854 [email protected]
1855 [email protected] "feature" 1855 [email protected] "("
1856 [email protected] "=" 1856 [email protected] "feature"
1857 [email protected] "\"std\"" 1857 [email protected] "="
1858 [email protected] ")" 1858 [email protected] "\"std\""
1859 [email protected] ")"
1859 [email protected] "]" 1860 [email protected] "]"
1860 [email protected] "mod" 1861 [email protected] "mod"
1861 [email protected] 1862 [email protected]
@@ -1865,16 +1866,17 @@ fn test_no_space_after_semi_colon() {
1865 [email protected] 1866 [email protected]
1866 [email protected] "#" 1867 [email protected] "#"
1867 [email protected] "[" 1868 [email protected] "["
1868 [email protected] 1869 [email protected]
1869 [email protected] 1870 [email protected]
1870 [email protected] 1871 [email protected]
1871 [email protected] "cfg" 1872 [email protected]
1872 [email protected] 1873 [email protected] "cfg"
1873 [email protected] "(" 1874 [email protected]
1874 [email protected] "feature" 1875 [email protected] "("
1875 [email protected] "=" 1876 [email protected] "feature"
1876 [email protected] "\"std\"" 1877 [email protected] "="
1877 [email protected] ")" 1878 [email protected] "\"std\""
1879 [email protected] ")"
1878 [email protected] "]" 1880 [email protected] "]"
1879 [email protected] "mod" 1881 [email protected] "mod"
1880 [email protected] 1882 [email protected]
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs
index b8242cd2f..a44c5e484 100644
--- a/crates/parser/src/grammar/attributes.rs
+++ b/crates/parser/src/grammar/attributes.rs
@@ -13,6 +13,7 @@ pub(super) fn outer_attrs(p: &mut Parser) {
13} 13}
14 14
15pub(super) fn meta(p: &mut Parser) { 15pub(super) fn meta(p: &mut Parser) {
16 let meta = p.start();
16 paths::use_path(p); 17 paths::use_path(p);
17 18
18 match p.current() { 19 match p.current() {
@@ -25,6 +26,8 @@ pub(super) fn meta(p: &mut Parser) {
25 T!['('] | T!['['] | T!['{'] => items::token_tree(p), 26 T!['('] | T!['['] | T!['{'] => items::token_tree(p),
26 _ => {} 27 _ => {}
27 } 28 }
29
30 meta.complete(p, META);
28} 31}
29 32
30fn attr(p: &mut Parser, inner: bool) { 33fn attr(p: &mut Parser, inner: bool) {
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index bcefd183a..5f10b82de 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -220,7 +220,7 @@ pub enum SyntaxKind {
220 ITEM_LIST, 220 ITEM_LIST,
221 ASSOC_ITEM_LIST, 221 ASSOC_ITEM_LIST,
222 ATTR, 222 ATTR,
223 META_ITEM, 223 META,
224 USE_TREE, 224 USE_TREE,
225 USE_TREE_LIST, 225 USE_TREE_LIST,
226 PATH, 226 PATH,
diff --git a/crates/profile/src/memory_usage.rs b/crates/profile/src/memory_usage.rs
index 6ef58c9c1..fbcb9e3c2 100644
--- a/crates/profile/src/memory_usage.rs
+++ b/crates/profile/src/memory_usage.rs
@@ -32,9 +32,7 @@ impl MemoryUsage {
32 allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize), 32 allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
33 } 33 }
34 } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] { 34 } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
35 // Note: This is incredibly slow. 35 memusage_linux()
36 let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
37 MemoryUsage { allocated: Bytes(alloc) }
38 } else if #[cfg(windows)] { 36 } else if #[cfg(windows)] {
39 // There doesn't seem to be an API for determining heap usage, so we try to 37 // There doesn't seem to be an API for determining heap usage, so we try to
40 // approximate that by using the Commit Charge value. 38 // approximate that by using the Commit Charge value.
@@ -58,6 +56,37 @@ impl MemoryUsage {
58 } 56 }
59} 57}
60 58
59#[cfg(all(target_os = "linux", target_env = "gnu", not(feature = "jemalloc")))]
60fn memusage_linux() -> MemoryUsage {
61 // Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2.
62 // mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB.
63 // mallinfo2 is very recent, so its presence needs to be detected at runtime.
64 // Both are abysmally slow.
65
66 use std::ffi::CStr;
67 use std::sync::atomic::{AtomicUsize, Ordering};
68
69 static MALLINFO2: AtomicUsize = AtomicUsize::new(1);
70
71 let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed);
72 if mallinfo2 == 1 {
73 let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap();
74 mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize;
75 // NB: races don't matter here, since they'll always store the same value
76 MALLINFO2.store(mallinfo2, Ordering::Relaxed);
77 }
78
79 if mallinfo2 == 0 {
80 // mallinfo2 does not exist, use mallinfo.
81 let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
82 MemoryUsage { allocated: Bytes(alloc) }
83 } else {
84 let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) };
85 let alloc = mallinfo2().uordblks as isize;
86 MemoryUsage { allocated: Bytes(alloc) }
87 }
88}
89
61#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] 90#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
62pub struct Bytes(isize); 91pub struct Bytes(isize);
63 92
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 2106732cd..f1525a649 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2018"
11doctest = false 11doctest = false
12 12
13[dependencies] 13[dependencies]
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = "2.0.0-pre.1"
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "=0.13.0-pre.6" 16rowan = "=0.13.0-pre.6"
17rustc_lexer = { version = "721.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "721.0.0", package = "rustc-ap-rustc_lexer" }
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 9a88fdb56..702de59a9 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -150,10 +150,7 @@ impl Attr {
150 pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } 150 pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) }
151 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } 151 pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) }
152 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } 152 pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) }
153 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } 153 pub fn meta(&self) -> Option<Meta> { support::child(&self.syntax) }
154 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
155 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
156 pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
157 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } 154 pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) }
158} 155}
159#[derive(Debug, Clone, PartialEq, Eq, Hash)] 156#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -632,6 +629,16 @@ impl WherePred {
632 pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } 629 pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
633} 630}
634#[derive(Debug, Clone, PartialEq, Eq, Hash)] 631#[derive(Debug, Clone, PartialEq, Eq, Hash)]
632pub struct Meta {
633 pub(crate) syntax: SyntaxNode,
634}
635impl Meta {
636 pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
637 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
638 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
639 pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
640}
641#[derive(Debug, Clone, PartialEq, Eq, Hash)]
635pub struct ExprStmt { 642pub struct ExprStmt {
636 pub(crate) syntax: SyntaxNode, 643 pub(crate) syntax: SyntaxNode,
637} 644}
@@ -2072,6 +2079,17 @@ impl AstNode for WherePred {
2072 } 2079 }
2073 fn syntax(&self) -> &SyntaxNode { &self.syntax } 2080 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2074} 2081}
2082impl AstNode for Meta {
2083 fn can_cast(kind: SyntaxKind) -> bool { kind == META }
2084 fn cast(syntax: SyntaxNode) -> Option<Self> {
2085 if Self::can_cast(syntax.kind()) {
2086 Some(Self { syntax })
2087 } else {
2088 None
2089 }
2090 }
2091 fn syntax(&self) -> &SyntaxNode { &self.syntax }
2092}
2075impl AstNode for ExprStmt { 2093impl AstNode for ExprStmt {
2076 fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT } 2094 fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT }
2077 fn cast(syntax: SyntaxNode) -> Option<Self> { 2095 fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3887,6 +3905,11 @@ impl std::fmt::Display for WherePred {
3887 std::fmt::Display::fmt(self.syntax(), f) 3905 std::fmt::Display::fmt(self.syntax(), f)
3888 } 3906 }
3889} 3907}
3908impl std::fmt::Display for Meta {
3909 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3910 std::fmt::Display::fmt(self.syntax(), f)
3911 }
3912}
3890impl std::fmt::Display for ExprStmt { 3913impl std::fmt::Display for ExprStmt {
3891 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 3914 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3892 std::fmt::Display::fmt(self.syntax(), f) 3915 std::fmt::Display::fmt(self.syntax(), f)
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index a60bc5ad9..3d27d2c1a 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -144,19 +144,20 @@ impl AttrKind {
144 144
145impl ast::Attr { 145impl ast::Attr {
146 pub fn as_simple_atom(&self) -> Option<SmolStr> { 146 pub fn as_simple_atom(&self) -> Option<SmolStr> {
147 if self.eq_token().is_some() || self.token_tree().is_some() { 147 let meta = self.meta()?;
148 if meta.eq_token().is_some() || meta.token_tree().is_some() {
148 return None; 149 return None;
149 } 150 }
150 self.simple_name() 151 self.simple_name()
151 } 152 }
152 153
153 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> { 154 pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
154 let tt = self.token_tree()?; 155 let tt = self.meta()?.token_tree()?;
155 Some((self.simple_name()?, tt)) 156 Some((self.simple_name()?, tt))
156 } 157 }
157 158
158 pub fn simple_name(&self) -> Option<SmolStr> { 159 pub fn simple_name(&self) -> Option<SmolStr> {
159 let path = self.path()?; 160 let path = self.meta()?.path()?;
160 match (path.segment(), path.qualifier()) { 161 match (path.segment(), path.qualifier()) {
161 (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()), 162 (Some(segment), None) => Some(segment.syntax().first_token()?.text().into()),
162 _ => None, 163 _ => None,
@@ -174,6 +175,18 @@ impl ast::Attr {
174 _ => AttrKind::Outer, 175 _ => AttrKind::Outer,
175 } 176 }
176 } 177 }
178
179 pub fn path(&self) -> Option<ast::Path> {
180 self.meta()?.path()
181 }
182
183 pub fn expr(&self) -> Option<ast::Expr> {
184 self.meta()?.expr()
185 }
186
187 pub fn token_tree(&self) -> Option<ast::TokenTree> {
188 self.meta()?.token_tree()
189 }
177} 190}
178 191
179#[derive(Debug, Clone, PartialEq, Eq)] 192#[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/crates/syntax/test_data/parser/err/0005_attribute_recover.rast b/crates/syntax/test_data/parser/err/0005_attribute_recover.rast
index 4845a6563..6202c8bfe 100644
--- a/crates/syntax/test_data/parser/err/0005_attribute_recover.rast
+++ b/crates/syntax/test_data/parser/err/0005_attribute_recover.rast
@@ -3,20 +3,21 @@ [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "#" 4 [email protected] "#"
5 [email protected] "[" 5 [email protected] "["
6 [email protected] 6 [email protected]
7 [email protected] 7 [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "foo" 9 [email protected]
10 [email protected] 10 [email protected] "foo"
11 [email protected] "(" 11 [email protected]
12 [email protected] "foo" 12 [email protected] "("
13 [email protected] "," 13 [email protected] "foo"
14 [email protected] " " 14 [email protected] ","
15 [email protected] "+" 15 [email protected] " "
16 [email protected] "," 16 [email protected] "+"
17 [email protected] " " 17 [email protected] ","
18 [email protected] "92" 18 [email protected] " "
19 [email protected] ")" 19 [email protected] "92"
20 [email protected] ")"
20 [email protected] "]" 21 [email protected] "]"
21 [email protected] "\n" 22 [email protected] "\n"
22 [email protected] "fn" 23 [email protected] "fn"
@@ -35,24 +36,25 @@ [email protected]
35 [email protected] 36 [email protected]
36 [email protected] "#" 37 [email protected] "#"
37 [email protected] "[" 38 [email protected] "["
38 [email protected] 39 [email protected]
39 [email protected] 40 [email protected]
40 [email protected] 41 [email protected]
41 [email protected] "foo" 42 [email protected]
42 [email protected] 43 [email protected] "foo"
43 [email protected] "(" 44 [email protected]
44 [email protected] "\n" 45 [email protected] "("
45 [email protected] "fn" 46 [email protected] "\n"
46 [email protected] " " 47 [email protected] "fn"
47 [email protected] "foo" 48 [email protected] " "
48 [email protected] 49 [email protected] "foo"
49 [email protected] "(" 50 [email protected]
50 [email protected] ")" 51 [email protected] "("
51 [email protected] " " 52 [email protected] ")"
52 [email protected] 53 [email protected] " "
53 [email protected] "{" 54 [email protected]
54 [email protected] "\n" 55 [email protected] "{"
55 [email protected] "}" 56 [email protected] "\n"
57 [email protected] "}"
56 [email protected] "\n" 58 [email protected] "\n"
57error 53..53: expected R_PAREN 59error 53..53: expected R_PAREN
58error 53..53: expected `]` 60error 53..53: expected `]`
diff --git a/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast b/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast
index a443b37db..846279748 100644
--- a/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast
+++ b/crates/syntax/test_data/parser/err/0031_block_inner_attrs.rast
@@ -27,14 +27,15 @@ [email protected]
27 [email protected] "#" 27 [email protected] "#"
28 [email protected] "!" 28 [email protected] "!"
29 [email protected] "[" 29 [email protected] "["
30 [email protected] 30 [email protected]
31 [email protected] 31 [email protected]
32 [email protected] 32 [email protected]
33 [email protected] "doc" 33 [email protected]
34 [email protected] 34 [email protected] "doc"
35 [email protected] "(" 35 [email protected]
36 [email protected] "\"Inner attributes not ..." 36 [email protected] "("
37 [email protected] ")" 37 [email protected] "\"Inner attributes not ..."
38 [email protected] ")"
38 [email protected] "]" 39 [email protected] "]"
39 [email protected] "\n " 40 [email protected] "\n "
40 [email protected] "//! Nor are ModuleDoc ..." 41 [email protected] "//! Nor are ModuleDoc ..."
@@ -57,28 +58,30 @@ [email protected]
57 [email protected] "#" 58 [email protected] "#"
58 [email protected] "!" 59 [email protected] "!"
59 [email protected] "[" 60 [email protected] "["
60 [email protected] 61 [email protected]
61 [email protected] 62 [email protected]
62 [email protected] 63 [email protected]
63 [email protected] "doc" 64 [email protected]
64 [email protected] 65 [email protected] "doc"
65 [email protected] "(" 66 [email protected]
66 [email protected] "\"Nor here\"" 67 [email protected] "("
67 [email protected] ")" 68 [email protected] "\"Nor here\""
69 [email protected] ")"
68 [email protected] "]" 70 [email protected] "]"
69 [email protected] "\n " 71 [email protected] "\n "
70 [email protected] 72 [email protected]
71 [email protected] "#" 73 [email protected] "#"
72 [email protected] "!" 74 [email protected] "!"
73 [email protected] "[" 75 [email protected] "["
74 [email protected] 76 [email protected]
75 [email protected] 77 [email protected]
76 [email protected] 78 [email protected]
77 [email protected] "doc" 79 [email protected]
78 [email protected] 80 [email protected] "doc"
79 [email protected] "(" 81 [email protected]
80 [email protected] "\"We error on each attr\"" 82 [email protected] "("
81 [email protected] ")" 83 [email protected] "\"We error on each attr\""
84 [email protected] ")"
82 [email protected] "]" 85 [email protected] "]"
83 [email protected] "\n " 86 [email protected] "\n "
84 [email protected] "//! Nor are ModuleDoc ..." 87 [email protected] "//! Nor are ModuleDoc ..."
@@ -99,14 +102,15 @@ [email protected]
99 [email protected] "#" 102 [email protected] "#"
100 [email protected] "!" 103 [email protected] "!"
101 [email protected] "[" 104 [email protected] "["
102 [email protected] 105 [email protected]
103 [email protected] 106 [email protected]
104 [email protected] 107 [email protected]
105 [email protected] "doc" 108 [email protected]
106 [email protected] 109 [email protected] "doc"
107 [email protected] "(" 110 [email protected]
108 [email protected] "\"Nor here\"" 111 [email protected] "("
109 [email protected] ")" 112 [email protected] "\"Nor here\""
113 [email protected] ")"
110 [email protected] "]" 114 [email protected] "]"
111 [email protected] "\n " 115 [email protected] "\n "
112 [email protected] "//! Nor are ModuleDoc ..." 116 [email protected] "//! Nor are ModuleDoc ..."
diff --git a/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast b/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast
index 672dd054a..b6209639d 100644
--- a/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast
+++ b/crates/syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast
@@ -135,14 +135,15 @@ [email protected]
135 [email protected] 135 [email protected]
136 [email protected] "#" 136 [email protected] "#"
137 [email protected] "[" 137 [email protected] "["
138 [email protected] 138 [email protected]
139 [email protected] 139 [email protected]
140 [email protected] 140 [email protected]
141 [email protected] "cfg" 141 [email protected]
142 [email protected] 142 [email protected] "cfg"
143 [email protected] "(" 143 [email protected]
144 [email protected] "test" 144 [email protected] "("
145 [email protected] ")" 145 [email protected] "test"
146 [email protected] ")"
146 [email protected] "]" 147 [email protected] "]"
147 [email protected] "\n " 148 [email protected] "\n "
148 [email protected] 149 [email protected]
diff --git a/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast b/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast
index 33bb085e9..84c8e9ee7 100644
--- a/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast
+++ b/crates/syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast
@@ -47,14 +47,15 @@ [email protected]
47 [email protected] 47 [email protected]
48 [email protected] "#" 48 [email protected] "#"
49 [email protected] "[" 49 [email protected] "["
50 [email protected] 50 [email protected]
51 [email protected] 51 [email protected]
52 [email protected] 52 [email protected]
53 [email protected] "cfg" 53 [email protected]
54 [email protected] 54 [email protected] "cfg"
55 [email protected] "(" 55 [email protected]
56 [email protected] "test" 56 [email protected] "("
57 [email protected] ")" 57 [email protected] "test"
58 [email protected] ")"
58 [email protected] "]" 59 [email protected] "]"
59 [email protected] "\n " 60 [email protected] "\n "
60 [email protected] "}" 61 [email protected] "}"
diff --git a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast b/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast
index 8fd8d5e59..7b8b7284f 100644
--- a/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast
+++ b/crates/syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast
@@ -15,10 +15,11 @@ [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "#" 16 [email protected] "#"
17 [email protected] "[" 17 [email protected] "["
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
20 [email protected] 20 [email protected]
21 [email protected] "A" 21 [email protected]
22 [email protected] "A"
22 [email protected] "]" 23 [email protected] "]"
23 [email protected] " " 24 [email protected] " "
24 [email protected] 25 [email protected]
@@ -35,10 +36,11 @@ [email protected]
35 [email protected] 36 [email protected]
36 [email protected] "#" 37 [email protected] "#"
37 [email protected] "[" 38 [email protected] "["
38 [email protected] 39 [email protected]
39 [email protected] 40 [email protected]
40 [email protected] 41 [email protected]
41 [email protected] "B" 42 [email protected]
43 [email protected] "B"
42 [email protected] "]" 44 [email protected] "]"
43 [email protected] " " 45 [email protected] " "
44 [email protected] 46 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast
index 9ae271817..402950bcc 100644
--- a/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast
@@ -12,18 +12,19 @@ [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "#" 13 [email protected] "#"
14 [email protected] "[" 14 [email protected] "["
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "serde" 18 [email protected]
19 [email protected] 19 [email protected] "serde"
20 [email protected] "(" 20 [email protected]
21 [email protected] "with" 21 [email protected] "("
22 [email protected] " " 22 [email protected] "with"
23 [email protected] "=" 23 [email protected] " "
24 [email protected] " " 24 [email protected] "="
25 [email protected] "\"url_serde\"" 25 [email protected] " "
26 [email protected] ")" 26 [email protected] "\"url_serde\""
27 [email protected] ")"
27 [email protected] "]" 28 [email protected] "]"
28 [email protected] "\n " 29 [email protected] "\n "
29 [email protected] 30 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
index 4d09c9f50..db2b645b0 100644
--- a/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
@@ -12,18 +12,19 @@ [email protected]
12 [email protected] 12 [email protected]
13 [email protected] "#" 13 [email protected] "#"
14 [email protected] "[" 14 [email protected] "["
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "serde" 18 [email protected]
19 [email protected] 19 [email protected] "serde"
20 [email protected] "(" 20 [email protected]
21 [email protected] "with" 21 [email protected] "("
22 [email protected] " " 22 [email protected] "with"
23 [email protected] "=" 23 [email protected] " "
24 [email protected] " " 24 [email protected] "="
25 [email protected] "\"url_serde\"" 25 [email protected] " "
26 [email protected] ")" 26 [email protected] "\"url_serde\""
27 [email protected] ")"
27 [email protected] "]" 28 [email protected] "]"
28 [email protected] "\n " 29 [email protected] "\n "
29 [email protected] 30 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast b/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast
index 141a7b203..24ac1d66a 100644
--- a/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast
@@ -26,14 +26,15 @@ [email protected]
26 [email protected] "#" 26 [email protected] "#"
27 [email protected] "!" 27 [email protected] "!"
28 [email protected] "[" 28 [email protected] "["
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] 31 [email protected]
32 [email protected] "doc" 32 [email protected]
33 [email protected] 33 [email protected] "doc"
34 [email protected] "(" 34 [email protected]
35 [email protected] "\"This is also a doc c ..." 35 [email protected] "("
36 [email protected] ")" 36 [email protected] "\"This is also a doc c ..."
37 [email protected] ")"
37 [email protected] "]" 38 [email protected] "]"
38 [email protected] "\n" 39 [email protected] "\n"
39 [email protected] "}" 40 [email protected] "}"
diff --git a/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast b/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
index ec7a00f1d..7fbeee203 100644
--- a/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
@@ -25,42 +25,45 @@ [email protected]
25 [email protected] "#" 25 [email protected] "#"
26 [email protected] "!" 26 [email protected] "!"
27 [email protected] "[" 27 [email protected] "["
28 [email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] "doc" 31 [email protected]
32 [email protected] 32 [email protected] "doc"
33 [email protected] "(" 33 [email protected]
34 [email protected] "\"Inner attribute\"" 34 [email protected] "("
35 [email protected] ")" 35 [email protected] "\"Inner attribute\""
36 [email protected] ")"
36 [email protected] "]" 37 [email protected] "]"
37 [email protected] "\n " 38 [email protected] "\n "
38 [email protected] 39 [email protected]
39 [email protected] "#" 40 [email protected] "#"
40 [email protected] "!" 41 [email protected] "!"
41 [email protected] "[" 42 [email protected] "["
42 [email protected] 43 [email protected]
43 [email protected] 44 [email protected]
44 [email protected] 45 [email protected]
45 [email protected] "doc" 46 [email protected]
46 [email protected] 47 [email protected] "doc"
47 [email protected] "(" 48 [email protected]
48 [email protected] "\"Can be\"" 49 [email protected] "("
49 [email protected] ")" 50 [email protected] "\"Can be\""
51 [email protected] ")"
50 [email protected] "]" 52 [email protected] "]"
51 [email protected] "\n " 53 [email protected] "\n "
52 [email protected] 54 [email protected]
53 [email protected] "#" 55 [email protected] "#"
54 [email protected] "!" 56 [email protected] "!"
55 [email protected] "[" 57 [email protected] "["
56 [email protected] 58 [email protected]
57 [email protected] 59 [email protected]
58 [email protected] 60 [email protected]
59 [email protected] "doc" 61 [email protected]
60 [email protected] 62 [email protected] "doc"
61 [email protected] "(" 63 [email protected]
62 [email protected] "\"Stacked\"" 64 [email protected] "("
63 [email protected] ")" 65 [email protected] "\"Stacked\""
66 [email protected] ")"
64 [email protected] "]" 67 [email protected] "]"
65 [email protected] "\n " 68 [email protected] "\n "
66 [email protected] 69 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast b/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
index 97924da05..40852f514 100644
--- a/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
@@ -25,18 +25,19 @@ [email protected]
25 [email protected] 25 [email protected]
26 [email protected] "#" 26 [email protected] "#"
27 [email protected] "[" 27 [email protected] "["
28 [email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] 30 [email protected]
31 [email protected] "cfg" 31 [email protected]
32 [email protected] 32 [email protected] "cfg"
33 [email protected] "(" 33 [email protected]
34 [email protected] "feature" 34 [email protected] "("
35 [email protected] " " 35 [email protected] "feature"
36 [email protected] "=" 36 [email protected] " "
37 [email protected] " " 37 [email protected] "="
38 [email protected] "\"some\"" 38 [email protected] " "
39 [email protected] ")" 39 [email protected] "\"some\""
40 [email protected] ")"
40 [email protected] "]" 41 [email protected] "]"
41 [email protected] "\n " 42 [email protected] "\n "
42 [email protected] 43 [email protected]
@@ -53,18 +54,19 @@ [email protected]
53 [email protected] 54 [email protected]
54 [email protected] "#" 55 [email protected] "#"
55 [email protected] "[" 56 [email protected] "["
56 [email protected] 57 [email protected]
57 [email protected] 58 [email protected]
58 [email protected] 59 [email protected]
59 [email protected] "cfg" 60 [email protected]
60 [email protected] 61 [email protected] "cfg"
61 [email protected] "(" 62 [email protected]
62 [email protected] "feature" 63 [email protected] "("
63 [email protected] " " 64 [email protected] "feature"
64 [email protected] "=" 65 [email protected] " "
65 [email protected] " " 66 [email protected] "="
66 [email protected] "\"other\"" 67 [email protected] " "
67 [email protected] ")" 68 [email protected] "\"other\""
69 [email protected] ")"
68 [email protected] "]" 70 [email protected] "]"
69 [email protected] "\n " 71 [email protected] "\n "
70 [email protected] 72 [email protected]
@@ -81,52 +83,55 @@ [email protected]
81 [email protected] 83 [email protected]
82 [email protected] "#" 84 [email protected] "#"
83 [email protected] "[" 85 [email protected] "["
84 [email protected] 86 [email protected]
85 [email protected] 87 [email protected]
86 [email protected] 88 [email protected]
87 [email protected] "cfg" 89 [email protected]
88 [email protected] 90 [email protected] "cfg"
89 [email protected] "(" 91 [email protected]
90 [email protected] "feature" 92 [email protected] "("
91 [email protected] " " 93 [email protected] "feature"
92 [email protected] "=" 94 [email protected] " "
93 [email protected] " " 95 [email protected] "="
94 [email protected] "\"many\"" 96 [email protected] " "
95 [email protected] ")" 97 [email protected] "\"many\""
98 [email protected] ")"
96 [email protected] "]" 99 [email protected] "]"
97 [email protected] "\n " 100 [email protected] "\n "
98 [email protected] 101 [email protected]
99 [email protected] "#" 102 [email protected] "#"
100 [email protected] "[" 103 [email protected] "["
101 [email protected] 104 [email protected]
102 [email protected] 105 [email protected]
103 [email protected] 106 [email protected]
104 [email protected] "cfg" 107 [email protected]
105 [email protected] 108 [email protected] "cfg"
106 [email protected] "(" 109 [email protected]
107 [email protected] "feature" 110 [email protected] "("
108 [email protected] " " 111 [email protected] "feature"
109 [email protected] "=" 112 [email protected] " "
110 [email protected] " " 113 [email protected] "="
111 [email protected] "\"attributes\"" 114 [email protected] " "
112 [email protected] ")" 115 [email protected] "\"attributes\""
116 [email protected] ")"
113 [email protected] "]" 117 [email protected] "]"
114 [email protected] "\n " 118 [email protected] "\n "
115 [email protected] 119 [email protected]
116 [email protected] "#" 120 [email protected] "#"
117 [email protected] "[" 121 [email protected] "["
118 [email protected] 122 [email protected]
119 [email protected] 123 [email protected]
120 [email protected] 124 [email protected]
121 [email protected] "cfg" 125 [email protected]
122 [email protected] 126 [email protected] "cfg"
123 [email protected] "(" 127 [email protected]
124 [email protected] "feature" 128 [email protected] "("
125 [email protected] " " 129 [email protected] "feature"
126 [email protected] "=" 130 [email protected] " "
127 [email protected] " " 131 [email protected] "="
128 [email protected] "\"before\"" 132 [email protected] " "
129 [email protected] ")" 133 [email protected] "\"before\""
134 [email protected] ")"
130 [email protected] "]" 135 [email protected] "]"
131 [email protected] "\n " 136 [email protected] "\n "
132 [email protected] 137 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
index 616aa984e..840181383 100644
--- a/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast
@@ -10,14 +10,15 @@ [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "#" 11 [email protected] "#"
12 [email protected] "[" 12 [email protected] "["
13 [email protected] 13 [email protected]
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "derive" 16 [email protected]
17 [email protected] 17 [email protected] "derive"
18 [email protected] "(" 18 [email protected]
19 [email protected] "Lifetime" 19 [email protected] "("
20 [email protected] ")" 20 [email protected] "Lifetime"
21 [email protected] ")"
21 [email protected] "]" 22 [email protected] "]"
22 [email protected] " " 23 [email protected] " "
23 [email protected] 24 [email protected]
@@ -28,14 +29,15 @@ [email protected]
28 [email protected] 29 [email protected]
29 [email protected] "#" 30 [email protected] "#"
30 [email protected] "[" 31 [email protected] "["
31 [email protected] 32 [email protected]
32 [email protected] 33 [email protected]
33 [email protected] 34 [email protected]
34 [email protected] "derive" 35 [email protected]
35 [email protected] 36 [email protected] "derive"
36 [email protected] "(" 37 [email protected]
37 [email protected] "Type" 38 [email protected] "("
38 [email protected] ")" 39 [email protected] "Type"
40 [email protected] ")"
39 [email protected] "]" 41 [email protected] "]"
40 [email protected] " " 42 [email protected] " "
41 [email protected] 43 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast b/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
index 54ea2c7c6..5e82214c0 100644
--- a/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
@@ -24,14 +24,15 @@ [email protected]
24 [email protected] 24 [email protected]
25 [email protected] "#" 25 [email protected] "#"
26 [email protected] "[" 26 [email protected] "["
27 [email protected] 27 [email protected]
28 [email protected] 28 [email protected]
29 [email protected] 29 [email protected]
30 [email protected] "cfg" 30 [email protected]
31 [email protected] 31 [email protected] "cfg"
32 [email protected] "(" 32 [email protected]
33 [email protected] "test" 33 [email protected] "("
34 [email protected] ")" 34 [email protected] "test"
35 [email protected] ")"
35 [email protected] "]" 36 [email protected] "]"
36 [email protected] " " 37 [email protected] " "
37 [email protected] 38 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast b/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
index 0342e64f3..178204fec 100644
--- a/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
@@ -15,10 +15,11 @@ [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "#" 16 [email protected] "#"
17 [email protected] "[" 17 [email protected] "["
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
20 [email protected] 20 [email protected]
21 [email protected] "A" 21 [email protected]
22 [email protected] "A"
22 [email protected] "]" 23 [email protected] "]"
23 [email protected] " " 24 [email protected] " "
24 [email protected] 25 [email protected]
@@ -36,10 +37,11 @@ [email protected]
36 [email protected] 37 [email protected]
37 [email protected] "#" 38 [email protected] "#"
38 [email protected] "[" 39 [email protected] "["
39 [email protected] 40 [email protected]
40 [email protected] 41 [email protected]
41 [email protected] 42 [email protected]
42 [email protected] "B" 43 [email protected]
44 [email protected] "B"
43 [email protected] "]" 45 [email protected] "]"
44 [email protected] " " 46 [email protected] " "
45 [email protected] 47 [email protected]
@@ -56,19 +58,21 @@ [email protected]
56 [email protected] 58 [email protected]
57 [email protected] "#" 59 [email protected] "#"
58 [email protected] "[" 60 [email protected] "["
59 [email protected] 61 [email protected]
60 [email protected] 62 [email protected]
61 [email protected] 63 [email protected]
62 [email protected] "C" 64 [email protected]
65 [email protected] "C"
63 [email protected] "]" 66 [email protected] "]"
64 [email protected] " " 67 [email protected] " "
65 [email protected] 68 [email protected]
66 [email protected] "#" 69 [email protected] "#"
67 [email protected] "[" 70 [email protected] "["
68 [email protected] 71 [email protected]
69 [email protected] 72 [email protected]
70 [email protected] 73 [email protected]
71 [email protected] "D" 74 [email protected]
75 [email protected] "D"
72 [email protected] "]" 76 [email protected] "]"
73 [email protected] " " 77 [email protected] " "
74 [email protected] 78 [email protected]
@@ -79,10 +83,11 @@ [email protected]
79 [email protected] 83 [email protected]
80 [email protected] "#" 84 [email protected] "#"
81 [email protected] "[" 85 [email protected] "["
82 [email protected] 86 [email protected]
83 [email protected] 87 [email protected]
84 [email protected] 88 [email protected]
85 [email protected] "D" 89 [email protected]
90 [email protected] "D"
86 [email protected] "]" 91 [email protected] "]"
87 [email protected] " " 92 [email protected] " "
88 [email protected] 93 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast b/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast
index 3b46e5b47..9daac234a 100644
--- a/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast
@@ -19,10 +19,11 @@ [email protected]
19 [email protected] 19 [email protected]
20 [email protected] "#" 20 [email protected] "#"
21 [email protected] "[" 21 [email protected] "["
22 [email protected] 22 [email protected]
23 [email protected] 23 [email protected]
24 [email protected] 24 [email protected]
25 [email protected] "A" 25 [email protected]
26 [email protected] "A"
26 [email protected] "]" 27 [email protected] "]"
27 [email protected] " " 28 [email protected] " "
28 [email protected] 29 [email protected]
@@ -42,10 +43,11 @@ [email protected]
42 [email protected] 43 [email protected]
43 [email protected] "#" 44 [email protected] "#"
44 [email protected] "[" 45 [email protected] "["
45 [email protected] 46 [email protected]
46 [email protected] 47 [email protected]
47 [email protected] 48 [email protected]
48 [email protected] "B" 49 [email protected]
50 [email protected] "B"
49 [email protected] "]" 51 [email protected] "]"
50 [email protected] " " 52 [email protected] " "
51 [email protected] "&" 53 [email protected] "&"
diff --git a/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast b/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast
index 4c07cefa6..c3a79836a 100644
--- a/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0130_let_stmt.rast
@@ -109,10 +109,11 @@ [email protected]
109 [email protected] 109 [email protected]
110 [email protected] "#" 110 [email protected] "#"
111 [email protected] "[" 111 [email protected] "["
112 [email protected] 112 [email protected]
113 [email protected] 113 [email protected]
114 [email protected] 114 [email protected]
115 [email protected] "attr" 115 [email protected]
116 [email protected] "attr"
116 [email protected] "]" 117 [email protected] "]"
117 [email protected] 118 [email protected]
118 [email protected] "|" 119 [email protected] "|"
diff --git a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
index c54e64e3f..891eace59 100644
--- a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
@@ -10,10 +10,11 @@ [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "#" 11 [email protected] "#"
12 [email protected] "[" 12 [email protected] "["
13 [email protected] 13 [email protected]
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "must_use" 16 [email protected]
17 [email protected] "must_use"
17 [email protected] "]" 18 [email protected] "]"
18 [email protected] " " 19 [email protected] " "
19 [email protected] 20 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast b/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
index a84088bf3..a363e592b 100644
--- a/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast
@@ -10,10 +10,11 @@ [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "#" 11 [email protected] "#"
12 [email protected] "[" 12 [email protected] "["
13 [email protected] 13 [email protected]
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "attr1" 16 [email protected]
17 [email protected] "attr1"
17 [email protected] "]" 18 [email protected] "]"
18 [email protected] " " 19 [email protected] " "
19 [email protected] 20 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast
index e9202a612..c606a7c9b 100644
--- a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast
@@ -87,17 +87,18 @@ [email protected]
87 [email protected] 87 [email protected]
88 [email protected] "#" 88 [email protected] "#"
89 [email protected] "[" 89 [email protected] "["
90 [email protected] 90 [email protected]
91 [email protected] 91 [email protected]
92 [email protected] 92 [email protected]
93 [email protected] "cfg" 93 [email protected]
94 [email protected] 94 [email protected] "cfg"
95 [email protected] "(" 95 [email protected]
96 [email protected] "any" 96 [email protected] "("
97 [email protected] 97 [email protected] "any"
98 [email protected] "(" 98 [email protected]
99 [email protected] ")" 99 [email protected] "("
100 [email protected] ")" 100 [email protected] ")"
101 [email protected] ")"
101 [email protected] "]" 102 [email protected] "]"
102 [email protected] " " 103 [email protected] " "
103 [email protected] 104 [email protected]
diff --git a/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast
index f284aafcd..26cdc2945 100644
--- a/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0150_array_attrs.rast
@@ -31,14 +31,15 @@ [email protected]
31 [email protected] 31 [email protected]
32 [email protected] "#" 32 [email protected] "#"
33 [email protected] "[" 33 [email protected] "["
34 [email protected] 34 [email protected]
35 [email protected] 35 [email protected]
36 [email protected] 36 [email protected]
37 [email protected] "cfg" 37 [email protected]
38 [email protected] 38 [email protected] "cfg"
39 [email protected] "(" 39 [email protected]
40 [email protected] "test" 40 [email protected] "("
41 [email protected] ")" 41 [email protected] "test"
42 [email protected] ")"
42 [email protected] "]" 43 [email protected] "]"
43 [email protected] " " 44 [email protected] " "
44 [email protected] "2" 45 [email protected] "2"
diff --git a/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast b/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast
index 2905c5f1a..1d20765b0 100644
--- a/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast
@@ -23,10 +23,11 @@ [email protected]
23 [email protected] 23 [email protected]
24 [email protected] "#" 24 [email protected] "#"
25 [email protected] "[" 25 [email protected] "["
26 [email protected] 26 [email protected]
27 [email protected] 27 [email protected]
28 [email protected] 28 [email protected]
29 [email protected] "attr" 29 [email protected]
30 [email protected] "attr"
30 [email protected] "]" 31 [email protected] "]"
31 [email protected] " " 32 [email protected] " "
32 [email protected] "92" 33 [email protected] "92"
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast
index d34b21abe..3b6612677 100644
--- a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast
@@ -34,14 +34,15 @@ [email protected]
34 [email protected] 34 [email protected]
35 [email protected] "#" 35 [email protected] "#"
36 [email protected] "[" 36 [email protected] "["
37 [email protected] 37 [email protected]
38 [email protected] 38 [email protected]
39 [email protected] 39 [email protected]
40 [email protected] "cfg" 40 [email protected]
41 [email protected] 41 [email protected] "cfg"
42 [email protected] "(" 42 [email protected]
43 [email protected] "test" 43 [email protected] "("
44 [email protected] ")" 44 [email protected] "test"
45 [email protected] ")"
45 [email protected] "]" 46 [email protected] "]"
46 [email protected] " " 47 [email protected] " "
47 [email protected] "2" 48 [email protected] "2"
diff --git a/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast b/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast
index 42587243a..be2d1dc12 100644
--- a/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast
+++ b/crates/syntax/test_data/parser/ok/0006_inner_attributes.rast
@@ -3,182 +3,192 @@ [email protected]
3 [email protected] "#" 3 [email protected] "#"
4 [email protected] "!" 4 [email protected] "!"
5 [email protected] "[" 5 [email protected] "["
6 [email protected] 6 [email protected]
7 [email protected] 7 [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "attr" 9 [email protected]
10 [email protected] "attr"
10 [email protected] "]" 11 [email protected] "]"
11 [email protected] "\n" 12 [email protected] "\n"
12 [email protected] 13 [email protected]
13 [email protected] "#" 14 [email protected] "#"
14 [email protected] "!" 15 [email protected] "!"
15 [email protected] "[" 16 [email protected] "["
16 [email protected] 17 [email protected]
17 [email protected] 18 [email protected]
18 [email protected] 19 [email protected]
19 [email protected] "attr" 20 [email protected]
20 [email protected] 21 [email protected] "attr"
21 [email protected] "(" 22 [email protected]
22 [email protected] "true" 23 [email protected] "("
23 [email protected] ")" 24 [email protected] "true"
25 [email protected] ")"
24 [email protected] "]" 26 [email protected] "]"
25 [email protected] "\n" 27 [email protected] "\n"
26 [email protected] 28 [email protected]
27 [email protected] "#" 29 [email protected] "#"
28 [email protected] "!" 30 [email protected] "!"
29 [email protected] "[" 31 [email protected] "["
30 [email protected] 32 [email protected]
31 [email protected] 33 [email protected]
32 [email protected] 34 [email protected]
33 [email protected] "attr" 35 [email protected]
34 [email protected] 36 [email protected] "attr"
35 [email protected] "(" 37 [email protected]
36 [email protected] "ident" 38 [email protected] "("
37 [email protected] ")" 39 [email protected] "ident"
40 [email protected] ")"
38 [email protected] "]" 41 [email protected] "]"
39 [email protected] "\n" 42 [email protected] "\n"
40 [email protected] 43 [email protected]
41 [email protected] "#" 44 [email protected] "#"
42 [email protected] "!" 45 [email protected] "!"
43 [email protected] "[" 46 [email protected] "["
44 [email protected] 47 [email protected]
45 [email protected] 48 [email protected]
46 [email protected] 49 [email protected]
47 [email protected] "attr" 50 [email protected]
48 [email protected] 51 [email protected] "attr"
49 [email protected] "(" 52 [email protected]
50 [email protected] "ident" 53 [email protected] "("
51 [email protected] "," 54 [email protected] "ident"
52 [email protected] " " 55 [email protected] ","
53 [email protected] "100" 56 [email protected] " "
54 [email protected] "," 57 [email protected] "100"
55 [email protected] " " 58 [email protected] ","
56 [email protected] "true" 59 [email protected] " "
57 [email protected] "," 60 [email protected] "true"
58 [email protected] " " 61 [email protected] ","
59 [email protected] "\"true\"" 62 [email protected] " "
60 [email protected] "," 63 [email protected] "\"true\""
61 [email protected] " " 64 [email protected] ","
62 [email protected] "ident" 65 [email protected] " "
63 [email protected] " " 66 [email protected] "ident"
64 [email protected] "=" 67 [email protected] " "
65 [email protected] " " 68 [email protected] "="
66 [email protected] "100" 69 [email protected] " "
67 [email protected] "," 70 [email protected] "100"
68 [email protected] " " 71 [email protected] ","
69 [email protected] "ident" 72 [email protected] " "
70 [email protected] " " 73 [email protected] "ident"
71 [email protected] "=" 74 [email protected] " "
72 [email protected] " " 75 [email protected] "="
73 [email protected] "\"hello\"" 76 [email protected] " "
74 [email protected] "," 77 [email protected] "\"hello\""
75 [email protected] " " 78 [email protected] ","
76 [email protected] "ident" 79 [email protected] " "
77 [email protected] 80 [email protected] "ident"
78 [email protected] "(" 81 [email protected]
79 [email protected] "100" 82 [email protected] "("
80 [email protected] ")" 83 [email protected] "100"
81 [email protected] ")" 84 [email protected] ")"
85 [email protected] ")"
82 [email protected] "]" 86 [email protected] "]"
83 [email protected] "\n" 87 [email protected] "\n"
84 [email protected] 88 [email protected]
85 [email protected] "#" 89 [email protected] "#"
86 [email protected] "!" 90 [email protected] "!"
87 [email protected] "[" 91 [email protected] "["
88 [email protected] 92 [email protected]
89 [email protected] 93 [email protected]
90 [email protected] 94 [email protected]
91 [email protected] "attr" 95 [email protected]
92 [email protected] 96 [email protected] "attr"
93 [email protected] "(" 97 [email protected]
94 [email protected] "100" 98 [email protected] "("
95 [email protected] ")" 99 [email protected] "100"
100 [email protected] ")"
96 [email protected] "]" 101 [email protected] "]"
97 [email protected] "\n" 102 [email protected] "\n"
98 [email protected] 103 [email protected]
99 [email protected] "#" 104 [email protected] "#"
100 [email protected] "!" 105 [email protected] "!"
101 [email protected] "[" 106 [email protected] "["
102 [email protected] 107 [email protected]
103 [email protected] 108 [email protected]
104 [email protected] 109 [email protected]
105 [email protected] "attr" 110 [email protected]
106 [email protected] 111 [email protected] "attr"
107 [email protected] "(" 112 [email protected]
108 [email protected] "enabled" 113 [email protected] "("
109 [email protected] " " 114 [email protected] "enabled"
110 [email protected] "=" 115 [email protected] " "
111 [email protected] " " 116 [email protected] "="
112 [email protected] "true" 117 [email protected] " "
113 [email protected] ")" 118 [email protected] "true"
119 [email protected] ")"
114 [email protected] "]" 120 [email protected] "]"
115 [email protected] "\n" 121 [email protected] "\n"
116 [email protected] 122 [email protected]
117 [email protected] "#" 123 [email protected] "#"
118 [email protected] "!" 124 [email protected] "!"
119 [email protected] "[" 125 [email protected] "["
120 [email protected] 126 [email protected]
121 [email protected] 127 [email protected]
122 [email protected] 128 [email protected]
123 [email protected] "enabled" 129 [email protected]
124 [email protected] 130 [email protected] "enabled"
125 [email protected] "(" 131 [email protected]
126 [email protected] "true" 132 [email protected] "("
127 [email protected] ")" 133 [email protected] "true"
134 [email protected] ")"
128 [email protected] "]" 135 [email protected] "]"
129 [email protected] "\n" 136 [email protected] "\n"
130 [email protected] 137 [email protected]
131 [email protected] "#" 138 [email protected] "#"
132 [email protected] "!" 139 [email protected] "!"
133 [email protected] "[" 140 [email protected] "["
134 [email protected] 141 [email protected]
135 [email protected] 142 [email protected]
136 [email protected] 143 [email protected]
137 [email protected] "attr" 144 [email protected]
138 [email protected] 145 [email protected] "attr"
139 [email protected] "(" 146 [email protected]
140 [email protected] "\"hello\"" 147 [email protected] "("
141 [email protected] ")" 148 [email protected] "\"hello\""
149 [email protected] ")"
142 [email protected] "]" 150 [email protected] "]"
143 [email protected] "\n" 151 [email protected] "\n"
144 [email protected] 152 [email protected]
145 [email protected] "#" 153 [email protected] "#"
146 [email protected] "!" 154 [email protected] "!"
147 [email protected] "[" 155 [email protected] "["
148 [email protected] 156 [email protected]
149 [email protected] 157 [email protected]
150 [email protected] 158 [email protected]
151 [email protected] "repr" 159 [email protected]
152 [email protected] 160 [email protected] "repr"
153 [email protected] "(" 161 [email protected]
154 [email protected] "C" 162 [email protected] "("
155 [email protected] "," 163 [email protected] "C"
156 [email protected] " " 164 [email protected] ","
157 [email protected] "align" 165 [email protected] " "
158 [email protected] " " 166 [email protected] "align"
159 [email protected] "=" 167 [email protected] " "
160 [email protected] " " 168 [email protected] "="
161 [email protected] "4" 169 [email protected] " "
162 [email protected] ")" 170 [email protected] "4"
171 [email protected] ")"
163 [email protected] "]" 172 [email protected] "]"
164 [email protected] "\n" 173 [email protected] "\n"
165 [email protected] 174 [email protected]
166 [email protected] "#" 175 [email protected] "#"
167 [email protected] "!" 176 [email protected] "!"
168 [email protected] "[" 177 [email protected] "["
169 [email protected] 178 [email protected]
170 [email protected] 179 [email protected]
171 [email protected] 180 [email protected]
172 [email protected] "repr" 181 [email protected]
173 [email protected] 182 [email protected] "repr"
174 [email protected] "(" 183 [email protected]
175 [email protected] "C" 184 [email protected] "("
176 [email protected] "," 185 [email protected] "C"
177 [email protected] " " 186 [email protected] ","
178 [email protected] "align" 187 [email protected] " "
179 [email protected] 188 [email protected] "align"
180 [email protected] "(" 189 [email protected]
181 [email protected] "4" 190 [email protected] "("
182 [email protected] ")" 191 [email protected] "4"
183 [email protected] ")" 192 [email protected] ")"
193 [email protected] ")"
184 [email protected] "]" 194 [email protected] "]"
diff --git a/crates/syntax/test_data/parser/ok/0008_mod_item.rast b/crates/syntax/test_data/parser/ok/0008_mod_item.rast
index b2c1d791f..8b1e0a52d 100644
--- a/crates/syntax/test_data/parser/ok/0008_mod_item.rast
+++ b/crates/syntax/test_data/parser/ok/0008_mod_item.rast
@@ -65,10 +65,11 @@ [email protected]
65 [email protected] "#" 65 [email protected] "#"
66 [email protected] "!" 66 [email protected] "!"
67 [email protected] "[" 67 [email protected] "["
68 [email protected] 68 [email protected]
69 [email protected] 69 [email protected]
70 [email protected] 70 [email protected]
71 [email protected] "attr" 71 [email protected]
72 [email protected] "attr"
72 [email protected] "]" 73 [email protected] "]"
73 [email protected] "\n " 74 [email protected] "\n "
74 [email protected] 75 [email protected]
diff --git a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast
index 478fdba75..ff5877a7b 100644
--- a/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast
+++ b/crates/syntax/test_data/parser/ok/0011_outer_attribute.rast
@@ -3,23 +3,25 @@ [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "#" 4 [email protected] "#"
5 [email protected] "[" 5 [email protected] "["
6 [email protected] 6 [email protected]
7 [email protected] 7 [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "cfg" 9 [email protected]
10 [email protected] 10 [email protected] "cfg"
11 [email protected] "(" 11 [email protected]
12 [email protected] "test" 12 [email protected] "("
13 [email protected] ")" 13 [email protected] "test"
14 [email protected] ")"
14 [email protected] "]" 15 [email protected] "]"
15 [email protected] "\n" 16 [email protected] "\n"
16 [email protected] 17 [email protected]
17 [email protected] "#" 18 [email protected] "#"
18 [email protected] "[" 19 [email protected] "["
19 [email protected] 20 [email protected]
20 [email protected] 21 [email protected]
21 [email protected] 22 [email protected]
22 [email protected] "ignore" 23 [email protected]
24 [email protected] "ignore"
23 [email protected] "]" 25 [email protected] "]"
24 [email protected] "\n" 26 [email protected] "\n"
25 [email protected] "fn" 27 [email protected] "fn"
@@ -38,15 +40,16 @@ [email protected]
38 [email protected] 40 [email protected]
39 [email protected] "#" 41 [email protected] "#"
40 [email protected] "[" 42 [email protected] "["
41 [email protected] 43 [email protected]
42 [email protected] 44 [email protected]
43 [email protected] 45 [email protected]
44 [email protected] "path" 46 [email protected]
45 [email protected] " " 47 [email protected] "path"
46 [email protected] "=" 48 [email protected] " "
47 [email protected] " " 49 [email protected] "="
48 [email protected] 50 [email protected] " "
49 [email protected] "\"a.rs\"" 51 [email protected]
52 [email protected] "\"a.rs\""
50 [email protected] "]" 53 [email protected] "]"
51 [email protected] "\n" 54 [email protected] "\n"
52 [email protected] "mod" 55 [email protected] "mod"
diff --git a/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast b/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast
index a3e091ad3..94791f771 100644
--- a/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast
+++ b/crates/syntax/test_data/parser/ok/0017_attr_trailing_comma.rast
@@ -3,15 +3,16 @@ [email protected]
3 [email protected] 3 [email protected]
4 [email protected] "#" 4 [email protected] "#"
5 [email protected] "[" 5 [email protected] "["
6 [email protected] 6 [email protected]
7 [email protected] 7 [email protected]
8 [email protected] 8 [email protected]
9 [email protected] "foo" 9 [email protected]
10 [email protected] 10 [email protected] "foo"
11 [email protected] "(" 11 [email protected]
12 [email protected] "a" 12 [email protected] "("
13 [email protected] "," 13 [email protected] "a"
14 [email protected] ")" 14 [email protected] ","
15 [email protected] ")"
15 [email protected] "]" 16 [email protected] "]"
16 [email protected] "\n" 17 [email protected] "\n"
17 [email protected] "fn" 18 [email protected] "fn"
diff --git a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast
index 46b192dc1..20675dbf5 100644
--- a/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast
+++ b/crates/syntax/test_data/parser/ok/0035_weird_exprs.rast
@@ -11,71 +11,76 @@ [email protected]
11 [email protected] "#" 11 [email protected] "#"
12 [email protected] "!" 12 [email protected] "!"
13 [email protected] "[" 13 [email protected] "["
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] 16 [email protected]
17 [email protected] "allow" 17 [email protected]
18 [email protected] 18 [email protected] "allow"
19 [email protected] "(" 19 [email protected]
20 [email protected] "non_camel_case_types" 20 [email protected] "("
21 [email protected] ")" 21 [email protected] "non_camel_case_types"
22 [email protected] ")"
22 [email protected] "]" 23 [email protected] "]"
23 [email protected] "\n" 24 [email protected] "\n"
24 [email protected] 25 [email protected]
25 [email protected] "#" 26 [email protected] "#"
26 [email protected] "!" 27 [email protected] "!"
27 [email protected] "[" 28 [email protected] "["
28 [email protected] 29 [email protected]
29 [email protected] 30 [email protected]
30 [email protected] 31 [email protected]
31 [email protected] "allow" 32 [email protected]
32 [email protected] 33 [email protected] "allow"
33 [email protected] "(" 34 [email protected]
34 [email protected] "dead_code" 35 [email protected] "("
35 [email protected] ")" 36 [email protected] "dead_code"
37 [email protected] ")"
36 [email protected] "]" 38 [email protected] "]"
37 [email protected] "\n" 39 [email protected] "\n"
38 [email protected] 40 [email protected]
39 [email protected] "#" 41 [email protected] "#"
40 [email protected] "!" 42 [email protected] "!"
41 [email protected] "[" 43 [email protected] "["
42 [email protected] 44 [email protected]
43 [email protected] 45 [email protected]
44 [email protected] 46 [email protected]
45 [email protected] "allow" 47 [email protected]
46 [email protected] 48 [email protected] "allow"
47 [email protected] "(" 49 [email protected]
48 [email protected] "unreachable_code" 50 [email protected] "("
49 [email protected] ")" 51 [email protected] "unreachable_code"
52 [email protected] ")"
50 [email protected] "]" 53 [email protected] "]"
51 [email protected] "\n" 54 [email protected] "\n"
52 [email protected] 55 [email protected]
53 [email protected] "#" 56 [email protected] "#"
54 [email protected] "!" 57 [email protected] "!"
55 [email protected] "[" 58 [email protected] "["
56 [email protected] 59 [email protected]
57 [email protected] 60 [email protected]
58 [email protected] 61 [email protected]
59 [email protected] "allow" 62 [email protected]
60 [email protected] 63 [email protected] "allow"
61 [email protected] "(" 64 [email protected]
62 [email protected] "unused_parens" 65 [email protected] "("
63 [email protected] ")" 66 [email protected] "unused_parens"
67 [email protected] ")"
64 [email protected] "]" 68 [email protected] "]"
65 [email protected] "\n\n" 69 [email protected] "\n\n"
66 [email protected] 70 [email protected]
67 [email protected] "#" 71 [email protected] "#"
68 [email protected] "!" 72 [email protected] "!"
69 [email protected] "[" 73 [email protected] "["
70 [email protected] 74 [email protected]
71 [email protected] 75 [email protected]
72 [email protected] 76 [email protected]
73 [email protected] "recursion_limit" 77 [email protected]
74 [email protected] " " 78 [email protected] "recursion_limit"
75 [email protected] "=" 79 [email protected] " "
76 [email protected] " " 80 [email protected] "="
77 [email protected] 81 [email protected] " "
78 [email protected] "\"128\"" 82 [email protected]
83 [email protected] "\"128\""
79 [email protected] "]" 84 [email protected] "]"
80 [email protected] "\n\n" 85 [email protected] "\n\n"
81 [email protected] 86 [email protected]
diff --git a/crates/syntax/test_data/parser/ok/0044_let_attrs.rast b/crates/syntax/test_data/parser/ok/0044_let_attrs.rast
index af44a4dbe..d0e7a1dbe 100644
--- a/crates/syntax/test_data/parser/ok/0044_let_attrs.rast
+++ b/crates/syntax/test_data/parser/ok/0044_let_attrs.rast
@@ -17,18 +17,19 @@ [email protected]
17 [email protected] 17 [email protected]
18 [email protected] "#" 18 [email protected] "#"
19 [email protected] "[" 19 [email protected] "["
20 [email protected] 20 [email protected]
21 [email protected] 21 [email protected]
22 [email protected] 22 [email protected]
23 [email protected] "cfg" 23 [email protected]
24 [email protected] 24 [email protected] "cfg"
25 [email protected] "(" 25 [email protected]
26 [email protected] "feature" 26 [email protected] "("
27 [email protected] " " 27 [email protected] "feature"
28 [email protected] "=" 28 [email protected] " "
29 [email protected] " " 29 [email protected] "="
30 [email protected] "\"backtrace\"" 30 [email protected] " "
31 [email protected] ")" 31 [email protected] "\"backtrace\""
32 [email protected] ")"
32 [email protected] "]" 33 [email protected] "]"
33 [email protected] "\n " 34 [email protected] "\n "
34 [email protected] "let" 35 [email protected] "let"
diff --git a/crates/syntax/test_data/parser/ok/0045_block_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast
index 5e50b4e0b..7fbd635d0 100644
--- a/crates/syntax/test_data/parser/ok/0045_block_attrs.rast
+++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast
@@ -15,14 +15,15 @@ [email protected]
15 [email protected] "#" 15 [email protected] "#"
16 [email protected] "!" 16 [email protected] "!"
17 [email protected] "[" 17 [email protected] "["
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
20 [email protected] 20 [email protected]
21 [email protected] "doc" 21 [email protected]
22 [email protected] 22 [email protected] "doc"
23 [email protected] "(" 23 [email protected]
24 [email protected] "\"Inner attributes all ..." 24 [email protected] "("
25 [email protected] ")" 25 [email protected] "\"Inner attributes all ..."
26 [email protected] ")"
26 [email protected] "]" 27 [email protected] "]"
27 [email protected] "\n " 28 [email protected] "\n "
28 [email protected] "//! As are ModuleDoc ..." 29 [email protected] "//! As are ModuleDoc ..."
@@ -35,28 +36,30 @@ [email protected]
35 [email protected] "#" 36 [email protected] "#"
36 [email protected] "!" 37 [email protected] "!"
37 [email protected] "[" 38 [email protected] "["
38 [email protected] 39 [email protected]
39 [email protected] 40 [email protected]
40 [email protected] 41 [email protected]
41 [email protected] "doc" 42 [email protected]
42 [email protected] 43 [email protected] "doc"
43 [email protected] "(" 44 [email protected]
44 [email protected] "\"Inner attributes are ..." 45 [email protected] "("
45 [email protected] ")" 46 [email protected] "\"Inner attributes are ..."
47 [email protected] ")"
46 [email protected] "]" 48 [email protected] "]"
47 [email protected] "\n " 49 [email protected] "\n "
48 [email protected] 50 [email protected]
49 [email protected] "#" 51 [email protected] "#"
50 [email protected] "!" 52 [email protected] "!"
51 [email protected] "[" 53 [email protected] "["
52 [email protected] 54 [email protected]
53 [email protected] 55 [email protected]
54 [email protected] 56 [email protected]
55 [email protected] "doc" 57 [email protected]
56 [email protected] 58 [email protected] "doc"
57 [email protected] "(" 59 [email protected]
58 [email protected] "\"Being validated is n ..." 60 [email protected] "("
59 [email protected] ")" 61 [email protected] "\"Being validated is n ..."
62 [email protected] ")"
60 [email protected] "]" 63 [email protected] "]"
61 [email protected] "\n " 64 [email protected] "\n "
62 [email protected] "//! As are ModuleDoc ..." 65 [email protected] "//! As are ModuleDoc ..."
@@ -71,14 +74,15 @@ [email protected]
71 [email protected] "#" 74 [email protected] "#"
72 [email protected] "!" 75 [email protected] "!"
73 [email protected] "[" 76 [email protected] "["
74 [email protected] 77 [email protected]
75 [email protected] 78 [email protected]
76 [email protected] 79 [email protected]
77 [email protected] "doc" 80 [email protected]
78 [email protected] 81 [email protected] "doc"
79 [email protected] "(" 82 [email protected]
80 [email protected] "\"Inner attributes are ..." 83 [email protected] "("
81 [email protected] ")" 84 [email protected] "\"Inner attributes are ..."
85 [email protected] ")"
82 [email protected] "]" 86 [email protected] "]"
83 [email protected] "\n " 87 [email protected] "\n "
84 [email protected] "//! As are ModuleDoc ..." 88 [email protected] "//! As are ModuleDoc ..."
@@ -111,14 +115,15 @@ [email protected]
111 [email protected] 115 [email protected]
112 [email protected] "#" 116 [email protected] "#"
113 [email protected] "[" 117 [email protected] "["
114 [email protected] 118 [email protected]
115 [email protected] 119 [email protected]
116 [email protected] 120 [email protected]
117 [email protected] "doc" 121 [email protected]
118 [email protected] 122 [email protected] "doc"
119 [email protected] "(" 123 [email protected]
120 [email protected] "\"Outer attributes are ..." 124 [email protected] "("
121 [email protected] ")" 125 [email protected] "\"Outer attributes are ..."
126 [email protected] ")"
122 [email protected] "]" 127 [email protected] "]"
123 [email protected] " " 128 [email protected] " "
124 [email protected] "{" 129 [email protected] "{"
@@ -200,14 +205,15 @@ [email protected]
200 [email protected] "#" 205 [email protected] "#"
201 [email protected] "!" 206 [email protected] "!"
202 [email protected] "[" 207 [email protected] "["
203 [email protected] 208 [email protected]
204 [email protected] 209 [email protected]
205 [email protected] 210 [email protected]
206 [email protected] "allow" 211 [email protected]
207 [email protected] 212 [email protected] "allow"
208 [email protected] "(" 213 [email protected]
209 [email protected] "unused_variables" 214 [email protected] "("
210 [email protected] ")" 215 [email protected] "unused_variables"
216 [email protected] ")"
211 [email protected] "]" 217 [email protected] "]"
212 [email protected] " " 218 [email protected] " "
213 [email protected] "// this is `inner_at ..." 219 [email protected] "// this is `inner_at ..."
diff --git a/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast b/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast
index 37594769a..854ff9d56 100644
--- a/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast
+++ b/crates/syntax/test_data/parser/ok/0046_extern_inner_attributes.rast
@@ -14,14 +14,15 @@ [email protected]
14 [email protected] "#" 14 [email protected] "#"
15 [email protected] "!" 15 [email protected] "!"
16 [email protected] "[" 16 [email protected] "["
17 [email protected] 17 [email protected]
18 [email protected] 18 [email protected]
19 [email protected] 19 [email protected]
20 [email protected] "doc" 20 [email protected]
21 [email protected] 21 [email protected] "doc"
22 [email protected] "(" 22 [email protected]
23 [email protected] "\"This is also a doc c ..." 23 [email protected] "("
24 [email protected] ")" 24 [email protected] "\"This is also a doc c ..."
25 [email protected] ")"
25 [email protected] "]" 26 [email protected] "]"
26 [email protected] "\n" 27 [email protected] "\n"
27 [email protected] "}" 28 [email protected] "}"
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
index 88470c41c..f935a0df5 100644
--- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
+++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast
@@ -10,19 +10,21 @@ [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "#" 11 [email protected] "#"
12 [email protected] "[" 12 [email protected] "["
13 [email protected] 13 [email protected]
14 [email protected] 14 [email protected]
15 [email protected] 15 [email protected]
16 [email protected] "attr1" 16 [email protected]
17 [email protected] "attr1"
17 [email protected] "]" 18 [email protected] "]"
18 [email protected] " " 19 [email protected] " "
19 [email protected] 20 [email protected]
20 [email protected] "#" 21 [email protected] "#"
21 [email protected] "[" 22 [email protected] "["
22 [email protected] 23 [email protected]
23 [email protected] 24 [email protected]
24 [email protected] 25 [email protected]
25 [email protected] "attr2" 26 [email protected]
27 [email protected] "attr2"
26 [email protected] "]" 28 [email protected] "]"
27 [email protected] " " 29 [email protected] " "
28 [email protected] 30 [email protected]
@@ -52,10 +54,11 @@ [email protected]
52 [email protected] 54 [email protected]
53 [email protected] "#" 55 [email protected] "#"
54 [email protected] "[" 56 [email protected] "["
55 [email protected] 57 [email protected]
56 [email protected] 58 [email protected]
57 [email protected] 59 [email protected]
58 [email protected] "attr1" 60 [email protected]
61 [email protected] "attr1"
59 [email protected] "]" 62 [email protected] "]"
60 [email protected] " " 63 [email protected] " "
61 [email protected] 64 [email protected]
@@ -111,10 +114,11 @@ [email protected]
111 [email protected] 114 [email protected]
112 [email protected] "#" 115 [email protected] "#"
113 [email protected] "[" 116 [email protected] "["
114 [email protected] 117 [email protected]
115 [email protected] 118 [email protected]
116 [email protected] 119 [email protected]
117 [email protected] "attr" 120 [email protected]
121 [email protected] "attr"
118 [email protected] "]" 122 [email protected] "]"
119 [email protected] " " 123 [email protected] " "
120 [email protected] "..." 124 [email protected] "..."
@@ -157,10 +161,11 @@ [email protected]
157 [email protected] 161 [email protected]
158 [email protected] "#" 162 [email protected] "#"
159 [email protected] "[" 163 [email protected] "["
160 [email protected] 164 [email protected]
161 [email protected] 165 [email protected]
162 [email protected] 166 [email protected]
163 [email protected] "attr" 167 [email protected]
168 [email protected] "attr"
164 [email protected] "]" 169 [email protected] "]"
165 [email protected] " " 170 [email protected] " "
166 [email protected] 171 [email protected]
@@ -207,10 +212,11 @@ [email protected]
207 [email protected] 212 [email protected]
208 [email protected] "#" 213 [email protected] "#"
209 [email protected] "[" 214 [email protected] "["
210 [email protected] 215 [email protected]
211 [email protected] 216 [email protected]
212 [email protected] 217 [email protected]
213 [email protected] "attr" 218 [email protected]
219 [email protected] "attr"
214 [email protected] "]" 220 [email protected] "]"
215 [email protected] " " 221 [email protected] " "
216 [email protected] 222 [email protected]
@@ -229,10 +235,11 @@ [email protected]
229 [email protected] "#" 235 [email protected] "#"
230 [email protected] " " 236 [email protected] " "
231 [email protected] "[" 237 [email protected] "["
232 [email protected] 238 [email protected]
233 [email protected] 239 [email protected]
234 [email protected] 240 [email protected]
235 [email protected] "attr" 241 [email protected]
242 [email protected] "attr"
236 [email protected] "]" 243 [email protected] "]"
237 [email protected] " " 244 [email protected] " "
238 [email protected] 245 [email protected]
@@ -275,10 +282,11 @@ [email protected]
275 [email protected] 282 [email protected]
276 [email protected] "#" 283 [email protected] "#"
277 [email protected] "[" 284 [email protected] "["
278 [email protected] 285 [email protected]
279 [email protected] 286 [email protected]
280 [email protected] 287 [email protected]
281 [email protected] "must_use" 288 [email protected]
289 [email protected] "must_use"
282 [email protected] "]" 290 [email protected] "]"
283 [email protected] " " 291 [email protected] " "
284 [email protected] 292 [email protected]
@@ -300,10 +308,11 @@ [email protected]
300 [email protected] 308 [email protected]
301 [email protected] "#" 309 [email protected] "#"
302 [email protected] "[" 310 [email protected] "["
303 [email protected] 311 [email protected]
304 [email protected] 312 [email protected]
305 [email protected] 313 [email protected]
306 [email protected] "attr" 314 [email protected]
315 [email protected] "attr"
307 [email protected] "]" 316 [email protected] "]"
308 [email protected] " " 317 [email protected] " "
309 [email protected] 318 [email protected]
@@ -325,10 +334,11 @@ [email protected]
325 [email protected] 334 [email protected]
326 [email protected] "#" 335 [email protected] "#"
327 [email protected] "[" 336 [email protected] "["
328 [email protected] 337 [email protected]
329 [email protected] 338 [email protected]
330 [email protected] 339 [email protected]
331 [email protected] "attr" 340 [email protected]
341 [email protected] "attr"
332 [email protected] "]" 342 [email protected] "]"
333 [email protected] " " 343 [email protected] " "
334 [email protected] "&" 344 [email protected] "&"
@@ -357,10 +367,11 @@ [email protected]
357 [email protected] 367 [email protected]
358 [email protected] "#" 368 [email protected] "#"
359 [email protected] "[" 369 [email protected] "["
360 [email protected] 370 [email protected]
361 [email protected] 371 [email protected]
362 [email protected] 372 [email protected]
363 [email protected] "attr" 373 [email protected]
374 [email protected] "attr"
364 [email protected] "]" 375 [email protected] "]"
365 [email protected] " " 376 [email protected] " "
366 [email protected] "&" 377 [email protected] "&"
@@ -391,10 +402,11 @@ [email protected]
391 [email protected] 402 [email protected]
392 [email protected] "#" 403 [email protected] "#"
393 [email protected] "[" 404 [email protected] "["
394 [email protected] 405 [email protected]
395 [email protected] 406 [email protected]
396 [email protected] 407 [email protected]
397 [email protected] "attr" 408 [email protected]
409 [email protected] "attr"
398 [email protected] "]" 410 [email protected] "]"
399 [email protected] " " 411 [email protected] " "
400 [email protected] "&" 412 [email protected] "&"
@@ -426,10 +438,11 @@ [email protected]
426 [email protected] 438 [email protected]
427 [email protected] "#" 439 [email protected] "#"
428 [email protected] "[" 440 [email protected] "["
429 [email protected] 441 [email protected]
430 [email protected] 442 [email protected]
431 [email protected] 443 [email protected]
432 [email protected] "attr" 444 [email protected]
445 [email protected] "attr"
433 [email protected] "]" 446 [email protected] "]"
434 [email protected] " " 447 [email protected] " "
435 [email protected] "&" 448 [email protected] "&"
@@ -457,10 +470,11 @@ [email protected]
457 [email protected] 470 [email protected]
458 [email protected] "#" 471 [email protected] "#"
459 [email protected] "[" 472 [email protected] "["
460 [email protected] 473 [email protected]
461 [email protected] 474 [email protected]
462 [email protected] 475 [email protected]
463 [email protected] "attr" 476 [email protected]
477 [email protected] "attr"
464 [email protected] "]" 478 [email protected] "]"
465 [email protected] " " 479 [email protected] " "
466 [email protected] 480 [email protected]
@@ -489,10 +503,11 @@ [email protected]
489 [email protected] 503 [email protected]
490 [email protected] "#" 504 [email protected] "#"
491 [email protected] "[" 505 [email protected] "["
492 [email protected] 506 [email protected]
493 [email protected] 507 [email protected]
494 [email protected] 508 [email protected]
495 [email protected] "attr" 509 [email protected]
510 [email protected] "attr"
496 [email protected] "]" 511 [email protected] "]"
497 [email protected] " " 512 [email protected] " "
498 [email protected] 513 [email protected]
diff --git a/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast b/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
index 87d8ebcba..97416f16a 100644
--- a/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
+++ b/crates/syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
@@ -5,10 +5,11 @@ [email protected]
5 [email protected] 5 [email protected]
6 [email protected] "#" 6 [email protected] "#"
7 [email protected] "[" 7 [email protected] "["
8 [email protected] 8 [email protected]
9 [email protected] 9 [email protected]
10 [email protected] 10 [email protected]
11 [email protected] "macro_export" 11 [email protected]
12 [email protected] "macro_export"
12 [email protected] "]" 13 [email protected] "]"
13 [email protected] "\n" 14 [email protected] "\n"
14 [email protected] "macro_rules" 15 [email protected] "macro_rules"
diff --git a/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast b/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast
index 0c22c31a4..e75848f0f 100644
--- a/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast
+++ b/crates/syntax/test_data/parser/ok/0062_macro_2.0.rast
@@ -55,10 +55,11 @@ [email protected]
55 [email protected] 55 [email protected]
56 [email protected] "#" 56 [email protected] "#"
57 [email protected] "[" 57 [email protected] "["
58 [email protected] 58 [email protected]
59 [email protected] 59 [email protected]
60 [email protected] 60 [email protected]
61 [email protected] "test" 61 [email protected]
62 [email protected] "test"
62 [email protected] "]" 63 [email protected] "]"
63 [email protected] "\n" 64 [email protected] "\n"
64 [email protected] "fn" 65 [email protected] "fn"
diff --git a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast
index f7c094898..dcc4105c9 100644
--- a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast
+++ b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast
@@ -96,14 +96,15 @@ [email protected]
96 [email protected] 96 [email protected]
97 [email protected] "#" 97 [email protected] "#"
98 [email protected] "[" 98 [email protected] "["
99 [email protected] 99 [email protected]
100 [email protected] 100 [email protected]
101 [email protected] 101 [email protected]
102 [email protected] "cfg" 102 [email protected]
103 [email protected] 103 [email protected] "cfg"
104 [email protected] "(" 104 [email protected]
105 [email protected] "never" 105 [email protected] "("
106 [email protected] ")" 106 [email protected] "never"
107 [email protected] ")"
107 [email protected] "]" 108 [email protected] "]"
108 [email protected] " " 109 [email protected] " "
109 [email protected] 110 [email protected]
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 997770958..c4fc91386 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,7 +11,7 @@ anyhow = "1.0.26"
11flate2 = "1.0" 11flate2 = "1.0"
12proc-macro2 = "1.0.8" 12proc-macro2 = "1.0.8"
13quote = "1.0.2" 13quote = "1.0.2"
14ungrammar = "=1.13" 14ungrammar = "=1.14"
15walkdir = "2.3.1" 15walkdir = "2.3.1"
16write-json = "0.1.0" 16write-json = "0.1.0"
17xshell = "0.1" 17xshell = "0.1"
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 0fd1d13e6..fe37d0245 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -184,7 +184,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
184 "ITEM_LIST", 184 "ITEM_LIST",
185 "ASSOC_ITEM_LIST", 185 "ASSOC_ITEM_LIST",
186 "ATTR", 186 "ATTR",
187 "META_ITEM", // not an item actually 187 "META",
188 "USE_TREE", 188 "USE_TREE",
189 "USE_TREE_LIST", 189 "USE_TREE_LIST",
190 "PATH", 190 "PATH",