sway_core/semantic_analysis/namespace/
lexical_scope.rs

1use crate::{
2    decl_engine::{parsed_engine::ParsedDeclEngineGet, parsed_id::ParsedDeclId, *},
3    engine_threading::{Engines, PartialEqWithEngines, PartialEqWithEnginesContext},
4    language::{
5        parsed::{Declaration, FunctionDeclaration},
6        ty::{self, TyDecl, TyStorageDecl},
7        Visibility,
8    },
9    namespace::*,
10    semantic_analysis::{ast_node::ConstShadowingMode, GenericShadowingMode},
11    type_system::*,
12};
13
14use super::{root::ResolvedDeclaration, TraitMap};
15
16use parking_lot::RwLock;
17use sway_error::{
18    error::{CompileError, ShadowingSource},
19    handler::{ErrorEmitted, Handler},
20};
21use sway_types::{span::Span, IdentUnique, Named, Spanned};
22
23use std::{collections::HashMap, sync::Arc};
24
25pub enum ResolvedFunctionDecl {
26    Parsed(ParsedDeclId<FunctionDeclaration>),
27    Typed(DeclRefFunction),
28}
29
30impl ResolvedFunctionDecl {
31    pub fn expect_typed(self) -> DeclRefFunction {
32        match self {
33            ResolvedFunctionDecl::Parsed(_) => panic!(),
34            ResolvedFunctionDecl::Typed(fn_ref) => fn_ref,
35        }
36    }
37}
38
39// The following types were using im::OrdMap but it revealed to be
40// much slower than using HashMap and sorting on iterationn.
41pub(super) type SymbolMap = HashMap<Ident, ResolvedDeclaration>;
42pub(super) type SymbolUniqueMap = HashMap<IdentUnique, ResolvedDeclaration>;
43
44type SourceIdent = Ident;
45
46pub(super) type GlobSynonyms =
47    HashMap<Ident, Vec<(ModulePathBuf, ResolvedDeclaration, Visibility)>>;
48pub(super) type ItemSynonyms = HashMap<
49    Ident,
50    (
51        Option<SourceIdent>,
52        ModulePathBuf,
53        ResolvedDeclaration,
54        Visibility,
55    ),
56>;
57
58/// Represents a lexical scope integer-based identifier, which can be used to reference
59/// specific a lexical scope.
60pub type LexicalScopeId = usize;
61
62/// Represents a lexical scope path, a vector of lexical scope identifiers, which specifies
63/// the path from root to a specific lexical scope in the hierarchy.
64pub type LexicalScopePath = Vec<LexicalScopeId>;
65
66/// A `LexicalScope` contains a set of all items that exist within the lexical scope via declaration or
67/// importing, along with all its associated hierarchical scopes.
68#[derive(Clone, Debug, Default)]
69pub struct LexicalScope {
70    /// The set of symbols, implementations, synonyms and aliases present within this scope.
71    pub items: Items,
72    /// The set of available scopes defined inside this scope's hierarchy.
73    pub children: Vec<LexicalScopeId>,
74    /// The parent scope associated with this scope. Will be None for a root scope.
75    pub parent: Option<LexicalScopeId>,
76    /// The parent while visiting scopes and push popping scopes from a stack.
77    /// This may differ from parent as we may revisit the scope in a different order during type check.
78    pub visitor_parent: Option<LexicalScopeId>,
79    /// The declaration associated with this scope. This will initially be a [ParsedDeclId],
80    /// but can be replaced to be a [DeclId] once the declaration is type checked.
81    pub declaration: Option<ResolvedDeclaration>,
82}
83
84/// The set of items that exist within some lexical scope via declaration or importing.
85#[derive(Clone, Debug, Default)]
86pub struct Items {
87    /// An map from `Ident`s to their associated declarations.
88    pub(crate) symbols: SymbolMap,
89
90    /// An map from `IdentUnique`s to their associated declarations.
91    /// This uses an Arc<RwLock<SymbolUniqueMap>> so it is shared between all
92    /// Items clones. This is intended so we can keep the symbols of previous
93    /// lexical scopes while collecting_unifications scopes.
94    pub(crate) symbols_unique_while_collecting_unifications: Arc<RwLock<SymbolUniqueMap>>,
95
96    pub(crate) implemented_traits: TraitMap,
97    /// Contains symbols imported using star imports (`use foo::*`.).
98    ///
99    /// When star importing from multiple modules the same name may be imported more than once. This
100    /// is not an error, but it is an error to use the name without a module path. To represent
101    /// this, use_glob_synonyms maps identifiers to a vector of (module path, type declaration)
102    /// tuples.
103    pub(crate) use_glob_synonyms: GlobSynonyms,
104    /// Contains symbols imported using item imports (`use foo::bar`).
105    ///
106    /// For aliased item imports `use ::foo::bar::Baz as Wiz` the map key is `Wiz`. `Baz` is stored
107    /// as the optional source identifier for error reporting purposes.
108    pub(crate) use_item_synonyms: ItemSynonyms,
109    /// If there is a storage declaration (which are only valid in contracts), store it here.
110    pub(crate) declared_storage: Option<DeclRefStorage>,
111}
112
113impl Items {
114    /// Immutable access to the inner symbol map.
115    pub fn symbols(&self) -> &SymbolMap {
116        &self.symbols
117    }
118
119    #[allow(clippy::too_many_arguments)]
120    pub fn apply_storage_load(
121        &self,
122        handler: &Handler,
123        engines: &Engines,
124        namespace: &Namespace,
125        namespace_names: &[Ident],
126        fields: &[Ident],
127        storage_fields: &[ty::TyStorageField],
128        storage_keyword_span: Span,
129    ) -> Result<(ty::TyStorageAccess, TypeId), ErrorEmitted> {
130        match self.declared_storage {
131            Some(ref decl_ref) => {
132                let storage = engines.de().get_storage(&decl_ref.id().clone());
133                storage.apply_storage_load(
134                    handler,
135                    engines,
136                    namespace,
137                    namespace_names,
138                    fields,
139                    storage_fields,
140                    storage_keyword_span,
141                )
142            }
143            None => Err(handler.emit_err(CompileError::NoDeclaredStorage {
144                span: fields[0].span(),
145            })),
146        }
147    }
148
149    pub fn set_storage_declaration(
150        &mut self,
151        handler: &Handler,
152        decl_ref: DeclRefStorage,
153    ) -> Result<(), ErrorEmitted> {
154        if self.declared_storage.is_some() {
155            return Err(handler.emit_err(CompileError::MultipleStorageDeclarations {
156                span: decl_ref.span(),
157            }));
158        }
159        self.declared_storage = Some(decl_ref);
160        Ok(())
161    }
162
163    pub fn get_all_declared_symbols(&self) -> Vec<&Ident> {
164        let mut keys: Vec<_> = self.symbols().keys().collect();
165        keys.sort();
166        keys
167    }
168
169    pub fn resolve_symbol(
170        &self,
171        handler: &Handler,
172        engines: &Engines,
173        symbol: &Ident,
174        current_mod_path: &ModulePathBuf,
175    ) -> Result<Option<(ResolvedDeclaration, ModulePathBuf)>, ErrorEmitted> {
176        // Check locally declared items. Any name clash with imports will have already been reported as an error.
177        if let Some(decl) = self.symbols.get(symbol) {
178            return Ok(Some((decl.clone(), current_mod_path.clone())));
179        }
180
181        // Check item imports
182        if let Some((_, decl_path, decl, _)) = self.use_item_synonyms.get(symbol) {
183            return Ok(Some((decl.clone(), decl_path.clone())));
184        }
185
186        // Check glob imports
187        if let Some(decls) = self.use_glob_synonyms.get(symbol) {
188            if decls.len() == 1 {
189                return Ok(Some((decls[0].1.clone(), decls[0].0.clone())));
190            } else if decls.is_empty() {
191                return Err(handler.emit_err(CompileError::Internal(
192                    "The name {symbol} was bound in a star import, but no corresponding module paths were found",
193                    symbol.span(),
194                )));
195            } else {
196                return Err(handler.emit_err(CompileError::SymbolWithMultipleBindings {
197                    name: symbol.clone(),
198                    paths: decls
199                        .iter()
200                        .map(|(path, decl, _)| {
201                            get_path_for_decl(path, decl, engines, &current_mod_path[0]).join("::")
202                        })
203                        .collect(),
204                    span: symbol.span(),
205                }));
206            }
207        }
208
209        Ok(None)
210    }
211
212    pub(crate) fn insert_parsed_symbol(
213        handler: &Handler,
214        engines: &Engines,
215        module: &mut Module,
216        name: Ident,
217        item: Declaration,
218        const_shadowing_mode: ConstShadowingMode,
219        generic_shadowing_mode: GenericShadowingMode,
220    ) -> Result<(), ErrorEmitted> {
221        Self::insert_symbol(
222            handler,
223            engines,
224            module,
225            name,
226            ResolvedDeclaration::Parsed(item),
227            const_shadowing_mode,
228            generic_shadowing_mode,
229            false,
230        )
231    }
232
233    #[allow(clippy::too_many_arguments)]
234    pub(crate) fn insert_typed_symbol(
235        handler: &Handler,
236        engines: &Engines,
237        module: &mut Module,
238        name: Ident,
239        item: ty::TyDecl,
240        const_shadowing_mode: ConstShadowingMode,
241        generic_shadowing_mode: GenericShadowingMode,
242        collecting_unifications: bool,
243    ) -> Result<(), ErrorEmitted> {
244        Self::insert_symbol(
245            handler,
246            engines,
247            module,
248            name,
249            ResolvedDeclaration::Typed(item),
250            const_shadowing_mode,
251            generic_shadowing_mode,
252            collecting_unifications,
253        )
254    }
255
256    #[allow(clippy::too_many_arguments)]
257    pub(crate) fn insert_symbol(
258        handler: &Handler,
259        engines: &Engines,
260        module: &mut Module,
261        name: Ident,
262        item: ResolvedDeclaration,
263        const_shadowing_mode: ConstShadowingMode,
264        generic_shadowing_mode: GenericShadowingMode,
265        collecting_unifications: bool,
266    ) -> Result<(), ErrorEmitted> {
267        let parsed_decl_engine = engines.pe();
268        let decl_engine = engines.de();
269
270        #[allow(unused)]
271        let append_shadowing_error_parsed =
272            |ident: &Ident,
273             decl: &Declaration,
274             is_use: bool,
275             is_alias: bool,
276             item: &Declaration,
277             const_shadowing_mode: ConstShadowingMode| {
278                use Declaration::*;
279                match (
280                    ident,
281                    decl,
282                    is_use,
283                    is_alias,
284                    &item,
285                    const_shadowing_mode,
286                    generic_shadowing_mode,
287                ) {
288                    // A general remark for using the `ShadowingSource::LetVar`.
289                    // If the shadowing is detected at this stage, the variable is for
290                    // sure a local variable, because in the case of pattern matching
291                    // struct field variables, the error is already reported and
292                    // the compilation do not proceed to the point of inserting
293                    // the pattern variable into the items.
294
295                    // variable shadowing a constant
296                    (
297                        constant_ident,
298                        ConstantDeclaration(decl_id),
299                        is_imported_constant,
300                        is_alias,
301                        VariableDeclaration { .. },
302                        _,
303                        _,
304                    ) => {
305                        handler.emit_err(CompileError::ConstantsCannotBeShadowed {
306                            shadowing_source: ShadowingSource::LetVar,
307                            name: (&name).into(),
308                            constant_span: constant_ident.span(),
309                            constant_decl_span: if is_imported_constant {
310                                parsed_decl_engine.get(decl_id).span.clone()
311                            } else {
312                                Span::dummy()
313                            },
314                            is_alias,
315                        });
316                    }
317                    // variable shadowing a configurable
318                    (
319                        configurable_ident,
320                        ConfigurableDeclaration(_),
321                        _,
322                        _,
323                        VariableDeclaration { .. },
324                        _,
325                        _,
326                    ) => {
327                        handler.emit_err(CompileError::ConfigurablesCannotBeShadowed {
328                            shadowing_source: ShadowingSource::LetVar,
329                            name: (&name).into(),
330                            configurable_span: configurable_ident.span(),
331                        });
332                    }
333                    // constant shadowing a constant sequentially
334                    (
335                        constant_ident,
336                        ConstantDeclaration(decl_id),
337                        is_imported_constant,
338                        is_alias,
339                        ConstantDeclaration { .. },
340                        ConstShadowingMode::Sequential,
341                        _,
342                    ) => {
343                        handler.emit_err(CompileError::ConstantsCannotBeShadowed {
344                            shadowing_source: ShadowingSource::Const,
345                            name: (&name).into(),
346                            constant_span: constant_ident.span(),
347                            constant_decl_span: if is_imported_constant {
348                                parsed_decl_engine.get(decl_id).span.clone()
349                            } else {
350                                Span::dummy()
351                            },
352                            is_alias,
353                        });
354                    }
355                    // constant shadowing a configurable sequentially
356                    (
357                        configurable_ident,
358                        ConfigurableDeclaration(_),
359                        _,
360                        _,
361                        ConstantDeclaration { .. },
362                        ConstShadowingMode::Sequential,
363                        _,
364                    ) => {
365                        handler.emit_err(CompileError::ConfigurablesCannotBeShadowed {
366                            shadowing_source: ShadowingSource::Const,
367                            name: (&name).into(),
368                            configurable_span: configurable_ident.span(),
369                        });
370                    }
371                    // constant shadowing a variable
372                    (_, VariableDeclaration(decl_id), _, _, ConstantDeclaration { .. }, _, _) => {
373                        handler.emit_err(CompileError::ConstantShadowsVariable {
374                            name: (&name).into(),
375                            variable_span: parsed_decl_engine.get(decl_id).name.span(),
376                        });
377                    }
378                    // constant shadowing a constant item-style (outside of a function body)
379                    (
380                        constant_ident,
381                        ConstantDeclaration { .. },
382                        _,
383                        _,
384                        ConstantDeclaration { .. },
385                        ConstShadowingMode::ItemStyle,
386                        _,
387                    ) => {
388                        handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable {
389                            existing_constant_or_configurable: "Constant",
390                            new_constant_or_configurable: "Constant",
391                            name: (&name).into(),
392                            existing_span: constant_ident.span(),
393                        });
394                    }
395                    // constant shadowing a configurable item-style (outside of a function body)
396                    (
397                        configurable_ident,
398                        ConfigurableDeclaration { .. },
399                        _,
400                        _,
401                        ConstantDeclaration { .. },
402                        ConstShadowingMode::ItemStyle,
403                        _,
404                    ) => {
405                        handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable {
406                            existing_constant_or_configurable: "Configurable",
407                            new_constant_or_configurable: "Constant",
408                            name: (&name).into(),
409                            existing_span: configurable_ident.span(),
410                        });
411                    }
412                    // configurable shadowing a constant item-style (outside of a function body)
413                    (
414                        constant_ident,
415                        ConstantDeclaration { .. },
416                        _,
417                        _,
418                        ConfigurableDeclaration { .. },
419                        ConstShadowingMode::ItemStyle,
420                        _,
421                    ) => {
422                        handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable {
423                            existing_constant_or_configurable: "Constant",
424                            new_constant_or_configurable: "Configurable",
425                            name: (&name).into(),
426                            existing_span: constant_ident.span(),
427                        });
428                    }
429                    // type or type alias shadowing another type or type alias
430                    // trait/abi shadowing another trait/abi
431                    // type or type alias shadowing a trait/abi, or vice versa
432                    (
433                        _,
434                        StructDeclaration { .. }
435                        | EnumDeclaration { .. }
436                        | TypeAliasDeclaration { .. }
437                        | TraitDeclaration { .. }
438                        | AbiDeclaration { .. },
439                        _,
440                        _,
441                        StructDeclaration { .. }
442                        | EnumDeclaration { .. }
443                        | TypeAliasDeclaration { .. }
444                        | TraitDeclaration { .. }
445                        | AbiDeclaration { .. },
446                        _,
447                        _,
448                    ) => {
449                        handler.emit_err(CompileError::MultipleDefinitionsOfName {
450                            name: name.clone(),
451                            span: name.span(),
452                        });
453                    }
454                    _ => {}
455                }
456            };
457
458        let append_shadowing_error_typed =
459            |ident: &Ident,
460             decl: &ty::TyDecl,
461             is_use: bool,
462             is_alias: bool,
463             item: &ty::TyDecl,
464             const_shadowing_mode: ConstShadowingMode| {
465                use ty::TyDecl::*;
466                match (
467                    ident,
468                    decl,
469                    is_use,
470                    is_alias,
471                    &item,
472                    const_shadowing_mode,
473                    generic_shadowing_mode,
474                ) {
475                    // A general remark for using the `ShadowingSource::LetVar`.
476                    // If the shadowing is detected at this stage, the variable is for
477                    // sure a local variable, because in the case of pattern matching
478                    // struct field variables, the error is already reported and
479                    // the compilation do not proceed to the point of inserting
480                    // the pattern variable into the items.
481
482                    // variable shadowing a constant
483                    (
484                        constant_ident,
485                        ConstantDecl(constant_decl),
486                        is_imported_constant,
487                        is_alias,
488                        VariableDecl { .. },
489                        _,
490                        _,
491                    ) => {
492                        handler.emit_err(CompileError::ConstantsCannotBeShadowed {
493                            shadowing_source: ShadowingSource::LetVar,
494                            name: (&name).into(),
495                            constant_span: constant_ident.span(),
496                            constant_decl_span: if is_imported_constant {
497                                decl_engine.get(&constant_decl.decl_id).span.clone()
498                            } else {
499                                Span::dummy()
500                            },
501                            is_alias,
502                        });
503                    }
504                    // variable shadowing a configurable
505                    (configurable_ident, ConfigurableDecl(_), _, _, VariableDecl { .. }, _, _) => {
506                        handler.emit_err(CompileError::ConfigurablesCannotBeShadowed {
507                            shadowing_source: ShadowingSource::LetVar,
508                            name: (&name).into(),
509                            configurable_span: configurable_ident.span(),
510                        });
511                    }
512                    // constant shadowing a constant sequentially
513                    (
514                        constant_ident,
515                        ConstantDecl(constant_decl),
516                        is_imported_constant,
517                        is_alias,
518                        ConstantDecl { .. },
519                        ConstShadowingMode::Sequential,
520                        _,
521                    ) => {
522                        handler.emit_err(CompileError::ConstantsCannotBeShadowed {
523                            shadowing_source: ShadowingSource::Const,
524                            name: (&name).into(),
525                            constant_span: constant_ident.span(),
526                            constant_decl_span: if is_imported_constant {
527                                decl_engine.get(&constant_decl.decl_id).span.clone()
528                            } else {
529                                Span::dummy()
530                            },
531                            is_alias,
532                        });
533                    }
534                    // constant shadowing a configurable sequentially
535                    (
536                        configurable_ident,
537                        ConfigurableDecl(_),
538                        _,
539                        _,
540                        ConstantDecl { .. },
541                        ConstShadowingMode::Sequential,
542                        _,
543                    ) => {
544                        handler.emit_err(CompileError::ConfigurablesCannotBeShadowed {
545                            shadowing_source: ShadowingSource::Const,
546                            name: (&name).into(),
547                            configurable_span: configurable_ident.span(),
548                        });
549                    }
550                    // constant shadowing a variable
551                    (_, VariableDecl(variable_decl), _, _, ConstantDecl { .. }, _, _) => {
552                        handler.emit_err(CompileError::ConstantShadowsVariable {
553                            name: (&name).into(),
554                            variable_span: variable_decl.name.span(),
555                        });
556                    }
557                    // constant shadowing a constant item-style (outside of a function body)
558                    (
559                        constant_ident,
560                        ConstantDecl { .. },
561                        _,
562                        _,
563                        ConstantDecl { .. },
564                        ConstShadowingMode::ItemStyle,
565                        _,
566                    ) => {
567                        handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable {
568                            existing_constant_or_configurable: "Constant",
569                            new_constant_or_configurable: "Constant",
570                            name: (&name).into(),
571                            existing_span: constant_ident.span(),
572                        });
573                    }
574                    // constant shadowing a configurable item-style (outside of a function body)
575                    (
576                        configurable_ident,
577                        ConfigurableDecl { .. },
578                        _,
579                        _,
580                        ConstantDecl { .. },
581                        ConstShadowingMode::ItemStyle,
582                        _,
583                    ) => {
584                        handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable {
585                            existing_constant_or_configurable: "Configurable",
586                            new_constant_or_configurable: "Constant",
587                            name: (&name).into(),
588                            existing_span: configurable_ident.span(),
589                        });
590                    }
591                    // configurable shadowing a constant item-style (outside of a function body)
592                    (
593                        constant_ident,
594                        ConstantDecl { .. },
595                        _,
596                        _,
597                        ConfigurableDecl { .. },
598                        ConstShadowingMode::ItemStyle,
599                        _,
600                    ) => {
601                        handler.emit_err(CompileError::ConstantDuplicatesConstantOrConfigurable {
602                            existing_constant_or_configurable: "Constant",
603                            new_constant_or_configurable: "Configurable",
604                            name: (&name).into(),
605                            existing_span: constant_ident.span(),
606                        });
607                    }
608                    // type or type alias shadowing another type or type alias
609                    // trait/abi shadowing another trait/abi
610                    // type or type alias shadowing a trait/abi, or vice versa
611                    (
612                        _,
613                        StructDecl { .. }
614                        | EnumDecl { .. }
615                        | TypeAliasDecl { .. }
616                        | TraitDecl { .. }
617                        | AbiDecl { .. },
618                        _,
619                        _,
620                        StructDecl { .. }
621                        | EnumDecl { .. }
622                        | TypeAliasDecl { .. }
623                        | TraitDecl { .. }
624                        | AbiDecl { .. },
625                        _,
626                        _,
627                    ) => {
628                        handler.emit_err(CompileError::MultipleDefinitionsOfName {
629                            name: name.clone(),
630                            span: name.span(),
631                        });
632                    }
633                    // generic parameter shadowing another generic parameter
634                    (
635                        _,
636                        GenericTypeForFunctionScope { .. },
637                        _,
638                        _,
639                        GenericTypeForFunctionScope { .. },
640                        _,
641                        GenericShadowingMode::Disallow,
642                    ) => {
643                        handler.emit_err(CompileError::GenericShadowsGeneric {
644                            name: (&name).into(),
645                        });
646                    }
647                    _ => {}
648                }
649            };
650
651        let append_shadowing_error =
652            |ident: &Ident,
653             decl: &ResolvedDeclaration,
654             is_use: bool,
655             is_alias: bool,
656             item: &ResolvedDeclaration,
657             const_shadowing_mode: ConstShadowingMode| {
658                if const_shadowing_mode == ConstShadowingMode::Allow {
659                    return;
660                }
661                match (decl, item) {
662                    // TODO: Do not handle any shadowing errors while handling parsed declarations yet,
663                    // or else we will emit errors in a different order from the source code order.
664                    // Update this once the full AST resolving pass is in.
665                    (ResolvedDeclaration::Typed(_decl), ResolvedDeclaration::Parsed(_item)) => {}
666                    (ResolvedDeclaration::Parsed(_decl), ResolvedDeclaration::Parsed(_item)) => {}
667                    (ResolvedDeclaration::Typed(decl), ResolvedDeclaration::Typed(item)) => {
668                        append_shadowing_error_typed(
669                            ident,
670                            decl,
671                            is_use,
672                            is_alias,
673                            item,
674                            const_shadowing_mode,
675                        )
676                    }
677                    _ => unreachable!(),
678                }
679            };
680
681        let _ = module.walk_scope_chain_early_return(|lexical_scope| {
682            if let Some((ident, decl)) = lexical_scope.items.symbols.get_key_value(&name) {
683                append_shadowing_error(
684                    ident,
685                    decl,
686                    false,
687                    false,
688                    &item.clone(),
689                    const_shadowing_mode,
690                );
691            }
692
693            if let Some((ident, (imported_ident, _, decl, _))) =
694                lexical_scope.items.use_item_synonyms.get_key_value(&name)
695            {
696                append_shadowing_error(
697                    ident,
698                    decl,
699                    true,
700                    imported_ident.is_some(),
701                    &item,
702                    const_shadowing_mode,
703                );
704            }
705            Ok(None::<()>)
706        });
707
708        if collecting_unifications {
709            module
710                .current_items_mut()
711                .symbols_unique_while_collecting_unifications
712                .write()
713                .insert(name.clone().into(), item.clone());
714        }
715
716        module.current_items_mut().symbols.insert(name, item);
717
718        Ok(())
719    }
720
721    // Add a new binding into use_glob_synonyms. The symbol may already be bound by an earlier
722    // insertion, in which case the new binding is added as well so that multiple bindings exist.
723    //
724    // There are a few edge cases were a new binding will replace an old binding. These edge cases
725    // are a consequence of the prelude reexports not being implemented properly. See comments in
726    // the code for details.
727    pub(crate) fn insert_glob_use_symbol(
728        &mut self,
729        engines: &Engines,
730        symbol: Ident,
731        src_path: ModulePathBuf,
732        decl: &ResolvedDeclaration,
733        visibility: Visibility,
734    ) {
735        if let Some(cur_decls) = self.use_glob_synonyms.get_mut(&symbol) {
736            // Name already bound. Check if the decl is already imported
737            let ctx = PartialEqWithEnginesContext::new(engines);
738            match cur_decls
739                .iter()
740                .position(|(_cur_path, cur_decl, _cur_visibility)| cur_decl.eq(decl, &ctx))
741            {
742                Some(index) if matches!(visibility, Visibility::Public) => {
743                    // The name is already bound to this decl. If the new symbol is more visible
744                    // than the old one, then replace the old one.
745                    cur_decls[index] = (src_path.to_vec(), decl.clone(), visibility);
746                }
747                Some(_) => {
748                    // Same binding as the existing one. Do nothing.
749                }
750                None => {
751                    // New decl for this name. Add it to the end
752                    cur_decls.push((src_path.to_vec(), decl.clone(), visibility));
753                }
754            }
755        } else {
756            let new_vec = vec![(src_path.to_vec(), decl.clone(), visibility)];
757            self.use_glob_synonyms.insert(symbol, new_vec);
758        }
759    }
760
761    pub(crate) fn check_symbol(&self, name: &Ident) -> Result<ResolvedDeclaration, CompileError> {
762        self.symbols
763            .get(name)
764            .cloned()
765            .ok_or_else(|| CompileError::SymbolNotFound {
766                name: name.clone(),
767                span: name.span(),
768            })
769    }
770
771    pub(crate) fn check_symbols_unique_while_collecting_unifications(
772        &self,
773        name: &Ident,
774    ) -> Result<ResolvedDeclaration, CompileError> {
775        self.symbols_unique_while_collecting_unifications
776            .read()
777            .get(&name.into())
778            .cloned()
779            .ok_or_else(|| CompileError::SymbolNotFound {
780                name: name.clone(),
781                span: name.span(),
782            })
783    }
784
785    pub(crate) fn clear_symbols_unique_while_collecting_unifications(&self) {
786        self.symbols_unique_while_collecting_unifications
787            .write()
788            .clear();
789    }
790
791    pub(crate) fn has_storage_declared(&self) -> bool {
792        self.declared_storage.is_some()
793    }
794
795    pub fn get_declared_storage(&self, decl_engine: &DeclEngine) -> Option<TyStorageDecl> {
796        self.declared_storage
797            .as_ref()
798            .map(|decl_ref| (*decl_engine.get_storage(decl_ref)).clone())
799    }
800
801    pub(crate) fn get_storage_field_descriptors(
802        &self,
803        handler: &Handler,
804        decl_engine: &DeclEngine,
805    ) -> Result<Vec<ty::TyStorageField>, ErrorEmitted> {
806        match self.get_declared_storage(decl_engine) {
807            Some(storage) => Ok(storage.fields.clone()),
808            None => {
809                let msg = "unknown source location";
810                let span = Span::new(Arc::from(msg), 0, msg.len(), None).unwrap();
811                Err(handler.emit_err(CompileError::NoDeclaredStorage { span }))
812            }
813        }
814    }
815}
816
817pub(super) fn get_path_for_decl(
818    path: &[sway_types::BaseIdent],
819    decl: &ResolvedDeclaration,
820    engines: &Engines,
821    package_name: &Ident,
822) -> Vec<String> {
823    // Do not report the package name as part of the error if the path is in the current package.
824    let skip_package_name = path[0] == *package_name;
825    let mut path_names = path
826        .iter()
827        .skip(if skip_package_name { 1 } else { 0 })
828        .map(|x| x.to_string())
829        .collect::<Vec<_>>();
830    match decl {
831        ResolvedDeclaration::Parsed(decl) => {
832            if let Declaration::EnumVariantDeclaration(decl) = decl {
833                let enum_decl = engines.pe().get_enum(&decl.enum_ref);
834                path_names.push(enum_decl.name().to_string())
835            };
836        }
837        ResolvedDeclaration::Typed(decl) => {
838            if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl { enum_ref, .. }) = decl {
839                path_names.push(enum_ref.name().to_string())
840            };
841        }
842    }
843    path_names
844}