1use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
2
3use ecow::EcoString;
4
5use crate::ast::{BindingId as AstBindingId, Pattern, RestPattern, Span};
6use crate::types::Type;
7
8use super::{Definition, File, ModuleInfo};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11struct ReceiverId(Span);
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ReceiverCoercion {
15 AutoAddress,
17 AutoDeref,
19}
20
21#[derive(Debug, Clone, Default)]
22pub struct CoercionInfo {
23 receivers: HashMap<ReceiverId, ReceiverCoercion>,
24}
25
26impl CoercionInfo {
27 pub fn mark_coercion(&mut self, span: Span, coercion: ReceiverCoercion) {
28 self.receivers.insert(ReceiverId(span), coercion);
29 }
30
31 pub fn get_coercion(&self, span: Span) -> Option<ReceiverCoercion> {
32 self.receivers.get(&ReceiverId(span)).copied()
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37struct BindingId(Span);
38
39#[derive(Debug, Clone, Default)]
40pub struct UnusedInfo {
41 bindings: HashSet<BindingId>,
42 definitions: HashSet<BindingId>,
43 pub imports_by_module: HashMap<EcoString, HashSet<EcoString>>,
44}
45
46impl UnusedInfo {
47 pub fn mark_binding_unused(&mut self, span: Span) {
48 self.bindings.insert(BindingId(span));
49 }
50
51 pub fn is_unused_binding(&self, pattern: &Pattern) -> bool {
52 match pattern {
53 Pattern::Identifier { span, .. } => self.bindings.contains(&BindingId(*span)),
54 _ => false,
55 }
56 }
57
58 pub fn is_unused_rest_binding(&self, rest: &RestPattern) -> bool {
59 match rest {
60 RestPattern::Bind { span, .. } => self.bindings.contains(&BindingId(*span)),
61 _ => false,
62 }
63 }
64
65 pub fn mark_definition_unused(&mut self, span: Span) {
66 self.definitions.insert(BindingId(span));
67 }
68
69 pub fn is_unused_definition(&self, span: &Span) -> bool {
70 self.definitions.contains(&BindingId(*span))
71 }
72}
73
74#[derive(Debug, Clone, Default)]
75pub struct MutationInfo {
76 bindings: HashSet<AstBindingId>,
77}
78
79impl MutationInfo {
80 pub fn mark_binding_mutated(&mut self, id: AstBindingId) {
81 self.bindings.insert(id);
82 }
83
84 pub fn is_mutated(&self, id: AstBindingId) -> bool {
85 self.bindings.contains(&id)
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum DotAccessKind {
96 StructField { is_exported: bool },
98 TupleStructField { is_newtype: bool },
102 TupleElement,
104 ModuleMember,
106 ValueEnumVariant,
108 EnumVariant,
110 InstanceMethod { is_exported: bool },
112 InstanceMethodValue {
116 is_exported: bool,
117 is_pointer_receiver: bool,
118 },
119 StaticMethod { is_exported: bool },
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub enum NativeTypeKind {
129 Slice,
130 EnumeratedSlice,
131 Map,
132 Channel,
133 Sender,
134 Receiver,
135 String,
136}
137
138impl NativeTypeKind {
139 pub fn from_type(ty: &Type) -> Option<Self> {
140 let resolved = ty.resolve().strip_refs();
141 if let Type::Constructor { ref id, .. } = resolved
142 && (id.starts_with("@import/go:") || id.starts_with("go:"))
143 {
144 return None;
145 }
146 let name = resolved.get_name()?;
147 Self::from_name(name)
148 }
149
150 pub fn from_name(name: &str) -> Option<Self> {
151 match name {
152 "Slice" => Some(Self::Slice),
153 "EnumeratedSlice" => Some(Self::EnumeratedSlice),
154 "Map" => Some(Self::Map),
155 "Channel" => Some(Self::Channel),
156 "Sender" => Some(Self::Sender),
157 "Receiver" => Some(Self::Receiver),
158 "string" => Some(Self::String),
159 _ => None,
160 }
161 }
162}
163
164#[derive(Debug, Clone, Copy, PartialEq, Eq)]
168pub enum CallKind {
169 Regular,
171 TupleStructConstructor,
173 AssertType,
175 UfcsMethod,
177 NativeConstructor(NativeTypeKind),
179 NativeMethod(NativeTypeKind),
181 NativeMethodIdentifier(NativeTypeKind),
183 ReceiverMethodUfcs { is_public: bool },
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
188struct ResolutionId(Span);
189
190#[derive(Debug, Clone, Default)]
195pub struct ResolutionInfo {
196 dot_accesses: HashMap<ResolutionId, DotAccessKind>,
197 calls: HashMap<ResolutionId, CallKind>,
198}
199
200impl ResolutionInfo {
201 pub fn mark_dot_access(&mut self, span: Span, kind: DotAccessKind) {
202 self.dot_accesses.insert(ResolutionId(span), kind);
203 }
204
205 pub fn get_dot_access(&self, span: Span) -> Option<DotAccessKind> {
206 self.dot_accesses.get(&ResolutionId(span)).copied()
207 }
208
209 pub fn mark_call(&mut self, span: Span, meta: CallKind) {
210 self.calls.insert(ResolutionId(span), meta);
211 }
212
213 pub fn get_call(&self, span: Span) -> Option<CallKind> {
214 self.calls.get(&ResolutionId(span)).copied()
215 }
216}
217
218pub struct EmitInput {
219 pub files: HashMap<u32, File>,
220 pub definitions: HashMap<EcoString, Definition>,
221 pub modules: HashMap<String, ModuleInfo>,
222 pub entry_module_id: String,
223 pub unused: UnusedInfo,
224 pub mutations: MutationInfo,
225 pub coercions: CoercionInfo,
226 pub resolutions: ResolutionInfo,
227 pub cached_modules: HashSet<String>,
228 pub ufcs_methods: HashSet<(String, String)>,
229}