]> git.lizzy.rs Git - rust.git/blob - crates/parser/src/grammar/paths.rs
Apply a few clippy suggestions
[rust.git] / crates / parser / src / grammar / paths.rs
1 use super::*;
2
3 pub(super) const PATH_FIRST: TokenSet =
4     TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![:], T![<]]);
5
6 pub(super) fn is_path_start(p: &Parser) -> bool {
7     is_use_path_start(p) || p.at(T![<])
8 }
9
10 pub(super) fn is_use_path_start(p: &Parser) -> bool {
11     match p.current() {
12         IDENT | T![self] | T![super] | T![crate] => true,
13         T![:] if p.at(T![::]) => true,
14         _ => false,
15     }
16 }
17
18 pub(super) fn use_path(p: &mut Parser) {
19     path(p, Mode::Use)
20 }
21
22 pub(crate) fn type_path(p: &mut Parser) {
23     path(p, Mode::Type)
24 }
25
26 pub(super) fn expr_path(p: &mut Parser) {
27     path(p, Mode::Expr)
28 }
29
30 #[derive(Clone, Copy, Eq, PartialEq)]
31 enum Mode {
32     Use,
33     Type,
34     Expr,
35 }
36
37 fn path(p: &mut Parser, mode: Mode) {
38     let path = p.start();
39     path_segment(p, mode, true);
40     let mut qual = path.complete(p, PATH);
41     loop {
42         let use_tree = matches!(p.nth(2), T![*] | T!['{']);
43         if p.at(T![::]) && !use_tree {
44             let path = qual.precede(p);
45             p.bump(T![::]);
46             path_segment(p, mode, false);
47             let path = path.complete(p, PATH);
48             qual = path;
49         } else {
50             break;
51         }
52     }
53 }
54
55 fn path_segment(p: &mut Parser, mode: Mode, first: bool) {
56     let m = p.start();
57     // test qual_paths
58     // type X = <A as B>::Output;
59     // fn foo() { <usize as Default>::default(); }
60     if first && p.eat(T![<]) {
61         types::type_(p);
62         if p.eat(T![as]) {
63             if is_use_path_start(p) {
64                 types::path_type(p);
65             } else {
66                 p.error("expected a trait");
67             }
68         }
69         p.expect(T![>]);
70     } else {
71         let mut empty = true;
72         if first {
73             p.eat(T![::]);
74             empty = false;
75         }
76         match p.current() {
77             IDENT => {
78                 name_ref(p);
79                 opt_path_type_args(p, mode);
80             }
81             // test crate_path
82             // use crate::foo;
83             T![self] | T![super] | T![crate] => {
84                 let m = p.start();
85                 p.bump_any();
86                 m.complete(p, NAME_REF);
87             }
88             _ => {
89                 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
90                 if empty {
91                     // test_err empty_segment
92                     // use crate::;
93                     m.abandon(p);
94                     return;
95                 }
96             }
97         };
98     }
99     m.complete(p, PATH_SEGMENT);
100 }
101
102 fn opt_path_type_args(p: &mut Parser, mode: Mode) {
103     match mode {
104         Mode::Use => {}
105         Mode::Type => {
106             // test path_fn_trait_args
107             // type F = Box<Fn(i32) -> ()>;
108             if p.at(T!['(']) {
109                 params::param_list_fn_trait(p);
110                 opt_ret_type(p);
111             } else {
112                 type_args::opt_generic_arg_list(p, false)
113             }
114         }
115         Mode::Expr => type_args::opt_generic_arg_list(p, true),
116     }
117 }