sway_core/decl_engine/
id.rs

1use crate::{
2    decl_engine::*,
3    engine_threading::*,
4    language::ty::{
5        TyConstantDecl, TyDeclParsedType, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait,
6        TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType, TyTypeAliasDecl,
7    },
8    type_system::*,
9};
10use serde::{Deserialize, Serialize};
11use std::{
12    collections::hash_map::DefaultHasher,
13    fmt,
14    hash::{Hash, Hasher},
15    marker::PhantomData,
16};
17use sway_types::{Named, Spanned};
18
19pub type DeclIdIndexType = usize;
20
21/// An ID used to refer to an item in the [DeclEngine](super::decl_engine::DeclEngine)
22pub struct DeclId<T>(DeclIdIndexType, PhantomData<T>);
23
24impl<T> fmt::Debug for DeclId<T> {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        f.debug_tuple("DeclId").field(&self.0).finish()
27    }
28}
29
30#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)]
31pub struct DeclUniqueId(pub(crate) u64);
32
33impl<T> DeclId<T> {
34    pub(crate) fn inner(&self) -> DeclIdIndexType {
35        self.0
36    }
37
38    pub fn unique_id(&self) -> DeclUniqueId
39    where
40        T: 'static,
41    {
42        let mut hasher = DefaultHasher::default();
43        std::any::TypeId::of::<T>().hash(&mut hasher);
44        self.0.hash(&mut hasher);
45
46        DeclUniqueId(hasher.finish())
47    }
48}
49
50impl<T> Copy for DeclId<T> {}
51impl<T> Clone for DeclId<T> {
52    fn clone(&self) -> Self {
53        *self
54    }
55}
56
57impl<T> Eq for DeclId<T> {}
58impl<T> Hash for DeclId<T> {
59    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
60        self.0.hash(state)
61    }
62}
63impl<T> PartialEq for DeclId<T> {
64    fn eq(&self, other: &Self) -> bool {
65        self.0.eq(&other.0)
66    }
67}
68impl<T> PartialOrd for DeclId<T> {
69    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
70        Some(self.cmp(other))
71    }
72}
73impl<T> Ord for DeclId<T> {
74    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
75        self.0.cmp(&other.0)
76    }
77}
78
79impl<T> DeclId<T> {
80    pub(crate) fn new(id: usize) -> Self {
81        DeclId(id, PhantomData)
82    }
83
84    pub(crate) fn replace_id(&mut self, index: Self) {
85        self.0 = index.0;
86    }
87
88    pub(crate) fn dummy() -> Self {
89        // we assume that `usize::MAX` id is not possible in practice
90        Self(usize::MAX, PhantomData)
91    }
92}
93
94#[allow(clippy::from_over_into)]
95impl<T> Into<usize> for DeclId<T> {
96    fn into(self) -> usize {
97        self.0
98    }
99}
100
101impl<T> DebugWithEngines for DeclId<T>
102where
103    DeclEngine: DeclEngineIndex<T>,
104    T: Named + Spanned + DebugWithEngines,
105{
106    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
107        let decl = engines.de().get(self);
108        DebugWithEngines::fmt(&decl, f, engines)
109    }
110}
111
112impl<T> EqWithEngines for DeclId<T>
113where
114    DeclEngine: DeclEngineIndex<T>,
115    T: Named + Spanned + PartialEqWithEngines + EqWithEngines,
116{
117}
118
119impl<T> PartialEqWithEngines for DeclId<T>
120where
121    DeclEngine: DeclEngineIndex<T>,
122    T: Named + Spanned + PartialEqWithEngines,
123{
124    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
125        let decl_engine = ctx.engines().de();
126        let l_decl = decl_engine.get(self);
127        let r_decl = decl_engine.get(other);
128        l_decl.name() == r_decl.name() && l_decl.eq(&r_decl, ctx)
129    }
130}
131
132impl<T> HashWithEngines for DeclId<T>
133where
134    DeclEngine: DeclEngineIndex<T>,
135    T: Named + Spanned + HashWithEngines,
136{
137    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
138        let decl_engine = engines.de();
139        let decl = decl_engine.get(self);
140        decl.name().hash(state);
141        decl.hash(state, engines);
142    }
143}
144
145impl SubstTypes for DeclId<TyFunctionDecl> {
146    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
147        let decl_engine = ctx.engines.de();
148        let mut decl = (*decl_engine.get(self)).clone();
149        if decl.subst(ctx).has_changes() {
150            decl_engine.replace(*self, decl);
151            HasChanges::Yes
152        } else {
153            HasChanges::No
154        }
155    }
156}
157impl SubstTypes for DeclId<TyTraitDecl> {
158    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
159        let decl_engine = ctx.engines.de();
160        let mut decl = (*decl_engine.get(self)).clone();
161        if decl.subst(ctx).has_changes() {
162            decl_engine.replace(*self, decl);
163            HasChanges::Yes
164        } else {
165            HasChanges::No
166        }
167    }
168}
169impl SubstTypes for DeclId<TyTraitFn> {
170    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
171        let decl_engine = ctx.engines.de();
172        let mut decl = (*decl_engine.get(self)).clone();
173        if decl.subst(ctx).has_changes() {
174            decl_engine.replace(*self, decl);
175            HasChanges::Yes
176        } else {
177            HasChanges::No
178        }
179    }
180}
181impl SubstTypes for DeclId<TyImplSelfOrTrait> {
182    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
183        let decl_engine = ctx.engines.de();
184        let mut decl = (*decl_engine.get(self)).clone();
185        if decl.subst(ctx).has_changes() {
186            decl_engine.replace(*self, decl);
187            HasChanges::Yes
188        } else {
189            HasChanges::No
190        }
191    }
192}
193impl SubstTypes for DeclId<TyStructDecl> {
194    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
195        let decl_engine = ctx.engines.de();
196        let mut decl = (*decl_engine.get(self)).clone();
197        if decl.subst(ctx).has_changes() {
198            decl_engine.replace(*self, decl);
199            HasChanges::Yes
200        } else {
201            HasChanges::No
202        }
203    }
204}
205impl SubstTypes for DeclId<TyEnumDecl> {
206    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
207        let decl_engine = ctx.engines.de();
208        let mut decl = (*decl_engine.get(self)).clone();
209        if decl.subst(ctx).has_changes() {
210            decl_engine.replace(*self, decl);
211            HasChanges::Yes
212        } else {
213            HasChanges::No
214        }
215    }
216}
217impl SubstTypes for DeclId<TyTypeAliasDecl> {
218    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
219        let decl_engine = ctx.engines.de();
220        let mut decl = (*decl_engine.get(self)).clone();
221        if decl.subst(ctx).has_changes() {
222            decl_engine.replace(*self, decl);
223            HasChanges::Yes
224        } else {
225            HasChanges::No
226        }
227    }
228}
229
230impl SubstTypes for DeclId<TyTraitType> {
231    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
232        let decl_engine = ctx.engines.de();
233        let mut decl = (*decl_engine.get(self)).clone();
234        if decl.subst(ctx).has_changes() {
235            decl_engine.replace(*self, decl);
236            HasChanges::Yes
237        } else {
238            HasChanges::No
239        }
240    }
241}
242
243// This implementation deviates from all other DeclId<...> implementations.
244// For more, see https://github.com/FuelLabs/sway/pull/7440#discussion_r2428833840.
245// A better solution will be implemented in the future.
246//
247// TL;DR:
248// When a constant is declared inside a function, its value is shared by every
249// “version” of that function—that is, by all monomorphizations.  If we “replace” the
250// constant, as other implementations do, we would change its value in *every* version,
251// which is incorrect.
252impl SubstTypes for DeclId<TyConstantDecl> {
253    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
254        let decl_engine = ctx.engines.de();
255        let mut decl = (*decl_engine.get(self)).clone();
256        if decl.subst(ctx).has_changes() {
257            *self = *decl_engine
258                .insert(decl, decl_engine.get_parsed_decl_id(self).as_ref())
259                .id();
260            HasChanges::Yes
261        } else {
262            HasChanges::No
263        }
264    }
265}
266
267impl<T> DeclId<T>
268where
269    DeclEngine: DeclEngineIndex<T> + DeclEngineInsert<T> + DeclEngineGetParsedDeclId<T>,
270    T: Named + Spanned + SubstTypes + Clone + TyDeclParsedType,
271{
272    pub(crate) fn subst_types_and_insert_new(
273        &self,
274        ctx: &SubstTypesContext,
275    ) -> Option<DeclRef<Self>> {
276        let decl_engine = ctx.engines.de();
277        let mut decl = (*decl_engine.get(self)).clone();
278        if decl.subst(ctx).has_changes() {
279            Some(decl_engine.insert(decl, decl_engine.get_parsed_decl_id(self).as_ref()))
280        } else {
281            None
282        }
283    }
284}
285
286impl<T> Serialize for DeclId<T> {
287    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
288    where
289        S: serde::Serializer,
290    {
291        self.0.serialize(serializer)
292    }
293}
294
295impl<'de, T> Deserialize<'de> for DeclId<T> {
296    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
297    where
298        D: serde::Deserializer<'de>,
299    {
300        let id = DeclIdIndexType::deserialize(deserializer)?;
301        Ok(DeclId::new(id))
302    }
303}