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.get(&self.id).is_concrete(ctx.engines)
107 {
108 let mut decl = (*decl_engine.get(&self.id)).clone();
109 if decl.subst(ctx).has_changes() {
110 Some(decl_engine.insert(decl, decl_engine.get_parsed_decl_id(&self.id).as_ref()))
111 } else {
112 None
113 }
114 } else {
115 None
116 }
117 }
118}
119
120impl<T> DeclRef<DeclId<T>>
121where
122 AssociatedItemDeclId: From<DeclId<T>>,
123{
124 pub(crate) fn with_parent(
125 self,
126 decl_engine: &DeclEngine,
127 parent: AssociatedItemDeclId,
128 ) -> Self {
129 let id: DeclId<T> = self.id;
130 decl_engine.register_parent(id.into(), parent);
131 self
132 }
133}
134
135impl<T> DeclRef<DeclId<T>>
136where
137 AssociatedItemDeclId: From<DeclId<T>>,
138 DeclEngine: DeclEngineIndex<T> + DeclEngineInsert<T> + DeclEngineGetParsedDeclId<T>,
139 T: Named + Spanned + IsConcrete + SubstTypes + Clone + TyDeclParsedType,
140{
141 pub(crate) fn subst_types_and_insert_new_with_parent(
142 &self,
143 ctx: &SubstTypesContext,
144 ) -> Option<Self> {
145 let decl_engine = ctx.engines.de();
146 let mut decl = (*decl_engine.get(&self.id)).clone();
147 if decl.subst(ctx).has_changes() {
148 Some(
149 decl_engine
150 .insert(decl, decl_engine.get_parsed_decl_id(&self.id).as_ref())
151 .with_parent(decl_engine, self.id.into()),
152 )
153 } else {
154 None
155 }
156 }
157}
158
159impl<T> EqWithEngines for DeclRef<DeclId<T>>
160where
161 DeclEngine: DeclEngineIndex<T>,
162 T: Named + Spanned + PartialEqWithEngines + EqWithEngines,
163{
164}
165
166impl<T> PartialEqWithEngines for DeclRef<DeclId<T>>
167where
168 DeclEngine: DeclEngineIndex<T>,
169 T: Named + Spanned + PartialEqWithEngines,
170{
171 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
172 let decl_engine = ctx.engines().de();
173 let DeclRef {
174 name: ln,
175 id: lid,
176 decl_span: _,
179 } = self;
181 let DeclRef {
182 name: rn,
183 id: rid,
184 decl_span: _,
187 } = other;
189 ln == rn && decl_engine.get(lid).eq(&decl_engine.get(rid), ctx)
190 }
191}
192
193impl<T> HashWithEngines for DeclRef<DeclId<T>>
194where
195 DeclEngine: DeclEngineIndex<T>,
196 T: Named + Spanned + HashWithEngines,
197{
198 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
199 let decl_engine = engines.de();
200 let DeclRef {
201 name,
202 id,
203 decl_span: _,
206 } = self;
207 name.hash(state);
208 decl_engine.get(id).hash(state, engines);
209 }
210}
211
212impl EqWithEngines for DeclRefMixedInterface {}
213impl PartialEqWithEngines for DeclRefMixedInterface {
214 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
215 let decl_engine = ctx.engines().de();
216 match (&self.id, &other.id) {
217 (InterfaceDeclId::Abi(self_id), InterfaceDeclId::Abi(other_id)) => {
218 let left = decl_engine.get(self_id);
219 let right = decl_engine.get(other_id);
220 self.name == other.name && left.eq(&right, ctx)
221 }
222 (InterfaceDeclId::Trait(self_id), InterfaceDeclId::Trait(other_id)) => {
223 let left = decl_engine.get(self_id);
224 let right = decl_engine.get(other_id);
225 self.name == other.name && left.eq(&right, ctx)
226 }
227 _ => false,
228 }
229 }
230}
231
232impl HashWithEngines for DeclRefMixedInterface {
233 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
234 match self.id {
235 InterfaceDeclId::Abi(id) => {
236 state.write_u8(0);
237 let decl_engine = engines.de();
238 let decl = decl_engine.get(&id);
239 decl.hash(state, engines);
240 }
241 InterfaceDeclId::Trait(id) => {
242 state.write_u8(1);
243 let decl_engine = engines.de();
244 let decl = decl_engine.get(&id);
245 decl.hash(state, engines);
246 }
247 }
248 }
249}
250
251impl<I> Spanned for DeclRef<I> {
252 fn span(&self) -> Span {
253 self.decl_span.clone()
254 }
255}
256
257impl<T> SubstTypes for DeclRef<DeclId<T>>
258where
259 DeclEngine: DeclEngineIndex<T>,
260 T: Named + Spanned + SubstTypes + Clone,
261{
262 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
263 let decl_engine = ctx.engines.de();
264 let mut decl = (*decl_engine.get(&self.id)).clone();
265 if decl.subst(ctx).has_changes() {
266 decl_engine.replace(self.id, decl);
267 HasChanges::Yes
268 } else {
269 HasChanges::No
270 }
271 }
272}
273
274impl ReplaceDecls for DeclRefFunction {
275 fn replace_decls_inner(
276 &mut self,
277 decl_mapping: &DeclMapping,
278 handler: &Handler,
279 ctx: &mut TypeCheckContext,
280 ) -> Result<bool, ErrorEmitted> {
281 let engines = ctx.engines();
282 let decl_engine = engines.de();
283
284 let func = decl_engine.get(self);
285
286 if let Some(new_decl_ref) = decl_mapping.find_match(
287 handler,
288 ctx.engines(),
289 self.id.into(),
290 func.implementing_for_typeid,
291 ctx.self_type(),
292 )? {
293 return Ok(
294 if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref {
295 self.id = new_decl_ref;
296 true
297 } else {
298 false
299 },
300 );
301 }
302 let all_parents = decl_engine.find_all_parents(engines, &self.id);
303 for parent in all_parents.iter() {
304 if let Some(new_decl_ref) = decl_mapping.find_match(
305 handler,
306 ctx.engines(),
307 parent.clone(),
308 func.implementing_for_typeid,
309 ctx.self_type(),
310 )? {
311 return Ok(
312 if let AssociatedItemDeclId::Function(new_decl_ref) = new_decl_ref {
313 self.id = new_decl_ref;
314 true
315 } else {
316 false
317 },
318 );
319 }
320 }
321 Ok(false)
322 }
323}
324
325impl ReplaceFunctionImplementingType for DeclRefFunction {
326 fn replace_implementing_type(&mut self, engines: &Engines, implementing_type: ty::TyDecl) {
327 let decl_engine = engines.de();
328 let mut decl = (*decl_engine.get(&self.id)).clone();
329 decl.set_implementing_type(implementing_type);
330 decl_engine.replace(self.id, decl);
331 }
332}