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
//! File and span related types.
// FIXME: This should probably be moved into its own crate.
use std::fmt;

use salsa::InternId;
use tt::SyntaxContext;
use vfs::FileId;

pub type ErasedFileAstId = la_arena::Idx<syntax::SyntaxNodePtr>;

// The first inde is always the root node's AstId
pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
    la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(0));

pub type SpanData = tt::SpanData<SpanAnchor, SyntaxContextId>;

#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SyntaxContextId(InternId);

impl fmt::Debug for SyntaxContextId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if *self == Self::SELF_REF {
            f.debug_tuple("SyntaxContextId")
                .field(&{
                    #[derive(Debug)]
                    #[allow(non_camel_case_types)]
                    struct SELF_REF;
                    SELF_REF
                })
                .finish()
        } else {
            f.debug_tuple("SyntaxContextId").field(&self.0).finish()
        }
    }
}
crate::impl_intern_key!(SyntaxContextId);

impl fmt::Display for SyntaxContextId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0.as_u32())
    }
}

impl SyntaxContext for SyntaxContextId {
    const DUMMY: Self = Self::ROOT;
}
// inherent trait impls please tyvm
impl SyntaxContextId {
    pub const ROOT: Self = SyntaxContextId(unsafe { InternId::new_unchecked(0) });
    // veykril(HACK): FIXME salsa doesn't allow us fetching the id of the current input to be allocated so
    // we need a special value that behaves as the current context.
    pub const SELF_REF: Self =
        SyntaxContextId(unsafe { InternId::new_unchecked(InternId::MAX - 1) });

    pub fn is_root(self) -> bool {
        self == Self::ROOT
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct SpanAnchor {
    pub file_id: FileId,
    pub ast_id: ErasedFileAstId,
}

impl fmt::Debug for SpanAnchor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id.into_raw()).finish()
    }
}

impl tt::SpanAnchor for SpanAnchor {
    const DUMMY: Self = SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID };
}

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interning. You can check details here:
/// <https://en.wikipedia.org/wiki/String_interning>).
///
/// The two variants are encoded in a single u32 which are differentiated by the MSB.
/// If the MSB is 0, the value represents a `FileId`, otherwise the remaining 31 bits represent a
/// `MacroCallId`.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct HirFileId(u32);

impl From<HirFileId> for u32 {
    fn from(value: HirFileId) -> Self {
        value.0
    }
}

impl From<MacroCallId> for HirFileId {
    fn from(value: MacroCallId) -> Self {
        value.as_file()
    }
}

impl fmt::Debug for HirFileId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.repr().fmt(f)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFileId {
    pub macro_call_id: MacroCallId,
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MacroCallId(salsa::InternId);
crate::impl_intern_key!(MacroCallId);

impl MacroCallId {
    pub fn as_file(self) -> HirFileId {
        MacroFileId { macro_call_id: self }.into()
    }

    pub fn as_macro_file(self) -> MacroFileId {
        MacroFileId { macro_call_id: self }
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum HirFileIdRepr {
    FileId(FileId),
    MacroFile(MacroFileId),
}

impl fmt::Debug for HirFileIdRepr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::FileId(arg0) => f.debug_tuple("FileId").field(&arg0.index()).finish(),
            Self::MacroFile(arg0) => {
                f.debug_tuple("MacroFile").field(&arg0.macro_call_id.0).finish()
            }
        }
    }
}

impl From<FileId> for HirFileId {
    fn from(id: FileId) -> Self {
        assert!(id.index() < Self::MAX_FILE_ID);
        HirFileId(id.index())
    }
}

impl From<MacroFileId> for HirFileId {
    fn from(MacroFileId { macro_call_id: MacroCallId(id) }: MacroFileId) -> Self {
        let id = id.as_u32();
        assert!(id < Self::MAX_FILE_ID);
        HirFileId(id | Self::MACRO_FILE_TAG_MASK)
    }
}

impl HirFileId {
    const MAX_FILE_ID: u32 = u32::MAX ^ Self::MACRO_FILE_TAG_MASK;
    const MACRO_FILE_TAG_MASK: u32 = 1 << 31;

    #[inline]
    pub fn is_macro(self) -> bool {
        self.0 & Self::MACRO_FILE_TAG_MASK != 0
    }

    #[inline]
    pub fn macro_file(self) -> Option<MacroFileId> {
        match self.0 & Self::MACRO_FILE_TAG_MASK {
            0 => None,
            _ => Some(MacroFileId {
                macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)),
            }),
        }
    }

    #[inline]
    pub fn file_id(self) -> Option<FileId> {
        match self.0 & Self::MACRO_FILE_TAG_MASK {
            0 => Some(FileId::from_raw(self.0)),
            _ => None,
        }
    }

    #[inline]
    pub fn repr(self) -> HirFileIdRepr {
        match self.0 & Self::MACRO_FILE_TAG_MASK {
            0 => HirFileIdRepr::FileId(FileId::from_raw(self.0)),
            _ => HirFileIdRepr::MacroFile(MacroFileId {
                macro_call_id: MacroCallId(InternId::from(self.0 ^ Self::MACRO_FILE_TAG_MASK)),
            }),
        }
    }
}