Skip to main content

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