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