1use crate::{
24 decl_engine::*,
25 engine_threading::*,
26 language::ty::{
27 self, TyAbiDecl, TyConstantDecl, TyDeclParsedType, TyEnumDecl, TyFunctionDecl,
28 TyImplSelfOrTrait, TyStorageDecl, TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType,
29 },
30 semantic_analysis::TypeCheckContext,
31 type_system::*,
32};
33use serde::{Deserialize, Serialize};
34use std::hash::{Hash, Hasher};
35use sway_error::handler::{ErrorEmitted, Handler};
36use sway_types::{Ident, Named, Span, Spanned};
37
38pub type DeclRefFunction = DeclRef<DeclId<TyFunctionDecl>>;
39pub type DeclRefTrait = DeclRef<DeclId<TyTraitDecl>>;
40pub type DeclRefTraitFn = DeclRef<DeclId<TyTraitFn>>;
41pub type DeclRefTraitType = DeclRef<DeclId<TyTraitType>>;
42pub type DeclRefImplTrait = DeclRef<DeclId<TyImplSelfOrTrait>>;
43pub type DeclRefStruct = DeclRef<DeclId<TyStructDecl>>;
44pub type DeclRefStorage = DeclRef<DeclId<TyStorageDecl>>;
45pub type DeclRefAbi = DeclRef<DeclId<TyAbiDecl>>;
46pub type DeclRefConstant = DeclRef<DeclId<TyConstantDecl>>;
47pub type DeclRefEnum = DeclRef<DeclId<TyEnumDecl>>;
48
49pub type DeclRefMixedFunctional = DeclRef<AssociatedItemDeclId>;
50pub type DeclRefMixedInterface = DeclRef<InterfaceDeclId>;
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct DeclRef<I> {
57 name: Ident,
60
61 id: I,
63
64 decl_span: Span,
66}
67
68impl<I> DeclRef<I> {
69 pub(crate) fn new(name: Ident, id: I, decl_span: Span) -> Self {
70 DeclRef {
71 name,
72 id,
73 decl_span,
74 }
75 }
76
77 pub fn name(&self) -> &Ident {
78 &self.name
79 }
80
81 pub fn id(&self) -> &I {
82 &self.id
83 }
84
85 pub fn decl_span(&self) -> &Span {
86 &self.decl_span
87 }
88}
89
90impl<T> DeclRef<DeclId<T>> {
91 pub(crate) fn replace_id(&mut self, index: DeclId<T>) {
92 self.id.replace_id(index);
93 }
94}
95
96impl<T> DeclRef<DeclId<T>>
97where
98 DeclEngine: DeclEngineIndex<T> + DeclEngineInsert<T> + DeclEngineGetParsedDeclId<T>,
99 T: Named + Spanned + IsConcrete + SubstTypes + Clone + TyDeclParsedType,
100{
101 pub(crate) fn subst_types_and_insert_new(&self, ctx: &SubstTypesContext) -> Option<Self> {
102 let decl_engine = ctx.engines.de();
103 if ctx
104 .type_subst_map
105 .is_some_and(|tsm| tsm.source_ids_contains_concrete_type(ctx.engines))
106 || !decl_engine
107 .get(&self.id)
108 .is_concrete(ctx.handler, ctx.engines)
109 {
110 let mut decl = (*decl_engine.get(&self.id)).clone();
111 if decl.subst(ctx).has_changes() {
112 Some(decl_engine.insert(decl, decl_engine.get_parsed_decl_id(&self.id).as_ref()))
113 } else {
114 None
115 }
116 } else {
117 None
118 }
119 }
120}
121
122impl<T> DeclRef<DeclId<T>>
123where
124 AssociatedItemDeclId: From<DeclId<T>>,
125{
126 pub(crate) fn with_parent(
127 self,
128 decl_engine: &DeclEngine,
129 parent: AssociatedItemDeclId,
130 ) -> Self {
131 let id: DeclId<T> = self.id;
132 decl_engine.register_parent(id.into(), parent);
133 self
134 }
135}
136
137impl<T> DeclRef<DeclId<T>>
138where
139 AssociatedItemDeclId: From<DeclId<T>>,
140 DeclEngine: DeclEngineIndex<T> + DeclEngineInsert<T> + DeclEngineGetParsedDeclId<T>,
141 T: Named + Spanned + IsConcrete + SubstTypes + Clone + TyDeclParsedType,
142{
143 pub(crate) fn subst_types_and_insert_new_with_parent(
144 &self,
145 ctx: &SubstTypesContext,
146 ) -> Option<Self> {
147 let decl_engine = ctx.engines.de();
148 let mut decl = (*decl_engine.get(&self.id)).clone();
149 if decl.subst(ctx).has_changes() {
150 Some(
151 decl_engine
152 .insert(decl, decl_engine.get_parsed_decl_id(&self.id).as_ref())
153 .with_parent(decl_engine, self.id.into()),
154 )
155 } else {
156 None
157 }
158 }
159}
160
161impl<T> EqWithEngines for DeclRef<DeclId<T>>
162where
163 DeclEngine: DeclEngineIndex<T>,
164 T: Named + Spanned + PartialEqWithEngines + EqWithEngines,
165{
166}
167
168impl<T> PartialEqWithEngines for DeclRef<DeclId<T>>
169where
170 DeclEngine: DeclEngineIndex<T>,
171 T: Named + Spanned + PartialEqWithEngines,
172{
173 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
174 let decl_engine = ctx.engines().de();
175 let DeclRef {
176 name: ln,
177 id: lid,
178 decl_span: _,
181 } = self;
183 let DeclRef {
184 name: rn,
185 id: rid,
186 decl_span: _,
189 } = other;
191 ln == rn && decl_engine.get(lid).eq(&decl_engine.get(rid), ctx)
192 }
193}
194
195impl<T> HashWithEngines for DeclRef<DeclId<T>>
196where
197 DeclEngine: DeclEngineIndex<T>,
198 T: Named + Spanned + HashWithEngines,
199{
200 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
201 let decl_engine = engines.de();
202 let DeclRef {
203 name,
204 id,
205 decl_span: _,
208 } = self;
209 name.hash(state);
210 decl_engine.get(id).hash(state, engines);
211 }
212}
213
214impl EqWithEngines for DeclRefMixedInterface {}
215impl PartialEqWithEngines for DeclRefMixedInterface {
216 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
217 let decl_engine = ctx.engines().de();
218 match (&self.id, &other.id) {
219 (InterfaceDeclId::Abi(self_id), InterfaceDeclId::Abi(other_id)) => {
220 let left = decl_engine.get(self_id);
221 let right = decl_engine.get(other_id);
222 self.name == other.name && left.eq(&right, ctx)
223 }
224 (InterfaceDeclId::Trait(self_id), InterfaceDeclId::Trait(other_id)) => {
225 let left = decl_engine.get(self_id);
226 let right = decl_engine.get(other_id);
227 self.name == other.name && left.eq(&right, ctx)
228 }
229 _ => false,
230 }
231 }
232}
233
234impl HashWithEngines for DeclRefMixedInterface {
235 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
236 match self.id {
237 InterfaceDeclId::Abi(id) => {
238 state.write_u8(0);
239 let decl_engine = engines.de();
240 let decl = decl_engine.get(&id);
241 decl.hash(state, engines);
242 }
243 InterfaceDeclId::Trait(id) => {
244 state.write_u8(1);
245 let decl_engine = engines.de();
246 let decl = decl_engine.get(&id);
247 decl.hash(state, engines);
248 }
249 }
250 }
251}
252
253impl<I> Spanned for DeclRef<I> {
254 fn span(&self) -> Span {
255 self.decl_span.clone()
256 }
257}
258
259impl<T> SubstTypes for DeclRef<DeclId<T>>
260where
261 DeclEngine: DeclEngineIndex<T>,
262 T: Named + Spanned + SubstTypes + Clone,
263{
264 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
265 let decl_engine = ctx.engines.de();
266 let mut decl = (*decl_engine.get(&self.id)).clone();
267 if decl.subst(ctx).has_changes() {
268 decl_engine.replace(self.id, decl);
269 HasChanges::Yes
270 } else {
271 HasChanges::No
272 }
273 }
274}
275
276impl ReplaceDecls for DeclRefFunction {
277 fn replace_decls_inner(
278 &mut self,
279 decl_mapping: &DeclMapping,
280 handler: &Handler,
281 ctx: &mut TypeCheckContext,
282 ) -> Result<bool, ErrorEmitted> {
283 let engines = ctx.engines();
284 let decl_engine = engines.de();
285
286 let func = decl_engine.get(self);
287
288 if let Some(new_decl_ref) = decl_mapping.find_match(
289 handler,
290 ctx.engines(),
291 self.id.into(),
292 func.implementing_for,
293 ctx.self_type(),
294 )? {
295 return Ok(
296 if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref {
297 self.id = new_decl_ref;
298 true
299 } else {
300 false
301 },
302 );
303 }
304 let all_parents = decl_engine.find_all_parents(engines, &self.id);
305 for parent in all_parents.iter() {
306 if let Some(new_decl_ref) = decl_mapping.find_match(
307 handler,
308 ctx.engines(),
309 parent.clone(),
310 func.implementing_for,
311 ctx.self_type(),
312 )? {
313 return Ok(
314 if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref {
315 self.id = new_decl_ref;
316 true
317 } else {
318 false
319 },
320 );
321 }
322 }
323 Ok(false)
324 }
325}
326
327impl ReplaceFunctionImplementingType for DeclRefFunction {
328 fn replace_implementing_type(&mut self, engines: &Engines, implementing_type: ty::TyDecl) {
329 let decl_engine = engines.de();
330 let mut decl = (*decl_engine.get(&self.id)).clone();
331 decl.set_implementing_type(implementing_type);
332 decl_engine.replace(self.id, decl);
333 }
334}