summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs
blob: 919d9b91ebab5dede8a8f5b3fce37348e8874338 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use super::*;

pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) {
    let m;
    if p.at(T![::]) && p.nth(2) == T![<] {
        m = p.start();
        p.bump(T![::]);
    } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
        m = p.start();
    } else {
        return;
    }

    delimited(p, T![<], T![>], T![,], GENERIC_ARG_FIRST, generic_arg);
    m.complete(p, GENERIC_ARG_LIST);
}

const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[
    LIFETIME_IDENT,
    IDENT,
    T!['{'],
    T![true],
    T![false],
    T![-],
    INT_NUMBER,
    FLOAT_NUMBER,
    CHAR,
    BYTE,
    STRING,
    BYTE_STRING,
])
.union(types::TYPE_FIRST);

// test generic_arg
// type T = S<i32>;
fn generic_arg(p: &mut Parser<'_>) -> bool {
    match p.current() {
        LIFETIME_IDENT => lifetime_arg(p),
        T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
        k if k.is_literal() => const_arg(p),
        // test associated_type_bounds
        // fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}

        // test macro_inside_generic_arg
        // type A = Foo<syn::Token![_]>;
        IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => {
            let m = p.start();
            name_ref(p);
            opt_generic_arg_list(p, false);
            match p.current() {
                T![=] => {
                    p.bump_any();
                    if types::TYPE_FIRST.contains(p.current()) {
                        // test assoc_type_eq
                        // type T = StreamingIterator<Item<'a> = &'a T>;
                        types::type_(p);
                    } else {
                        // test assoc_const_eq
                        // fn foo<F: Foo<N=3>>() {}
                        // const TEST: usize = 3;
                        // fn bar<F: Foo<N={TEST}>>() {}
                        const_arg(p);
                    }
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                // test assoc_type_bound
                // type T = StreamingIterator<Item<'a>: Clone>;
                T![:] if !p.at(T![::]) => {
                    generic_params::bounds(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                _ => {
                    let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH);
                    let m = paths::type_path_for_qualifier(p, m);
                    m.precede(p).complete(p, PATH_TYPE).precede(p).complete(p, TYPE_ARG);
                }
            }
        }
        _ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
        _ => return false,
    }
    true
}

// test lifetime_arg
// type T = S<'static>;
fn lifetime_arg(p: &mut Parser<'_>) {
    let m = p.start();
    lifetime(p);
    m.complete(p, LIFETIME_ARG);
}

pub(super) fn const_arg_expr(p: &mut Parser<'_>) {
    // The tests in here are really for `const_arg`, which wraps the content
    // CONST_ARG.
    match p.current() {
        // test const_arg_block
        // type T = S<{90 + 2}>;
        T!['{'] => {
            expressions::block_expr(p);
        }
        // test const_arg_literal
        // type T = S<"hello", 0xdeadbeef>;
        k if k.is_literal() => {
            expressions::literal(p);
        }
        // test const_arg_bool_literal
        // type T = S<true>;
        T![true] | T![false] => {
            expressions::literal(p);
        }
        // test const_arg_negative_number
        // type T = S<-92>;
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
        }
        _ => {
            // This shouldn't be hit by `const_arg`
            let lm = p.start();
            paths::use_path(p);
            lm.complete(p, PATH_EXPR);
        }
    }
}

// test const_arg
// type T = S<92>;
pub(super) fn const_arg(p: &mut Parser<'_>) {
    let m = p.start();
    const_arg_expr(p);
    m.complete(p, CONST_ARG);
}

fn type_arg(p: &mut Parser<'_>) {
    let m = p.start();
    types::type_(p);
    m.complete(p, TYPE_ARG);
}