sway_core/decl_engine/
ref.rs

1//! Represents the use of / syntactic reference to a declaration.
2//!
3//! ### Is a [DeclRef] effectively the same as a [DeclId]?
4//!
5//! A [DeclRef] is a smart wrapper around a [DeclId] and canonically represents
6//! the use / syntactic reference to a declaration. This does not include the
7//! syntactic locations for where declarations are declared though. For example,
8//! function declaration `fn my_function() { .. }` would just create a [DeclId],
9//! while function application `my_function()` would create a [DeclRef].
10//!
11//! [DeclRef] contains a [DeclId] field `id`, as well as some additional helpful
12//! information. These additional fields include an [Ident] for the declaration
13//! `name` and a [Span] for the declaration `decl_span`. Note, `name` and
14//! `decl_span` can also be found by using `id` to get the declaration itself
15//! from the [DeclEngine]. But the [DeclRef] type allows Sway compiler writers
16//! to reduce unnecessary lookups into the [DeclEngine] when only the `name` or
17//! `decl_span` is desired.
18//!
19//! It is recommend to use [DeclId] for cases like function declaration
20//! `fn my_function() { .. }`, and to use [DeclRef] for cases like function
21//! application `my_function()`.
22
23use 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/// Represents the use of / syntactic reference to a declaration. A
53/// smart-wrapper around a [DeclId], containing additional information about a
54/// declaration.
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct DeclRef<I> {
57    /// The name of the declaration.
58    // NOTE: In the case of storage, the name is "storage".
59    name: Ident,
60
61    /// The index into the [DeclEngine].
62    id: I,
63
64    /// The [Span] of the entire declaration.
65    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            // these fields are not used in comparison because they aren't
177            // relevant/a reliable source of obj v. obj distinction
178            decl_span: _,
179            // temporarily omitted
180        } = self;
181        let DeclRef {
182            name: rn,
183            id: rid,
184            // these fields are not used in comparison because they aren't
185            // relevant/a reliable source of obj v. obj distinction
186            decl_span: _,
187            // temporarily omitted
188        } = 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            // these fields are not hashed because they aren't relevant/a
204            // reliable source of obj v. obj distinction
205            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}