aboutsummaryrefslogtreecommitdiff
path: root/xtask
diff options
context:
space:
mode:
Diffstat (limited to 'xtask')
-rw-r--r--xtask/Cargo.toml9
-rw-r--r--xtask/src/ast_src.rs2080
-rw-r--r--xtask/src/codegen/gen_syntax.rs296
-rw-r--r--xtask/src/codegen/rust.ungram544
-rw-r--r--xtask/src/dist.rs27
-rw-r--r--xtask/src/lib.rs1
-rw-r--r--xtask/src/main.rs13
-rw-r--r--xtask/src/metrics.rs279
-rw-r--r--xtask/src/not_bash.rs3
-rw-r--r--xtask/tests/tidy.rs1
10 files changed, 1177 insertions, 2076 deletions
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index d1cfb5909..8140da87f 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -10,9 +10,10 @@ license = "MIT OR Apache-2.0"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13walkdir = "2.3.1"
14pico-args = "0.3.1"
15quote = "1.0.2"
16proc-macro2 = "1.0.8"
17anyhow = "1.0.26" 13anyhow = "1.0.26"
18flate2 = "1.0" 14flate2 = "1.0"
15pico-args = "0.3.1"
16proc-macro2 = "1.0.8"
17quote = "1.0.2"
18ungrammar = "0.1.0"
19walkdir = "2.3.1"
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs
index 392648d71..114898e38 100644
--- a/xtask/src/ast_src.rs
+++ b/xtask/src/ast_src.rs
@@ -93,19 +93,19 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
93 ], 93 ],
94 nodes: &[ 94 nodes: &[
95 "SOURCE_FILE", 95 "SOURCE_FILE",
96 "STRUCT_DEF", 96 "STRUCT",
97 "UNION_DEF", 97 "UNION",
98 "ENUM_DEF", 98 "ENUM",
99 "FN_DEF", 99 "FN",
100 "RET_TYPE", 100 "RET_TYPE",
101 "EXTERN_CRATE_ITEM", 101 "EXTERN_CRATE",
102 "MODULE", 102 "MODULE",
103 "USE_ITEM", 103 "USE",
104 "STATIC_DEF", 104 "STATIC",
105 "CONST_DEF", 105 "CONST",
106 "TRAIT_DEF", 106 "TRAIT",
107 "IMPL_DEF", 107 "IMPL",
108 "TYPE_ALIAS_DEF", 108 "TYPE_ALIAS",
109 "MACRO_CALL", 109 "MACRO_CALL",
110 "TOKEN_TREE", 110 "TOKEN_TREE",
111 "MACRO_DEF", 111 "MACRO_DEF",
@@ -159,9 +159,9 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
159 "MATCH_ARM_LIST", 159 "MATCH_ARM_LIST",
160 "MATCH_ARM", 160 "MATCH_ARM",
161 "MATCH_GUARD", 161 "MATCH_GUARD",
162 "RECORD_LIT", 162 "RECORD_EXPR",
163 "RECORD_FIELD_LIST", 163 "RECORD_EXPR_FIELD_LIST",
164 "RECORD_FIELD", 164 "RECORD_EXPR_FIELD",
165 "EFFECT_EXPR", 165 "EFFECT_EXPR",
166 "BOX_EXPR", 166 "BOX_EXPR",
167 // postfix 167 // postfix
@@ -179,13 +179,14 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
179 "BIN_EXPR", 179 "BIN_EXPR",
180 "EXTERN_BLOCK", 180 "EXTERN_BLOCK",
181 "EXTERN_ITEM_LIST", 181 "EXTERN_ITEM_LIST",
182 "ENUM_VARIANT", 182 "VARIANT",
183 "RECORD_FIELD_DEF_LIST", 183 "RECORD_FIELD_LIST",
184 "RECORD_FIELD_DEF", 184 "RECORD_FIELD",
185 "TUPLE_FIELD_DEF_LIST", 185 "TUPLE_FIELD_LIST",
186 "TUPLE_FIELD_DEF", 186 "TUPLE_FIELD",
187 "ENUM_VARIANT_LIST", 187 "VARIANT_LIST",
188 "ITEM_LIST", 188 "ITEM_LIST",
189 "ASSOC_ITEM_LIST",
189 "ATTR", 190 "ATTR",
190 "META_ITEM", // not an item actually 191 "META_ITEM", // not an item actually
191 "USE_TREE", 192 "USE_TREE",
@@ -193,7 +194,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
193 "PATH", 194 "PATH",
194 "PATH_SEGMENT", 195 "PATH_SEGMENT",
195 "LITERAL", 196 "LITERAL",
196 "ALIAS", 197 "RENAME",
197 "VISIBILITY", 198 "VISIBILITY",
198 "WHERE_CLAUSE", 199 "WHERE_CLAUSE",
199 "WHERE_PRED", 200 "WHERE_PRED",
@@ -202,7 +203,8 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
202 "NAME_REF", 203 "NAME_REF",
203 "LET_STMT", 204 "LET_STMT",
204 "EXPR_STMT", 205 "EXPR_STMT",
205 "TYPE_PARAM_LIST", 206 "GENERIC_PARAM_LIST",
207 "GENERIC_PARAM",
206 "LIFETIME_PARAM", 208 "LIFETIME_PARAM",
207 "TYPE_PARAM", 209 "TYPE_PARAM",
208 "CONST_PARAM", 210 "CONST_PARAM",
@@ -223,2021 +225,37 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
223 ], 225 ],
224}; 226};
225 227
226pub(crate) struct AstSrc<'a> { 228#[derive(Default, Debug)]
227 pub(crate) tokens: &'a [&'a str], 229pub(crate) struct AstSrc {
228 pub(crate) nodes: &'a [AstNodeSrc<'a>], 230 pub(crate) tokens: Vec<String>,
229 pub(crate) enums: &'a [AstEnumSrc<'a>], 231 pub(crate) nodes: Vec<AstNodeSrc>,
230} 232 pub(crate) enums: Vec<AstEnumSrc>,
231
232pub(crate) struct AstNodeSrc<'a> {
233 pub(crate) doc: &'a [&'a str],
234 pub(crate) name: &'a str,
235 pub(crate) traits: &'a [&'a str],
236 pub(crate) fields: &'a [Field<'a>],
237}
238
239pub(crate) enum Field<'a> {
240 Token(&'a str),
241 Node { name: &'a str, src: FieldSrc<'a> },
242}
243
244pub(crate) enum FieldSrc<'a> {
245 Shorthand,
246 Optional(&'a str),
247 Many(&'a str),
248} 233}
249 234
250pub(crate) struct AstEnumSrc<'a> { 235#[derive(Debug)]
251 pub(crate) doc: &'a [&'a str], 236pub(crate) struct AstNodeSrc {
252 pub(crate) name: &'a str, 237 pub(crate) doc: Vec<String>,
253 pub(crate) traits: &'a [&'a str], 238 pub(crate) name: String,
254 pub(crate) variants: &'a [&'a str], 239 pub(crate) traits: Vec<String>,
240 pub(crate) fields: Vec<Field>,
255} 241}
256 242
257macro_rules! ast_nodes { 243#[derive(Debug, Eq, PartialEq)]
258 ($( 244pub(crate) enum Field {
259 $(#[doc = $doc:expr])+ 245 Token(String),
260 struct $name:ident$(: $($trait:ident),*)? { 246 Node { name: String, ty: String, cardinality: Cardinality },
261 $($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)?
262 }
263 )*) => {
264 [$(
265 AstNodeSrc {
266 doc: &[$($doc),*],
267 name: stringify!($name),
268 traits: &[$($(stringify!($trait)),*)?],
269 fields: &[
270 $(field!($(T![$token])? $field_name $($ty)?)),*
271 ],
272
273 }
274 ),*]
275 };
276} 247}
277 248
278macro_rules! field { 249#[derive(Debug, Eq, PartialEq)]
279 (T![$token:tt] T) => { 250pub(crate) enum Cardinality {
280 Field::Token(stringify!($token)) 251 Optional,
281 }; 252 Many,
282 ($field_name:ident) => {
283 Field::Node { name: stringify!($field_name), src: FieldSrc::Shorthand }
284 };
285 ($field_name:ident [$ty:ident]) => {
286 Field::Node { name: stringify!($field_name), src: FieldSrc::Many(stringify!($ty)) }
287 };
288 ($field_name:ident $ty:ident) => {
289 Field::Node { name: stringify!($field_name), src: FieldSrc::Optional(stringify!($ty)) }
290 };
291} 253}
292 254
293macro_rules! ast_enums { 255#[derive(Debug)]
294 ($( 256pub(crate) struct AstEnumSrc {
295 $(#[doc = $doc:expr])+ 257 pub(crate) doc: Vec<String>,
296 enum $name:ident $(: $($trait:ident),*)? { 258 pub(crate) name: String,
297 $($variant:ident),*$(,)? 259 pub(crate) traits: Vec<String>,
298 } 260 pub(crate) variants: Vec<String>,
299 )*) => {
300 [$(
301 AstEnumSrc {
302 doc: &[$($doc),*],
303 name: stringify!($name),
304 traits: &[$($(stringify!($trait)),*)?],
305 variants: &[$(stringify!($variant)),*],
306 }
307 ),*]
308 };
309} 261}
310
311pub(crate) const AST_SRC: AstSrc = AstSrc {
312 tokens: &["Whitespace", "Comment", "String", "RawString"],
313 nodes: &ast_nodes! {
314 /// The entire Rust source file. Includes all top-level inner attributes and module items.
315 ///
316 /// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html)
317 struct SourceFile: ModuleItemOwner, AttrsOwner, DocCommentsOwner {
318 modules: [Module],
319 }
320
321 /// Function definition either with body or not.
322 /// Includes all of its attributes and doc comments.
323 ///
324 /// ```
325 /// ❰
326 /// /// Docs
327 /// #[attr]
328 /// pub extern "C" fn foo<T>(#[attr] Patern {p}: Pattern) -> u32
329 /// where
330 /// T: Debug
331 /// {
332 /// 42
333 /// }
334 /// ❱
335 ///
336 /// extern "C" {
337 /// ❰ fn fn_decl(also_variadic_ffi: u32, ...) -> u32; ❱
338 /// }
339 /// ```
340 ///
341 /// - [Reference](https://doc.rust-lang.org/reference/items/functions.html)
342 /// - [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html#variadic-functions)
343 struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner {
344 Abi,
345 T![const],
346 T![default],
347 T![async],
348 T![unsafe],
349 T![fn],
350 ParamList,
351 RetType,
352 body: BlockExpr,
353 T![;]
354 }
355
356 /// Return type annotation.
357 ///
358 /// ```
359 /// fn foo(a: u32) ❰ -> Option<u32> ❱ { Some(a) }
360 /// ```
361 ///
362 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
363 struct RetType { T![->], TypeRef }
364
365 /// Struct definition.
366 /// Includes all of its attributes and doc comments.
367 ///
368 /// ```
369 /// ❰
370 /// /// Docs
371 /// #[attr]
372 /// struct Foo<T> where T: Debug {
373 /// /// Docs
374 /// #[attr]
375 /// pub a: u32,
376 /// b: T,
377 /// }
378 /// ❱
379 ///
380 /// ❰ struct Foo; ❱
381 /// ❰ struct Foo<T>(#[attr] T) where T: Debug; ❱
382 /// ```
383 ///
384 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
385 struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
386 T![struct],
387 FieldDefList,
388 T![;]
389 }
390
391 /// Union definition.
392 /// Includes all of its attributes and doc comments.
393 ///
394 /// ```
395 /// ❰
396 /// /// Docs
397 /// #[attr]
398 /// pub union Foo<T> where T: Debug {
399 /// /// Docs
400 /// #[attr]
401 /// a: T,
402 /// b: u32,
403 /// }
404 /// ❱
405 /// ```
406 ///
407 /// [Reference](https://doc.rust-lang.org/reference/items/unions.html)
408 struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
409 T![union],
410 RecordFieldDefList,
411 }
412
413 /// Record field definition list including enclosing curly braces.
414 ///
415 /// ```
416 /// struct Foo // same for union
417 /// ❰
418 /// {
419 /// a: u32,
420 /// b: bool,
421 /// }
422 /// ❱
423 /// ```
424 ///
425 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
426 struct RecordFieldDefList { T!['{'], fields: [RecordFieldDef], T!['}'] }
427
428 /// Record field definition including its attributes and doc comments.
429 ///
430 /// ` ``
431 /// same for union
432 /// struct Foo {
433 /// ❰
434 /// /// Docs
435 /// #[attr]
436 /// pub a: u32
437 /// ❱
438 ///
439 /// ❰ b: bool ❱
440 /// }
441 /// ```
442 ///
443 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
444 struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { }
445
446 /// Tuple field definition list including enclosing parens.
447 ///
448 /// ```
449 /// struct Foo ❰ (u32, String, Vec<u32>) ❱;
450 /// ```
451 ///
452 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
453 struct TupleFieldDefList { T!['('], fields: [TupleFieldDef], T![')'] }
454
455 /// Tuple field definition including its attributes.
456 ///
457 /// ```
458 /// struct Foo(❰ #[attr] u32 ❱);
459 /// ```
460 ///
461 /// [Reference](https://doc.rust-lang.org/reference/items/structs.html)
462 struct TupleFieldDef: VisibilityOwner, AttrsOwner {
463 TypeRef,
464 }
465
466 /// Enum definition.
467 /// Includes all of its attributes and doc comments.
468 ///
469 /// ```
470 /// ❰
471 /// /// Docs
472 /// #[attr]
473 /// pub enum Foo<T> where T: Debug {
474 /// /// Docs
475 /// #[attr]
476 /// Bar,
477 /// Baz(#[attr] u32),
478 /// Bruh {
479 /// a: u32,
480 /// /// Docs
481 /// #[attr]
482 /// b: T,
483 /// }
484 /// }
485 /// ❱
486 /// ```
487 ///
488 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
489 struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
490 T![enum],
491 variant_list: EnumVariantList,
492 }
493
494 /// Enum variant definition list including enclosing curly braces.
495 ///
496 /// ```
497 /// enum Foo
498 /// ❰
499 /// {
500 /// Bar,
501 /// Baz(u32),
502 /// Bruh {
503 /// a: u32
504 /// }
505 /// }
506 /// ❱
507 /// ```
508 ///
509 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
510 struct EnumVariantList {
511 T!['{'],
512 variants: [EnumVariant],
513 T!['}']
514 }
515
516 /// Enum variant definition including its attributes and discriminant value definition.
517 ///
518 /// ```
519 /// enum Foo {
520 /// ❰
521 /// /// Docs
522 /// #[attr]
523 /// Bar
524 /// ❱
525 ///
526 /// // same for tuple and record variants
527 /// }
528 /// ```
529 ///
530 /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html)
531 struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner {
532 FieldDefList,
533 T![=],
534 Expr
535 }
536
537 /// Trait definition.
538 /// Includes all of its attributes and doc comments.
539 ///
540 /// ```
541 /// ❰
542 /// /// Docs
543 /// #[attr]
544 /// pub unsafe trait Foo<T>: Debug where T: Debug {
545 /// // ...
546 /// }
547 /// ❱
548 /// ```
549 ///
550 /// [Reference](https://doc.rust-lang.org/reference/items/traits.html)
551 struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner {
552 T![unsafe],
553 T![auto],
554 T![trait],
555 ItemList,
556 }
557
558 /// Module definition either with body or not.
559 /// Includes all of its inner and outer attributes, module items, doc comments.
560 ///
561 /// ```
562 /// ❰
563 /// /// Docs
564 /// #[attr]
565 /// pub mod foo;
566 /// ❱
567 ///
568 /// ❰
569 /// /// Docs
570 /// #[attr]
571 /// pub mod bar {
572 /// //! Inner docs
573 /// #![inner_attr]
574 /// }
575 /// ❱
576 /// ```
577 ///
578 /// [Reference](https://doc.rust-lang.org/reference/items/modules.html)
579 struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner {
580 T![mod],
581 ItemList,
582 T![;]
583 }
584
585 /// Item defintion list.
586 /// This is used for both top-level items and impl block items.
587 ///
588 /// ```
589 /// ❰
590 /// fn foo {}
591 /// struct Bar;
592 /// enum Baz;
593 /// trait Bruh;
594 /// const BRUUH: u32 = 42;
595 /// ❱
596 ///
597 /// impl Foo
598 /// ❰
599 /// {
600 /// fn bar() {}
601 /// const BAZ: u32 = 42;
602 /// }
603 /// ❱
604 /// ```
605 ///
606 /// [Reference](https://doc.rust-lang.org/reference/items.html)
607 struct ItemList: ModuleItemOwner {
608 T!['{'],
609 assoc_items: [AssocItem],
610 T!['}']
611 }
612
613 /// Constant variable definition.
614 /// Includes all of its attributes and doc comments.
615 ///
616 /// ```
617 /// ❰
618 /// /// Docs
619 /// #[attr]
620 /// pub const FOO: u32 = 42;
621 /// ❱
622 /// ```
623 ///
624 /// [Reference](https://doc.rust-lang.org/reference/items/constant-items.html)
625 struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
626 T![default],
627 T![const],
628 T![=],
629 body: Expr,
630 T![;]
631 }
632
633
634 /// Static variable definition.
635 /// Includes all of its attributes and doc comments.
636 ///
637 /// ```
638 /// ❰
639 /// /// Docs
640 /// #[attr]
641 /// pub static mut FOO: u32 = 42;
642 /// ❱
643 /// ```
644 ///
645 /// [Reference](https://doc.rust-lang.org/reference/items/static-items.html)
646 struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
647 T![static],
648 T![mut],
649 T![=],
650 body: Expr,
651 T![;]
652 }
653
654 /// Type alias definition.
655 /// Includes associated type clauses with type bounds.
656 ///
657 /// ```
658 /// ❰
659 /// /// Docs
660 /// #[attr]
661 /// pub type Foo<T> where T: Debug = T;
662 /// ❱
663 ///
664 /// trait Bar {
665 /// ❰ type Baz: Debug; ❱
666 /// ❰ type Bruh = String; ❱
667 /// ❰ type Bruuh: Debug = u32; ❱
668 /// }
669 /// ```
670 ///
671 /// [Reference](https://doc.rust-lang.org/reference/items/type-aliases.html)
672 struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner {
673 T![default],
674 T![type],
675 T![=],
676 TypeRef,
677 T![;]
678 }
679
680 /// Inherent and trait impl definition.
681 /// Includes all of its inner and outer attributes.
682 ///
683 /// ```
684 /// ❰
685 /// #[attr]
686 /// unsafe impl<T> const !Foo for Bar where T: Debug {
687 /// #![inner_attr]
688 /// // ...
689 /// }
690 /// ❱
691 /// ```
692 ///
693 /// [Reference](https://doc.rust-lang.org/reference/items/implementations.html)
694 struct ImplDef: TypeParamsOwner, AttrsOwner, DocCommentsOwner {
695 T![default],
696 T![const],
697 T![unsafe],
698 T![impl],
699 T![!],
700 T![for],
701 ItemList,
702 }
703
704
705 /// Parenthesized type reference.
706 /// Note: parens are only used for grouping, this is not a tuple type.
707 ///
708 /// ```
709 /// // This is effectively just `u32`.
710 /// // Single-item tuple must be defined with a trailing comma: `(u32,)`
711 /// type Foo = ❰ (u32) ❱;
712 ///
713 /// let bar: &'static ❰ (dyn Debug) ❱ = "bruh";
714 /// ```
715 struct ParenType { T!['('], TypeRef, T![')'] }
716
717 /// Unnamed tuple type.
718 ///
719 /// ```
720 /// let foo: ❰ (u32, bool) ❱ = (42, true);
721 /// ```
722 ///
723 /// [Reference](https://doc.rust-lang.org/reference/types/tuple.html)
724 struct TupleType { T!['('], fields: [TypeRef], T![')'] }
725
726 /// The never type (i.e. the exclamation point).
727 ///
728 /// ```
729 /// type T = ❰ ! ❱;
730 ///
731 /// fn no_return() -> ❰ ! ❱ {
732 /// loop {}
733 /// }
734 /// ```
735 ///
736 /// [Reference](https://doc.rust-lang.org/reference/types/never.html)
737 struct NeverType { T![!] }
738
739 /// Path to a type.
740 /// Includes single identifier type names and elaborate paths with
741 /// generic parameters.
742 ///
743 /// ```
744 /// type Foo = ❰ String ❱;
745 /// type Bar = ❰ std::vec::Vec<T> ❱;
746 /// type Baz = ❰ ::bruh::<Bruuh as Iterator>::Item ❱;
747 /// ```
748 ///
749 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
750 struct PathType { Path }
751
752 /// Raw pointer type.
753 ///
754 /// ```
755 /// type Foo = ❰ *const u32 ❱;
756 /// type Bar = ❰ *mut u32 ❱;
757 /// ```
758 ///
759 /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html#raw-pointers-const-and-mut)
760 struct PointerType { T![*], T![const], T![mut], TypeRef }
761
762 /// Array type.
763 ///
764 /// ```
765 /// type Foo = ❰ [u32; 24 - 3] ❱;
766 /// ```
767 ///
768 /// [Reference](https://doc.rust-lang.org/reference/types/array.html)
769 struct ArrayType { T!['['], TypeRef, T![;], Expr, T![']'] }
770
771 /// Slice type.
772 ///
773 /// ```
774 /// type Foo = ❰ [u8] ❱;
775 /// ```
776 ///
777 /// [Reference](https://doc.rust-lang.org/reference/types/slice.html)
778 struct SliceType { T!['['], TypeRef, T![']'] }
779
780 /// Reference type.
781 ///
782 /// ```
783 /// type Foo = ❰ &'static str ❱;
784 /// ```
785 ///
786 /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html)
787 struct ReferenceType { T![&], T![lifetime], T![mut], TypeRef }
788
789 /// Placeholder type (i.e. the underscore).
790 ///
791 /// ```
792 /// let foo: ❰ _ ❱ = 42_u32;
793 /// ```
794 ///
795 /// [Reference](https://doc.rust-lang.org/reference/types/inferred.html)
796 struct PlaceholderType { T![_] }
797
798 /// Function pointer type (not to be confused with `Fn*` family of traits).
799 ///
800 /// ```
801 /// type Foo = ❰ async fn(#[attr] u32, named: bool) -> u32 ❱;
802 ///
803 /// type Bar = ❰ extern "C" fn(variadic: u32, #[attr] ...) ❱;
804 /// ```
805 ///
806 /// [Reference](https://doc.rust-lang.org/reference/types/function-pointer.html)
807 struct FnPointerType { Abi, T![unsafe], T![fn], ParamList, RetType }
808
809 /// Higher order type.
810 ///
811 /// ```
812 /// type Foo = ❰ for<'a> fn(&'a str) ❱;
813 /// ```
814 ///
815 /// [Reference](https://doc.rust-lang.org/nomicon/hrtb.html)
816 struct ForType { T![for], TypeParamList, TypeRef }
817
818 /// Opaque `impl Trait` type.
819 ///
820 /// ```
821 /// fn foo(bar: ❰ impl Debug + Eq ❱) {}
822 /// ```
823 ///
824 /// [Reference](https://doc.rust-lang.org/reference/types/impl-trait.html)
825 struct ImplTraitType: TypeBoundsOwner { T![impl] }
826
827 /// Trait object type.
828 ///
829 /// ```
830 /// type Foo = ❰ dyn Debug ❱;
831 /// ```
832 ///
833 /// [Reference](https://doc.rust-lang.org/reference/types/trait-object.html)
834 struct DynTraitType: TypeBoundsOwner { T![dyn] }
835
836 /// Tuple literal.
837 ///
838 /// ```
839 /// ❰ (42, true) ❱;
840 /// ```
841 ///
842 /// [Reference](https://doc.rust-lang.org/reference/expressions/tuple-expr.html)
843 struct TupleExpr: AttrsOwner { T!['('], exprs: [Expr], T![')'] }
844
845 /// Array literal.
846 ///
847 /// ```
848 /// ❰ [#![inner_attr] true, false, true] ❱;
849 ///
850 /// ❰ ["baz"; 24] ❱;
851 /// ```
852 ///
853 /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
854 struct ArrayExpr: AttrsOwner { T!['['], exprs: [Expr], T![;], T![']'] }
855
856 /// Parenthesized expression.
857 /// Note: parens are only used for grouping, this is not a tuple literal.
858 ///
859 /// ```
860 /// ❰ (#![inner_attr] 2 + 2) ❱ * 2;
861 /// ```
862 ///
863 /// [Reference](https://doc.rust-lang.org/reference/expressions/grouped-expr.html)
864 struct ParenExpr: AttrsOwner { T!['('], Expr, T![')'] }
865
866 /// Path to a symbol in expression context.
867 /// Includes single identifier variable names and elaborate paths with
868 /// generic parameters.
869 ///
870 /// ```
871 /// ❰ Some::<i32> ❱;
872 /// ❰ foo ❱ + 42;
873 /// ❰ Vec::<i32>::push ❱;
874 /// ❰ <[i32]>::reverse ❱;
875 /// ❰ <String as std::borrow::Borrow<str>>::borrow ❱;
876 /// ```
877 ///
878 /// [Reference](https://doc.rust-lang.org/reference/expressions/path-expr.html)
879 struct PathExpr { Path }
880
881 /// Anonymous callable object literal a.k.a. closure, lambda or functor.
882 ///
883 /// ```
884 /// ❰ || 42 ❱;
885 /// ❰ |a: u32| val + 1 ❱;
886 /// ❰ async |#[attr] Pattern(_): Pattern| { bar } ❱;
887 /// ❰ move || baz ❱;
888 /// ❰ || -> u32 { closure_with_ret_type_annotation_requires_block_expr } ❱
889 /// ```
890 ///
891 /// [Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html)
892 struct LambdaExpr: AttrsOwner {
893 T![static], // Note(@matklad): I belive this is (used to be?) syntax for generators
894 T![async],
895 T![move],
896 ParamList,
897 RetType,
898 body: Expr,
899 }
900
901 /// If expression. Includes both regular `if` and `if let` forms.
902 /// Beware that `else if` is a special case syntax sugar, because in general
903 /// there has to be block expression after `else`.
904 ///
905 /// ```
906 /// ❰ if bool_cond { 42 } ❱
907 /// ❰ if bool_cond { 42 } else { 24 } ❱
908 /// ❰ if bool_cond { 42 } else if bool_cond2 { 42 } ❱
909 ///
910 /// ❰
911 /// if let Pattern(foo) = bar {
912 /// foo
913 /// } else {
914 /// panic!();
915 /// }
916 /// ❱
917 /// ```
918 ///
919 /// [Reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
920 struct IfExpr: AttrsOwner { T![if], Condition }
921
922 /// Unconditional loop expression.
923 ///
924 /// ```
925 /// ❰
926 /// loop {
927 /// // yeah, it's that simple...
928 /// }
929 /// ❱
930 /// ```
931 ///
932 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html)
933 struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] }
934
935 /// Block expression with an optional prefix (label, try ketword,
936 /// unsafe keyword, async keyword...).
937 ///
938 /// ```
939 /// ❰
940 /// 'label: try {
941 /// None?
942 /// }
943 /// ❱
944 /// ```
945 ///
946 /// - [try block](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html)
947 /// - [unsafe block](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks)
948 /// - [async block](https://doc.rust-lang.org/reference/expressions/block-expr.html#async-blocks)
949 struct EffectExpr: AttrsOwner { Label, T![try], T![unsafe], T![async], BlockExpr }
950
951
952 /// For loop expression.
953 /// Note: record struct literals are not valid as iterable expression
954 /// due to ambiguity.
955 ///
956 /// ```
957 /// ❰
958 /// for i in (0..4) {
959 /// dbg!(i);
960 /// }
961 /// ❱
962 /// ```
963 ///
964 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops)
965 struct ForExpr: AttrsOwner, LoopBodyOwner {
966 T![for],
967 Pat,
968 T![in],
969 iterable: Expr,
970 }
971
972 /// While loop expression. Includes both regular `while` and `while let` forms.
973 ///
974 /// ```
975 /// ❰
976 /// while bool_cond {
977 /// 42;
978 /// }
979 /// ❱
980 /// ❰
981 /// while let Pattern(foo) = bar {
982 /// bar += 1;
983 /// }
984 /// ❱
985 /// ```
986 ///
987 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
988 struct WhileExpr: AttrsOwner, LoopBodyOwner { T![while], Condition }
989
990 /// Continue expression.
991 ///
992 /// ```
993 /// while bool_cond {
994 /// ❰ continue ❱;
995 /// }
996 ///
997 /// 'outer: loop {
998 /// loop {
999 /// ❰ continue 'outer ❱;
1000 /// }
1001 /// }
1002 ///
1003 /// ```
1004 ///
1005 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions)
1006 struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] }
1007
1008 /// Break expression.
1009 ///
1010 /// ```
1011 /// while bool_cond {
1012 /// ❰ break ❱;
1013 /// }
1014 /// 'outer: loop {
1015 /// for foo in bar {
1016 /// ❰ break 'outer ❱;
1017 /// }
1018 /// }
1019 /// 'outer: loop {
1020 /// loop {
1021 /// ❰ break 'outer 42 ❱;
1022 /// }
1023 /// }
1024 /// ```
1025 ///
1026 /// [Refernce](https://doc.rust-lang.org/reference/expressions/loop-expr.html#break-expressions)
1027 struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr }
1028
1029 /// Label.
1030 ///
1031 /// ```
1032 /// ❰ 'outer: ❱ loop {}
1033 ///
1034 /// let foo = ❰ 'bar: ❱ loop {}
1035 ///
1036 /// ❰ 'baz: ❱ {
1037 /// break 'baz;
1038 /// }
1039 /// ```
1040 ///
1041 /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html?highlight=label#loop-labels)
1042 /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
1043 struct Label { T![lifetime] }
1044
1045 /// Block expression. Includes unsafe blocks and block labels.
1046 ///
1047 /// ```
1048 /// let foo = ❰
1049 /// {
1050 /// #![inner_attr]
1051 /// ❰ { } ❱
1052 ///
1053 /// ❰ 'label: { break 'label } ❱
1054 /// }
1055 /// ❱;
1056 /// ```
1057 ///
1058 /// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html)
1059 /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md)
1060 struct BlockExpr: AttrsOwner, ModuleItemOwner {
1061 Label, T!['{'], statements: [Stmt], Expr, T!['}'],
1062 }
1063
1064 /// Return expression.
1065 ///
1066 /// ```
1067 /// || ❰ return 42 ❱;
1068 ///
1069 /// fn bar() {
1070 /// ❰ return ❱;
1071 /// }
1072 /// ```
1073 ///
1074 /// [Reference](https://doc.rust-lang.org/reference/expressions/return-expr.html)
1075 struct ReturnExpr: AttrsOwner { Expr }
1076
1077 /// Call expression (not to be confused with method call expression, it is
1078 /// a separate ast node).
1079 ///
1080 /// ```
1081 /// ❰ foo() ❱;
1082 /// ❰ &str::len("bar") ❱;
1083 /// ❰ <&str as PartialEq<&str>>::eq(&"", &"") ❱;
1084 /// ```
1085 ///
1086 /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
1087 struct CallExpr: ArgListOwner { Expr }
1088
1089 /// Method call expression.
1090 ///
1091 /// ```
1092 /// ❰ receiver_expr.method() ❱;
1093 /// ❰ receiver_expr.method::<T>(42, true) ❱;
1094 ///
1095 /// ❰ ❰ ❰ foo.bar() ❱ .baz() ❱ .bruh() ❱;
1096 /// ```
1097 ///
1098 /// [Reference](https://doc.rust-lang.org/reference/expressions/method-call-expr.html)
1099 struct MethodCallExpr: AttrsOwner, ArgListOwner {
1100 Expr, T![.], NameRef, TypeArgList,
1101 }
1102
1103 /// Index expression a.k.a. subscript operator call.
1104 ///
1105 /// ```
1106 /// ❰ foo[42] ❱;
1107 /// ```
1108 ///
1109 /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html)
1110 struct IndexExpr: AttrsOwner { T!['['], T![']'] }
1111
1112 /// Field access expression.
1113 ///
1114 /// ```
1115 /// ❰ expr.bar ❱;
1116 ///
1117 /// ❰ ❰ ❰ foo.bar ❱ .baz ❱ .bruh ❱;
1118 /// ```
1119 ///
1120 /// [Reference](https://doc.rust-lang.org/reference/expressions/field-expr.html)
1121 struct FieldExpr: AttrsOwner { Expr, T![.], NameRef }
1122
1123 /// Await operator call expression.
1124 ///
1125 /// ```
1126 /// ❰ expr.await ❱;
1127 /// ```
1128 ///
1129 /// [Reference](https://doc.rust-lang.org/reference/expressions/await-expr.html)
1130 struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] }
1131
1132 /// The question mark operator call.
1133 ///
1134 /// ```
1135 /// ❰ expr? ❱;
1136 /// ```
1137 ///
1138 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator)
1139 struct TryExpr: AttrsOwner { Expr, T![?] }
1140
1141 /// Type cast expression.
1142 ///
1143 /// ```
1144 /// ❰ expr as T ❱;
1145 /// ```
1146 ///
1147 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions)
1148 struct CastExpr: AttrsOwner { Expr, T![as], TypeRef }
1149
1150
1151 /// Borrow operator call.
1152 ///
1153 /// ```
1154 /// ❰ &foo ❱;
1155 /// ❰ &mut bar ❱;
1156 /// ❰ &raw const bar ❱;
1157 /// ❰ &raw mut bar ❱;
1158 /// ```
1159 ///
1160 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators)
1161 struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], T![const], Expr }
1162
1163 /// Prefix operator call. This is either `!` or `*` or `-`.
1164 ///
1165 /// ```
1166 /// ❰ !foo ❱;
1167 /// ❰ *bar ❱;
1168 /// ❰ -42 ❱;
1169 /// ```
1170 ///
1171 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html)
1172 struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr }
1173
1174 /// Box operator call.
1175 ///
1176 /// ```
1177 /// ❰ box 42 ❱;
1178 /// ```
1179 ///
1180 /// [RFC](https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b1d20284b43f87cbe1c6/text/0809-box-and-in-for-stdlib.md)
1181 struct BoxExpr: AttrsOwner { T![box], Expr }
1182
1183 /// Range operator call.
1184 ///
1185 /// ```
1186 /// ❰ 0..42 ❱;
1187 /// ❰ ..42 ❱;
1188 /// ❰ 0.. ❱;
1189 /// ❰ .. ❱;
1190 /// ❰ 0..=42 ❱;
1191 /// ❰ ..=42 ❱;
1192 /// ```
1193 ///
1194 /// [Reference](https://doc.rust-lang.org/reference/expressions/range-expr.html)
1195 struct RangeExpr: AttrsOwner { /*RangeOp*/ }
1196
1197
1198 /// Binary operator call.
1199 /// Includes all arithmetic, logic, bitwise and assignment operators.
1200 ///
1201 /// ```
1202 /// ❰ 2 + ❰ 2 * 2 ❱ ❱;
1203 /// ❰ ❰ true && false ❱ || true ❱;
1204 /// ```
1205 ///
1206 /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators)
1207 struct BinExpr: AttrsOwner { /*BinOp*/ }
1208
1209
1210 /// [Raw] string, [raw] byte string, char, byte, integer, float or bool literal.
1211 ///
1212 /// ```
1213 /// ❰ "str" ❱;
1214 /// ❰ br##"raw byte str"## ❱;
1215 /// ❰ 'c' ❱;
1216 /// ❰ b'c' ❱;
1217 /// ❰ 42 ❱;
1218 /// ❰ 1e9 ❱;
1219 /// ❰ true ❱;
1220 /// ```
1221 ///
1222 /// [Reference](https://doc.rust-lang.org/reference/expressions/literal-expr.html)
1223 struct Literal { /*LiteralToken*/ }
1224
1225 /// Match expression.
1226 ///
1227 /// ```
1228 /// ❰
1229 /// match expr {
1230 /// Pat1 => {}
1231 /// Pat2(_) => 42,
1232 /// }
1233 /// ❱
1234 /// ```
1235 ///
1236 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1237 struct MatchExpr: AttrsOwner { T![match], Expr, MatchArmList }
1238
1239 /// Match arm list part of match expression. Includes its inner attributes.
1240 ///
1241 /// ```
1242 /// match expr
1243 /// ❰
1244 /// {
1245 /// #![inner_attr]
1246 /// Pat1 => {}
1247 /// Pat2(_) => 42,
1248 /// }
1249 /// ❱
1250 /// ```
1251 ///
1252 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1253 struct MatchArmList: AttrsOwner { T!['{'], arms: [MatchArm], T!['}'] }
1254
1255
1256 /// Match arm.
1257 /// Note: record struct literals are not valid as target match expression
1258 /// due to ambiguity.
1259 /// ```
1260 /// match expr {
1261 /// ❰ #[attr] Pattern(it) if bool_cond => it ❱,
1262 /// }
1263 /// ```
1264 ///
1265 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html)
1266 struct MatchArm: AttrsOwner {
1267 pat: Pat,
1268 guard: MatchGuard,
1269 T![=>],
1270 Expr,
1271 }
1272
1273 /// Match guard.
1274 ///
1275 /// ```
1276 /// match expr {
1277 /// Pattern(it) ❰ if bool_cond ❱ => it,
1278 /// }
1279 /// ```
1280 ///
1281 /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards)
1282 struct MatchGuard { T![if], Expr }
1283
1284 /// Record literal expression. The same syntax is used for structs,
1285 /// unions and record enum variants.
1286 ///
1287 /// ```
1288 /// ❰
1289 /// foo::Bar {
1290 /// #![inner_attr]
1291 /// baz: 42,
1292 /// bruh: true,
1293 /// ..spread
1294 /// }
1295 /// ❱
1296 /// ```
1297 ///
1298 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1299 struct RecordLit { Path, RecordFieldList}
1300
1301 /// Record field list including enclosing curly braces.
1302 ///
1303 /// foo::Bar ❰
1304 /// {
1305 /// baz: 42,
1306 /// ..spread
1307 /// }
1308 /// ❱
1309 ///
1310 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1311 struct RecordFieldList {
1312 T!['{'],
1313 fields: [RecordField],
1314 T![..],
1315 spread: Expr,
1316 T!['}']
1317 }
1318
1319 /// Record field.
1320 ///
1321 /// ```
1322 /// foo::Bar {
1323 /// ❰ #[attr] baz: 42 ❱
1324 /// }
1325 /// ```
1326 ///
1327 /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html)
1328 struct RecordField: AttrsOwner { NameRef, T![:], Expr }
1329
1330 /// Disjunction of patterns.
1331 ///
1332 /// ```
1333 /// let ❰ Foo(it) | Bar(it) | Baz(it) ❱ = bruh;
1334 /// ```
1335 ///
1336 /// [Reference](https://doc.rust-lang.org/reference/patterns.html)
1337 struct OrPat { pats: [Pat] }
1338
1339 /// Parenthesized pattern.
1340 /// Note: parens are only used for grouping, this is not a tuple pattern.
1341 ///
1342 /// ```
1343 /// if let ❰ &(0..=42) ❱ = foo {}
1344 /// ```
1345 ///
1346 /// https://doc.rust-lang.org/reference/patterns.html#grouped-patterns
1347 struct ParenPat { T!['('], Pat, T![')'] }
1348
1349 /// Reference pattern.
1350 /// Note: this has nothing to do with `ref` keyword, the latter is used in bind patterns.
1351 ///
1352 /// ```
1353 /// let ❰ &mut foo ❱ = bar;
1354 ///
1355 /// let ❰ & ❰ &mut ❰ &_ ❱ ❱ ❱ = baz;
1356 /// ```
1357 ///
1358 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#reference-patterns)
1359 struct RefPat { T![&], T![mut], Pat }
1360
1361 /// Box pattern.
1362 ///
1363 /// ```
1364 /// let ❰ box foo ❱ = box 42;
1365 /// ```
1366 ///
1367 /// [Unstable book](https://doc.rust-lang.org/unstable-book/language-features/box-patterns.html)
1368 struct BoxPat { T![box], Pat }
1369
1370 /// Bind pattern.
1371 ///
1372 /// ```
1373 /// match foo {
1374 /// Some(❰ ref mut bar ❱) => {}
1375 /// ❰ baz @ None ❱ => {}
1376 /// }
1377 /// ```
1378 ///
1379 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#identifier-patterns)
1380 struct BindPat: AttrsOwner, NameOwner { T![ref], T![mut], T![@], Pat }
1381
1382 /// Placeholder pattern a.k.a. the wildcard pattern or the underscore.
1383 ///
1384 /// ```
1385 /// let ❰ _ ❱ = foo;
1386 /// ```
1387 ///
1388 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern)
1389 struct PlaceholderPat { T![_] }
1390
1391 /// Rest-of-the record/tuple pattern.
1392 /// Note: this is not the unbonded range pattern (even more: it doesn't exist).
1393 ///
1394 /// ```
1395 /// let Foo { bar, ❰ .. ❱ } = baz;
1396 /// let (❰ .. ❱, bruh) = (42, 24, 42);
1397 /// let Bruuh(❰ .. ❱) = bruuuh;
1398 /// ```
1399 ///
1400 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1401 struct DotDotPat { T![..] }
1402
1403 /// Path pattern.
1404 /// Doesn't include the underscore pattern (it is a special case, namely `PlaceholderPat`).
1405 ///
1406 /// ```
1407 /// let ❰ foo::bar::Baz ❱ { .. } = bruh;
1408 /// if let ❰ CONST ❱ = 42 {}
1409 /// ```
1410 ///
1411 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#path-patterns)
1412 struct PathPat { Path }
1413
1414 /// Slice pattern.
1415 ///
1416 /// ```
1417 /// let ❰ [foo, bar, baz] ❱ = [1, 2, 3];
1418 /// ```
1419 ///
1420 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#slice-patterns)
1421 struct SlicePat { T!['['], args: [Pat], T![']'] }
1422
1423 /// Range pattern.
1424 ///
1425 /// ```
1426 /// match foo {
1427 /// ❰ 0..42 ❱ => {}
1428 /// ❰ 0..=42 ❱ => {}
1429 /// }
1430 /// ```
1431 ///
1432 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#range-patterns)
1433 struct RangePat { } // FIXME(@matklad): here should be T![..], T![..=] I think, if we don't already have an accessor in expresions_ext
1434
1435 /// Literal pattern.
1436 /// Includes only bool, number, char, and string literals.
1437 ///
1438 /// ```
1439 /// match foo {
1440 /// Number(❰ 42 ❱) => {}
1441 /// String(❰ "42" ❱) => {}
1442 /// Bool(❰ true ❱) => {}
1443 /// }
1444 /// ```
1445 ///
1446 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#literal-patterns)
1447 struct LiteralPat { Literal }
1448
1449 /// Macro invocation in pattern position.
1450 ///
1451 /// ```
1452 /// let ❰ foo!(my custom syntax) ❱ = baz;
1453 ///
1454 /// ```
1455 /// [Reference](https://doc.rust-lang.org/reference/macros.html#macro-invocation)
1456 struct MacroPat { MacroCall }
1457
1458 /// Record literal pattern.
1459 ///
1460 /// ```
1461 /// let ❰ foo::Bar { baz, .. } ❱ = bruh;
1462 /// ```
1463 ///
1464 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1465 struct RecordPat { RecordFieldPatList, Path }
1466
1467 /// Record literal's field patterns list including enclosing curly braces.
1468 ///
1469 /// ```
1470 /// let foo::Bar ❰ { baz, bind @ bruh, .. } ❱ = bruuh;
1471 /// ``
1472 ///
1473 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1474 struct RecordFieldPatList {
1475 T!['{'],
1476 pats: [RecordInnerPat],
1477 record_field_pats: [RecordFieldPat],
1478 bind_pats: [BindPat],
1479 T![..],
1480 T!['}']
1481 }
1482
1483 /// Record literal's field pattern.
1484 /// Note: record literal can also match tuple structs.
1485 ///
1486 /// ```
1487 /// let Foo { ❰ bar: _ ❱ } = baz;
1488 /// let TupleStruct { ❰ 0: _ ❱ } = bruh;
1489 /// ```
1490 ///
1491 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns)
1492 struct RecordFieldPat: AttrsOwner { NameRef, T![:], Pat }
1493
1494 /// Tuple struct literal pattern.
1495 ///
1496 /// ```
1497 /// let ❰ foo::Bar(baz, bruh) ❱ = bruuh;
1498 /// ```
1499 ///
1500 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-struct-patterns)
1501 struct TupleStructPat { Path, T!['('], args: [Pat], T![')'] }
1502
1503 /// Tuple pattern.
1504 /// Note: this doesn't include tuple structs (see `TupleStructPat`)
1505 ///
1506 /// ```
1507 /// let ❰ (foo, bar, .., baz) ❱ = bruh;
1508 /// ```
1509 ///
1510 /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-patterns)
1511 struct TuplePat { T!['('], args: [Pat], T![')'] }
1512
1513 /// Visibility.
1514 ///
1515 /// ```
1516 /// ❰ pub mod ❱ foo;
1517 /// ❰ pub(crate) ❱ struct Bar;
1518 /// ❰ pub(self) ❱ enum Baz {}
1519 /// ❰ pub(super) ❱ fn bruh() {}
1520 /// ❰ pub(in bruuh::bruuuh) ❱ type T = u64;
1521 /// ```
1522 ///
1523 /// [Reference](https://doc.rust-lang.org/reference/visibility-and-privacy.html)
1524 struct Visibility { T![pub], T![super], T![self], T![crate] }
1525
1526 /// Single identifier.
1527 /// Note(@matklad): `Name` is for things that install a new name into the scope,
1528 /// `NameRef` is a usage of a name. Most of the time, this definition/reference
1529 /// distinction can be determined purely syntactically, ie in
1530 /// ```
1531 /// fn foo() { foo() }
1532 /// ```
1533 /// the first foo is `Name`, the second one is `NameRef`.
1534 /// The notable exception are patterns, where in
1535 /// ``
1536 /// let x = 92
1537 /// ```
1538 /// `x` can be semantically either a name or a name ref, depeding on
1539 /// wether there's an `x` constant in scope.
1540 /// We use `Name` for patterns, and disambiguate semantically (see `NameClass` in ide_db).
1541 ///
1542 /// ```
1543 /// let ❰ foo ❱ = bar;
1544 /// struct ❰ Baz ❱;
1545 /// fn ❰ bruh ❱() {}
1546 /// ```
1547 ///
1548 /// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
1549 struct Name { T![ident] }
1550
1551 /// Reference to a name.
1552 /// See the explanation on the difference between `Name` and `NameRef`
1553 /// in `Name` ast node docs.
1554 ///
1555 /// ```
1556 /// let foo = ❰ bar ❱(❰ Baz(❰ bruh ❱) ❱;
1557 /// ```
1558 ///
1559 /// [Reference](https://doc.rust-lang.org/reference/identifiers.html)
1560 struct NameRef { }
1561
1562 /// Macro call.
1563 /// Includes all of its attributes and doc comments.
1564 ///
1565 /// ```
1566 /// ❰
1567 /// /// Docs
1568 /// #[attr]
1569 /// macro_rules! foo { // macro rules is also a macro call
1570 /// ($bar: tt) => {}
1571 /// }
1572 /// ❱
1573 ///
1574 /// // semicolon is a part of `MacroCall` when it is used in item positions
1575 /// ❰ foo!(); ❱
1576 ///
1577 /// fn main() {
1578 /// ❰ foo!() ❱; // macro call in expression positions doesn't include the semi
1579 /// }
1580 /// ```
1581 ///
1582 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
1583 struct MacroCall: NameOwner, AttrsOwner, DocCommentsOwner {
1584 Path, T![!], TokenTree, T![;]
1585 }
1586
1587 /// Attribute.
1588 ///
1589 /// ```
1590 /// ❰ #![inner_attr] ❱
1591 ///
1592 /// ❰ #[attr] ❱
1593 /// ❰ #[foo = "bar"] ❱
1594 /// ❰ #[baz(bruh::bruuh = "42")] ❱
1595 /// struct Foo;
1596 /// ```
1597 ///
1598 /// [Reference](https://doc.rust-lang.org/reference/attributes.html)
1599 struct Attr { T![#], T![!], T!['['], Path, T![=], input: AttrInput, T![']'] }
1600
1601 /// Stores a list of lexer tokens and other `TokenTree`s.
1602 /// It appears in attributes, macro_rules and macro call (foo!)
1603 ///
1604 /// ```
1605 /// macro_call! ❰ { my syntax here } ❱;
1606 /// ```
1607 ///
1608 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
1609 struct TokenTree {}
1610
1611 /// Generic lifetime, type and constants parameters list **declaration**.
1612 ///
1613 /// ```
1614 /// fn foo❰ <'a, 'b, T, U, const BAR: u64> ❱() {}
1615 ///
1616 /// struct Baz❰ <T> ❱(T);
1617 ///
1618 /// impl❰ <T> ❱ Bruh<T> {}
1619 ///
1620 /// type Bruuh = for❰ <'a> ❱ fn(&'a str) -> &'a str;
1621 /// ```
1622 ///
1623 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1624 struct TypeParamList {
1625 T![<],
1626 generic_params: [GenericParam],
1627 type_params: [TypeParam],
1628 lifetime_params: [LifetimeParam],
1629 const_params: [ConstParam],
1630 T![>]
1631 }
1632
1633 /// Single type parameter **declaration**.
1634 ///
1635 /// ```
1636 /// fn foo<❰ K ❱, ❰ I ❱, ❰ E: Debug ❱, ❰ V = DefaultType ❱>() {}
1637 /// ```
1638 ///
1639 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1640 struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner {
1641 T![=],
1642 default_type: TypeRef,
1643 }
1644
1645 /// Const generic parameter **declaration**.
1646 /// ```
1647 /// fn foo<T, U, ❰ const BAR: usize ❱, ❰ const BAZ: bool ❱>() {}
1648 /// ```
1649 ///
1650 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
1651 struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner {
1652 T![=],
1653 default_val: Expr,
1654 }
1655
1656 /// Lifetime parameter **declaration**.
1657 ///
1658 /// ```
1659 /// fn foo<❰ 'a ❱, ❰ 'b ❱, V, G, D>(bar: &'a str, baz: &'b mut str) {}
1660 /// ```
1661 ///
1662 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html)
1663 struct LifetimeParam: AttrsOwner { T![lifetime] }
1664
1665 /// Type bound declaration clause.
1666 ///
1667 /// ```
1668 /// fn foo<T: ❰ ?Sized ❱ + ❰ Debug ❱>() {}
1669 ///
1670 /// trait Bar<T>
1671 /// where
1672 /// T: ❰ Send ❱ + ❰ Sync ❱
1673 /// {
1674 /// type Baz: ❰ !Sync ❱ + ❰ Debug ❱ + ❰ ?const Add ❱;
1675 /// }
1676 /// ```
1677 ///
1678 /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
1679 struct TypeBound { T![lifetime], /* Question, */ T![const], /* Question, */ TypeRef }
1680
1681 /// Type bounds list.
1682 ///
1683 /// ```
1684 ///
1685 /// fn foo<T: ❰ ?Sized + Debug ❱>() {}
1686 ///
1687 /// trait Bar<T>
1688 /// where
1689 /// T: ❰ Send + Sync ❱
1690 /// {
1691 /// type Baz: ❰ !Sync + Debug ❱;
1692 /// }
1693 /// ```
1694 ///
1695 /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html)
1696 struct TypeBoundList { bounds: [TypeBound] }
1697
1698 /// Single where predicate.
1699 ///
1700 /// ```
1701 /// trait Foo<'a, 'b, T>
1702 /// where
1703 /// ❰ 'a: 'b ❱,
1704 /// ❰ T: IntoIterator ❱,
1705 /// ❰ for<'c> <T as IntoIterator>::Item: Bar<'c> ❱
1706 /// {}
1707 /// ```
1708 ///
1709 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
1710 struct WherePred: TypeBoundsOwner { T![for], TypeParamList, T![lifetime], TypeRef }
1711
1712 /// Where clause.
1713 ///
1714 /// ```
1715 /// trait Foo<'a, T> ❰ where 'a: 'static, T: Debug ❱ {}
1716 ///
1717 /// ```
1718 ///
1719 /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses)
1720 struct WhereClause { T![where], predicates: [WherePred] }
1721
1722 /// Abi declaration.
1723 /// Note: the abi string is optional.
1724 ///
1725 /// ```
1726 /// ❰ extern "C" ❱ {
1727 /// fn foo() {}
1728 /// }
1729 ///
1730 /// type Bar = ❰ extern ❱ fn() -> u32;
1731 ///
1732 /// type Baz = ❰ extern r#"stdcall"# ❱ fn() -> bool;
1733 /// ```
1734 ///
1735 /// - [Extern blocks reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
1736 /// - [FFI function pointers reference](https://doc.rust-lang.org/reference/items/functions.html#functions)
1737 struct Abi { /*String*/ }
1738
1739 /// Expression statement.
1740 ///
1741 /// ```
1742 /// ❰ 42; ❱
1743 /// ❰ foo(); ❱
1744 /// ❰ (); ❱
1745 /// ❰ {}; ❱
1746 ///
1747 /// // constructions with trailing curly brace can omit the semicolon
1748 /// // but only when there are satements immediately after them (this is important!)
1749 /// ❰ if bool_cond { } ❱
1750 /// ❰ loop {} ❱
1751 /// ❰ somestatment; ❱
1752 /// ```
1753 ///
1754 /// [Reference](https://doc.rust-lang.org/reference/statements.html)
1755 struct ExprStmt: AttrsOwner { Expr, T![;] }
1756
1757 /// Let statement.
1758 ///
1759 /// ```
1760 /// ❰ #[attr] let foo; ❱
1761 /// ❰ let bar: u64; ❱
1762 /// ❰ let baz = 42; ❱
1763 /// ❰ let bruh: bool = true; ❱
1764 /// ```
1765 ///
1766 /// [Reference](https://doc.rust-lang.org/reference/statements.html#let-statements)
1767 struct LetStmt: AttrsOwner, TypeAscriptionOwner {
1768 T![let],
1769 Pat,
1770 T![=],
1771 initializer: Expr,
1772 T![;],
1773 }
1774
1775 /// Condition of `if` or `while` expression.
1776 ///
1777 /// ```
1778 /// if ❰ true ❱ {}
1779 /// if ❰ let Pat(foo) = bar ❱ {}
1780 ///
1781 /// while ❰ true ❱ {}
1782 /// while ❰ let Pat(baz) = bruh ❱ {}
1783 /// ```
1784 ///
1785 /// [If expression reference](https://doc.rust-lang.org/reference/expressions/if-expr.html)
1786 /// [While expression reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops)
1787 struct Condition { T![let], Pat, T![=], Expr }
1788
1789 /// Parameter list **declaration**.
1790 ///
1791 /// ```
1792 /// fn foo❰ (a: u32, b: bool) ❱ -> u32 {}
1793 /// let bar = ❰ |a, b| ❱ {};
1794 ///
1795 /// impl Baz {
1796 /// fn bruh❰ (&self, a: u32) ❱ {}
1797 /// }
1798 /// ```
1799 ///
1800 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)ocs to codegen script
1801 struct ParamList { // FIXME: this node is used by closure expressions too, but hey use pipes instead of parens...
1802 T!['('],
1803 SelfParam,
1804 params: [Param],
1805 T![')']
1806 }
1807
1808 /// Self parameter **declaration**.
1809 ///
1810 /// ```
1811 /// impl Bruh {
1812 /// fn foo(❰ self ❱) {}
1813 /// fn bar(❰ &self ❱) {}
1814 /// fn baz(❰ &mut self ❱) {}
1815 /// fn blah<'a>(❰ &'a self ❱) {}
1816 /// fn blin(❰ self: Box<Self> ❱) {}
1817 /// }
1818 /// ```
1819 ///
1820 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
1821 struct SelfParam: TypeAscriptionOwner, AttrsOwner { T![&], T![mut], T![lifetime], T![self] }
1822
1823 /// Parameter **declaration**.
1824 ///
1825 /// ```
1826 /// fn foo(❰ #[attr] Pat(bar): Pat(u32) ❱, ❰ #[attr] _: bool ❱) {}
1827 ///
1828 /// extern "C" {
1829 /// fn bar(❰ baz: u32 ❱, ❰ ... ❱) -> u32;
1830 /// }
1831 /// ```
1832 ///
1833 /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)
1834 struct Param: TypeAscriptionOwner, AttrsOwner {
1835 Pat,
1836 T![...]
1837 }
1838
1839 /// Use declaration.
1840 ///
1841 /// ```
1842 /// ❰ #[attr] pub use foo; ❱
1843 /// ❰ use bar as baz; ❱
1844 /// ❰ use bruh::{self, bruuh}; ❱
1845 /// ❰ use { blin::blen, blah::* };
1846 /// ```
1847 ///
1848 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1849 struct UseItem: AttrsOwner, VisibilityOwner {
1850 T![use],
1851 UseTree,
1852 }
1853
1854 /// Use tree.
1855 ///
1856 /// ```
1857 /// pub use ❰ foo::❰ * ❱ ❱;
1858 /// use ❰ bar as baz ❱;
1859 /// use ❰ bruh::bruuh::{ ❰ self ❱, ❰ blin ❱ } ❱;
1860 /// use ❰ { ❰ blin::blen ❱ } ❱
1861 /// ```
1862 ///
1863 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1864 struct UseTree {
1865 Path, T![*], UseTreeList, Alias
1866 }
1867
1868 /// Item alias.
1869 /// Note: this is not the type alias.
1870 ///
1871 /// ```
1872 /// use foo ❰ as bar ❱;
1873 /// use baz::{bruh ❰ as _ ❱};
1874 /// extern crate bruuh ❰ as blin ❱;
1875 /// ```
1876 ///
1877 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1878 struct Alias: NameOwner { T![as] }
1879
1880 /// Sublist of use trees.
1881 ///
1882 /// ```
1883 /// use bruh::bruuh::❰ { ❰ self ❱, ❰ blin ❱ } ❱;
1884 /// use ❰ { blin::blen::❰ {} ❱ } ❱
1885 /// ```
1886 ///
1887 /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html)
1888 struct UseTreeList { T!['{'], use_trees: [UseTree], T!['}'] }
1889
1890 /// Extern crate item.
1891 ///
1892 /// ```
1893 /// ❰ #[attr] pub extern crate foo; ❱
1894 /// ❰ extern crate self as bar; ❱
1895 /// ```
1896 ///
1897 /// [Reference](https://doc.rust-lang.org/reference/items/extern-crates.html)
1898 struct ExternCrateItem: AttrsOwner, VisibilityOwner {
1899 T![extern], T![crate], NameRef, Alias,
1900 }
1901
1902 /// Call site arguments list.
1903 ///
1904 /// ```
1905 /// foo::<T, U>❰ (42, true) ❱;
1906 /// ```
1907 ///
1908 /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html)
1909 struct ArgList {
1910 T!['('],
1911 args: [Expr],
1912 T![')']
1913 }
1914
1915 /// Path to a symbol. Includes single identifier names and elaborate paths with
1916 /// generic parameters.
1917 ///
1918 /// ```
1919 /// (0..10).❰ ❰ collect ❱ ::<Vec<_>> ❱();
1920 /// ❰ ❰ ❰ Vec ❱ ::<u8> ❱ ::with_capacity ❱(1024);
1921 /// ❰ ❰ <❰ Foo ❱ as ❰ ❰ bar ❱ ::Bar ❱> ❱ ::baz ❱();
1922 /// ❰ ❰ <❰ bruh ❱> ❱ ::bruuh ❱();
1923 /// ```
1924 ///
1925 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
1926 struct Path {
1927 segment: PathSegment,
1928 T![::],
1929 qualifier: Path,
1930 }
1931
1932 /// Segment of the path to a symbol.
1933 /// Only path segment of an absolute path holds the `::` token,
1934 /// all other `::` tokens that connect path segments reside under `Path` itself.`
1935 ///
1936 /// ```
1937 /// (0..10).❰ collect ❱ :: ❰ <Vec<_>> ❱();
1938 /// ❰ Vec ❱ :: ❰ <u8> ❱ :: ❰ with_capacity ❱(1024);
1939 /// ❰ <❰ Foo ❱ as ❰ bar ❱ :: ❰ Bar ❱> ❱ :: ❰ baz ❱();
1940 /// ❰ <❰ bruh ❱> ❱ :: ❰ bruuh ❱();
1941 ///
1942 /// // Note that only in this case `::` token is inlcuded:
1943 /// ❰ ::foo ❱;
1944 /// ```
1945 ///
1946 /// [Reference](https://doc.rust-lang.org/reference/paths.html)
1947 struct PathSegment {
1948 T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>]
1949 }
1950
1951 /// List of type arguments that are passed at generic instantiation site.
1952 ///
1953 /// ```
1954 /// type _ = Foo ❰ ::<'a, u64, Item = Bar, 42, {true}> ❱::Bar;
1955 ///
1956 /// Vec❰ ::<bool> ❱::();
1957 /// ```
1958 ///
1959 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
1960 struct TypeArgList {
1961 T![::],
1962 T![<],
1963 generic_args: [GenericArg],
1964 type_args: [TypeArg],
1965 lifetime_args: [LifetimeArg],
1966 assoc_type_args: [AssocTypeArg],
1967 const_args: [ConstArg],
1968 T![>]
1969 }
1970
1971 /// Type argument that is passed at generic instantiation site.
1972 ///
1973 /// ```
1974 /// type _ = Foo::<'a, ❰ u64 ❱, ❰ bool ❱, Item = Bar, 42>::Baz;
1975 /// ```
1976 ///
1977 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
1978 struct TypeArg { TypeRef }
1979
1980 /// Associated type argument that is passed at generic instantiation site.
1981 /// ```
1982 /// type Foo = Bar::<'a, u64, bool, ❰ Item = Baz ❱, 42>::Bruh;
1983 ///
1984 /// trait Bruh<T>: Iterator<❰ Item: Debug ❱> {}
1985 /// ```
1986 ///
1987 struct AssocTypeArg : TypeBoundsOwner { NameRef, T![=], TypeRef }
1988
1989 /// Lifetime argument that is passed at generic instantiation site.
1990 ///
1991 /// ```
1992 /// fn foo<'a>(s: &'a str) {
1993 /// bar::<❰ 'a ❱>(s);
1994 /// }
1995 /// ```
1996 ///
1997 /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions)
1998 struct LifetimeArg { T![lifetime] }
1999
2000 /// Constant value argument that is passed at generic instantiation site.
2001 ///
2002 /// ```
2003 /// foo::<u32, ❰ { true } ❱>();
2004 ///
2005 /// bar::<❰ { 2 + 2} ❱>();
2006 /// ```
2007 ///
2008 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter)
2009 struct ConstArg { Literal, BlockExpr }
2010
2011
2012 /// FIXME: (@edwin0cheng) Remove it to use ItemList instead
2013 /// https://github.com/rust-analyzer/rust-analyzer/pull/4083#discussion_r422666243
2014 ///
2015 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
2016 struct MacroItems: ModuleItemOwner { }
2017
2018 /// FIXME: (@edwin0cheng) add some documentation here. As per the writing
2019 /// of this comment this ast node is not used.
2020 ///
2021 /// ```
2022 /// // FIXME: example here
2023 /// ```
2024 ///
2025 /// [Reference](https://doc.rust-lang.org/reference/macros.html)
2026 struct MacroStmts {
2027 statements: [Stmt],
2028 Expr,
2029 }
2030
2031 /// List of items in an extern block.
2032 ///
2033 /// ```
2034 /// extern "C" ❰
2035 /// {
2036 /// fn foo();
2037 /// static var: u32;
2038 /// }
2039 /// ❱
2040 /// ```
2041 ///
2042 /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
2043 struct ExternItemList: ModuleItemOwner {
2044 T!['{'],
2045 extern_items: [ExternItem],
2046 T!['}']
2047 }
2048
2049 /// Extern block.
2050 ///
2051 /// ```
2052 /// ❰
2053 /// extern "C" {
2054 /// fn foo();
2055 /// }
2056 /// ❱
2057 ///
2058 /// ```
2059 ///
2060 /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html)
2061 struct ExternBlock {
2062 Abi,
2063 ExternItemList
2064 }
2065
2066 /// Meta item in an attribute.
2067 ///
2068 /// ```
2069 /// #[❰ bar::baz = "42" ❱]
2070 /// #[❰ bruh(bruuh("true")) ❱]
2071 /// struct Foo;
2072 /// ```
2073 ///
2074 /// [Reference](https://doc.rust-lang.org/reference/attributes.html?highlight=meta,item#meta-item-attribute-syntax)
2075 struct MetaItem {
2076 Path, T![=], AttrInput, nested_meta_items: [MetaItem]
2077 }
2078
2079 /// Macro 2.0 definition.
2080 /// Their syntax is still WIP by rustc team...
2081 /// ```
2082 /// ❰
2083 /// macro foo { }
2084 /// ❱
2085 /// ```
2086 ///
2087 /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1584-macros.md)
2088 struct MacroDef {
2089 Name, TokenTree
2090 }
2091 },
2092 enums: &ast_enums! {
2093 /// Any kind of nominal type definition.
2094 enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner {
2095 StructDef, EnumDef, UnionDef,
2096 }
2097
2098 /// Any kind of **declared** generic parameter
2099 enum GenericParam {
2100 LifetimeParam,
2101 TypeParam,
2102 ConstParam
2103 }
2104
2105 /// Any kind of generic argument passed at instantiation site
2106 enum GenericArg {
2107 LifetimeArg,
2108 TypeArg,
2109 ConstArg,
2110 AssocTypeArg
2111 }
2112
2113 /// Any kind of construct valid in type context
2114 enum TypeRef {
2115 ParenType,
2116 TupleType,
2117 NeverType,
2118 PathType,
2119 PointerType,
2120 ArrayType,
2121 SliceType,
2122 ReferenceType,
2123 PlaceholderType,
2124 FnPointerType,
2125 ForType,
2126 ImplTraitType,
2127 DynTraitType,
2128 }
2129
2130 /// Any kind of top-level item that may appear in a module
2131 enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner {
2132 StructDef,
2133 UnionDef,
2134 EnumDef,
2135 FnDef,
2136 TraitDef,
2137 TypeAliasDef,
2138 ImplDef,
2139 UseItem,
2140 ExternCrateItem,
2141 ConstDef,
2142 StaticDef,
2143 Module,
2144 MacroCall,
2145 ExternBlock
2146 }
2147
2148
2149
2150 /// Any kind of item that may appear in an impl block
2151 ///
2152 /// // FIXME: impl blocks can also contain MacroCall
2153 enum AssocItem: NameOwner, AttrsOwner {
2154 FnDef, TypeAliasDef, ConstDef
2155 }
2156
2157 /// Any kind of item that may appear in an extern block
2158 ///
2159 /// // FIXME: extern blocks can also contain MacroCall
2160 enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner {
2161 FnDef, StaticDef
2162 }
2163
2164 /// Any kind of expression
2165 enum Expr: AttrsOwner {
2166 TupleExpr,
2167 ArrayExpr,
2168 ParenExpr,
2169 PathExpr,
2170 LambdaExpr,
2171 IfExpr,
2172 LoopExpr,
2173 ForExpr,
2174 WhileExpr,
2175 ContinueExpr,
2176 BreakExpr,
2177 Label,
2178 BlockExpr,
2179 ReturnExpr,
2180 MatchExpr,
2181 RecordLit,
2182 CallExpr,
2183 IndexExpr,
2184 MethodCallExpr,
2185 FieldExpr,
2186 AwaitExpr,
2187 TryExpr,
2188 EffectExpr,
2189 CastExpr,
2190 RefExpr,
2191 PrefixExpr,
2192 RangeExpr,
2193 BinExpr,
2194 Literal,
2195 MacroCall,
2196 BoxExpr,
2197 }
2198
2199 /// Any kind of pattern
2200 enum Pat {
2201 OrPat,
2202 ParenPat,
2203 RefPat,
2204 BoxPat,
2205 BindPat,
2206 PlaceholderPat,
2207 DotDotPat,
2208 PathPat,
2209 RecordPat,
2210 TupleStructPat,
2211 TuplePat,
2212 SlicePat,
2213 RangePat,
2214 LiteralPat,
2215 MacroPat,
2216 }
2217
2218 /// Any kind of pattern that appears directly inside of the curly
2219 /// braces of a record pattern
2220 enum RecordInnerPat {
2221 RecordFieldPat,
2222 BindPat
2223 }
2224
2225 /// Any kind of input to an attribute
2226 enum AttrInput { Literal, TokenTree }
2227
2228 /// Any kind of statement
2229 /// Note: there are no empty statements, these are just represented as
2230 /// bare semicolons without a dedicated statement ast node.
2231 enum Stmt {
2232 LetStmt,
2233 ExprStmt,
2234 // macro calls are parsed as expression statements
2235 }
2236
2237 /// Any kind of fields list (record or tuple field lists)
2238 enum FieldDefList {
2239 RecordFieldDefList,
2240 TupleFieldDefList,
2241 }
2242 },
2243};
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 745a25862..d6a72ccc0 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,34 +3,43 @@
3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype 3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype
4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. 4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`.
5 5
6use std::{collections::HashSet, fmt::Write}; 6use std::{
7 collections::{BTreeSet, HashSet},
8 fmt::Write,
9};
7 10
8use proc_macro2::{Punct, Spacing}; 11use proc_macro2::{Punct, Spacing};
9use quote::{format_ident, quote}; 12use quote::{format_ident, quote};
13use ungrammar::{Grammar, Rule};
10 14
11use crate::{ 15use crate::{
12 ast_src::{AstSrc, Field, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC}, 16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC},
13 codegen::{self, update, Mode}, 17 codegen::{self, update, Mode},
14 project_root, Result, 18 project_root, Result,
15}; 19};
16 20
17pub fn generate_syntax(mode: Mode) -> Result<()> { 21pub fn generate_syntax(mode: Mode) -> Result<()> {
22 let grammar = include_str!("rust.ungram")
23 .parse::<Grammar>()
24 .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err));
25 let ast = lower(&grammar);
26
18 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); 27 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS);
19 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 28 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
20 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 29 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
21 30
22 let ast_tokens_file = project_root().join(codegen::AST_TOKENS); 31 let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
23 let contents = generate_tokens(AST_SRC)?; 32 let contents = generate_tokens(&ast)?;
24 update(ast_tokens_file.as_path(), &contents, mode)?; 33 update(ast_tokens_file.as_path(), &contents, mode)?;
25 34
26 let ast_nodes_file = project_root().join(codegen::AST_NODES); 35 let ast_nodes_file = project_root().join(codegen::AST_NODES);
27 let contents = generate_nodes(KINDS_SRC, AST_SRC)?; 36 let contents = generate_nodes(KINDS_SRC, &ast)?;
28 update(ast_nodes_file.as_path(), &contents, mode)?; 37 update(ast_nodes_file.as_path(), &contents, mode)?;
29 38
30 Ok(()) 39 Ok(())
31} 40}
32 41
33fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> { 42fn generate_tokens(grammar: &AstSrc) -> Result<String> {
34 let tokens = grammar.tokens.iter().map(|token| { 43 let tokens = grammar.tokens.iter().map(|token| {
35 let name = format_ident!("{}", token); 44 let name = format_ident!("{}", token);
36 let kind = format_ident!("{}", to_upper_snake_case(token)); 45 let kind = format_ident!("{}", to_upper_snake_case(token));
@@ -62,13 +71,13 @@ fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> {
62 Ok(pretty) 71 Ok(pretty)
63} 72}
64 73
65fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { 74fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> {
66 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar 75 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
67 .nodes 76 .nodes
68 .iter() 77 .iter()
69 .map(|node| { 78 .map(|node| {
70 let name = format_ident!("{}", node.name); 79 let name = format_ident!("{}", node.name);
71 let kind = format_ident!("{}", to_upper_snake_case(node.name)); 80 let kind = format_ident!("{}", to_upper_snake_case(&node.name));
72 let traits = node.traits.iter().map(|trait_name| { 81 let traits = node.traits.iter().map(|trait_name| {
73 let trait_name = format_ident!("{}", trait_name); 82 let trait_name = format_ident!("{}", trait_name);
74 quote!(impl ast::#trait_name for #name {}) 83 quote!(impl ast::#trait_name for #name {})
@@ -192,8 +201,8 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
192 }) 201 })
193 .unzip(); 202 .unzip();
194 203
195 let enum_names = grammar.enums.iter().map(|it| it.name); 204 let enum_names = grammar.enums.iter().map(|it| &it.name);
196 let node_names = grammar.nodes.iter().map(|it| it.name); 205 let node_names = grammar.nodes.iter().map(|it| &it.name);
197 206
198 let display_impls = 207 let display_impls =
199 enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| { 208 enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
@@ -212,9 +221,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
212 .nodes 221 .nodes
213 .iter() 222 .iter()
214 .map(|kind| to_pascal_case(kind)) 223 .map(|kind| to_pascal_case(kind))
215 .filter(|name| !defined_nodes.contains(name.as_str())) 224 .filter(|name| !defined_nodes.iter().any(|&it| it == name))
216 { 225 {
217 eprintln!("Warning: node {} not defined in ast source", node); 226 drop(node)
227 // TODO: restore this
228 // eprintln!("Warning: node {} not defined in ast source", node);
218 } 229 }
219 230
220 let ast = quote! { 231 let ast = quote! {
@@ -236,12 +247,12 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
236 let mut res = String::with_capacity(ast.len() * 2); 247 let mut res = String::with_capacity(ast.len() * 2);
237 248
238 let mut docs = 249 let mut docs =
239 grammar.nodes.iter().map(|it| it.doc).chain(grammar.enums.iter().map(|it| it.doc)); 250 grammar.nodes.iter().map(|it| &it.doc).chain(grammar.enums.iter().map(|it| &it.doc));
240 251
241 for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") { 252 for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") {
242 res.push_str(chunk); 253 res.push_str(chunk);
243 if let Some(doc) = docs.next() { 254 if let Some(doc) = docs.next() {
244 write_doc_comment(doc, &mut res); 255 write_doc_comment(&doc, &mut res);
245 } 256 }
246 } 257 }
247 258
@@ -249,7 +260,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
249 Ok(pretty) 260 Ok(pretty)
250} 261}
251 262
252fn write_doc_comment(contents: &[&str], dest: &mut String) { 263fn write_doc_comment(contents: &[String], dest: &mut String) {
253 for line in contents { 264 for line in contents {
254 writeln!(dest, "///{}", line).unwrap(); 265 writeln!(dest, "///{}", line).unwrap();
255 } 266 }
@@ -296,7 +307,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
296 307
297 let ast = quote! { 308 let ast = quote! {
298 #![allow(bad_style, missing_docs, unreachable_pub)] 309 #![allow(bad_style, missing_docs, unreachable_pub)]
299 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`. 310 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.
300 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 311 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
301 #[repr(u16)] 312 #[repr(u16)]
302 pub enum SyntaxKind { 313 pub enum SyntaxKind {
@@ -363,6 +374,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
363 #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)* 374 #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)*
364 [lifetime] => { $crate::SyntaxKind::LIFETIME }; 375 [lifetime] => { $crate::SyntaxKind::LIFETIME };
365 [ident] => { $crate::SyntaxKind::IDENT }; 376 [ident] => { $crate::SyntaxKind::IDENT };
377 [shebang] => { $crate::SyntaxKind::SHEBANG };
366 } 378 }
367 }; 379 };
368 380
@@ -413,9 +425,13 @@ fn to_pascal_case(s: &str) -> String {
413 buf 425 buf
414} 426}
415 427
416impl Field<'_> { 428fn pluralize(s: &str) -> String {
429 format!("{}s", s)
430}
431
432impl Field {
417 fn is_many(&self) -> bool { 433 fn is_many(&self) -> bool {
418 matches!(self, Field::Node { src: FieldSrc::Many(_), .. }) 434 matches!(self, Field::Node { cardinality: Cardinality::Many, .. })
419 } 435 }
420 fn token_kind(&self) -> Option<proc_macro2::TokenStream> { 436 fn token_kind(&self) -> Option<proc_macro2::TokenStream> {
421 match self { 437 match self {
@@ -429,7 +445,7 @@ impl Field<'_> {
429 fn method_name(&self) -> proc_macro2::Ident { 445 fn method_name(&self) -> proc_macro2::Ident {
430 match self { 446 match self {
431 Field::Token(name) => { 447 Field::Token(name) => {
432 let name = match *name { 448 let name = match name.as_str() {
433 ";" => "semicolon", 449 ";" => "semicolon",
434 "->" => "thin_arrow", 450 "->" => "thin_arrow",
435 "'{'" => "l_curly", 451 "'{'" => "l_curly",
@@ -448,29 +464,257 @@ impl Field<'_> {
448 "." => "dot", 464 "." => "dot",
449 ".." => "dotdot", 465 ".." => "dotdot",
450 "..." => "dotdotdot", 466 "..." => "dotdotdot",
467 "..=" => "dotdoteq",
451 "=>" => "fat_arrow", 468 "=>" => "fat_arrow",
452 "@" => "at", 469 "@" => "at",
453 ":" => "colon", 470 ":" => "colon",
454 "::" => "coloncolon", 471 "::" => "coloncolon",
455 "#" => "pound", 472 "#" => "pound",
456 "?" => "question_mark", 473 "?" => "question_mark",
474 "," => "comma",
457 _ => name, 475 _ => name,
458 }; 476 };
459 format_ident!("{}_token", name) 477 format_ident!("{}_token", name)
460 } 478 }
461 Field::Node { name, src } => match src { 479 Field::Node { name, .. } => {
462 FieldSrc::Shorthand => format_ident!("{}", to_lower_snake_case(name)), 480 if name == "type" {
463 _ => format_ident!("{}", name), 481 format_ident!("ty")
464 }, 482 } else {
483 format_ident!("{}", name)
484 }
485 }
465 } 486 }
466 } 487 }
467 fn ty(&self) -> proc_macro2::Ident { 488 fn ty(&self) -> proc_macro2::Ident {
468 match self { 489 match self {
469 Field::Token(_) => format_ident!("SyntaxToken"), 490 Field::Token(_) => format_ident!("SyntaxToken"),
470 Field::Node { name, src } => match src { 491 Field::Node { ty, .. } => format_ident!("{}", ty),
471 FieldSrc::Optional(ty) | FieldSrc::Many(ty) => format_ident!("{}", ty), 492 }
472 FieldSrc::Shorthand => format_ident!("{}", name), 493 }
473 }, 494}
495
496fn lower(grammar: &Grammar) -> AstSrc {
497 let mut res = AstSrc::default();
498 res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()];
499
500 let nodes = grammar
501 .iter()
502 .filter(|&node| match grammar[node].rule {
503 Rule::Node(it) if it == node => false,
504 _ => true,
505 })
506 .collect::<Vec<_>>();
507
508 for &node in &nodes {
509 let name = grammar[node].name.clone();
510 let rule = &grammar[node].rule;
511 match lower_enum(grammar, rule) {
512 Some(variants) => {
513 let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
514 res.enums.push(enum_src);
515 }
516 None => {
517 let mut fields = Vec::new();
518 lower_rule(&mut fields, grammar, None, rule);
519 res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields });
520 }
521 }
522 }
523
524 deduplicate_fields(&mut res);
525 extract_enums(&mut res);
526 extract_struct_traits(&mut res);
527 extract_enum_traits(&mut res);
528 res
529}
530
531fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
532 let alternatives = match rule {
533 Rule::Alt(it) => it,
534 _ => return None,
535 };
536 let mut variants = Vec::new();
537 for alternative in alternatives {
538 match alternative {
539 Rule::Node(it) => variants.push(grammar[*it].name.clone()),
540 _ => return None,
541 }
542 }
543 Some(variants)
544}
545
546fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
547 if lower_comma_list(acc, grammar, label, rule) {
548 return;
549 }
550
551 match rule {
552 Rule::Node(node) => {
553 let ty = grammar[*node].name.clone();
554 let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
555 let field = Field::Node { name, ty, cardinality: Cardinality::Optional };
556 acc.push(field);
557 }
558 Rule::Token(token) => {
559 assert!(label.is_none());
560 let mut name = grammar[*token].name.clone();
561 if name != "int_number" && name != "string" {
562 if "[]{}()".contains(&name) {
563 name = format!("'{}'", name);
564 }
565 let field = Field::Token(name);
566 acc.push(field);
567 }
568 }
569 Rule::Rep(inner) => {
570 if let Rule::Node(node) = &**inner {
571 let ty = grammar[*node].name.clone();
572 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
573 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
574 acc.push(field);
575 return;
576 }
577 todo!("{:?}", rule)
578 }
579 Rule::Labeled { label: l, rule } => {
580 assert!(label.is_none());
581 lower_rule(acc, grammar, Some(l), rule);
582 }
583 Rule::Seq(rules) | Rule::Alt(rules) => {
584 for rule in rules {
585 lower_rule(acc, grammar, label, rule)
586 }
474 } 587 }
588 Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),
589 }
590}
591
592// (T (',' T)* ','?)
593fn lower_comma_list(
594 acc: &mut Vec<Field>,
595 grammar: &Grammar,
596 label: Option<&String>,
597 rule: &Rule,
598) -> bool {
599 let rule = match rule {
600 Rule::Seq(it) => it,
601 _ => return false,
602 };
603 let (node, repeat, trailing_comma) = match rule.as_slice() {
604 [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
605 (node, repeat, trailing_comma)
606 }
607 _ => return false,
608 };
609 let repeat = match &**repeat {
610 Rule::Seq(it) => it,
611 _ => return false,
612 };
613 match repeat.as_slice() {
614 [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
615 _ => return false,
616 }
617 let ty = grammar[*node].name.clone();
618 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
619 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
620 acc.push(field);
621 true
622}
623
624fn deduplicate_fields(ast: &mut AstSrc) {
625 for node in &mut ast.nodes {
626 let mut i = 0;
627 'outer: while i < node.fields.len() {
628 for j in 0..i {
629 let f1 = &node.fields[i];
630 let f2 = &node.fields[j];
631 if f1 == f2 {
632 node.fields.remove(i);
633 continue 'outer;
634 }
635 }
636 i += 1;
637 }
638 }
639}
640
641fn extract_enums(ast: &mut AstSrc) {
642 for node in &mut ast.nodes {
643 for enm in &ast.enums {
644 let mut to_remove = Vec::new();
645 for (i, field) in node.fields.iter().enumerate() {
646 let ty = field.ty().to_string();
647 if enm.variants.iter().any(|it| it == &ty) {
648 to_remove.push(i);
649 }
650 }
651 if to_remove.len() == enm.variants.len() {
652 node.remove_field(to_remove);
653 let ty = enm.name.clone();
654 let name = to_lower_snake_case(&ty);
655 node.fields.push(Field::Node { name, ty, cardinality: Cardinality::Optional });
656 }
657 }
658 }
659}
660
661fn extract_struct_traits(ast: &mut AstSrc) {
662 let traits: &[(&str, &[&str])] = &[
663 ("AttrsOwner", &["attrs"]),
664 ("NameOwner", &["name"]),
665 ("VisibilityOwner", &["visibility"]),
666 ("GenericParamsOwner", &["generic_param_list", "where_clause"]),
667 ("TypeBoundsOwner", &["type_bound_list", "colon_token"]),
668 ("ModuleItemOwner", &["items"]),
669 ("LoopBodyOwner", &["label", "loop_body"]),
670 ("ArgListOwner", &["arg_list"]),
671 ];
672
673 for node in &mut ast.nodes {
674 for (name, methods) in traits {
675 extract_struct_trait(node, name, methods);
676 }
677 }
678}
679
680fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) {
681 let mut to_remove = Vec::new();
682 for (i, field) in node.fields.iter().enumerate() {
683 let method_name = field.method_name().to_string();
684 if methods.iter().any(|&it| it == &method_name) {
685 to_remove.push(i);
686 }
687 }
688 if to_remove.len() == methods.len() {
689 node.traits.push(trait_name.to_string());
690 node.remove_field(to_remove);
691 }
692}
693
694fn extract_enum_traits(ast: &mut AstSrc) {
695 for enm in &mut ast.enums {
696 let nodes = &ast.nodes;
697 let mut variant_traits = enm
698 .variants
699 .iter()
700 .map(|var| nodes.iter().find(|it| &it.name == var).unwrap())
701 .map(|node| node.traits.iter().cloned().collect::<BTreeSet<_>>());
702
703 let mut enum_traits = match variant_traits.next() {
704 Some(it) => it,
705 None => continue,
706 };
707 for traits in variant_traits {
708 enum_traits = enum_traits.intersection(&traits).cloned().collect();
709 }
710 enm.traits = enum_traits.into_iter().collect();
711 }
712}
713
714impl AstNodeSrc {
715 fn remove_field(&mut self, to_remove: Vec<usize>) {
716 to_remove.into_iter().rev().for_each(|idx| {
717 self.fields.remove(idx);
718 });
475 } 719 }
476} 720}
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
new file mode 100644
index 000000000..8f0e66278
--- /dev/null
+++ b/xtask/src/codegen/rust.ungram
@@ -0,0 +1,544 @@
1SourceFile =
2 'shebang'?
3 Attr*
4 Item*
5
6Item =
7 Const
8| Enum
9| ExternBlock
10| ExternCrate
11| Fn
12| Impl
13| MacroCall
14| Module
15| Static
16| Struct
17| Trait
18| TypeAlias
19| Union
20| Use
21
22Module =
23 Attr* Visibility? 'mod' Name
24 (ItemList | ';')
25
26ItemList =
27 '{' Attr* Item* '}'
28
29ExternCrate =
30 Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Rename? ';'
31
32Rename =
33 'as' (Name | '_')
34
35Use =
36 Attr* Visibility? 'use' UseTree ';'
37
38UseTree =
39 (Path? '::')? ('*' | UseTreeList )
40| Path Rename?
41
42UseTreeList =
43 '{' (UseTree (',' UseTree)* ','?)? '}'
44
45Fn =
46 Attr* Visibility?
47 'default'? ('async' | 'const')? 'unsafe'? Abi?
48 'fn' Name GenericParamList? ParamList RetType?
49 WhereClause?
50 (body:BlockExpr | ';')
51
52Abi =
53 'extern' 'string'?
54
55ParamList =
56 '('(
57 SelfParam
58 | (SelfParam ',')? (Param (',' Param)* ','?)?
59 )')'
60
61SelfParam =
62 Attr* (
63 ('&' 'lifetime'?)? 'mut'? 'self'
64 | 'mut'? 'self' ':' Type
65 )
66
67Param =
68 Attr* (
69 Pat (':' Type)
70 | Type
71 | '...'
72 )
73
74RetType =
75 '->' Type
76
77TypeAlias =
78 Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
79 '=' Type ';'
80
81Struct =
82 Attr* Visibility? 'struct' Name GenericParamList? (
83 WhereClause? (RecordFieldList | ';')
84 | TupleFieldList WhereClause? ';'
85 )
86
87RecordFieldList =
88 '{' fields:(RecordField (',' RecordField)* ','?)? '}'
89
90RecordField =
91 Attr* Visibility? Name ':' Type
92
93TupleFieldList =
94 '(' fields:(TupleField (',' TupleField)* ','?)? ')'
95
96TupleField =
97 Attr* Visibility? Type
98
99FieldList =
100 RecordFieldList
101| TupleFieldList
102
103Enum =
104 Attr* Visibility? 'enum' Name GenericParamList? WhereClause?
105 VariantList
106
107VariantList =
108 '{' (Variant (',' Variant)* ','?)? '}'
109
110Variant =
111 Attr* Visibility? Name FieldList ('=' Expr)?
112
113Union =
114 Attr* Visibility? 'union' Name GenericParamList? WhereClause?
115 RecordFieldList
116
117AdtDef =
118 Struct
119| Enum
120| Union
121
122Const =
123 Attr* Visibility? 'default'? 'const' (Name | '_') ':' Type
124 '=' body:Expr ';'
125
126Static =
127 Attr* Visibility? 'static'? 'mut'? Name ':' Type
128 '=' body:Expr ';'
129
130Trait =
131 Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name GenericParamList
132 (':' TypeBoundList?)? WhereClause
133 AssocItemList
134
135AssocItemList =
136 '{' Attr* AssocItem* '}'
137
138AssocItem =
139 Fn
140| TypeAlias
141| Const
142| MacroCall
143
144Impl =
145 Attr* Visibility?
146 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? (
147 Type
148 | '!'? Type 'for' Type
149 ) WhereClause?
150 AssocItemList
151
152ExternBlock =
153 Attr* Abi ExternItemList
154
155ExternItemList =
156 '{' Attr* ExternItem* '}'
157
158ExternItem =
159 Fn | Static | MacroCall
160
161GenericParamList =
162 '<' (GenericParam (',' GenericParam)* ','?)? '>'
163
164GenericParam =
165 LifetimeParam
166| TypeParam
167| ConstParam
168
169TypeParam =
170 Attr* Name (':' TypeBoundList?)?
171 ('=' default_type:Type)?
172
173ConstParam =
174 Attr* 'const' Name ':' Type
175 ('=' default_val:Expr)?
176
177LifetimeParam =
178 Attr* 'lifetime'
179
180Visibility =
181 'pub' ('('
182 'super'
183 | 'self'
184 | 'crate'
185 | 'in' Path
186 ')')?
187
188Attr =
189 '#' '!'? '[' Path ('=' Literal | TokenTree)? ']'
190
191Type =
192 ParenType
193| TupleType
194| NeverType
195| PathType
196| PointerType
197| ArrayType
198| SliceType
199| ReferenceType
200| PlaceholderType
201| FnPointerType
202| ForType
203| ImplTraitType
204| DynTraitType
205
206ParenType =
207 '(' Type ')'
208
209TupleType =
210 '(' fields:Type* ')'
211
212NeverType =
213 '!'
214
215PathType =
216 Path
217
218PointerType =
219 '*' ('const' | 'mut') Type
220
221ArrayType =
222 '[' Type ';' Expr ']'
223
224SliceType =
225 '[' Type ']'
226
227ReferenceType =
228 '&' 'lifetime'? 'mut'? Type
229
230PlaceholderType =
231 '_'
232
233FnPointerType =
234 Abi 'unsafe'? 'fn' ParamList RetType?
235
236ForType =
237 'for' GenericParamList Type
238
239ImplTraitType =
240 'impl' TypeBoundList
241
242DynTraitType =
243 'dyn' TypeBoundList
244
245TupleExpr =
246 Attr* '(' Expr* ')'
247
248ArrayExpr =
249 Attr* '[' (Expr* | Expr ';' Expr) ']'
250
251ParenExpr =
252 Attr* '(' Expr ')'
253
254PathExpr =
255 Path
256
257LambdaExpr =
258 Attr* 'static'? 'async'? 'move'? ParamList RetType?
259 body:Expr
260
261IfExpr =
262 Attr* 'if' Condition
263
264Condition =
265 'let' Pat '=' Expr
266| Expr
267
268EffectExpr =
269 Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr
270
271LoopExpr =
272 Attr* Label? 'loop'
273 loop_body:BlockExpr?
274
275ForExpr =
276 Attr* Label? 'for' Pat 'in' iterable:Expr
277 loop_body:BlockExpr?
278
279WhileExpr =
280 Attr* Label? 'while' Condition
281 loop_body:BlockExpr?
282
283ContinueExpr =
284 Attr* 'continue' 'lifetime'?
285
286BreakExpr =
287 Attr* 'break' 'lifetime'? Expr?
288
289Label =
290 'lifetime'
291
292BlockExpr =
293 Attr* Label
294 '{'
295 Item*
296 statements:Stmt*
297 Expr?
298 '}'
299
300ReturnExpr =
301 Attr* 'return' Expr
302
303CallExpr =
304 Attr* Expr ArgList
305
306MethodCallExpr =
307 Attr* Expr '.' NameRef TypeArgList? ArgList
308
309ArgList =
310 '(' args:Expr* ')'
311
312FieldExpr =
313 Attr* Expr '.' NameRef
314
315IndexExpr =
316 Attr* '[' ']'
317
318AwaitExpr =
319 Attr* Expr '.' 'await'
320
321TryExpr =
322 Attr* Expr '?'
323
324CastExpr =
325 Attr* Expr 'as' Type
326
327RefExpr =
328 Attr* '&' ('raw' | 'mut' | 'const') Expr
329
330PrefixExpr =
331 Attr* Expr
332
333BoxExpr =
334 Attr* 'box' Expr
335
336RangeExpr =
337 Attr*
338
339BinExpr =
340 Attr*
341
342Literal =
343 'int_number'
344
345MatchExpr =
346 Attr* 'match' Expr MatchArmList
347
348MatchArmList =
349 '{' arms:MatchArm* '}'
350
351MatchArm =
352 Attr* Pat guard:MatchGuard? '=>' Expr
353
354MatchGuard =
355 'if' Expr
356
357RecordExpr =
358 Path RecordExprFieldList
359
360RecordExprFieldList =
361 '{'
362 fields:RecordExprField*
363 ('..' spread:Expr)?
364 '}'
365
366RecordExprField =
367 Attr* NameRef (':' Expr)?
368
369OrPat =
370 Pat*
371
372ParenPat =
373 '(' Pat ')'
374
375RefPat =
376 '&' 'mut'? Pat
377
378BoxPat =
379 'box' Path
380
381BindPat =
382 Attr* 'ref'? 'mut'? Name ('@' Pat)?
383
384PlaceholderPat =
385 '_'
386
387DotDotPat =
388 '..'
389
390PathPat =
391 Path
392
393SlicePat =
394 '[' args:Pat* ']'
395
396RangePat =
397 '..' | '..='
398
399LiteralPat =
400 Literal
401
402MacroPat =
403 MacroCall
404
405RecordPat =
406 Path RecordFieldPatList
407
408RecordFieldPatList =
409 '{'
410 record_field_pats:RecordFieldPat*
411 BindPat*
412 '..'?
413 '}'
414
415RecordFieldPat =
416 Attr* NameRef ':' Pat
417
418TupleStructPat =
419 Path '(' args:Pat* ')'
420
421TuplePat =
422 '(' args:Pat* ')'
423
424Name =
425 'ident'
426
427NameRef =
428 'ident' | 'int_number'
429
430MacroCall =
431 Attr* Path '!' Name? TokenTree ';'?
432
433MacroDef =
434 Name TokenTree
435
436TokenTree =
437 '(' ')' | '{' '}' | '[' ']'
438
439MacroItems =
440 Item*
441
442MacroStmts =
443 statements:Stmt*
444 Expr?
445
446TypeBound =
447 'lifetime' | 'const'? Type
448
449TypeBoundList =
450 bounds:TypeBound*
451
452WherePred =
453 ('for' GenericParamList)? ('lifetime' | Type) ':' TypeBoundList
454
455WhereClause =
456 'where' predicates:WherePred*
457
458ExprStmt =
459 Attr* Expr ';'
460
461LetStmt =
462 Attr* 'let' Pat (':' Type)
463 '=' initializer:Expr ';'
464
465Path =
466 (qualifier:Path '::')? segment:PathSegment
467
468PathSegment =
469 '::' | 'crate' | 'self' | 'super'
470| '<' NameRef TypeArgList ParamList RetType PathType '>'
471
472TypeArgList =
473 '::'? '<'
474 TypeArg*
475 LifetimeArg*
476 AssocTypeArg*
477 ConstArg*
478 '>'
479
480TypeArg =
481 Type
482
483AssocTypeArg =
484 NameRef (':' TypeBoundList | '=' Type)
485
486LifetimeArg =
487 'lifetime'
488
489ConstArg =
490 Literal | BlockExpr BlockExpr
491
492Stmt =
493 LetStmt
494| ExprStmt
495
496Pat =
497 OrPat
498| ParenPat
499| RefPat
500| BoxPat
501| BindPat
502| PlaceholderPat
503| DotDotPat
504| PathPat
505| RecordPat
506| TupleStructPat
507| TuplePat
508| SlicePat
509| RangePat
510| LiteralPat
511| MacroPat
512
513Expr =
514 TupleExpr
515| ArrayExpr
516| ParenExpr
517| PathExpr
518| LambdaExpr
519| IfExpr
520| LoopExpr
521| ForExpr
522| WhileExpr
523| ContinueExpr
524| BreakExpr
525| Label
526| BlockExpr
527| ReturnExpr
528| MatchExpr
529| RecordExpr
530| CallExpr
531| IndexExpr
532| MethodCallExpr
533| FieldExpr
534| AwaitExpr
535| TryExpr
536| EffectExpr
537| CastExpr
538| RefExpr
539| PrefixExpr
540| RangeExpr
541| BinExpr
542| Literal
543| MacroCall
544| BoxExpr
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index c198c0907..01d903cde 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -13,17 +13,24 @@ use crate::{
13 project_root, 13 project_root,
14}; 14};
15 15
16pub fn run_dist(nightly: bool, client_version: Option<String>) -> Result<()> { 16pub struct DistCmd {
17 let dist = project_root().join("dist"); 17 pub nightly: bool,
18 rm_rf(&dist)?; 18 pub client_version: Option<String>,
19 fs2::create_dir_all(&dist)?; 19}
20 20
21 if let Some(version) = client_version { 21impl DistCmd {
22 let release_tag = if nightly { "nightly".to_string() } else { date_iso()? }; 22 pub fn run(self) -> Result<()> {
23 dist_client(&version, &release_tag)?; 23 let dist = project_root().join("dist");
24 rm_rf(&dist)?;
25 fs2::create_dir_all(&dist)?;
26
27 if let Some(version) = self.client_version {
28 let release_tag = if self.nightly { "nightly".to_string() } else { date_iso()? };
29 dist_client(&version, &release_tag)?;
30 }
31 dist_server()?;
32 Ok(())
24 } 33 }
25 dist_server()?;
26 Ok(())
27} 34}
28 35
29fn dist_client(version: &str, release_tag: &str) -> Result<()> { 36fn dist_client(version: &str, release_tag: &str) -> Result<()> {
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 94d451e23..2fdb08f2e 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -7,6 +7,7 @@ pub mod install;
7pub mod release; 7pub mod release;
8pub mod dist; 8pub mod dist;
9pub mod pre_commit; 9pub mod pre_commit;
10pub mod metrics;
10 11
11pub mod codegen; 12pub mod codegen;
12mod ast_src; 13mod ast_src;
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 53d3ce3e7..b69b884e5 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -13,8 +13,9 @@ use std::env;
13use pico_args::Arguments; 13use pico_args::Arguments;
14use xtask::{ 14use xtask::{
15 codegen::{self, Mode}, 15 codegen::{self, Mode},
16 dist::run_dist, 16 dist::DistCmd,
17 install::{ClientOpt, InstallCmd, Malloc, ServerOpt}, 17 install::{ClientOpt, InstallCmd, Malloc, ServerOpt},
18 metrics::MetricsCmd,
18 not_bash::pushd, 19 not_bash::pushd,
19 pre_commit, project_root, 20 pre_commit, project_root,
20 release::{PromoteCmd, ReleaseCmd}, 21 release::{PromoteCmd, ReleaseCmd},
@@ -115,7 +116,12 @@ FLAGS:
115 let nightly = args.contains("--nightly"); 116 let nightly = args.contains("--nightly");
116 let client_version: Option<String> = args.opt_value_from_str("--client")?; 117 let client_version: Option<String> = args.opt_value_from_str("--client")?;
117 args.finish()?; 118 args.finish()?;
118 run_dist(nightly, client_version) 119 DistCmd { nightly, client_version }.run()
120 }
121 "metrics" => {
122 let dry_run = args.contains("--dry-run");
123 args.finish()?;
124 MetricsCmd { dry_run }.run()
119 } 125 }
120 _ => { 126 _ => {
121 eprintln!( 127 eprintln!(
@@ -133,7 +139,8 @@ SUBCOMMANDS:
133 codegen 139 codegen
134 install 140 install
135 lint 141 lint
136 dist" 142 dist
143 promote"
137 ); 144 );
138 Ok(()) 145 Ok(())
139 } 146 }
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs
new file mode 100644
index 000000000..9ac3fa51d
--- /dev/null
+++ b/xtask/src/metrics.rs
@@ -0,0 +1,279 @@
1use std::{
2 collections::BTreeMap,
3 env,
4 fmt::{self, Write as _},
5 io::Write as _,
6 path::Path,
7 time::{Instant, SystemTime, UNIX_EPOCH},
8};
9
10use anyhow::{bail, format_err, Result};
11
12use crate::not_bash::{fs2, pushd, pushenv, rm_rf, run};
13
14type Unit = String;
15
16pub struct MetricsCmd {
17 pub dry_run: bool,
18}
19
20impl MetricsCmd {
21 pub fn run(self) -> Result<()> {
22 let mut metrics = Metrics::new()?;
23 if !self.dry_run {
24 rm_rf("./target/release")?;
25 }
26 if !Path::new("./target/rustc-perf").exists() {
27 fs2::create_dir_all("./target/rustc-perf")?;
28 run!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")?;
29 }
30 {
31 let _d = pushd("./target/rustc-perf");
32 run!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033")?;
33 }
34
35 let _env = pushenv("RA_METRICS", "1");
36
37 metrics.measure_build()?;
38 metrics.measure_analysis_stats_self()?;
39 metrics.measure_analysis_stats("ripgrep")?;
40 metrics.measure_analysis_stats("webrender")?;
41
42 if !self.dry_run {
43 let _d = pushd("target");
44 let metrics_token = env::var("METRICS_TOKEN").unwrap();
45 let repo = format!("https://{}@github.com/rust-analyzer/metrics.git", metrics_token);
46 run!("git clone --depth 1 {}", repo)?;
47 let _d = pushd("metrics");
48
49 let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
50 writeln!(file, "{}", metrics.json())?;
51 run!("git add .")?;
52 run!("git -c user.name=Bot -c [email protected] commit --message 📈")?;
53 run!("git push origin master")?;
54 }
55 eprintln!("{:#?}", metrics);
56 Ok(())
57 }
58}
59
60impl Metrics {
61 fn measure_build(&mut self) -> Result<()> {
62 eprintln!("\nMeasuring build");
63 run!("cargo fetch")?;
64
65 let time = Instant::now();
66 run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?;
67 let time = time.elapsed();
68 self.report("build", time.as_millis() as u64, "ms".into());
69 Ok(())
70 }
71 fn measure_analysis_stats_self(&mut self) -> Result<()> {
72 self.measure_analysis_stats_path("self", &".")
73 }
74 fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> {
75 self.measure_analysis_stats_path(
76 bench,
77 &format!("./target/rustc-perf/collector/benchmarks/{}", bench),
78 )
79 }
80 fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
81 eprintln!("\nMeasuring analysis-stats/{}", name);
82 let output = run!("./target/release/rust-analyzer analysis-stats --quiet {}", path)?;
83 for (metric, value, unit) in parse_metrics(&output) {
84 self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
85 }
86 Ok(())
87 }
88}
89
90fn parse_metrics(output: &str) -> Vec<(&str, u64, &str)> {
91 output
92 .lines()
93 .filter_map(|it| {
94 let entry = it.split(':').collect::<Vec<_>>();
95 match entry.as_slice() {
96 ["METRIC", name, value, unit] => Some((*name, value.parse().unwrap(), *unit)),
97 _ => None,
98 }
99 })
100 .collect()
101}
102
103#[derive(Debug)]
104struct Metrics {
105 host: Host,
106 timestamp: SystemTime,
107 revision: String,
108 metrics: BTreeMap<String, (u64, Unit)>,
109}
110
111#[derive(Debug)]
112struct Host {
113 os: String,
114 cpu: String,
115 mem: String,
116}
117
118impl Metrics {
119 fn new() -> Result<Metrics> {
120 let host = Host::new()?;
121 let timestamp = SystemTime::now();
122 let revision = run!("git rev-parse HEAD")?;
123 Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() })
124 }
125
126 fn report(&mut self, name: &str, value: u64, unit: Unit) {
127 self.metrics.insert(name.into(), (value, unit));
128 }
129
130 fn json(&self) -> Json {
131 let mut json = Json::default();
132 self.to_json(&mut json);
133 json
134 }
135 fn to_json(&self, json: &mut Json) {
136 json.begin_object();
137 {
138 json.field("host");
139 self.host.to_json(json);
140
141 json.field("timestamp");
142 let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap();
143 json.number(timestamp.as_secs() as f64);
144
145 json.field("revision");
146 json.string(&self.revision);
147
148 json.field("metrics");
149 json.begin_object();
150 {
151 for (k, (value, unit)) in &self.metrics {
152 json.field(k);
153 json.begin_array();
154 {
155 json.number(*value as f64);
156 json.string(unit);
157 }
158 json.end_array();
159 }
160 }
161 json.end_object()
162 }
163 json.end_object();
164 }
165}
166
167impl Host {
168 fn new() -> Result<Host> {
169 if cfg!(not(target_os = "linux")) {
170 bail!("can only collect metrics on Linux ");
171 }
172
173 let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();
174
175 let cpu =
176 read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();
177
178 let mem = read_field("/proc/meminfo", "MemTotal:")?;
179
180 return Ok(Host { os, cpu, mem });
181
182 fn read_field<'a>(path: &str, field: &str) -> Result<String> {
183 let text = fs2::read_to_string(path)?;
184
185 let line = text
186 .lines()
187 .find(|it| it.starts_with(field))
188 .ok_or_else(|| format_err!("can't parse {}", path))?;
189 Ok(line[field.len()..].trim().to_string())
190 }
191 }
192 fn to_json(&self, json: &mut Json) {
193 json.begin_object();
194 {
195 json.field("os");
196 json.string(&self.os);
197
198 json.field("cpu");
199 json.string(&self.cpu);
200
201 json.field("mem");
202 json.string(&self.mem);
203 }
204 json.end_object();
205 }
206}
207
208struct State {
209 obj: bool,
210 first: bool,
211}
212
213#[derive(Default)]
214struct Json {
215 stack: Vec<State>,
216 buf: String,
217}
218
219impl Json {
220 fn begin_object(&mut self) {
221 self.stack.push(State { obj: true, first: true });
222 self.buf.push('{');
223 }
224 fn end_object(&mut self) {
225 self.stack.pop();
226 self.buf.push('}')
227 }
228 fn begin_array(&mut self) {
229 self.stack.push(State { obj: false, first: true });
230 self.buf.push('[');
231 }
232 fn end_array(&mut self) {
233 self.stack.pop();
234 self.buf.push(']')
235 }
236 fn field(&mut self, name: &str) {
237 self.object_comma();
238 self.string_token(name);
239 self.buf.push(':');
240 }
241 fn string(&mut self, value: &str) {
242 self.array_comma();
243 self.string_token(value);
244 }
245 fn string_token(&mut self, value: &str) {
246 self.buf.push('"');
247 self.buf.extend(value.escape_default());
248 self.buf.push('"');
249 }
250 fn number(&mut self, value: f64) {
251 self.array_comma();
252 write!(self.buf, "{}", value).unwrap();
253 }
254
255 fn array_comma(&mut self) {
256 let state = self.stack.last_mut().unwrap();
257 if state.obj {
258 return;
259 }
260 if !state.first {
261 self.buf.push(',');
262 }
263 state.first = false;
264 }
265
266 fn object_comma(&mut self) {
267 let state = self.stack.last_mut().unwrap();
268 if !state.first {
269 self.buf.push(',');
270 }
271 state.first = false;
272 }
273}
274
275impl fmt::Display for Json {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(f, "{}", self.buf)
278 }
279}
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs
index 0f3a56b25..ef811e5bf 100644
--- a/xtask/src/not_bash.rs
+++ b/xtask/src/not_bash.rs
@@ -186,7 +186,8 @@ impl Env {
186 fn pushd(&mut self, dir: PathBuf) { 186 fn pushd(&mut self, dir: PathBuf) {
187 let dir = self.cwd().join(dir); 187 let dir = self.cwd().join(dir);
188 self.pushd_stack.push(dir); 188 self.pushd_stack.push(dir);
189 env::set_current_dir(self.cwd()).unwrap(); 189 env::set_current_dir(self.cwd())
190 .unwrap_or_else(|err| panic!("Failed to set cwd to {}: {}", self.cwd().display(), err));
190 } 191 }
191 fn popd(&mut self) { 192 fn popd(&mut self) {
192 self.pushd_stack.pop().unwrap(); 193 self.pushd_stack.pop().unwrap();
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index adadffc53..d65a2acbc 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -55,7 +55,6 @@ fn check_licenses() {
550BSD OR MIT OR Apache-2.0 550BSD OR MIT OR Apache-2.0
56Apache-2.0 OR BSL-1.0 56Apache-2.0 OR BSL-1.0
57Apache-2.0 OR MIT 57Apache-2.0 OR MIT
58Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
59Apache-2.0/MIT 58Apache-2.0/MIT
60BSD-2-Clause 59BSD-2-Clause
61BSD-3-Clause 60BSD-3-Clause