Unnamed repository; edit this file 'description' to name the repository.
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
//! The home of `HirDatabase`, which is the Salsa database containing all the
//! type inference-related queries.

use std::sync;

use base_db::{impl_intern_key, salsa, CrateId, Upcast};
use hir_def::{
    db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId,
    DefWithBodyId, EnumVariantId, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId,
    TypeOrConstParamId, VariantId,
};
use la_arena::ArenaMap;
use smallvec::SmallVec;
use triomphe::Arc;

use crate::{
    chalk_db,
    consteval::ConstEvalError,
    layout::{Layout, LayoutError},
    method_resolution::{InherentImpls, TraitImpls, TyFingerprint},
    mir::{BorrowckResult, MirBody, MirLowerError},
    Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, InferenceResult,
    Interner, PolyFnSig, QuantifiedWhereClause, ReturnTypeImplTraits, Substitution, TraitRef, Ty,
    TyDefId, ValueTyDefId,
};
use hir_expand::name::Name;

#[salsa::query_group(HirDatabaseStorage)]
pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
    #[salsa::invoke(infer_wait)]
    #[salsa::transparent]
    fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;

    #[salsa::invoke(crate::infer::infer_query)]
    fn infer_query(&self, def: DefWithBodyId) -> Arc<InferenceResult>;

    #[salsa::invoke(crate::mir::mir_body_query)]
    #[salsa::cycle(crate::mir::mir_body_recover)]
    fn mir_body(&self, def: DefWithBodyId) -> Result<Arc<MirBody>, MirLowerError>;

    #[salsa::invoke(crate::mir::mir_body_for_closure_query)]
    fn mir_body_for_closure(&self, def: ClosureId) -> Result<Arc<MirBody>, MirLowerError>;

    #[salsa::invoke(crate::mir::borrowck_query)]
    fn borrowck(&self, def: DefWithBodyId) -> Result<Arc<[BorrowckResult]>, MirLowerError>;

    #[salsa::invoke(crate::lower::ty_query)]
    #[salsa::cycle(crate::lower::ty_recover)]
    fn ty(&self, def: TyDefId) -> Binders<Ty>;

    #[salsa::invoke(crate::lower::value_ty_query)]
    fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;

    #[salsa::invoke(crate::lower::impl_self_ty_query)]
    #[salsa::cycle(crate::lower::impl_self_ty_recover)]
    fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;

    #[salsa::invoke(crate::lower::const_param_ty_query)]
    fn const_param_ty(&self, def: ConstParamId) -> Ty;

    #[salsa::invoke(crate::consteval::const_eval_query)]
    #[salsa::cycle(crate::consteval::const_eval_recover)]
    fn const_eval(&self, def: DefWithBodyId, subst: Substitution) -> Result<Const, ConstEvalError>;

    #[salsa::invoke(crate::consteval::const_eval_discriminant_variant)]
    #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)]
    fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>;

    #[salsa::invoke(crate::lower::impl_trait_query)]
    fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;

    #[salsa::invoke(crate::lower::field_types_query)]
    fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;

    #[salsa::invoke(crate::layout::layout_of_adt_query)]
    #[salsa::cycle(crate::layout::layout_of_adt_recover)]
    fn layout_of_adt(&self, def: AdtId, subst: Substitution) -> Result<Layout, LayoutError>;

    #[salsa::invoke(crate::layout::target_data_layout_query)]
    fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;

    #[salsa::invoke(crate::lower::callable_item_sig)]
    fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;

    #[salsa::invoke(crate::lower::return_type_impl_traits)]
    fn return_type_impl_traits(
        &self,
        def: FunctionId,
    ) -> Option<Arc<Binders<ReturnTypeImplTraits>>>;

    #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
    #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
    fn generic_predicates_for_param(
        &self,
        def: GenericDefId,
        param_id: TypeOrConstParamId,
        assoc_name: Option<Name>,
    ) -> Arc<[Binders<QuantifiedWhereClause>]>;

    #[salsa::invoke(crate::lower::generic_predicates_query)]
    fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<QuantifiedWhereClause>]>;

    #[salsa::invoke(crate::lower::trait_environment_for_body_query)]
    #[salsa::transparent]
    fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<crate::TraitEnvironment>;

    #[salsa::invoke(crate::lower::trait_environment_query)]
    fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>;

    #[salsa::invoke(crate::lower::generic_defaults_query)]
    #[salsa::cycle(crate::lower::generic_defaults_recover)]
    fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>;

    #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
    fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;

    #[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
    fn inherent_impls_in_block(&self, block: BlockId) -> Arc<InherentImpls>;

    /// Collects all crates in the dependency graph that have impls for the
    /// given fingerprint. This is only used for primitive types and types
    /// annotated with `rustc_has_incoherent_inherent_impls`; for other types
    /// we just look at the crate where the type is defined.
    #[salsa::invoke(crate::method_resolution::incoherent_inherent_impl_crates)]
    fn incoherent_inherent_impl_crates(
        &self,
        krate: CrateId,
        fp: TyFingerprint,
    ) -> SmallVec<[CrateId; 2]>;

    #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
    fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;

    #[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
    fn trait_impls_in_block(&self, block: BlockId) -> Arc<TraitImpls>;

    #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
    fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<[Arc<TraitImpls>]>;

    // Interned IDs for Chalk integration
    #[salsa::interned]
    fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
    #[salsa::interned]
    fn intern_type_or_const_param_id(
        &self,
        param_id: TypeOrConstParamId,
    ) -> InternedTypeOrConstParamId;
    #[salsa::interned]
    fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId;
    #[salsa::interned]
    fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
    #[salsa::interned]
    fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
    #[salsa::interned]
    fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId;

    #[salsa::invoke(chalk_db::associated_ty_data_query)]
    fn associated_ty_data(
        &self,
        id: chalk_db::AssocTypeId,
    ) -> sync::Arc<chalk_db::AssociatedTyDatum>;

    #[salsa::invoke(chalk_db::trait_datum_query)]
    fn trait_datum(
        &self,
        krate: CrateId,
        trait_id: chalk_db::TraitId,
    ) -> sync::Arc<chalk_db::TraitDatum>;

    #[salsa::invoke(chalk_db::struct_datum_query)]
    fn struct_datum(
        &self,
        krate: CrateId,
        struct_id: chalk_db::AdtId,
    ) -> sync::Arc<chalk_db::StructDatum>;

    #[salsa::invoke(chalk_db::impl_datum_query)]
    fn impl_datum(
        &self,
        krate: CrateId,
        impl_id: chalk_db::ImplId,
    ) -> sync::Arc<chalk_db::ImplDatum>;

    #[salsa::invoke(chalk_db::fn_def_datum_query)]
    fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>;

    #[salsa::invoke(chalk_db::fn_def_variance_query)]
    fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances;

    #[salsa::invoke(chalk_db::adt_variance_query)]
    fn adt_variance(&self, adt_id: chalk_db::AdtId) -> chalk_db::Variances;

    #[salsa::invoke(chalk_db::associated_ty_value_query)]
    fn associated_ty_value(
        &self,
        krate: CrateId,
        id: chalk_db::AssociatedTyValueId,
    ) -> sync::Arc<chalk_db::AssociatedTyValue>;

    #[salsa::invoke(crate::traits::normalize_projection_query)]
    #[salsa::transparent]
    fn normalize_projection(
        &self,
        projection: crate::ProjectionTy,
        env: Arc<crate::TraitEnvironment>,
    ) -> Ty;

    #[salsa::invoke(trait_solve_wait)]
    #[salsa::transparent]
    fn trait_solve(
        &self,
        krate: CrateId,
        block: Option<BlockId>,
        goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
    ) -> Option<crate::Solution>;

    #[salsa::invoke(crate::traits::trait_solve_query)]
    fn trait_solve_query(
        &self,
        krate: CrateId,
        block: Option<BlockId>,
        goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
    ) -> Option<crate::Solution>;

    #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
    fn program_clauses_for_chalk_env(
        &self,
        krate: CrateId,
        block: Option<BlockId>,
        env: chalk_ir::Environment<Interner>,
    ) -> chalk_ir::ProgramClauses<Interner>;
}

fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
    let _p = profile::span("infer:wait").detail(|| match def {
        DefWithBodyId::FunctionId(it) => db.function_data(it).name.to_string(),
        DefWithBodyId::StaticId(it) => db.static_data(it).name.clone().to_string(),
        DefWithBodyId::ConstId(it) => {
            db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
        }
        DefWithBodyId::VariantId(it) => {
            db.enum_data(it.parent).variants[it.local_id].name.to_string()
        }
    });
    db.infer_query(def)
}

fn trait_solve_wait(
    db: &dyn HirDatabase,
    krate: CrateId,
    block: Option<BlockId>,
    goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution> {
    let _p = profile::span("trait_solve::wait");
    db.trait_solve_query(krate, block, goal)
}

#[test]
fn hir_database_is_object_safe() {
    fn _assert_object_safe(_: &dyn HirDatabase) {}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedTypeOrConstParamId(salsa::InternId);
impl_intern_key!(InternedTypeOrConstParamId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedLifetimeParamId(salsa::InternId);
impl_intern_key!(InternedLifetimeParamId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedConstParamId(salsa::InternId);
impl_intern_key!(InternedConstParamId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedOpaqueTyId(salsa::InternId);
impl_intern_key!(InternedOpaqueTyId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedClosureId(salsa::InternId);
impl_intern_key!(InternedClosureId);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternedGeneratorId(salsa::InternId);
impl_intern_key!(InternedGeneratorId);

/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
/// we have different IDs for struct and enum variant constructors.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct InternedCallableDefId(salsa::InternId);
impl_intern_key!(InternedCallableDefId);
='n681' href='#n681'>681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
//! proc-macro tests

#[macro_use]
mod utils;
use utils::*;

use expect_test::expect;

#[test]
fn test_derive_empty() {
    assert_expand(
        "DeriveEmpty",
        r#"struct S { field: &'r#lt fn(u32) -> &'a r#u32 }"#,
        expect![[r#"
            IDENT 1 struct
            IDENT 1 S
            GROUP {} 1 1 1
              IDENT 1 field
              PUNCT 1 : [alone]
              PUNCT 1 & [joint]
              PUNCT 1 ' [joint]
              IDENT 1 r#lt
              IDENT 1 fn
              GROUP () 1 1 1
                IDENT 1 u32
              PUNCT 1 - [joint]
              PUNCT 1 > [alone]
              PUNCT 1 & [joint]
              PUNCT 1 ' [joint]
              IDENT 1 a
              IDENT 1 r#u32
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@0..6#ROOT2024 struct
            IDENT 42:Root[0000, 0]@7..8#ROOT2024 S
            GROUP {} 42:Root[0000, 0]@9..10#ROOT2024 42:Root[0000, 0]@46..47#ROOT2024 42:Root[0000, 0]@9..47#ROOT2024
              IDENT 42:Root[0000, 0]@11..16#ROOT2024 field
              PUNCT 42:Root[0000, 0]@16..17#ROOT2024 : [alone]
              PUNCT 42:Root[0000, 0]@18..19#ROOT2024 & [joint]
              PUNCT 42:Root[0000, 0]@22..23#ROOT2024 ' [joint]
              IDENT 42:Root[0000, 0]@22..24#ROOT2024 r#lt
              IDENT 42:Root[0000, 0]@25..27#ROOT2024 fn
              GROUP () 42:Root[0000, 0]@27..28#ROOT2024 42:Root[0000, 0]@31..32#ROOT2024 42:Root[0000, 0]@27..32#ROOT2024
                IDENT 42:Root[0000, 0]@28..31#ROOT2024 u32
              PUNCT 42:Root[0000, 0]@33..34#ROOT2024 - [joint]
              PUNCT 42:Root[0000, 0]@34..35#ROOT2024 > [alone]
              PUNCT 42:Root[0000, 0]@36..37#ROOT2024 & [joint]
              PUNCT 42:Root[0000, 0]@38..39#ROOT2024 ' [joint]
              IDENT 42:Root[0000, 0]@38..39#ROOT2024 a
              IDENT 42:Root[0000, 0]@42..45#ROOT2024 r#u32
        "#]],
    );
}

#[test]
fn test_derive_reemit_helpers() {
    assert_expand(
        "DeriveReemit",
        r#"
#[helper(build_fn(private, name = "partial_build"))]
pub struct Foo {
    /// The domain where this federated instance is running
    #[helper(setter(into))]
    pub(crate) domain: String,
}
"#,
        expect![[r#"
            PUNCT 1 # [joint]
            GROUP [] 1 1 1
              IDENT 1 helper
              GROUP () 1 1 1
                IDENT 1 build_fn
                GROUP () 1 1 1
                  IDENT 1 private
                  PUNCT 1 , [alone]
                  IDENT 1 name
                  PUNCT 1 = [alone]
                  LITER 1 Str partial_build
            IDENT 1 pub
            IDENT 1 struct
            IDENT 1 Foo
            GROUP {} 1 1 1
              PUNCT 1 # [alone]
              GROUP [] 1 1 1
                IDENT 1 doc
                PUNCT 1 = [alone]
                LITER 1 Str / The domain where this federated instance is running
              PUNCT 1 # [joint]
              GROUP [] 1 1 1
                IDENT 1 helper
                GROUP () 1 1 1
                  IDENT 1 setter
                  GROUP () 1 1 1
                    IDENT 1 into
              IDENT 1 pub
              GROUP () 1 1 1
                IDENT 1 crate
              IDENT 1 domain
              PUNCT 1 : [alone]
              IDENT 1 String
              PUNCT 1 , [alone]


            PUNCT 1 # [joint]
            GROUP [] 1 1 1
              IDENT 1 helper
              GROUP () 1 1 1
                IDENT 1 build_fn
                GROUP () 1 1 1
                  IDENT 1 private
                  PUNCT 1 , [alone]
                  IDENT 1 name
                  PUNCT 1 = [alone]
                  LITER 1 Str partial_build
            IDENT 1 pub
            IDENT 1 struct
            IDENT 1 Foo
            GROUP {} 1 1 1
              PUNCT 1 # [alone]
              GROUP [] 1 1 1
                IDENT 1 doc
                PUNCT 1 = [alone]
                LITER 1 Str / The domain where this federated instance is running
              PUNCT 1 # [joint]
              GROUP [] 1 1 1
                IDENT 1 helper
                GROUP () 1 1 1
                  IDENT 1 setter
                  GROUP () 1 1 1
                    IDENT 1 into
              IDENT 1 pub
              GROUP () 1 1 1
                IDENT 1 crate
              IDENT 1 domain
              PUNCT 1 : [alone]
              IDENT 1 String
              PUNCT 1 , [alone]
        "#]],
        expect![[r#"
            PUNCT 42:Root[0000, 0]@1..2#ROOT2024 # [joint]
            GROUP [] 42:Root[0000, 0]@2..3#ROOT2024 42:Root[0000, 0]@52..53#ROOT2024 42:Root[0000, 0]@2..53#ROOT2024
              IDENT 42:Root[0000, 0]@3..9#ROOT2024 helper
              GROUP () 42:Root[0000, 0]@9..10#ROOT2024 42:Root[0000, 0]@51..52#ROOT2024 42:Root[0000, 0]@9..52#ROOT2024
                IDENT 42:Root[0000, 0]@10..18#ROOT2024 build_fn
                GROUP () 42:Root[0000, 0]@18..19#ROOT2024 42:Root[0000, 0]@50..51#ROOT2024 42:Root[0000, 0]@18..51#ROOT2024
                  IDENT 42:Root[0000, 0]@19..26#ROOT2024 private
                  PUNCT 42:Root[0000, 0]@26..27#ROOT2024 , [alone]
                  IDENT 42:Root[0000, 0]@28..32#ROOT2024 name
                  PUNCT 42:Root[0000, 0]@33..34#ROOT2024 = [alone]
                  LITER 42:Root[0000, 0]@35..50#ROOT2024 Str partial_build
            IDENT 42:Root[0000, 0]@54..57#ROOT2024 pub
            IDENT 42:Root[0000, 0]@58..64#ROOT2024 struct
            IDENT 42:Root[0000, 0]@65..68#ROOT2024 Foo
            GROUP {} 42:Root[0000, 0]@69..70#ROOT2024 42:Root[0000, 0]@190..191#ROOT2024 42:Root[0000, 0]@69..191#ROOT2024
              PUNCT 42:Root[0000, 0]@0..0#ROOT2024 # [alone]
              GROUP [] 42:Root[0000, 0]@0..0#ROOT2024 42:Root[0000, 0]@0..0#ROOT2024 42:Root[0000, 0]@0..0#ROOT2024
                IDENT 42:Root[0000, 0]@0..0#ROOT2024 doc
                PUNCT 42:Root[0000, 0]@0..0#ROOT2024 = [alone]
                LITER 42:Root[0000, 0]@75..130#ROOT2024 Str / The domain where this federated instance is running
              PUNCT 42:Root[0000, 0]@135..136#ROOT2024 # [joint]
              GROUP [] 42:Root[0000, 0]@136..137#ROOT2024 42:Root[0000, 0]@157..158#ROOT2024 42:Root[0000, 0]@136..158#ROOT2024
                IDENT 42:Root[0000, 0]@137..143#ROOT2024 helper
                GROUP () 42:Root[0000, 0]@143..144#ROOT2024 42:Root[0000, 0]@156..157#ROOT2024 42:Root[0000, 0]@143..157#ROOT2024
                  IDENT 42:Root[0000, 0]@144..150#ROOT2024 setter
                  GROUP () 42:Root[0000, 0]@150..151#ROOT2024 42:Root[0000, 0]@155..156#ROOT2024 42:Root[0000, 0]@150..156#ROOT2024
                    IDENT 42:Root[0000, 0]@151..155#ROOT2024 into
              IDENT 42:Root[0000, 0]@163..166#ROOT2024 pub
              GROUP () 42:Root[0000, 0]@166..167#ROOT2024 42:Root[0000, 0]@172..173#ROOT2024 42:Root[0000, 0]@166..173#ROOT2024
                IDENT 42:Root[0000, 0]@167..172#ROOT2024 crate
              IDENT 42:Root[0000, 0]@174..180#ROOT2024 domain
              PUNCT 42:Root[0000, 0]@180..181#ROOT2024 : [alone]
              IDENT 42:Root[0000, 0]@182..188#ROOT2024 String
              PUNCT 42:Root[0000, 0]@188..189#ROOT2024 , [alone]


            PUNCT 42:Root[0000, 0]@1..2#ROOT2024 # [joint]
            GROUP [] 42:Root[0000, 0]@2..3#ROOT2024 42:Root[0000, 0]@52..53#ROOT2024 42:Root[0000, 0]@2..53#ROOT2024
              IDENT 42:Root[0000, 0]@3..9#ROOT2024 helper
              GROUP () 42:Root[0000, 0]@9..10#ROOT2024 42:Root[0000, 0]@51..52#ROOT2024 42:Root[0000, 0]@9..52#ROOT2024
                IDENT 42:Root[0000, 0]@10..18#ROOT2024 build_fn
                GROUP () 42:Root[0000, 0]@18..19#ROOT2024 42:Root[0000, 0]@50..51#ROOT2024 42:Root[0000, 0]@18..51#ROOT2024
                  IDENT 42:Root[0000, 0]@19..26#ROOT2024 private
                  PUNCT 42:Root[0000, 0]@26..27#ROOT2024 , [alone]
                  IDENT 42:Root[0000, 0]@28..32#ROOT2024 name
                  PUNCT 42:Root[0000, 0]@33..34#ROOT2024 = [alone]
                  LITER 42:Root[0000, 0]@35..50#ROOT2024 Str partial_build
            IDENT 42:Root[0000, 0]@54..57#ROOT2024 pub
            IDENT 42:Root[0000, 0]@58..64#ROOT2024 struct
            IDENT 42:Root[0000, 0]@65..68#ROOT2024 Foo
            GROUP {} 42:Root[0000, 0]@69..70#ROOT2024 42:Root[0000, 0]@190..191#ROOT2024 42:Root[0000, 0]@69..191#ROOT2024
              PUNCT 42:Root[0000, 0]@0..0#ROOT2024 # [alone]
              GROUP [] 42:Root[0000, 0]@0..0#ROOT2024 42:Root[0000, 0]@0..0#ROOT2024 42:Root[0000, 0]@0..0#ROOT2024
                IDENT 42:Root[0000, 0]@0..0#ROOT2024 doc
                PUNCT 42:Root[0000, 0]@0..0#ROOT2024 = [alone]
                LITER 42:Root[0000, 0]@75..130#ROOT2024 Str / The domain where this federated instance is running
              PUNCT 42:Root[0000, 0]@135..136#ROOT2024 # [joint]
              GROUP [] 42:Root[0000, 0]@136..137#ROOT2024 42:Root[0000, 0]@157..158#ROOT2024 42:Root[0000, 0]@136..158#ROOT2024
                IDENT 42:Root[0000, 0]@137..143#ROOT2024 helper
                GROUP () 42:Root[0000, 0]@143..144#ROOT2024 42:Root[0000, 0]@156..157#ROOT2024 42:Root[0000, 0]@143..157#ROOT2024
                  IDENT 42:Root[0000, 0]@144..150#ROOT2024 setter
                  GROUP () 42:Root[0000, 0]@150..151#ROOT2024 42:Root[0000, 0]@155..156#ROOT2024 42:Root[0000, 0]@150..156#ROOT2024
                    IDENT 42:Root[0000, 0]@151..155#ROOT2024 into
              IDENT 42:Root[0000, 0]@163..166#ROOT2024 pub
              GROUP () 42:Root[0000, 0]@166..167#ROOT2024 42:Root[0000, 0]@172..173#ROOT2024 42:Root[0000, 0]@166..173#ROOT2024
                IDENT 42:Root[0000, 0]@167..172#ROOT2024 crate
              IDENT 42:Root[0000, 0]@174..180#ROOT2024 domain
              PUNCT 42:Root[0000, 0]@180..181#ROOT2024 : [alone]
              IDENT 42:Root[0000, 0]@182..188#ROOT2024 String
              PUNCT 42:Root[0000, 0]@188..189#ROOT2024 , [alone]
        "#]],
    );
}

#[test]
fn test_derive_error() {
    assert_expand(
        "DeriveError",
        r#"struct S { field: u32 }"#,
        expect![[r#"
            IDENT 1 struct
            IDENT 1 S
            GROUP {} 1 1 1
              IDENT 1 field
              PUNCT 1 : [alone]
              IDENT 1 u32


            IDENT 1 compile_error
            PUNCT 1 ! [joint]
            GROUP () 1 1 1
              LITER 1 Str #[derive(DeriveError)] struct S {field : u32}
            PUNCT 1 ; [alone]
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@0..6#ROOT2024 struct
            IDENT 42:Root[0000, 0]@7..8#ROOT2024 S
            GROUP {} 42:Root[0000, 0]@9..10#ROOT2024 42:Root[0000, 0]@22..23#ROOT2024 42:Root[0000, 0]@9..23#ROOT2024
              IDENT 42:Root[0000, 0]@11..16#ROOT2024 field
              PUNCT 42:Root[0000, 0]@16..17#ROOT2024 : [alone]
              IDENT 42:Root[0000, 0]@18..21#ROOT2024 u32


            IDENT 42:Root[0000, 0]@0..13#ROOT2024 compile_error
            PUNCT 42:Root[0000, 0]@13..14#ROOT2024 ! [joint]
            GROUP () 42:Root[0000, 0]@14..15#ROOT2024 42:Root[0000, 0]@62..63#ROOT2024 42:Root[0000, 0]@14..63#ROOT2024
              LITER 42:Root[0000, 0]@15..62#ROOT2024 Str #[derive(DeriveError)] struct S {field : u32}
            PUNCT 42:Root[0000, 0]@63..64#ROOT2024 ; [alone]
        "#]],
    );
}

#[test]
fn test_fn_like_macro_noop() {
    assert_expand(
        "fn_like_noop",
        r#"ident, 0, 1, []"#,
        expect![[r#"
            IDENT 1 ident
            PUNCT 1 , [alone]
            LITER 1 Integer 0
            PUNCT 1 , [alone]
            LITER 1 Integer 1
            PUNCT 1 , [alone]
            GROUP [] 1 1 1


            IDENT 1 ident
            PUNCT 1 , [alone]
            LITER 1 Integer 0
            PUNCT 1 , [alone]
            LITER 1 Integer 1
            PUNCT 1 , [alone]
            GROUP [] 1 1 1
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@0..5#ROOT2024 ident
            PUNCT 42:Root[0000, 0]@5..6#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@7..8#ROOT2024 Integer 0
            PUNCT 42:Root[0000, 0]@8..9#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@10..11#ROOT2024 Integer 1
            PUNCT 42:Root[0000, 0]@11..12#ROOT2024 , [alone]
            GROUP [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024 42:Root[0000, 0]@13..15#ROOT2024


            IDENT 42:Root[0000, 0]@0..5#ROOT2024 ident
            PUNCT 42:Root[0000, 0]@5..6#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@7..8#ROOT2024 Integer 0
            PUNCT 42:Root[0000, 0]@8..9#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@10..11#ROOT2024 Integer 1
            PUNCT 42:Root[0000, 0]@11..12#ROOT2024 , [alone]
            GROUP [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024 42:Root[0000, 0]@13..15#ROOT2024
        "#]],
    );
}

#[test]
fn test_fn_like_macro_clone_ident_subtree() {
    assert_expand(
        "fn_like_clone_tokens",
        r#"ident, [ident2, ident3]"#,
        expect![[r#"
            IDENT 1 ident
            PUNCT 1 , [alone]
            GROUP [] 1 1 1
              IDENT 1 ident2
              PUNCT 1 , [alone]
              IDENT 1 ident3


            IDENT 1 ident
            PUNCT 1 , [alone]
            GROUP [] 1 1 1
              IDENT 1 ident2
              PUNCT 1 , [alone]
              IDENT 1 ident3
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@0..5#ROOT2024 ident
            PUNCT 42:Root[0000, 0]@5..6#ROOT2024 , [alone]
            GROUP [] 42:Root[0000, 0]@7..8#ROOT2024 42:Root[0000, 0]@22..23#ROOT2024 42:Root[0000, 0]@7..23#ROOT2024
              IDENT 42:Root[0000, 0]@8..14#ROOT2024 ident2
              PUNCT 42:Root[0000, 0]@14..15#ROOT2024 , [alone]
              IDENT 42:Root[0000, 0]@16..22#ROOT2024 ident3


            IDENT 42:Root[0000, 0]@0..5#ROOT2024 ident
            PUNCT 42:Root[0000, 0]@5..6#ROOT2024 , [alone]
            GROUP [] 42:Root[0000, 0]@7..23#ROOT2024 42:Root[0000, 0]@7..23#ROOT2024 42:Root[0000, 0]@7..23#ROOT2024
              IDENT 42:Root[0000, 0]@8..14#ROOT2024 ident2
              PUNCT 42:Root[0000, 0]@14..15#ROOT2024 , [alone]
              IDENT 42:Root[0000, 0]@16..22#ROOT2024 ident3
        "#]],
    );
}

#[test]
fn test_fn_like_macro_clone_raw_ident() {
    assert_expand(
        "fn_like_clone_tokens",
        "r#async",
        expect![[r#"
            IDENT 1 r#async


            IDENT 1 r#async
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@2..7#ROOT2024 r#async


            IDENT 42:Root[0000, 0]@2..7#ROOT2024 r#async
        "#]],
    );
}

#[test]
fn test_fn_like_fn_like_span_join() {
    assert_expand(
        "fn_like_span_join",
        "foo     bar",
        expect![[r#"
            IDENT 1 foo
            IDENT 1 bar


            IDENT 1 r#joined
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@0..3#ROOT2024 foo
            IDENT 42:Root[0000, 0]@8..11#ROOT2024 bar


            IDENT 42:Root[0000, 0]@0..11#ROOT2024 r#joined
        "#]],
    );
}

#[test]
fn test_fn_like_fn_like_span_ops() {
    assert_expand(
        "fn_like_span_ops",
        "set_def_site resolved_at_def_site start_span",
        expect![[r#"
            IDENT 1 set_def_site
            IDENT 1 resolved_at_def_site
            IDENT 1 start_span


            IDENT 0 set_def_site
            IDENT 1 resolved_at_def_site
            IDENT 1 start_span
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@0..12#ROOT2024 set_def_site
            IDENT 42:Root[0000, 0]@13..33#ROOT2024 resolved_at_def_site
            IDENT 42:Root[0000, 0]@34..44#ROOT2024 start_span


            IDENT 41:Root[0000, 0]@0..150#ROOT2024 set_def_site
            IDENT 42:Root[0000, 0]@13..33#ROOT2024 resolved_at_def_site
            IDENT 42:Root[0000, 0]@34..34#ROOT2024 start_span
        "#]],
    );
}

#[test]
fn test_fn_like_mk_literals() {
    assert_expand(
        "fn_like_mk_literals",
        r#""#,
        expect![[r#"


            LITER 1 ByteStr byte_string
            LITER 1 Char c
            LITER 1 Str string
            LITER 1 Str -string
            LITER 1 CStr cstring
            LITER 1 Float 3.14f64
            LITER 1 Float -3.14f64
            LITER 1 Float 3.14
            LITER 1 Float -3.14
            LITER 1 Integer 123i64
            LITER 1 Integer -123i64
            LITER 1 Integer 123
            LITER 1 Integer -123
        "#]],
        expect![[r#"


            LITER 42:Root[0000, 0]@0..100#ROOT2024 ByteStr byte_string
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Char c
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Str string
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Str -string
            LITER 42:Root[0000, 0]@0..100#ROOT2024 CStr cstring
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Float 3.14f64
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Float -3.14f64
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Float 3.14
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Float -3.14
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Integer 123i64
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Integer -123i64
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Integer 123
            LITER 42:Root[0000, 0]@0..100#ROOT2024 Integer -123
        "#]],
    );
}

#[test]
fn test_fn_like_mk_idents() {
    assert_expand(
        "fn_like_mk_idents",
        r#""#,
        expect![[r#"


            IDENT 1 standard
            IDENT 1 r#raw
        "#]],
        expect![[r#"


            IDENT 42:Root[0000, 0]@0..100#ROOT2024 standard
            IDENT 42:Root[0000, 0]@0..100#ROOT2024 r#raw
        "#]],
    );
}

#[test]
fn test_fn_like_macro_clone_literals() {
    assert_expand(
        "fn_like_clone_tokens",
        r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##, 'a', b'b', c"null""###,
        expect![[r#"
            LITER 1 Integer 1u16
            PUNCT 1 , [alone]
            LITER 1 Integer 2_u32
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Integer 4i64
            PUNCT 1 , [alone]
            LITER 1 Float 3.14f32
            PUNCT 1 , [alone]
            LITER 1 Str hello bridge
            PUNCT 1 , [alone]
            LITER 1 Str suffixedsuffix
            PUNCT 1 , [alone]
            LITER 1 StrRaw(2) raw
            PUNCT 1 , [alone]
            LITER 1 Char a
            PUNCT 1 , [alone]
            LITER 1 Byte b
            PUNCT 1 , [alone]
            LITER 1 CStr null


            LITER 1 Integer 1u16
            PUNCT 1 , [alone]
            LITER 1 Integer 2_u32
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Integer 4i64
            PUNCT 1 , [alone]
            LITER 1 Float 3.14f32
            PUNCT 1 , [alone]
            LITER 1 Str hello bridge
            PUNCT 1 , [alone]
            LITER 1 Str suffixedsuffix
            PUNCT 1 , [alone]
            LITER 1 StrRaw(2) raw
            PUNCT 1 , [alone]
            LITER 1 Char a
            PUNCT 1 , [alone]
            LITER 1 Byte b
            PUNCT 1 , [alone]
            LITER 1 CStr null
        "#]],
        expect![[r#"
            LITER 42:Root[0000, 0]@0..4#ROOT2024 Integer 1u16
            PUNCT 42:Root[0000, 0]@4..5#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@6..11#ROOT2024 Integer 2_u32
            PUNCT 42:Root[0000, 0]@11..12#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@13..14#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@14..18#ROOT2024 Integer 4i64
            PUNCT 42:Root[0000, 0]@18..19#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@20..27#ROOT2024 Float 3.14f32
            PUNCT 42:Root[0000, 0]@27..28#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@29..43#ROOT2024 Str hello bridge
            PUNCT 42:Root[0000, 0]@43..44#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@45..61#ROOT2024 Str suffixedsuffix
            PUNCT 42:Root[0000, 0]@61..62#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@63..73#ROOT2024 StrRaw(2) raw
            PUNCT 42:Root[0000, 0]@73..74#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@75..78#ROOT2024 Char a
            PUNCT 42:Root[0000, 0]@78..79#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@80..84#ROOT2024 Byte b
            PUNCT 42:Root[0000, 0]@84..85#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@86..93#ROOT2024 CStr null


            LITER 42:Root[0000, 0]@0..4#ROOT2024 Integer 1u16
            PUNCT 42:Root[0000, 0]@4..5#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@6..11#ROOT2024 Integer 2_u32
            PUNCT 42:Root[0000, 0]@11..12#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@13..14#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@14..18#ROOT2024 Integer 4i64
            PUNCT 42:Root[0000, 0]@18..19#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@20..27#ROOT2024 Float 3.14f32
            PUNCT 42:Root[0000, 0]@27..28#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@29..43#ROOT2024 Str hello bridge
            PUNCT 42:Root[0000, 0]@43..44#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@45..61#ROOT2024 Str suffixedsuffix
            PUNCT 42:Root[0000, 0]@61..62#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@63..73#ROOT2024 StrRaw(2) raw
            PUNCT 42:Root[0000, 0]@73..74#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@75..78#ROOT2024 Char a
            PUNCT 42:Root[0000, 0]@78..79#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@80..84#ROOT2024 Byte b
            PUNCT 42:Root[0000, 0]@84..85#ROOT2024 , [alone]
            LITER 42:Root[0000, 0]@86..93#ROOT2024 CStr null
        "#]],
    );
}

#[test]
fn test_fn_like_macro_negative_literals() {
    assert_expand(
        "fn_like_clone_tokens",
        r###"-1u16, - 2_u32, -3.14f32, - 2.7"###,
        expect![[r#"
            PUNCT 1 - [alone]
            LITER 1 Integer 1u16
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Integer 2_u32
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Float 3.14f32
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Float 2.7


            PUNCT 1 - [alone]
            LITER 1 Integer 1u16
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Integer 2_u32
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Float 3.14f32
            PUNCT 1 , [alone]
            PUNCT 1 - [alone]
            LITER 1 Float 2.7
        "#]],
        expect![[r#"
            PUNCT 42:Root[0000, 0]@0..1#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@1..5#ROOT2024 Integer 1u16
            PUNCT 42:Root[0000, 0]@5..6#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@7..8#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@9..14#ROOT2024 Integer 2_u32
            PUNCT 42:Root[0000, 0]@14..15#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@16..17#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@17..24#ROOT2024 Float 3.14f32
            PUNCT 42:Root[0000, 0]@24..25#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@26..27#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@28..31#ROOT2024 Float 2.7


            PUNCT 42:Root[0000, 0]@0..1#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@1..5#ROOT2024 Integer 1u16
            PUNCT 42:Root[0000, 0]@5..6#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@7..8#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@9..14#ROOT2024 Integer 2_u32
            PUNCT 42:Root[0000, 0]@14..15#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@16..17#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@17..24#ROOT2024 Float 3.14f32
            PUNCT 42:Root[0000, 0]@24..25#ROOT2024 , [alone]
            PUNCT 42:Root[0000, 0]@26..27#ROOT2024 - [alone]
            LITER 42:Root[0000, 0]@28..31#ROOT2024 Float 2.7
        "#]],
    );
}

#[test]
fn test_attr_macro() {
    // Corresponds to
    //    #[proc_macro_test::attr_error(some arguments)]
    //    mod m {}
    assert_expand_attr(
        "attr_error",
        r#"mod m {}"#,
        r#"some arguments"#,
        expect![[r#"
            IDENT 1 mod
            IDENT 1 m
            GROUP {} 1 1 1


            IDENT 1 some
            IDENT 1 arguments


            IDENT 1 compile_error
            PUNCT 1 ! [joint]
            GROUP () 1 1 1
              LITER 1 Str #[attr_error(some arguments)] mod m {}
            PUNCT 1 ; [alone]
        "#]],
        expect![[r#"
            IDENT 42:Root[0000, 0]@0..3#ROOT2024 mod
            IDENT 42:Root[0000, 0]@4..5#ROOT2024 m
            GROUP {} 42:Root[0000, 0]@6..7#ROOT2024 42:Root[0000, 0]@7..8#ROOT2024 42:Root[0000, 0]@6..8#ROOT2024


            IDENT 42:Root[0000, 0]@0..4#ROOT2024 some
            IDENT 42:Root[0000, 0]@5..14#ROOT2024 arguments


            IDENT 42:Root[0000, 0]@0..13#ROOT2024 compile_error
            PUNCT 42:Root[0000, 0]@13..14#ROOT2024 ! [joint]
            GROUP () 42:Root[0000, 0]@14..15#ROOT2024 42:Root[0000, 0]@55..56#ROOT2024 42:Root[0000, 0]@14..56#ROOT2024
              LITER 42:Root[0000, 0]@15..55#ROOT2024 Str #[attr_error(some arguments)] mod m {}
            PUNCT 42:Root[0000, 0]@56..57#ROOT2024 ; [alone]
        "#]],
    );
}

#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: \"Mismatched token groups\""]
fn test_broken_input_unclosed_delim() {
    assert_expand("fn_like_clone_tokens", r###"{"###, expect![[]], expect![[]]);
}

#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: \"Unexpected '}'\""]
fn test_broken_input_unopened_delim() {
    assert_expand("fn_like_clone_tokens", r###"}"###, expect![[]], expect![[]]);
}

#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: \"Expected '}'\""]
fn test_broken_input_mismatched_delim() {
    assert_expand("fn_like_clone_tokens", r###"(}"###, expect![[]], expect![[]]);
}

#[test]
#[should_panic = "called `Result::unwrap()` on an `Err` value: \"Invalid identifier: `🪟`\""]
fn test_broken_input_unknowm_token() {
    assert_expand("fn_like_clone_tokens", r###"🪟"###, expect![[]], expect![[]]);
}

/// Tests that we find and classify all proc macros correctly.
#[test]
fn list_test_macros() {
    let res = list().join("\n");

    expect![[r#"
        fn_like_noop [Bang]
        fn_like_panic [Bang]
        fn_like_error [Bang]
        fn_like_clone_tokens [Bang]
        fn_like_mk_literals [Bang]
        fn_like_mk_idents [Bang]
        fn_like_span_join [Bang]
        fn_like_span_ops [Bang]
        attr_noop [Attr]
        attr_panic [Attr]
        attr_error [Attr]
        DeriveReemit [CustomDerive]
        DeriveEmpty [CustomDerive]
        DerivePanic [CustomDerive]
        DeriveError [CustomDerive]"#]]
    .assert_eq(&res);
}