]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / parser / src / grammar / paths.rs
CommitLineData
064997fb
FG
1use super::*;
2
3pub(super) const PATH_FIRST: TokenSet =
4 TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]);
5
6pub(super) fn is_path_start(p: &Parser<'_>) -> bool {
7 is_use_path_start(p) || p.at(T![<]) || p.at(T![Self])
8}
9
10pub(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
18pub(super) fn use_path(p: &mut Parser<'_>) {
19 path(p, Mode::Use);
20}
21
22pub(crate) fn type_path(p: &mut Parser<'_>) {
23 path(p, Mode::Type);
24}
25
26pub(super) fn expr_path(p: &mut Parser<'_>) {
27 path(p, Mode::Expr);
28}
29
30pub(crate) fn type_path_for_qualifier(
31 p: &mut Parser<'_>,
32 qual: CompletedMarker,
33) -> CompletedMarker {
34 path_for_qualifier(p, Mode::Type, qual)
35}
36
37#[derive(Clone, Copy, Eq, PartialEq)]
38enum Mode {
39 Use,
40 Type,
41 Expr,
42}
43
44fn path(p: &mut Parser<'_>, mode: Mode) {
45 let path = p.start();
46 path_segment(p, mode, true);
47 let qual = path.complete(p, PATH);
48 path_for_qualifier(p, mode, qual);
49}
50
51fn path_for_qualifier(
52 p: &mut Parser<'_>,
53 mode: Mode,
54 mut qual: CompletedMarker,
55) -> CompletedMarker {
56 loop {
57 let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
58 if p.at(T![::]) && !use_tree {
59 let path = qual.precede(p);
60 p.bump(T![::]);
61 path_segment(p, mode, false);
62 let path = path.complete(p, PATH);
63 qual = path;
64 } else {
65 return qual;
66 }
67 }
68}
69
70fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
71 let m = p.start();
72 // test qual_paths
73 // type X = <A as B>::Output;
74 // fn foo() { <usize as Default>::default(); }
75 if first && p.eat(T![<]) {
76 types::type_(p);
77 if p.eat(T![as]) {
78 if is_use_path_start(p) {
79 types::path_type(p);
80 } else {
81 p.error("expected a trait");
82 }
83 }
84 p.expect(T![>]);
85 } else {
6522a427 86 let empty = if first {
064997fb 87 p.eat(T![::]);
6522a427
EL
88 false
89 } else {
90 true
91 };
064997fb
FG
92 match p.current() {
93 IDENT => {
94 name_ref(p);
95 opt_path_type_args(p, mode);
96 }
97 // test crate_path
98 // use crate::foo;
99 T![self] | T![super] | T![crate] | T![Self] => {
100 let m = p.start();
101 p.bump_any();
102 m.complete(p, NAME_REF);
103 }
104 _ => {
105 p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
106 if empty {
107 // test_err empty_segment
108 // use crate::;
109 m.abandon(p);
110 return;
111 }
112 }
113 };
114 }
115 m.complete(p, PATH_SEGMENT);
116}
117
118fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
119 match mode {
120 Mode::Use => {}
121 Mode::Type => {
f2b60f7d
FG
122 // test typepathfn_with_coloncolon
123 // type F = Start::(Middle) -> (Middle)::End;
124 if p.at(T![::]) && p.nth_at(2, T!['(']) {
125 p.bump(T![::]);
126 }
064997fb
FG
127 // test path_fn_trait_args
128 // type F = Box<Fn(i32) -> ()>;
129 if p.at(T!['(']) {
130 params::param_list_fn_trait(p);
131 opt_ret_type(p);
132 } else {
133 generic_args::opt_generic_arg_list(p, false);
134 }
135 }
136 Mode::Expr => generic_args::opt_generic_arg_list(p, true),
137 }
138}