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.rs290
-rw-r--r--xtask/src/codegen/rust.ungram544
-rw-r--r--xtask/src/dist.rs56
-rw-r--r--xtask/src/install.rs14
-rw-r--r--xtask/src/lib.rs3
-rw-r--r--xtask/src/main.rs29
-rw-r--r--xtask/src/metrics.rs279
-rw-r--r--xtask/src/not_bash.rs20
-rw-r--r--xtask/src/release.rs36
-rw-r--r--xtask/tests/tidy.rs59
12 files changed, 1313 insertions, 2106 deletions
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index a8b9b010d..8140da87f 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -4,13 +4,16 @@ name = "xtask"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7license = "MIT OR Apache-2.0"
7 8
8[lib] 9[lib]
9doctest = false 10doctest = false
10 11
11[dependencies] 12[dependencies]
12walkdir = "2.3.1" 13anyhow = "1.0.26"
14flate2 = "1.0"
13pico-args = "0.3.1" 15pico-args = "0.3.1"
14quote = "1.0.2"
15proc-macro2 = "1.0.8" 16proc-macro2 = "1.0.8"
16anyhow = "1.0.26" 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..45b788bdb 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,251 @@ 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, .. } => format_ident!("{}", name),
462 FieldSrc::Shorthand => format_ident!("{}", to_lower_snake_case(name)),
463 _ => format_ident!("{}", name),
464 },
465 } 480 }
466 } 481 }
467 fn ty(&self) -> proc_macro2::Ident { 482 fn ty(&self) -> proc_macro2::Ident {
468 match self { 483 match self {
469 Field::Token(_) => format_ident!("SyntaxToken"), 484 Field::Token(_) => format_ident!("SyntaxToken"),
470 Field::Node { name, src } => match src { 485 Field::Node { ty, .. } => format_ident!("{}", ty),
471 FieldSrc::Optional(ty) | FieldSrc::Many(ty) => format_ident!("{}", ty),
472 FieldSrc::Shorthand => format_ident!("{}", name),
473 },
474 } 486 }
475 } 487 }
476} 488}
489
490fn lower(grammar: &Grammar) -> AstSrc {
491 let mut res = AstSrc::default();
492 res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()];
493
494 let nodes = grammar
495 .iter()
496 .filter(|&node| match grammar[node].rule {
497 Rule::Node(it) if it == node => false,
498 _ => true,
499 })
500 .collect::<Vec<_>>();
501
502 for &node in &nodes {
503 let name = grammar[node].name.clone();
504 let rule = &grammar[node].rule;
505 match lower_enum(grammar, rule) {
506 Some(variants) => {
507 let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
508 res.enums.push(enum_src);
509 }
510 None => {
511 let mut fields = Vec::new();
512 lower_rule(&mut fields, grammar, None, rule);
513 res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields });
514 }
515 }
516 }
517
518 deduplicate_fields(&mut res);
519 extract_enums(&mut res);
520 extract_struct_traits(&mut res);
521 extract_enum_traits(&mut res);
522 res
523}
524
525fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
526 let alternatives = match rule {
527 Rule::Alt(it) => it,
528 _ => return None,
529 };
530 let mut variants = Vec::new();
531 for alternative in alternatives {
532 match alternative {
533 Rule::Node(it) => variants.push(grammar[*it].name.clone()),
534 _ => return None,
535 }
536 }
537 Some(variants)
538}
539
540fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
541 if lower_comma_list(acc, grammar, label, rule) {
542 return;
543 }
544
545 match rule {
546 Rule::Node(node) => {
547 let ty = grammar[*node].name.clone();
548 let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
549 let field = Field::Node { name, ty, cardinality: Cardinality::Optional };
550 acc.push(field);
551 }
552 Rule::Token(token) => {
553 assert!(label.is_none());
554 let mut name = grammar[*token].name.clone();
555 if name != "int_number" && name != "string" {
556 if "[]{}()".contains(&name) {
557 name = format!("'{}'", name);
558 }
559 let field = Field::Token(name);
560 acc.push(field);
561 }
562 }
563 Rule::Rep(inner) => {
564 if let Rule::Node(node) = &**inner {
565 let ty = grammar[*node].name.clone();
566 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
567 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
568 acc.push(field);
569 return;
570 }
571 todo!("{:?}", rule)
572 }
573 Rule::Labeled { label: l, rule } => {
574 assert!(label.is_none());
575 lower_rule(acc, grammar, Some(l), rule);
576 }
577 Rule::Seq(rules) | Rule::Alt(rules) => {
578 for rule in rules {
579 lower_rule(acc, grammar, label, rule)
580 }
581 }
582 Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),
583 }
584}
585
586// (T (',' T)* ','?)
587fn lower_comma_list(
588 acc: &mut Vec<Field>,
589 grammar: &Grammar,
590 label: Option<&String>,
591 rule: &Rule,
592) -> bool {
593 let rule = match rule {
594 Rule::Seq(it) => it,
595 _ => return false,
596 };
597 let (node, repeat, trailing_comma) = match rule.as_slice() {
598 [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
599 (node, repeat, trailing_comma)
600 }
601 _ => return false,
602 };
603 let repeat = match &**repeat {
604 Rule::Seq(it) => it,
605 _ => return false,
606 };
607 match repeat.as_slice() {
608 [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
609 _ => return false,
610 }
611 let ty = grammar[*node].name.clone();
612 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
613 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
614 acc.push(field);
615 true
616}
617
618fn deduplicate_fields(ast: &mut AstSrc) {
619 for node in &mut ast.nodes {
620 let mut i = 0;
621 'outer: while i < node.fields.len() {
622 for j in 0..i {
623 let f1 = &node.fields[i];
624 let f2 = &node.fields[j];
625 if f1 == f2 {
626 node.fields.remove(i);
627 continue 'outer;
628 }
629 }
630 i += 1;
631 }
632 }
633}
634
635fn extract_enums(ast: &mut AstSrc) {
636 for node in &mut ast.nodes {
637 for enm in &ast.enums {
638 let mut to_remove = Vec::new();
639 for (i, field) in node.fields.iter().enumerate() {
640 let ty = field.ty().to_string();
641 if enm.variants.iter().any(|it| it == &ty) {
642 to_remove.push(i);
643 }
644 }
645 if to_remove.len() == enm.variants.len() {
646 node.remove_field(to_remove);
647 let ty = enm.name.clone();
648 let name = to_lower_snake_case(&ty);
649 node.fields.push(Field::Node { name, ty, cardinality: Cardinality::Optional });
650 }
651 }
652 }
653}
654
655fn extract_struct_traits(ast: &mut AstSrc) {
656 let traits: &[(&str, &[&str])] = &[
657 ("AttrsOwner", &["attrs"]),
658 ("NameOwner", &["name"]),
659 ("VisibilityOwner", &["visibility"]),
660 ("GenericParamsOwner", &["generic_param_list", "where_clause"]),
661 ("TypeBoundsOwner", &["type_bound_list", "colon_token"]),
662 ("ModuleItemOwner", &["items"]),
663 ("LoopBodyOwner", &["label", "loop_body"]),
664 ("ArgListOwner", &["arg_list"]),
665 ];
666
667 for node in &mut ast.nodes {
668 for (name, methods) in traits {
669 extract_struct_trait(node, name, methods);
670 }
671 }
672}
673
674fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) {
675 let mut to_remove = Vec::new();
676 for (i, field) in node.fields.iter().enumerate() {
677 let method_name = field.method_name().to_string();
678 if methods.iter().any(|&it| it == &method_name) {
679 to_remove.push(i);
680 }
681 }
682 if to_remove.len() == methods.len() {
683 node.traits.push(trait_name.to_string());
684 node.remove_field(to_remove);
685 }
686}
687
688fn extract_enum_traits(ast: &mut AstSrc) {
689 for enm in &mut ast.enums {
690 let nodes = &ast.nodes;
691 let mut variant_traits = enm
692 .variants
693 .iter()
694 .map(|var| nodes.iter().find(|it| &it.name == var).unwrap())
695 .map(|node| node.traits.iter().cloned().collect::<BTreeSet<_>>());
696
697 let mut enum_traits = match variant_traits.next() {
698 Some(it) => it,
699 None => continue,
700 };
701 for traits in variant_traits {
702 enum_traits = enum_traits.intersection(&traits).cloned().collect();
703 }
704 enm.traits = enum_traits.into_iter().collect();
705 }
706}
707
708impl AstNodeSrc {
709 fn remove_field(&mut self, to_remove: Vec<usize>) {
710 to_remove.into_iter().rev().for_each(|idx| {
711 self.fields.remove(idx);
712 });
713 }
714}
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
new file mode 100644
index 000000000..375df301f
--- /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' ':' ty:TypeRef
65 )
66
67Param =
68 Attr* (
69 Pat (':' ty:TypeRef)
70 | ty:TypeRef
71 | '...'
72 )
73
74RetType =
75 '->' ty:TypeRef
76
77TypeAlias =
78 Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
79 '=' ty:TypeRef ';'
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 ':' ty:TypeRef
92
93TupleFieldList =
94 '(' fields:(TupleField (',' TupleField)* ','?)? ')'
95
96TupleField =
97 Attr* Visibility? ty:TypeRef
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
117Const =
118 Attr* Visibility? 'default'? 'const' (Name | '_') ':' ty:TypeRef
119 '=' body:Expr ';'
120
121Static =
122 Attr* Visibility? 'static'? 'mut'? Name ':' ty:TypeRef
123 '=' body:Expr ';'
124
125Trait =
126 Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name GenericParamList
127 (':' TypeBoundList?)? WhereClause
128 AssocItemList
129
130AssocItemList =
131 '{' Attr* AssocItem* '}'
132
133AssocItem =
134 Fn
135| TypeAlias
136| Const
137| MacroCall
138
139Impl =
140 Attr* Visibility?
141 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? (
142 TypeRef
143 | '!'? TypeRef 'for' TypeRef
144 ) WhereClause?
145 AssocItemList
146
147ExternBlock =
148 Attr* Abi ExternItemList
149
150ExternItemList =
151 '{' Attr* ExternItem* '}'
152
153ExternItem =
154 Fn | Static | MacroCall
155
156GenericParamList =
157 '<' (GenericParam (',' GenericParam)* ','?)? '>'
158
159GenericParam =
160 LifetimeParam
161| TypeParam
162| ConstParam
163
164TypeParam =
165 Attr* Name (':' TypeBoundList?)?
166 ('=' default_type:TypeRef)?
167
168ConstParam =
169 Attr* 'const' Name ':' ty:TypeRef
170 ('=' default_val:Expr)?
171
172LifetimeParam =
173 Attr* 'lifetime'
174
175Visibility =
176 'pub' ('('
177 'super'
178 | 'self'
179 | 'crate'
180 | 'in' Path
181 ')')?
182
183Attr =
184 '#' '!'? '[' Path ('=' Literal | TokenTree)? ']'
185
186ParenType =
187 '(' ty:TypeRef ')'
188
189TupleType =
190 '(' fields:TypeRef* ')'
191
192NeverType =
193 '!'
194
195PathType =
196 Path
197
198PointerType =
199 '*' ('const' | 'mut') ty:TypeRef
200
201ArrayType =
202 '[' ty:TypeRef ';' Expr ']'
203
204SliceType =
205 '[' ty:TypeRef ']'
206
207ReferenceType =
208 '&' 'lifetime'? 'mut'? ty:TypeRef
209
210PlaceholderType =
211 '_'
212
213FnPointerType =
214 Abi 'unsafe'? 'fn' ParamList RetType?
215
216ForType =
217 'for' GenericParamList ty:TypeRef
218
219ImplTraitType =
220 'impl' TypeBoundList
221
222DynTraitType =
223 'dyn' TypeBoundList
224
225TupleExpr =
226 Attr* '(' Expr* ')'
227
228ArrayExpr =
229 Attr* '[' (Expr* | Expr ';' Expr) ']'
230
231ParenExpr =
232 Attr* '(' Expr ')'
233
234PathExpr =
235 Path
236
237LambdaExpr =
238 Attr* 'static'? 'async'? 'move'? ParamList RetType?
239 body:Expr
240
241IfExpr =
242 Attr* 'if' Condition
243
244Condition =
245 'let' Pat '=' Expr
246| Expr
247
248EffectExpr =
249 Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr
250
251LoopExpr =
252 Attr* Label? 'loop'
253 loop_body:BlockExpr?
254
255ForExpr =
256 Attr* Label? 'for' Pat 'in' iterable:Expr
257 loop_body:BlockExpr?
258
259WhileExpr =
260 Attr* Label? 'while' Condition
261 loop_body:BlockExpr?
262
263ContinueExpr =
264 Attr* 'continue' 'lifetime'?
265
266BreakExpr =
267 Attr* 'break' 'lifetime'? Expr?
268
269Label =
270 'lifetime'
271
272BlockExpr =
273 Attr* Label
274 '{'
275 Item*
276 statements:Stmt*
277 Expr?
278 '}'
279
280ReturnExpr =
281 Attr* 'return' Expr
282
283CallExpr =
284 Attr* Expr ArgList
285
286MethodCallExpr =
287 Attr* Expr '.' NameRef TypeArgList? ArgList
288
289ArgList =
290 '(' args:Expr* ')'
291
292FieldExpr =
293 Attr* Expr '.' NameRef
294
295IndexExpr =
296 Attr* '[' ']'
297
298AwaitExpr =
299 Attr* Expr '.' 'await'
300
301TryExpr =
302 Attr* Expr '?'
303
304CastExpr =
305 Attr* Expr 'as' ty:TypeRef
306
307RefExpr =
308 Attr* '&' ('raw' | 'mut' | 'const') Expr
309
310PrefixExpr =
311 Attr* Expr
312
313BoxExpr =
314 Attr* 'box' Expr
315
316RangeExpr =
317 Attr*
318
319BinExpr =
320 Attr*
321
322Literal =
323 'int_number'
324
325MatchExpr =
326 Attr* 'match' Expr MatchArmList
327
328MatchArmList =
329 '{' arms:MatchArm* '}'
330
331MatchArm =
332 Attr* Pat guard:MatchGuard? '=>' Expr
333
334MatchGuard =
335 'if' Expr
336
337RecordExpr =
338 Path RecordExprFieldList
339
340RecordExprFieldList =
341 '{'
342 fields:RecordExprField*
343 ('..' spread:Expr)?
344 '}'
345
346RecordExprField =
347 Attr* NameRef (':' Expr)?
348
349OrPat =
350 Pat*
351
352ParenPat =
353 '(' Pat ')'
354
355RefPat =
356 '&' 'mut'? Pat
357
358BoxPat =
359 'box' Path
360
361BindPat =
362 Attr* 'ref'? 'mut'? Name ('@' Pat)?
363
364PlaceholderPat =
365 '_'
366
367DotDotPat =
368 '..'
369
370PathPat =
371 Path
372
373SlicePat =
374 '[' args:Pat* ']'
375
376RangePat =
377 '..' | '..='
378
379LiteralPat =
380 Literal
381
382MacroPat =
383 MacroCall
384
385RecordPat =
386 Path RecordFieldPatList
387
388RecordFieldPatList =
389 '{'
390 record_field_pats:RecordFieldPat*
391 BindPat*
392 '..'?
393 '}'
394
395RecordFieldPat =
396 Attr* NameRef ':' Pat
397
398TupleStructPat =
399 Path '(' args:Pat* ')'
400
401TuplePat =
402 '(' args:Pat* ')'
403
404Name =
405 'ident'
406
407NameRef =
408 'ident' | 'int_number'
409
410MacroCall =
411 Attr* Path '!' Name? TokenTree ';'?
412
413MacroDef =
414 Name TokenTree
415
416TokenTree =
417 '(' ')' | '{' '}' | '[' ']'
418
419MacroItems =
420 Item*
421
422MacroStmts =
423 statements:Stmt*
424 Expr?
425
426TypeBound =
427 'lifetime' | 'const'? TypeRef
428
429TypeBoundList =
430 bounds:TypeBound*
431
432WherePred =
433 ('for' GenericParamList)? ('lifetime' | TypeRef) ':' TypeBoundList
434
435WhereClause =
436 'where' predicates:WherePred*
437
438ExprStmt =
439 Attr* Expr ';'
440
441LetStmt =
442 Attr* 'let' Pat (':' ty:TypeRef)
443 '=' initializer:Expr ';'
444
445Path =
446 (qualifier:Path '::')? segment:PathSegment
447
448PathSegment =
449 '::' | 'crate' | 'self' | 'super'
450| '<' NameRef TypeArgList ParamList RetType PathType '>'
451
452TypeArgList =
453 '::'? '<'
454 TypeArg*
455 LifetimeArg*
456 AssocTypeArg*
457 ConstArg*
458 '>'
459
460TypeArg =
461 TypeRef
462
463AssocTypeArg =
464 NameRef (':' TypeBoundList | '=' TypeRef)
465
466LifetimeArg =
467 'lifetime'
468
469ConstArg =
470 Literal | BlockExpr BlockExpr
471
472AdtDef =
473 Struct
474| Enum
475| Union
476
477TypeRef =
478 ParenType
479| TupleType
480| NeverType
481| PathType
482| PointerType
483| ArrayType
484| SliceType
485| ReferenceType
486| PlaceholderType
487| FnPointerType
488| ForType
489| ImplTraitType
490| DynTraitType
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 aef68089e..01d903cde 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -1,4 +1,10 @@
1use std::path::PathBuf; 1use flate2::{write::GzEncoder, Compression};
2use std::{
3 env,
4 fs::File,
5 io,
6 path::{Path, PathBuf},
7};
2 8
3use anyhow::Result; 9use anyhow::Result;
4 10
@@ -7,17 +13,24 @@ use crate::{
7 project_root, 13 project_root,
8}; 14};
9 15
10pub fn run_dist(nightly: bool, client_version: Option<String>) -> Result<()> { 16pub struct DistCmd {
11 let dist = project_root().join("dist"); 17 pub nightly: bool,
12 rm_rf(&dist)?; 18 pub client_version: Option<String>,
13 fs2::create_dir_all(&dist)?; 19}
20
21impl DistCmd {
22 pub fn run(self) -> Result<()> {
23 let dist = project_root().join("dist");
24 rm_rf(&dist)?;
25 fs2::create_dir_all(&dist)?;
14 26
15 if let Some(version) = client_version { 27 if let Some(version) = self.client_version {
16 let release_tag = if nightly { "nightly".to_string() } else { date_iso()? }; 28 let release_tag = if self.nightly { "nightly".to_string() } else { date_iso()? };
17 dist_client(&version, &release_tag)?; 29 dist_client(&version, &release_tag)?;
30 }
31 dist_server()?;
32 Ok(())
18 } 33 }
19 dist_server(nightly)?;
20 Ok(())
21} 34}
22 35
23fn dist_client(version: &str, release_tag: &str) -> Result<()> { 36fn dist_client(version: &str, release_tag: &str) -> Result<()> {
@@ -46,17 +59,12 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
46 Ok(()) 59 Ok(())
47} 60}
48 61
49fn dist_server(nightly: bool) -> Result<()> { 62fn dist_server() -> Result<()> {
50 if cfg!(target_os = "linux") { 63 if cfg!(target_os = "linux") {
51 std::env::set_var("CC", "clang"); 64 env::set_var("CC", "clang");
52 run!( 65 run!(
53 "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" 66 "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release"
54 // We'd want to add, but that requires setting the right linker somehow
55 // --features=jemalloc
56 )?; 67 )?;
57 if !nightly {
58 run!("strip ./target/release/rust-analyzer")?;
59 }
60 } else { 68 } else {
61 run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; 69 run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?;
62 } 70 }
@@ -71,8 +79,20 @@ fn dist_server(nightly: bool) -> Result<()> {
71 panic!("Unsupported OS") 79 panic!("Unsupported OS")
72 }; 80 };
73 81
74 fs2::copy(src, dst)?; 82 let src = Path::new(src);
83 let dst = Path::new(dst);
84
85 fs2::copy(&src, &dst)?;
86 gzip(&src, &dst.with_extension("gz"))?;
87
88 Ok(())
89}
75 90
91fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
92 let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
93 let mut input = io::BufReader::new(File::open(src_path)?);
94 io::copy(&mut input, &mut encoder)?;
95 encoder.finish()?;
76 Ok(()) 96 Ok(())
77} 97}
78 98
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index 9ba77a3aa..b25a6e301 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -19,7 +19,12 @@ pub enum ClientOpt {
19} 19}
20 20
21pub struct ServerOpt { 21pub struct ServerOpt {
22 pub jemalloc: bool, 22 pub malloc: Malloc,
23}
24
25pub enum Malloc {
26 System,
27 Mimalloc,
23} 28}
24 29
25impl InstallCmd { 30impl InstallCmd {
@@ -130,8 +135,11 @@ fn install_server(opts: ServerOpt) -> Result<()> {
130 ) 135 )
131 } 136 }
132 137
133 let jemalloc = if opts.jemalloc { "--features jemalloc" } else { "" }; 138 let malloc_feature = match opts.malloc {
134 let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", jemalloc); 139 Malloc::System => "",
140 Malloc::Mimalloc => "--features mimalloc",
141 };
142 let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", malloc_feature);
135 143
136 if res.is_err() && old_rust { 144 if res.is_err() && old_rust {
137 eprintln!( 145 eprintln!(
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 747654c1f..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;
@@ -20,7 +21,7 @@ use walkdir::{DirEntry, WalkDir};
20 21
21use crate::{ 22use crate::{
22 codegen::Mode, 23 codegen::Mode,
23 not_bash::{fs2, pushd, pushenv, rm_rf, run}, 24 not_bash::{fs2, pushd, pushenv, rm_rf},
24}; 25};
25 26
26pub use anyhow::{bail, Context as _, Result}; 27pub use anyhow::{bail, Context as _, Result};
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index f7a79362d..b69b884e5 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -13,11 +13,12 @@ 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, 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::ReleaseCmd, 21 release::{PromoteCmd, ReleaseCmd},
21 run_clippy, run_fuzzer, run_pre_cache, run_rustfmt, Result, 22 run_clippy, run_fuzzer, run_pre_cache, run_rustfmt, Result,
22}; 23};
23 24
@@ -45,7 +46,7 @@ USAGE:
45FLAGS: 46FLAGS:
46 --client-code Install only VS Code plugin 47 --client-code Install only VS Code plugin
47 --server Install only the language server 48 --server Install only the language server
48 --jemalloc Use jemalloc for server 49 --mimalloc Use mimalloc for server
49 -h, --help Prints help information 50 -h, --help Prints help information
50 " 51 "
51 ); 52 );
@@ -61,13 +62,14 @@ FLAGS:
61 return Ok(()); 62 return Ok(());
62 } 63 }
63 64
64 let jemalloc = args.contains("--jemalloc"); 65 let malloc =
66 if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System };
65 67
66 args.finish()?; 68 args.finish()?;
67 69
68 InstallCmd { 70 InstallCmd {
69 client: if server { None } else { Some(ClientOpt::VsCode) }, 71 client: if server { None } else { Some(ClientOpt::VsCode) },
70 server: if client_code { None } else { Some(ServerOpt { jemalloc }) }, 72 server: if client_code { None } else { Some(ServerOpt { malloc }) },
71 } 73 }
72 .run() 74 .run()
73 } 75 }
@@ -105,11 +107,21 @@ FLAGS:
105 args.finish()?; 107 args.finish()?;
106 ReleaseCmd { dry_run }.run() 108 ReleaseCmd { dry_run }.run()
107 } 109 }
110 "promote" => {
111 let dry_run = args.contains("--dry-run");
112 args.finish()?;
113 PromoteCmd { dry_run }.run()
114 }
108 "dist" => { 115 "dist" => {
109 let nightly = args.contains("--nightly"); 116 let nightly = args.contains("--nightly");
110 let client_version: Option<String> = args.opt_value_from_str("--client")?; 117 let client_version: Option<String> = args.opt_value_from_str("--client")?;
111 args.finish()?; 118 args.finish()?;
112 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()
113 } 125 }
114 _ => { 126 _ => {
115 eprintln!( 127 eprintln!(
@@ -127,7 +139,8 @@ SUBCOMMANDS:
127 codegen 139 codegen
128 install 140 install
129 lint 141 lint
130 dist" 142 dist
143 promote"
131 ); 144 );
132 Ok(()) 145 Ok(())
133 } 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 a6431e586..ef811e5bf 100644
--- a/xtask/src/not_bash.rs
+++ b/xtask/src/not_bash.rs
@@ -54,7 +54,8 @@ pub mod fs2 {
54 } 54 }
55} 55}
56 56
57macro_rules! _run { 57#[macro_export]
58macro_rules! run {
58 ($($expr:expr),*) => { 59 ($($expr:expr),*) => {
59 run!($($expr),*; echo = true) 60 run!($($expr),*; echo = true)
60 }; 61 };
@@ -65,7 +66,7 @@ macro_rules! _run {
65 $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin)) 66 $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin))
66 }; 67 };
67} 68}
68pub(crate) use _run as run; 69pub use crate::run;
69 70
70pub struct Pushd { 71pub struct Pushd {
71 _p: (), 72 _p: (),
@@ -153,7 +154,17 @@ fn run_process_inner(cmd: &str, echo: bool, stdin: Option<&[u8]>) -> Result<Stri
153 154
154// FIXME: some real shell lexing here 155// FIXME: some real shell lexing here
155fn shelx(cmd: &str) -> Vec<String> { 156fn shelx(cmd: &str) -> Vec<String> {
156 cmd.split_whitespace().map(|it| it.to_string()).collect() 157 let mut res = Vec::new();
158 for (string_piece, in_quotes) in cmd.split('\'').zip([false, true].iter().copied().cycle()) {
159 if in_quotes {
160 res.push(string_piece.to_string())
161 } else {
162 if !string_piece.is_empty() {
163 res.extend(string_piece.split_ascii_whitespace().map(|it| it.to_string()))
164 }
165 }
166 }
167 res
157} 168}
158 169
159struct Env { 170struct Env {
@@ -175,7 +186,8 @@ impl Env {
175 fn pushd(&mut self, dir: PathBuf) { 186 fn pushd(&mut self, dir: PathBuf) {
176 let dir = self.cwd().join(dir); 187 let dir = self.cwd().join(dir);
177 self.pushd_stack.push(dir); 188 self.pushd_stack.push(dir);
178 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));
179 } 191 }
180 fn popd(&mut self) { 192 fn popd(&mut self) {
181 self.pushd_stack.pop().unwrap(); 193 self.pushd_stack.pop().unwrap();
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index b6502b952..7fa0966aa 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -1,6 +1,6 @@
1use crate::{ 1use crate::{
2 codegen, is_release_tag, 2 codegen, is_release_tag,
3 not_bash::{date_iso, fs2, run}, 3 not_bash::{date_iso, fs2, pushd, run},
4 project_root, Mode, Result, 4 project_root, Mode, Result,
5}; 5};
6 6
@@ -37,6 +37,8 @@ Release: release:{}[]
37 37
38== Sponsors 38== Sponsors
39 39
40**Become a sponsor:** https://opencollective.com/rust-analyzer/[opencollective.com/rust-analyzer]
41
40== New Features 42== New Features
41 43
42* pr:[] . 44* pr:[] .
@@ -67,3 +69,35 @@ Release: release:{}[]
67 Ok(()) 69 Ok(())
68 } 70 }
69} 71}
72
73pub struct PromoteCmd {
74 pub dry_run: bool,
75}
76
77impl PromoteCmd {
78 pub fn run(self) -> Result<()> {
79 let _dir = pushd("../rust-rust-analyzer");
80 run!("git switch master")?;
81 run!("git fetch upstream")?;
82 run!("git reset --hard upstream/master")?;
83 run!("git submodule update --recursive")?;
84
85 let branch = format!("rust-analyzer-{}", date_iso()?);
86 run!("git switch -c {}", branch)?;
87 {
88 let _dir = pushd("src/tools/rust-analyzer");
89 run!("git fetch origin")?;
90 run!("git reset --hard origin/release")?;
91 }
92 run!("git add src/tools/rust-analyzer")?;
93 run!("git commit -m':arrow_up: rust-analyzer'")?;
94 if !self.dry_run {
95 run!("git push")?;
96 run!(
97 "xdg-open https://github.com/matklad/rust/pull/new/{}?body=r%3F%20%40ghost",
98 branch
99 )?;
100 }
101 Ok(())
102 }
103}
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index d38ac7f17..d65a2acbc 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -5,7 +5,7 @@ use std::{
5 5
6use xtask::{ 6use xtask::{
7 codegen::{self, Mode}, 7 codegen::{self, Mode},
8 not_bash::fs2, 8 not_bash::{fs2, run},
9 project_root, run_rustfmt, rust_files, 9 project_root, run_rustfmt, rust_files,
10}; 10};
11 11
@@ -49,19 +49,56 @@ fn rust_files_are_tidy() {
49 tidy_docs.finish(); 49 tidy_docs.finish();
50} 50}
51 51
52#[test]
53fn check_licenses() {
54 let expected = "
550BSD OR MIT OR Apache-2.0
56Apache-2.0 OR BSL-1.0
57Apache-2.0 OR MIT
58Apache-2.0/MIT
59BSD-2-Clause
60BSD-3-Clause
61CC0-1.0
62ISC
63MIT
64MIT / Apache-2.0
65MIT OR Apache-2.0
66MIT/Apache-2.0
67MIT/Apache-2.0 AND BSD-2-Clause
68Unlicense OR MIT
69Unlicense/MIT
70Zlib
71"
72 .lines()
73 .filter(|it| !it.is_empty())
74 .collect::<Vec<_>>();
75
76 let meta = run!("cargo metadata --format-version 1"; echo = false).unwrap();
77 let mut licenses = meta
78 .split(|c| c == ',' || c == '{' || c == '}')
79 .filter(|it| it.contains(r#""license""#))
80 .map(|it| it.trim())
81 .map(|it| it[r#""license":"#.len()..].trim_matches('"'))
82 .collect::<Vec<_>>();
83 licenses.sort();
84 licenses.dedup();
85 assert_eq!(licenses, expected);
86}
87
52fn check_todo(path: &Path, text: &str) { 88fn check_todo(path: &Path, text: &str) {
53 let whitelist = &[ 89 let need_todo = &[
54 // This file itself is whitelisted since this test itself contains matches. 90 // This file itself obviously needs to use todo (<- like this!).
55 "tests/cli.rs", 91 "tests/cli.rs",
56 // Some of our assists generate `todo!()` so those files are whitelisted. 92 // Some of our assists generate `todo!()`.
57 "tests/generated.rs", 93 "tests/generated.rs",
58 "handlers/add_missing_impl_members.rs", 94 "handlers/add_missing_impl_members.rs",
59 "handlers/add_function.rs",
60 "handlers/add_turbo_fish.rs", 95 "handlers/add_turbo_fish.rs",
61 // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make. 96 "handlers/generate_function.rs",
97 // To support generating `todo!()` in assists, we have `expr_todo()` in
98 // `ast::make`.
62 "ast/make.rs", 99 "ast/make.rs",
63 ]; 100 ];
64 if whitelist.iter().any(|p| path.ends_with(p)) { 101 if need_todo.iter().any(|p| path.ends_with(p)) {
65 return; 102 return;
66 } 103 }
67 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") { 104 if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
@@ -139,7 +176,7 @@ impl TidyDocs {
139 ) 176 )
140 } 177 }
141 178
142 let whitelist = [ 179 let poorly_documented = [
143 "ra_hir", 180 "ra_hir",
144 "ra_hir_expand", 181 "ra_hir_expand",
145 "ra_ide", 182 "ra_ide",
@@ -153,9 +190,9 @@ impl TidyDocs {
153 ]; 190 ];
154 191
155 let mut has_fixmes = 192 let mut has_fixmes =
156 whitelist.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>(); 193 poorly_documented.iter().map(|it| (*it, false)).collect::<HashMap<&str, bool>>();
157 'outer: for path in self.contains_fixme { 194 'outer: for path in self.contains_fixme {
158 for krate in whitelist.iter() { 195 for krate in poorly_documented.iter() {
159 if path.components().any(|it| it.as_os_str() == *krate) { 196 if path.components().any(|it| it.as_os_str() == *krate) {
160 has_fixmes.insert(krate, true); 197 has_fixmes.insert(krate, true);
161 continue 'outer; 198 continue 'outer;
@@ -166,7 +203,7 @@ impl TidyDocs {
166 203
167 for (krate, has_fixme) in has_fixmes.iter() { 204 for (krate, has_fixme) in has_fixmes.iter() {
168 if !has_fixme { 205 if !has_fixme {
169 panic!("crate {} is fully documented, remove it from the white list", krate) 206 panic!("crate {} is fully documented :tada:, remove it from the list of poorly documented crates", krate)
170 } 207 }
171 } 208 }
172 } 209 }