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