fe_analyzer/namespace/
items.rs

1use crate::constants::{EMITTABLE_TRAIT_NAME, INDEXED};
2use crate::context::{self, Analysis, Constant, NamedThing};
3use crate::display::{DisplayWithDb, Displayable};
4use crate::errors::{self, IncompleteItem, TypeError};
5use crate::namespace::types::{self, GenericType, Type, TypeId};
6use crate::traversal::pragma::check_pragma_version;
7use crate::AnalyzerDb;
8use crate::{builtins, errors::ConstEvalError};
9use fe_common::diagnostics::Diagnostic;
10use fe_common::diagnostics::Label;
11use fe_common::files::{common_prefix, Utf8Path};
12use fe_common::utils::files::{BuildFiles, ProjectMode};
13use fe_common::{impl_intern_key, FileKind, SourceFileId};
14use fe_parser::ast::GenericParameter;
15use fe_parser::node::{Node, Span};
16use fe_parser::{ast, node::NodeId};
17use indexmap::{indexmap, IndexMap};
18use smallvec::SmallVec;
19use smol_str::SmolStr;
20use std::rc::Rc;
21use std::{fmt, ops::Deref};
22use strum::IntoEnumIterator;
23
24use super::types::TraitOrType;
25
26/// A named item. This does not include things inside of
27/// a function body.
28#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
29pub enum Item {
30    Ingot(IngotId),
31    Module(ModuleId),
32    Type(TypeDef),
33    // GenericType probably shouldn't be a separate category.
34    // Any of the items inside TypeDef (struct, alias, etc)
35    // could be optionally generic.
36    GenericType(GenericType),
37    Trait(TraitId),
38    Impl(ImplId),
39    Function(FunctionId),
40    Constant(ModuleConstantId),
41    // Needed until we can represent keccak256 as a FunctionId.
42    // We can't represent keccak256's arg type yet.
43    BuiltinFunction(builtins::GlobalFunction),
44    Intrinsic(builtins::Intrinsic),
45    Attribute(AttributeId),
46}
47
48impl Item {
49    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
50        match self {
51            Item::Type(id) => id.name(db),
52            Item::Trait(id) => id.name(db),
53            Item::Impl(id) => id.name(db),
54            Item::GenericType(id) => id.name(),
55            Item::Function(id) => id.name(db),
56            Item::BuiltinFunction(id) => id.as_ref().into(),
57            Item::Intrinsic(id) => id.as_ref().into(),
58            Item::Constant(id) => id.name(db),
59            Item::Ingot(id) => id.name(db),
60            Item::Module(id) => id.name(db),
61            Item::Attribute(id) => id.name(db),
62        }
63    }
64
65    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
66        match self {
67            Item::Type(id) => id.name_span(db),
68            Item::Trait(id) => Some(id.name_span(db)),
69            Item::GenericType(_) => None,
70            Item::Function(id) => Some(id.name_span(db)),
71            Item::Constant(id) => Some(id.name_span(db)),
72            Item::BuiltinFunction(_)
73            | Item::Intrinsic(_)
74            | Item::Ingot(_)
75            | Item::Module(_)
76            | Item::Impl(_)
77            | Item::Attribute(_) => None,
78        }
79    }
80
81    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
82        match self {
83            // TODO: Consider whether to allow `pub module`.
84            Self::Ingot(_)
85            | Self::Module(_)
86            | Self::BuiltinFunction(_)
87            | Self::Intrinsic(_)
88            | Self::Impl(_)
89            | Self::GenericType(_) => true,
90            Self::Attribute(_) => false,
91            Self::Type(id) => id.is_public(db),
92            Self::Trait(id) => id.is_public(db),
93            Self::Function(id) => id.is_public(db),
94            Self::Constant(id) => id.is_public(db),
95        }
96    }
97
98    pub fn is_builtin(&self) -> bool {
99        match self {
100            Item::Type(TypeDef::Primitive(_))
101            | Item::GenericType(_)
102            | Item::BuiltinFunction(_)
103            | Item::Intrinsic(_) => true,
104            Item::Type(_)
105            | Item::Trait(_)
106            | Item::Impl(_)
107            | Item::Function(_)
108            | Item::Constant(_)
109            | Item::Ingot(_)
110            | Item::Attribute(_)
111            | Item::Module(_) => false,
112        }
113    }
114
115    pub fn is_struct(&self, val: &StructId) -> bool {
116        matches!(self, Item::Type(TypeDef::Struct(current)) if current == val)
117    }
118
119    pub fn is_contract(&self) -> bool {
120        matches!(self, Item::Type(TypeDef::Contract(_)))
121    }
122
123    pub fn item_kind_display_name(&self) -> &'static str {
124        match self {
125            Item::Type(TypeDef::Struct(_)) => "struct",
126            Item::Type(_) | Item::GenericType(_) => "type",
127            Item::Trait(_) => "trait",
128            Item::Impl(_) => "impl",
129            Item::Function(_) | Item::BuiltinFunction(_) => "function",
130            Item::Intrinsic(_) => "intrinsic function",
131            Item::Constant(_) => "constant",
132            Item::Ingot(_) => "ingot",
133            Item::Module(_) => "module",
134            Item::Attribute(_) => "attribute",
135        }
136    }
137
138    pub fn items(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, Item>> {
139        match self {
140            Item::Ingot(ingot) => ingot.items(db),
141            Item::Module(module) => module.items(db),
142            Item::Type(val) => val.items(db),
143            Item::GenericType(_)
144            | Item::Trait(_)
145            | Item::Impl(_)
146            | Item::Function(_)
147            | Item::Constant(_)
148            | Item::BuiltinFunction(_)
149            | Item::Attribute(_)
150            | Item::Intrinsic(_) => Rc::new(indexmap! {}),
151        }
152    }
153
154    pub fn parent(&self, db: &dyn AnalyzerDb) -> Option<Item> {
155        match self {
156            Item::Type(id) => id.parent(db),
157            Item::Trait(id) => Some(id.parent(db)),
158            Item::Impl(id) => Some(id.parent(db)),
159            Item::GenericType(_) => None,
160            Item::Function(id) => Some(id.parent(db)),
161            Item::Constant(id) => Some(id.parent(db)),
162            Item::Module(id) => Some(id.parent(db)),
163            Item::Attribute(id) => Some(id.parent(db)),
164            Item::BuiltinFunction(_) | Item::Intrinsic(_) | Item::Ingot(_) => None,
165        }
166    }
167
168    pub fn module(&self, db: &dyn AnalyzerDb) -> Option<ModuleId> {
169        if let Self::Module(id) = self {
170            return Some(*id);
171        }
172
173        let mut cur_item = *self;
174        while let Some(item) = cur_item.parent(db) {
175            if let Self::Module(id) = item {
176                return Some(id);
177            }
178            cur_item = item;
179        }
180
181        None
182    }
183
184    pub fn path(&self, db: &dyn AnalyzerDb) -> Rc<[SmolStr]> {
185        // The path is used to generate a yul identifier,
186        // eg `foo::Bar::new` becomes `$$foo$Bar$new`.
187        // Right now, the ingot name is the os path, so it could
188        // be "my project/src".
189        // For now, we'll just leave the ingot out of the path,
190        // because we can only compile a single ingot anyway.
191        match self.parent(db) {
192            Some(Item::Ingot(_)) | None => [self.name(db)][..].into(),
193            Some(parent) => {
194                let mut path = parent.path(db).to_vec();
195                path.push(self.name(db));
196                path.into()
197            }
198        }
199    }
200
201    pub fn dependency_graph(&self, db: &dyn AnalyzerDb) -> Option<Rc<DepGraph>> {
202        match self {
203            Item::Type(TypeDef::Contract(id)) => Some(id.dependency_graph(db)),
204            Item::Type(TypeDef::Struct(id)) => Some(id.dependency_graph(db)),
205            Item::Type(TypeDef::Enum(id)) => Some(id.dependency_graph(db)),
206            Item::Function(id) => Some(id.dependency_graph(db)),
207            _ => None,
208        }
209    }
210
211    pub fn resolve_path_segments(
212        &self,
213        db: &dyn AnalyzerDb,
214        segments: &[Node<SmolStr>],
215    ) -> Analysis<Option<NamedThing>> {
216        let mut curr_item = NamedThing::Item(*self);
217
218        for node in segments {
219            curr_item = match curr_item.resolve_path_segment(db, &node.kind) {
220                Some(item) => item,
221                None => {
222                    return Analysis {
223                        value: None,
224                        diagnostics: Rc::new([errors::error(
225                            "unresolved path item",
226                            node.span,
227                            "not found",
228                        )]),
229                    };
230                }
231            }
232        }
233
234        Analysis {
235            value: Some(curr_item),
236            diagnostics: Rc::new([]),
237        }
238    }
239
240    pub fn function_sig(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
241        match self {
242            Item::Type(TypeDef::Contract(id)) => id.function(db, name).map(|fun| fun.sig(db)),
243            Item::Type(TypeDef::Struct(id)) => id.function(db, name).map(|fun| fun.sig(db)),
244            Item::Impl(id) => id.function(db, name).map(|fun| fun.sig(db)),
245            Item::Trait(id) => id.function(db, name),
246            _ => None,
247        }
248    }
249
250    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
251        match self {
252            Item::Type(id) => id.sink_diagnostics(db, sink),
253            Item::Trait(id) => id.sink_diagnostics(db, sink),
254            Item::Impl(id) => id.sink_diagnostics(db, sink),
255            Item::Function(id) => id.sink_diagnostics(db, sink),
256            Item::GenericType(_)
257            | Item::BuiltinFunction(_)
258            | Item::Intrinsic(_)
259            | Item::Attribute(_) => {}
260            Item::Constant(id) => id.sink_diagnostics(db, sink),
261            Item::Ingot(id) => id.sink_diagnostics(db, sink),
262            Item::Module(id) => id.sink_diagnostics(db, sink),
263        }
264    }
265
266    pub fn attributes(&self, db: &dyn AnalyzerDb) -> Vec<AttributeId> {
267        if let Some(Item::Module(module)) = self.parent(db) {
268            let mut attributes = vec![];
269            for item in module.all_items(db).iter() {
270                if let Item::Attribute(attribute) = item {
271                    attributes.push(*attribute);
272                } else if item == self {
273                    return attributes;
274                } else {
275                    attributes = vec![];
276                }
277            }
278        }
279
280        vec![]
281    }
282}
283
284pub fn builtin_items() -> IndexMap<SmolStr, Item> {
285    let mut items = indexmap! {
286        SmolStr::new("bool") => Item::Type(TypeDef::Primitive(types::Base::Bool)),
287        SmolStr::new("address") => Item::Type(TypeDef::Primitive(types::Base::Address)),
288    };
289    items.extend(types::Integer::iter().map(|typ| {
290        (
291            typ.as_ref().into(),
292            Item::Type(TypeDef::Primitive(types::Base::Numeric(typ))),
293        )
294    }));
295    items.extend(types::GenericType::iter().map(|typ| (typ.name(), Item::GenericType(typ))));
296    items.extend(
297        builtins::GlobalFunction::iter()
298            .map(|fun| (fun.as_ref().into(), Item::BuiltinFunction(fun))),
299    );
300    items
301        .extend(builtins::Intrinsic::iter().map(|fun| (fun.as_ref().into(), Item::Intrinsic(fun))));
302    items
303}
304
305#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
306pub enum IngotMode {
307    /// The target of compilation. Expected to have a main.fe file.
308    Main,
309    /// A library; expected to have a lib.fe file.
310    Lib,
311    /// A fake ingot, created to hold a single module with any filename.
312    StandaloneModule,
313}
314
315/// An `Ingot` is composed of a tree of `Module`s (set via
316/// [`AnalyzerDb::set_ingot_module_tree`]), and doesn't have direct knowledge of
317/// files.
318#[derive(Debug, PartialEq, Eq, Hash, Clone)]
319pub struct Ingot {
320    pub name: SmolStr,
321    // pub version: SmolStr,
322    pub mode: IngotMode,
323    pub src_dir: SmolStr,
324}
325
326#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
327pub struct IngotId(pub(crate) u32);
328impl_intern_key!(IngotId);
329impl IngotId {
330    pub fn std_lib(db: &mut dyn AnalyzerDb) -> Self {
331        let ingot = IngotId::from_files(
332            db,
333            "std",
334            IngotMode::Lib,
335            FileKind::Std,
336            &fe_library::std_src_files(),
337        );
338        db.set_ingot_external_ingots(ingot, Rc::new(indexmap! {}));
339        ingot
340    }
341
342    pub fn from_build_files(db: &mut dyn AnalyzerDb, build_files: &BuildFiles) -> Self {
343        let ingots: IndexMap<_, _> = build_files
344            .project_files
345            .iter()
346            .map(|(project_path, project_files)| {
347                let mode = match project_files.mode {
348                    ProjectMode::Main => IngotMode::Main,
349                    ProjectMode::Lib => IngotMode::Lib,
350                };
351                (
352                    project_path,
353                    IngotId::from_files(
354                        db,
355                        &project_files.name,
356                        mode,
357                        FileKind::Local,
358                        &project_files.src,
359                    ),
360                )
361            })
362            .collect();
363
364        for (project_path, project_files) in &build_files.project_files {
365            let mut deps = indexmap! {
366                "std".into() => IngotId::std_lib(db)
367            };
368
369            for dependency in &project_files.dependencies {
370                deps.insert(
371                    dependency.name.clone(),
372                    ingots[&dependency.canonicalized_path],
373                );
374            }
375
376            db.set_ingot_external_ingots(ingots[&project_path], Rc::new(deps));
377        }
378
379        let root_ingot = ingots[&build_files.root_project_path];
380        db.set_root_ingot(root_ingot);
381        root_ingot
382    }
383
384    pub fn from_files(
385        db: &mut dyn AnalyzerDb,
386        name: &str,
387        mode: IngotMode,
388        file_kind: FileKind,
389        files: &[(impl AsRef<str>, impl AsRef<str>)],
390    ) -> Self {
391        // The common prefix of all file paths will be stored as the ingot
392        // src dir path, and all module file paths will be considered to be
393        // relative to this prefix.
394        let file_path_prefix = if files.len() == 1 {
395            // If there's only one source file, the "common prefix" is everything
396            // before the file name.
397            Utf8Path::new(files[0].0.as_ref())
398                .parent()
399                .unwrap_or_else(|| "".into())
400                .to_path_buf()
401        } else {
402            files
403                .iter()
404                .map(|(path, _)| Utf8Path::new(path).to_path_buf())
405                .reduce(|pref, path| common_prefix(&pref, &path))
406                .expect("`IngotId::from_files`: empty file list")
407        };
408
409        let ingot = db.intern_ingot(Rc::new(Ingot {
410            name: name.into(),
411            mode,
412            src_dir: file_path_prefix.as_str().into(),
413        }));
414
415        // Intern the source files
416        let file_ids = files
417            .iter()
418            .map(|(path, content)| {
419                SourceFileId::new(
420                    db.upcast_mut(),
421                    file_kind,
422                    path.as_ref(),
423                    content.as_ref().into(),
424                )
425            })
426            .collect();
427
428        db.set_ingot_files(ingot, file_ids);
429        ingot
430    }
431
432    pub fn external_ingots(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, IngotId>> {
433        db.ingot_external_ingots(*self)
434    }
435
436    pub fn all_modules(&self, db: &dyn AnalyzerDb) -> Rc<[ModuleId]> {
437        db.ingot_modules(*self)
438    }
439
440    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<Ingot> {
441        db.lookup_intern_ingot(*self)
442    }
443
444    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
445        self.data(db).name.clone()
446    }
447
448    /// Returns the `main.fe`, or `lib.fe` module, depending on the ingot "mode"
449    /// (IngotMode).
450    pub fn root_module(&self, db: &dyn AnalyzerDb) -> Option<ModuleId> {
451        db.ingot_root_module(*self)
452    }
453
454    pub fn items(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, Item>> {
455        self.root_module(db).expect("missing root module").items(db)
456    }
457
458    pub fn diagnostics(&self, db: &dyn AnalyzerDb) -> Vec<Diagnostic> {
459        let mut diagnostics = vec![];
460        self.sink_diagnostics(db, &mut diagnostics);
461        diagnostics
462    }
463
464    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
465        if self.root_module(db).is_none() {
466            let file_name = match self.data(db).mode {
467                IngotMode::Lib => "lib",
468                IngotMode::Main => "main",
469                IngotMode::StandaloneModule => unreachable!(), // always has a root module
470            };
471            sink.push(&Diagnostic::error(format!(
472                "The ingot named \"{}\" is missing a `{}` module. \
473                 \nPlease add a `src/{}.fe` file to the base directory.",
474                self.name(db),
475                file_name,
476                file_name,
477            )));
478        }
479        for module in self.all_modules(db).iter() {
480            module.sink_diagnostics(db, sink)
481        }
482    }
483
484    pub fn sink_external_ingot_diagnostics(
485        &self,
486        db: &dyn AnalyzerDb,
487        sink: &mut impl DiagnosticSink,
488    ) {
489        for ingot in self.external_ingots(db).values() {
490            ingot.sink_diagnostics(db, sink)
491        }
492    }
493}
494
495#[derive(Debug, PartialEq, Eq, Hash, Clone)]
496pub enum ModuleSource {
497    File(SourceFileId),
498    /// For directory modules without a corresponding source file
499    /// (which will soon not be allowed, and this variant can go away).
500    Dir(SmolStr),
501}
502
503#[derive(Debug, PartialEq, Eq, Hash, Clone)]
504pub struct Module {
505    pub name: SmolStr,
506    pub ingot: IngotId,
507    pub source: ModuleSource,
508}
509
510/// Id of a [`Module`], which corresponds to a single Fe source file.
511#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
512pub struct ModuleId(pub(crate) u32);
513impl_intern_key!(ModuleId);
514impl ModuleId {
515    pub fn new_standalone(db: &mut dyn AnalyzerDb, path: &str, content: &str) -> Self {
516        let std = IngotId::std_lib(db);
517        let ingot = IngotId::from_files(
518            db,
519            "",
520            IngotMode::StandaloneModule,
521            FileKind::Local,
522            &[(path, content)],
523        );
524
525        let deps = indexmap! { "std".into() => std };
526        db.set_ingot_external_ingots(ingot, Rc::new(deps));
527        db.set_root_ingot(ingot);
528
529        ingot
530            .root_module(db)
531            .expect("ModuleId::new_standalone ingot has no root module")
532    }
533
534    pub fn new(db: &dyn AnalyzerDb, name: &str, source: ModuleSource, ingot: IngotId) -> Self {
535        db.intern_module(
536            Module {
537                name: name.into(),
538                ingot,
539                source,
540            }
541            .into(),
542        )
543    }
544
545    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<Module> {
546        db.lookup_intern_module(*self)
547    }
548
549    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
550        self.data(db).name.clone()
551    }
552
553    pub fn file_path_relative_to_src_dir(&self, db: &dyn AnalyzerDb) -> SmolStr {
554        db.module_file_path(*self)
555    }
556
557    pub fn ast(&self, db: &dyn AnalyzerDb) -> Rc<ast::Module> {
558        db.module_parse(*self).value
559    }
560
561    pub fn ingot(&self, db: &dyn AnalyzerDb) -> IngotId {
562        self.data(db).ingot
563    }
564
565    pub fn is_incomplete(&self, db: &dyn AnalyzerDb) -> bool {
566        db.module_is_incomplete(*self)
567    }
568
569    pub fn is_in_std(&self, db: &dyn AnalyzerDb) -> bool {
570        self.ingot(db).name(db) == "std"
571    }
572
573    /// Includes duplicate names
574    pub fn all_items(&self, db: &dyn AnalyzerDb) -> Rc<[Item]> {
575        db.module_all_items(*self)
576    }
577
578    /// Includes duplicate names
579    pub fn all_impls(&self, db: &dyn AnalyzerDb) -> Rc<[ImplId]> {
580        db.module_all_impls(*self).value
581    }
582
583    pub fn impls(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<(TraitId, TypeId), ImplId>> {
584        db.module_impl_map(*self).value
585    }
586
587    /// Returns a map of the named items in the module
588    pub fn items(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, Item>> {
589        db.module_item_map(*self).value
590    }
591
592    /// Returns a `name -> (name_span, external_item)` map for all `use`
593    /// statements in a module.
594    pub fn used_items(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, (Span, Item)>> {
595        db.module_used_item_map(*self).value
596    }
597
598    pub fn tests(&self, db: &dyn AnalyzerDb) -> Vec<FunctionId> {
599        db.module_tests(*self)
600    }
601
602    /// Returns `true` if the `item` is in scope of the module.
603    pub fn is_in_scope(&self, db: &dyn AnalyzerDb, item: Item) -> bool {
604        if let Some(val) = item.module(db) {
605            if val == *self {
606                return true;
607            }
608        }
609
610        if let Some((_, val)) = self.used_items(db).get(&item.name(db)) {
611            if *val == item {
612                return true;
613            }
614        }
615        false
616    }
617
618    /// Returns all of the internal items, except for `use`d items. This is used
619    /// when resolving `use` statements, as it does not create a query
620    /// cycle.
621    pub fn non_used_internal_items(&self, db: &dyn AnalyzerDb) -> IndexMap<SmolStr, Item> {
622        let global_items = self.global_items(db);
623
624        self.submodules(db)
625            .iter()
626            .map(|module| (module.name(db), Item::Module(*module)))
627            .chain(global_items)
628            .collect()
629    }
630
631    /// Returns all of the internal items. Internal items refers to the set of
632    /// items visible when inside of a module.
633    pub fn internal_items(&self, db: &dyn AnalyzerDb) -> IndexMap<SmolStr, Item> {
634        let global_items = self.global_items(db);
635        let defined_items = self.items(db);
636        self.submodules(db)
637            .iter()
638            .map(|module| (module.name(db), Item::Module(*module)))
639            .chain(global_items)
640            .chain(defined_items.deref().clone())
641            .collect()
642    }
643
644    /// Resolve a path that starts with an item defined in the module.
645    pub fn resolve_path(
646        &self,
647        db: &dyn AnalyzerDb,
648        path: &ast::Path,
649    ) -> Analysis<Option<NamedThing>> {
650        Item::Module(*self).resolve_path_segments(db, &path.segments)
651    }
652
653    /// Resolve a path that starts with an internal item. We omit used items to
654    /// avoid a query cycle.
655    pub fn resolve_path_non_used_internal(
656        &self,
657        db: &dyn AnalyzerDb,
658        path: &ast::Path,
659    ) -> Analysis<Option<NamedThing>> {
660        let segments = &path.segments;
661        let first_segment = &segments[0];
662
663        if let Some(curr_item) = self.non_used_internal_items(db).get(&first_segment.kind) {
664            curr_item.resolve_path_segments(db, &segments[1..])
665        } else {
666            Analysis {
667                value: None,
668                diagnostics: Rc::new([errors::error(
669                    "unresolved path item",
670                    first_segment.span,
671                    "not found",
672                )]),
673            }
674        }
675    }
676
677    /// Resolve a path that starts with an internal item.
678    pub fn resolve_path_internal(
679        &self,
680        db: &dyn AnalyzerDb,
681        path: &ast::Path,
682    ) -> Analysis<Option<NamedThing>> {
683        let segments = &path.segments;
684        let first_segment = &segments[0];
685
686        if let Some(curr_item) = self.internal_items(db).get(&first_segment.kind) {
687            curr_item.resolve_path_segments(db, &segments[1..])
688        } else {
689            Analysis {
690                value: None,
691                diagnostics: Rc::new([errors::error(
692                    "unresolved path item",
693                    first_segment.span,
694                    "not found",
695                )]),
696            }
697        }
698    }
699
700    /// Returns `Err(IncompleteItem)` if the name could not be resolved, and the
701    /// module was not completely parsed (due to a syntax error).
702    pub fn resolve_name(
703        &self,
704        db: &dyn AnalyzerDb,
705        name: &str,
706    ) -> Result<Option<NamedThing>, IncompleteItem> {
707        if let Some(thing) = self.internal_items(db).get(name) {
708            Ok(Some(NamedThing::Item(*thing)))
709        } else if self.is_incomplete(db) {
710            Err(IncompleteItem::new())
711        } else {
712            Ok(None)
713        }
714    }
715
716    pub fn resolve_constant(
717        &self,
718        db: &dyn AnalyzerDb,
719        name: &str,
720    ) -> Result<Option<ModuleConstantId>, IncompleteItem> {
721        if let Some(constant) = self
722            .all_constants(db)
723            .iter()
724            .find(|id| id.name(db) == name)
725            .copied()
726        {
727            Ok(Some(constant))
728        } else if self.is_incomplete(db) {
729            Err(IncompleteItem::new())
730        } else {
731            Ok(None)
732        }
733    }
734    pub fn submodules(&self, db: &dyn AnalyzerDb) -> Rc<[ModuleId]> {
735        db.module_submodules(*self)
736    }
737
738    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
739        self.parent_module(db)
740            .map(Item::Module)
741            .unwrap_or_else(|| Item::Ingot(self.ingot(db)))
742    }
743
744    pub fn parent_module(&self, db: &dyn AnalyzerDb) -> Option<ModuleId> {
745        db.module_parent_module(*self)
746    }
747
748    /// All contracts, including from submodules and including duplicates
749    pub fn all_contracts(&self, db: &dyn AnalyzerDb) -> Vec<ContractId> {
750        self.submodules(db)
751            .iter()
752            .flat_map(|module| module.all_contracts(db))
753            .chain((*db.module_contracts(*self)).to_vec())
754            .collect::<Vec<_>>()
755    }
756
757    /// All functions, including from submodules and including duplicates
758    pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Vec<FunctionId> {
759        self.items(db)
760            .iter()
761            .filter_map(|(_, item)| {
762                if let Item::Function(function) = item {
763                    Some(*function)
764                } else {
765                    None
766                }
767            })
768            .collect()
769    }
770
771    /// Returns the map of ingot deps, built-ins, and the ingot itself as
772    /// "ingot".
773    pub fn global_items(&self, db: &dyn AnalyzerDb) -> IndexMap<SmolStr, Item> {
774        let ingot = self.ingot(db);
775        let mut items = ingot
776            .external_ingots(db)
777            .iter()
778            .map(|(name, ingot)| (name.clone(), Item::Ingot(*ingot)))
779            .chain(builtin_items())
780            .collect::<IndexMap<_, _>>();
781
782        if ingot.data(db).mode != IngotMode::StandaloneModule {
783            items.insert("ingot".into(), Item::Ingot(ingot));
784        }
785        items
786    }
787
788    /// All module constants.
789    pub fn all_constants(&self, db: &dyn AnalyzerDb) -> Rc<Vec<ModuleConstantId>> {
790        db.module_constants(*self)
791    }
792
793    pub fn diagnostics(&self, db: &dyn AnalyzerDb) -> Vec<Diagnostic> {
794        let mut diagnostics = vec![];
795        self.sink_diagnostics(db, &mut diagnostics);
796        diagnostics
797    }
798
799    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
800        let data = self.data(db);
801        if let ModuleSource::File(_) = data.source {
802            sink.push_all(db.module_parse(*self).diagnostics.iter())
803        }
804        let ast = self.ast(db);
805        for stmt in &ast.body {
806            if let ast::ModuleStmt::Pragma(inner) = stmt {
807                if let Some(diag) = check_pragma_version(inner) {
808                    sink.push(&diag)
809                }
810            }
811        }
812
813        // duplicate item name errors
814        sink.push_all(db.module_item_map(*self).diagnostics.iter());
815
816        // duplicate impl errors
817        sink.push_all(db.module_impl_map(*self).diagnostics.iter());
818
819        // errors for each item
820        self.all_items(db)
821            .iter()
822            .for_each(|id| id.sink_diagnostics(db, sink));
823
824        self.all_impls(db)
825            .iter()
826            .for_each(|id| id.sink_diagnostics(db, sink));
827    }
828
829    #[doc(hidden)]
830    // DO NOT USE THIS METHOD except for testing purpose.
831    pub fn from_raw_internal(raw: u32) -> Self {
832        Self(raw)
833    }
834}
835
836#[derive(Debug, PartialEq, Eq, Hash, Clone)]
837pub struct ModuleConstant {
838    pub ast: Node<ast::ConstantDecl>,
839    pub module: ModuleId,
840}
841
842#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
843pub struct ModuleConstantId(pub(crate) u32);
844impl_intern_key!(ModuleConstantId);
845
846impl ModuleConstantId {
847    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<ModuleConstant> {
848        db.lookup_intern_module_const(*self)
849    }
850    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
851        self.data(db).ast.span
852    }
853    pub fn typ(&self, db: &dyn AnalyzerDb) -> Result<types::TypeId, TypeError> {
854        db.module_constant_type(*self).value
855    }
856
857    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
858        self.data(db).ast.kind.name.kind.clone()
859    }
860
861    pub fn constant_value(&self, db: &dyn AnalyzerDb) -> Result<Constant, ConstEvalError> {
862        db.module_constant_value(*self).value
863    }
864
865    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Span {
866        self.data(db).ast.kind.name.span
867    }
868
869    pub fn value(&self, db: &dyn AnalyzerDb) -> ast::Expr {
870        self.data(db).ast.kind.value.kind.clone()
871    }
872
873    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
874        Item::Module(self.data(db).module)
875    }
876
877    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
878        self.data(db).ast.kind.pub_qual.is_some()
879    }
880
881    pub fn module(&self, db: &dyn AnalyzerDb) -> ModuleId {
882        self.data(db).module
883    }
884
885    pub fn node_id(&self, db: &dyn AnalyzerDb) -> NodeId {
886        self.data(db).ast.id
887    }
888
889    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
890        db.module_constant_type(*self)
891            .diagnostics
892            .iter()
893            .for_each(|d| sink.push(d));
894    }
895}
896
897#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
898pub enum TypeDef {
899    Alias(TypeAliasId),
900    Struct(StructId),
901    Enum(EnumId),
902    Contract(ContractId),
903    Primitive(types::Base),
904}
905
906impl TypeDef {
907    pub fn items(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, Item>> {
908        match self {
909            TypeDef::Struct(val) => {
910                // In the future we probably want to resolve instance methods as well. But this
911                // would require the caller to pass an instance as the first
912                // argument e.g. `Rectangle::can_hold(self_instance, other)`.
913                // This isn't yet supported so for now path access to functions is limited to
914                // static functions only.
915                val.pure_functions_as_items(db)
916            }
917            TypeDef::Enum(val) => val.pure_functions_as_items(db),
918            TypeDef::Contract(val) => val.pure_functions_as_items(db),
919            _ => Rc::new(indexmap! {}),
920        }
921    }
922
923    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
924        match self {
925            TypeDef::Alias(id) => id.name(db),
926            TypeDef::Struct(id) => id.name(db),
927            TypeDef::Enum(id) => id.name(db),
928            TypeDef::Contract(id) => id.name(db),
929            TypeDef::Primitive(typ) => typ.name(),
930        }
931    }
932
933    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
934        match self {
935            TypeDef::Alias(id) => Some(id.name_span(db)),
936            TypeDef::Struct(id) => Some(id.name_span(db)),
937            TypeDef::Enum(id) => Some(id.name_span(db)),
938            TypeDef::Contract(id) => Some(id.name_span(db)),
939            TypeDef::Primitive(_) => None,
940        }
941    }
942
943    pub fn typ(&self, db: &dyn AnalyzerDb) -> Result<Type, TypeError> {
944        match self {
945            TypeDef::Alias(id) => Ok(id.type_id(db)?.typ(db)),
946            TypeDef::Struct(id) => Ok(Type::Struct(*id)),
947            TypeDef::Enum(id) => Ok(Type::Enum(*id)),
948            TypeDef::Contract(id) => Ok(Type::Contract(*id)),
949            TypeDef::Primitive(base) => Ok(Type::Base(*base)),
950        }
951    }
952
953    pub fn type_id(&self, db: &dyn AnalyzerDb) -> Result<TypeId, TypeError> {
954        Ok(db.intern_type(self.typ(db)?))
955    }
956
957    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
958        match self {
959            Self::Alias(id) => id.is_public(db),
960            Self::Struct(id) => id.is_public(db),
961            Self::Enum(id) => id.is_public(db),
962            Self::Contract(id) => id.is_public(db),
963            Self::Primitive(_) => true,
964        }
965    }
966
967    pub fn parent(&self, db: &dyn AnalyzerDb) -> Option<Item> {
968        match self {
969            TypeDef::Alias(id) => Some(id.parent(db)),
970            TypeDef::Struct(id) => Some(id.parent(db)),
971            TypeDef::Enum(id) => Some(id.parent(db)),
972            TypeDef::Contract(id) => Some(id.parent(db)),
973            TypeDef::Primitive(_) => None,
974        }
975    }
976
977    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
978        match self {
979            TypeDef::Alias(id) => id.sink_diagnostics(db, sink),
980            TypeDef::Struct(id) => id.sink_diagnostics(db, sink),
981            TypeDef::Enum(id) => id.sink_diagnostics(db, sink),
982            TypeDef::Contract(id) => id.sink_diagnostics(db, sink),
983            TypeDef::Primitive(_) => {}
984        }
985    }
986}
987
988#[derive(Debug, PartialEq, Eq, Hash, Clone)]
989pub struct TypeAlias {
990    pub ast: Node<ast::TypeAlias>,
991    pub module: ModuleId,
992}
993
994#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
995pub struct TypeAliasId(pub(crate) u32);
996impl_intern_key!(TypeAliasId);
997
998impl TypeAliasId {
999    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<TypeAlias> {
1000        db.lookup_intern_type_alias(*self)
1001    }
1002    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
1003        self.data(db).ast.span
1004    }
1005    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1006        self.data(db).ast.name().into()
1007    }
1008    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Span {
1009        self.data(db).ast.kind.name.span
1010    }
1011    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
1012        self.data(db).ast.kind.pub_qual.is_some()
1013    }
1014    pub fn type_id(&self, db: &dyn AnalyzerDb) -> Result<types::TypeId, TypeError> {
1015        db.type_alias_type(*self).value
1016    }
1017    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
1018        Item::Module(self.data(db).module)
1019    }
1020    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1021        db.type_alias_type(*self)
1022            .diagnostics
1023            .iter()
1024            .for_each(|d| sink.push(d))
1025    }
1026}
1027
1028#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1029pub struct Contract {
1030    pub name: SmolStr,
1031    pub ast: Node<ast::Contract>,
1032    pub module: ModuleId,
1033}
1034
1035#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1036pub struct ContractId(pub(crate) u32);
1037impl_intern_key!(ContractId);
1038impl ContractId {
1039    pub fn as_type(&self, db: &dyn AnalyzerDb) -> TypeId {
1040        db.intern_type(Type::Contract(*self))
1041    }
1042    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<Contract> {
1043        db.lookup_intern_contract(*self)
1044    }
1045    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
1046        self.data(db).ast.span
1047    }
1048    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1049        self.data(db).ast.name().into()
1050    }
1051    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
1052        self.data(db).ast.kind.pub_qual.is_some()
1053    }
1054    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Span {
1055        self.data(db).ast.kind.name.span
1056    }
1057
1058    pub fn module(&self, db: &dyn AnalyzerDb) -> ModuleId {
1059        self.data(db).module
1060    }
1061
1062    pub fn fields(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, ContractFieldId>> {
1063        db.contract_field_map(*self).value
1064    }
1065
1066    pub fn field_type(
1067        &self,
1068        db: &dyn AnalyzerDb,
1069        name: &str,
1070    ) -> Option<Result<types::TypeId, TypeError>> {
1071        // Note: contract field types are wrapped in SPtr in `fn expr_attribute`
1072        let fields = db.contract_field_map(*self).value;
1073        Some(fields.get(name)?.typ(db))
1074    }
1075
1076    pub fn resolve_name(
1077        &self,
1078        db: &dyn AnalyzerDb,
1079        name: &str,
1080    ) -> Result<Option<NamedThing>, IncompleteItem> {
1081        if let Some(item) = self
1082            .function(db, name)
1083            .filter(|f| !f.takes_self(db))
1084            .map(Item::Function)
1085        {
1086            Ok(Some(NamedThing::Item(item)))
1087        } else {
1088            self.module(db).resolve_name(db, name)
1089        }
1090    }
1091
1092    pub fn init_function(&self, db: &dyn AnalyzerDb) -> Option<FunctionId> {
1093        db.contract_init_function(*self).value
1094    }
1095
1096    pub fn call_function(&self, db: &dyn AnalyzerDb) -> Option<FunctionId> {
1097        db.contract_call_function(*self).value
1098    }
1099
1100    pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Rc<[FunctionId]> {
1101        db.contract_all_functions(*self)
1102    }
1103
1104    /// User functions, public and not. Excludes `__init__` and `__call__`.
1105    pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1106        db.contract_function_map(*self).value
1107    }
1108
1109    /// Lookup a function by name. Searches all user functions, private or not.
1110    /// Excludes `__init__` and `__call__`.
1111    pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionId> {
1112        self.functions(db).get(name).copied()
1113    }
1114
1115    /// Excludes `__init__` and `__call__`.
1116    pub fn public_functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1117        db.contract_public_function_map(*self)
1118    }
1119
1120    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
1121        Item::Module(self.data(db).module)
1122    }
1123
1124    /// Dependency graph of the contract type, which consists of the field types
1125    /// and the dependencies of those types.
1126    ///
1127    /// NOTE: Contract items should *only*
1128    pub fn dependency_graph(&self, db: &dyn AnalyzerDb) -> Rc<DepGraph> {
1129        db.contract_dependency_graph(*self).0
1130    }
1131
1132    /// Dependency graph of the (imaginary) `__call__` function, which
1133    /// dispatches to the contract's public functions.
1134    pub fn runtime_dependency_graph(&self, db: &dyn AnalyzerDb) -> Rc<DepGraph> {
1135        db.contract_runtime_dependency_graph(*self).0
1136    }
1137
1138    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1139        // fields
1140        db.contract_field_map(*self).sink_diagnostics(sink);
1141        db.contract_all_fields(*self)
1142            .iter()
1143            .for_each(|field| field.sink_diagnostics(db, sink));
1144
1145        // functions
1146        db.contract_init_function(*self).sink_diagnostics(sink);
1147        db.contract_call_function(*self).sink_diagnostics(sink);
1148        db.contract_function_map(*self).sink_diagnostics(sink);
1149        db.contract_all_functions(*self)
1150            .iter()
1151            .for_each(|id| id.sink_diagnostics(db, sink));
1152    }
1153}
1154
1155#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1156pub struct ContractField {
1157    pub ast: Node<ast::Field>,
1158    pub parent: ContractId,
1159}
1160
1161#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1162pub struct ContractFieldId(pub(crate) u32);
1163impl_intern_key!(ContractFieldId);
1164impl ContractFieldId {
1165    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1166        self.data(db).ast.name().into()
1167    }
1168    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<ContractField> {
1169        db.lookup_intern_contract_field(*self)
1170    }
1171    pub fn typ(&self, db: &dyn AnalyzerDb) -> Result<types::TypeId, TypeError> {
1172        db.contract_field_type(*self).value
1173    }
1174    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1175        sink.push_all(db.contract_field_type(*self).diagnostics.iter())
1176    }
1177}
1178
1179#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1180pub struct FunctionSig {
1181    pub ast: Node<ast::FunctionSignature>,
1182    pub parent: Option<Item>,
1183    pub module: ModuleId,
1184}
1185
1186#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1187pub struct FunctionSigId(pub(crate) u32);
1188impl_intern_key!(FunctionSigId);
1189
1190impl FunctionSigId {
1191    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<FunctionSig> {
1192        db.lookup_intern_function_sig(*self)
1193    }
1194
1195    pub fn takes_self(&self, db: &dyn AnalyzerDb) -> bool {
1196        self.signature(db).self_decl.is_some()
1197    }
1198
1199    pub fn self_type(&self, db: &dyn AnalyzerDb) -> Option<types::TypeId> {
1200        match self.parent(db) {
1201            Item::Type(TypeDef::Contract(cid)) => Some(types::Type::SelfContract(cid).id(db)),
1202            Item::Type(TypeDef::Struct(sid)) => Some(types::Type::Struct(sid).id(db)),
1203            Item::Type(TypeDef::Enum(sid)) => Some(types::Type::Enum(sid).id(db)),
1204            Item::Impl(id) => Some(id.receiver(db)),
1205            Item::Type(TypeDef::Primitive(ty)) => Some(db.intern_type(Type::Base(ty))),
1206            _ => None,
1207        }
1208    }
1209    pub fn self_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
1210        Some(self.signature(db).self_decl?.span)
1211    }
1212    pub fn signature(&self, db: &dyn AnalyzerDb) -> Rc<types::FunctionSignature> {
1213        db.function_signature(*self).value
1214    }
1215
1216    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
1217        self.is_trait_fn(db) || self.is_impl_fn(db) || self.pub_span(db).is_some()
1218    }
1219    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1220        self.data(db).ast.kind.name.kind.clone()
1221    }
1222    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Span {
1223        self.data(db).ast.kind.name.span
1224    }
1225    pub fn unsafe_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
1226        self.data(db).ast.kind.unsafe_
1227    }
1228    pub fn is_constructor(&self, db: &dyn AnalyzerDb) -> bool {
1229        self.name(db) == "__init__"
1230    }
1231    pub fn pub_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
1232        self.data(db).ast.kind.pub_
1233    }
1234
1235    pub fn self_item(&self, db: &dyn AnalyzerDb) -> Option<Item> {
1236        let data = self.data(db);
1237        data.parent
1238    }
1239
1240    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
1241        self.self_item(db)
1242            .unwrap_or_else(|| Item::Module(self.module(db)))
1243    }
1244
1245    /// Looks up the `FunctionId` based on the parent of the function signature
1246    pub fn function(&self, db: &dyn AnalyzerDb) -> Option<FunctionId> {
1247        match self.parent(db) {
1248            Item::Type(TypeDef::Struct(id)) => id.function(db, &self.name(db)),
1249            Item::Type(TypeDef::Enum(id)) => id.function(db, &self.name(db)),
1250            Item::Impl(id) => id.function(db, &self.name(db)),
1251            Item::Type(TypeDef::Contract(id)) => id.function(db, &self.name(db)),
1252            _ => None,
1253        }
1254    }
1255
1256    pub fn is_trait_fn(&self, db: &dyn AnalyzerDb) -> bool {
1257        matches!(self.parent(db), Item::Trait(_))
1258    }
1259
1260    pub fn is_module_fn(&self, db: &dyn AnalyzerDb) -> bool {
1261        matches!(self.parent(db), Item::Module(_))
1262    }
1263
1264    pub fn is_impl_fn(&self, db: &dyn AnalyzerDb) -> bool {
1265        matches!(self.parent(db), Item::Impl(_))
1266    }
1267
1268    pub fn is_generic(&self, db: &dyn AnalyzerDb) -> bool {
1269        !self.data(db).ast.kind.generic_params.kind.is_empty()
1270    }
1271
1272    pub fn generic_params(&self, db: &dyn AnalyzerDb) -> Vec<GenericParameter> {
1273        self.data(db).ast.kind.generic_params.kind.clone()
1274    }
1275
1276    pub fn generic_param(&self, db: &dyn AnalyzerDb, param_name: &str) -> Option<GenericParameter> {
1277        self.generic_params(db)
1278            .iter()
1279            .find(|param| match param {
1280                GenericParameter::Unbounded(name) if name.kind == param_name => true,
1281                GenericParameter::Bounded { name, .. } if name.kind == param_name => true,
1282                _ => false,
1283            })
1284            .cloned()
1285    }
1286
1287    pub fn module(&self, db: &dyn AnalyzerDb) -> ModuleId {
1288        self.data(db).module
1289    }
1290
1291    pub fn is_contract_func(self, db: &dyn AnalyzerDb) -> bool {
1292        matches! {self.parent(db), Item::Type(TypeDef::Contract(_))}
1293    }
1294
1295    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1296        sink.push_all(db.function_signature(*self).diagnostics.iter());
1297    }
1298}
1299
1300#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1301pub struct Function {
1302    pub ast: Node<ast::Function>,
1303    pub sig: FunctionSigId,
1304}
1305
1306impl Function {
1307    pub fn new(
1308        db: &dyn AnalyzerDb,
1309        ast: &Node<ast::Function>,
1310        parent: Option<Item>,
1311        module: ModuleId,
1312    ) -> Self {
1313        let sig = db.intern_function_sig(Rc::new(FunctionSig {
1314            ast: ast.kind.sig.clone(),
1315            parent,
1316            module,
1317        }));
1318        Function {
1319            sig,
1320            ast: ast.clone(),
1321        }
1322    }
1323}
1324
1325#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1326pub struct FunctionId(pub(crate) u32);
1327impl_intern_key!(FunctionId);
1328impl FunctionId {
1329    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<Function> {
1330        db.lookup_intern_function(*self)
1331    }
1332    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
1333        self.data(db).ast.span
1334    }
1335    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1336        self.sig(db).name(db)
1337    }
1338    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Span {
1339        self.sig(db).name_span(db)
1340    }
1341    pub fn module(&self, db: &dyn AnalyzerDb) -> ModuleId {
1342        self.sig(db).module(db)
1343    }
1344    pub fn self_type(&self, db: &dyn AnalyzerDb) -> Option<types::TypeId> {
1345        self.sig(db).self_type(db)
1346    }
1347    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
1348        self.sig(db).parent(db)
1349    }
1350
1351    pub fn takes_self(&self, db: &dyn AnalyzerDb) -> bool {
1352        self.sig(db).takes_self(db)
1353    }
1354    pub fn self_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
1355        self.sig(db).self_span(db)
1356    }
1357    pub fn is_generic(&self, db: &dyn AnalyzerDb) -> bool {
1358        self.sig(db).is_generic(db)
1359    }
1360    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
1361        self.sig(db).is_public(db)
1362    }
1363    pub fn is_constructor(&self, db: &dyn AnalyzerDb) -> bool {
1364        self.sig(db).is_constructor(db)
1365    }
1366    pub fn is_unsafe(&self, db: &dyn AnalyzerDb) -> bool {
1367        self.unsafe_span(db).is_some()
1368    }
1369    pub fn unsafe_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
1370        self.sig(db).unsafe_span(db)
1371    }
1372    pub fn signature(&self, db: &dyn AnalyzerDb) -> Rc<types::FunctionSignature> {
1373        db.function_signature(self.data(db).sig).value
1374    }
1375    pub fn sig(&self, db: &dyn AnalyzerDb) -> FunctionSigId {
1376        self.data(db).sig
1377    }
1378    pub fn body(&self, db: &dyn AnalyzerDb) -> Rc<context::FunctionBody> {
1379        db.function_body(*self).value
1380    }
1381    pub fn dependency_graph(&self, db: &dyn AnalyzerDb) -> Rc<DepGraph> {
1382        db.function_dependency_graph(*self).0
1383    }
1384    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1385        sink.push_all(db.function_signature(self.data(db).sig).diagnostics.iter());
1386        sink.push_all(db.function_body(*self).diagnostics.iter());
1387    }
1388    pub fn is_contract_func(self, db: &dyn AnalyzerDb) -> bool {
1389        self.sig(db).is_contract_func(db)
1390    }
1391
1392    pub fn is_test(&self, db: &dyn AnalyzerDb) -> bool {
1393        Item::Function(*self)
1394            .attributes(db)
1395            .iter()
1396            .any(|attribute| attribute.name(db) == "test")
1397    }
1398}
1399
1400trait FunctionsAsItems {
1401    fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>>;
1402
1403    fn pure_functions_as_items(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, Item>> {
1404        Rc::new(
1405            self.functions(db)
1406                .iter()
1407                .filter_map(|(name, field)| {
1408                    if field.takes_self(db) {
1409                        None
1410                    } else {
1411                        Some((name.to_owned(), Item::Function(*field)))
1412                    }
1413                })
1414                .collect(),
1415        )
1416    }
1417}
1418
1419impl FunctionsAsItems for StructId {
1420    fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1421        self.functions(db)
1422    }
1423}
1424
1425impl FunctionsAsItems for EnumId {
1426    fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1427        self.functions(db)
1428    }
1429}
1430
1431impl FunctionsAsItems for ContractId {
1432    fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1433        self.functions(db)
1434    }
1435}
1436
1437#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1438pub struct Struct {
1439    pub ast: Node<ast::Struct>,
1440    pub module: ModuleId,
1441}
1442
1443#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1444pub struct StructId(pub(crate) u32);
1445impl_intern_key!(StructId);
1446impl StructId {
1447    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<Struct> {
1448        db.lookup_intern_struct(*self)
1449    }
1450    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
1451        self.data(db).ast.span
1452    }
1453    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1454        self.data(db).ast.name().into()
1455    }
1456    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Span {
1457        self.data(db).ast.kind.name.span
1458    }
1459
1460    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
1461        self.data(db).ast.kind.pub_qual.is_some()
1462    }
1463
1464    pub fn module(&self, db: &dyn AnalyzerDb) -> ModuleId {
1465        self.data(db).module
1466    }
1467
1468    pub fn as_type(&self, db: &dyn AnalyzerDb) -> TypeId {
1469        db.intern_type(Type::Struct(*self))
1470    }
1471
1472    pub fn has_private_field(&self, db: &dyn AnalyzerDb) -> bool {
1473        self.fields(db).values().any(|field| !field.is_public(db))
1474    }
1475
1476    pub fn field(&self, db: &dyn AnalyzerDb, name: &str) -> Option<StructFieldId> {
1477        self.fields(db).get(name).copied()
1478    }
1479
1480    pub fn fields(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, StructFieldId>> {
1481        db.struct_field_map(*self).value
1482    }
1483
1484    pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Rc<[FunctionId]> {
1485        db.struct_all_functions(*self)
1486    }
1487
1488    pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1489        db.struct_function_map(*self).value
1490    }
1491    pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionId> {
1492        self.functions(db).get(name).copied()
1493    }
1494    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
1495        Item::Module(self.data(db).module)
1496    }
1497    pub fn dependency_graph(&self, db: &dyn AnalyzerDb) -> Rc<DepGraph> {
1498        db.struct_dependency_graph(*self).value.0
1499    }
1500    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1501        sink.push_all(db.struct_field_map(*self).diagnostics.iter());
1502        sink.push_all(db.struct_dependency_graph(*self).diagnostics.iter());
1503
1504        db.struct_all_fields(*self)
1505            .iter()
1506            .for_each(|id| id.sink_diagnostics(db, sink));
1507
1508        db.struct_function_map(*self).sink_diagnostics(sink);
1509        db.struct_all_functions(*self)
1510            .iter()
1511            .for_each(|id| id.sink_diagnostics(db, sink));
1512    }
1513}
1514
1515#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1516pub struct StructField {
1517    pub ast: Node<ast::Field>,
1518    pub parent: StructId,
1519}
1520
1521#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1522pub struct StructFieldId(pub(crate) u32);
1523impl_intern_key!(StructFieldId);
1524impl StructFieldId {
1525    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1526        self.data(db).ast.name().into()
1527    }
1528    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
1529        self.data(db).ast.span
1530    }
1531    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<StructField> {
1532        db.lookup_intern_struct_field(*self)
1533    }
1534    pub fn attributes(&self, db: &dyn AnalyzerDb) -> Vec<SmolStr> {
1535        self.data(db)
1536            .ast
1537            .kind
1538            .attributes
1539            .iter()
1540            .map(|node| node.kind.clone())
1541            .collect()
1542    }
1543
1544    pub fn is_indexed(&self, db: &dyn AnalyzerDb) -> bool {
1545        self.attributes(db).contains(&INDEXED.into())
1546    }
1547
1548    pub fn typ(&self, db: &dyn AnalyzerDb) -> Result<types::TypeId, TypeError> {
1549        db.struct_field_type(*self).value
1550    }
1551    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
1552        self.data(db).ast.kind.is_pub
1553    }
1554
1555    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1556        db.struct_field_type(*self).sink_diagnostics(sink)
1557    }
1558}
1559
1560#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1561pub struct Attribute {
1562    pub ast: Node<SmolStr>,
1563    pub module: ModuleId,
1564}
1565#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1566pub struct AttributeId(pub(crate) u32);
1567impl_intern_key!(AttributeId);
1568
1569impl AttributeId {
1570    pub fn data(self, db: &dyn AnalyzerDb) -> Rc<Attribute> {
1571        db.lookup_intern_attribute(self)
1572    }
1573    pub fn span(self, db: &dyn AnalyzerDb) -> Span {
1574        self.data(db).ast.span
1575    }
1576    pub fn name(self, db: &dyn AnalyzerDb) -> SmolStr {
1577        self.data(db).ast.kind.to_owned()
1578    }
1579
1580    pub fn module(self, db: &dyn AnalyzerDb) -> ModuleId {
1581        self.data(db).module
1582    }
1583
1584    pub fn parent(self, db: &dyn AnalyzerDb) -> Item {
1585        Item::Module(self.data(db).module)
1586    }
1587}
1588
1589#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1590pub struct Enum {
1591    pub ast: Node<ast::Enum>,
1592    pub module: ModuleId,
1593}
1594#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1595pub struct EnumId(pub(crate) u32);
1596impl_intern_key!(EnumId);
1597
1598impl EnumId {
1599    pub fn data(self, db: &dyn AnalyzerDb) -> Rc<Enum> {
1600        db.lookup_intern_enum(self)
1601    }
1602    pub fn span(self, db: &dyn AnalyzerDb) -> Span {
1603        self.data(db).ast.span
1604    }
1605    pub fn name(self, db: &dyn AnalyzerDb) -> SmolStr {
1606        self.data(db).ast.name().into()
1607    }
1608    pub fn name_span(self, db: &dyn AnalyzerDb) -> Span {
1609        self.data(db).ast.kind.name.span
1610    }
1611
1612    pub fn as_type(self, db: &dyn AnalyzerDb) -> TypeId {
1613        db.intern_type(Type::Enum(self))
1614    }
1615
1616    pub fn is_public(self, db: &dyn AnalyzerDb) -> bool {
1617        self.data(db).ast.kind.pub_qual.is_some()
1618    }
1619
1620    pub fn variant(self, db: &dyn AnalyzerDb, name: &str) -> Option<EnumVariantId> {
1621        self.variants(db).get(name).copied()
1622    }
1623
1624    pub fn variants(self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, EnumVariantId>> {
1625        db.enum_variant_map(self).value
1626    }
1627
1628    pub fn module(self, db: &dyn AnalyzerDb) -> ModuleId {
1629        self.data(db).module
1630    }
1631
1632    pub fn parent(self, db: &dyn AnalyzerDb) -> Item {
1633        Item::Module(self.data(db).module)
1634    }
1635
1636    pub fn dependency_graph(self, db: &dyn AnalyzerDb) -> Rc<DepGraph> {
1637        db.enum_dependency_graph(self).value.0
1638    }
1639
1640    pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Rc<[FunctionId]> {
1641        db.enum_all_functions(*self)
1642    }
1643
1644    pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1645        db.enum_function_map(*self).value
1646    }
1647
1648    pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionId> {
1649        self.functions(db).get(name).copied()
1650    }
1651
1652    pub fn sink_diagnostics(self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1653        sink.push_all(db.enum_variant_map(self).diagnostics.iter());
1654        sink.push_all(db.enum_dependency_graph(self).diagnostics.iter());
1655
1656        db.enum_all_variants(self)
1657            .iter()
1658            .for_each(|variant| variant.sink_diagnostics(db, sink));
1659
1660        db.enum_function_map(self).sink_diagnostics(sink);
1661        db.enum_all_functions(self)
1662            .iter()
1663            .for_each(|id| id.sink_diagnostics(db, sink));
1664    }
1665}
1666
1667#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1668pub struct EnumVariant {
1669    pub ast: Node<ast::Variant>,
1670    pub tag: usize,
1671    pub parent: EnumId,
1672}
1673
1674#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1675pub struct EnumVariantId(pub(crate) u32);
1676impl_intern_key!(EnumVariantId);
1677impl EnumVariantId {
1678    pub fn data(self, db: &dyn AnalyzerDb) -> Rc<EnumVariant> {
1679        db.lookup_intern_enum_variant(self)
1680    }
1681    pub fn name(self, db: &dyn AnalyzerDb) -> SmolStr {
1682        self.data(db).ast.name().into()
1683    }
1684    pub fn span(self, db: &dyn AnalyzerDb) -> Span {
1685        self.data(db).ast.span
1686    }
1687    pub fn name_with_parent(self, db: &dyn AnalyzerDb) -> SmolStr {
1688        let parent = self.parent(db);
1689        format!("{}::{}", parent.name(db), self.name(db)).into()
1690    }
1691
1692    pub fn kind(self, db: &dyn AnalyzerDb) -> Result<EnumVariantKind, TypeError> {
1693        db.enum_variant_kind(self).value
1694    }
1695
1696    pub fn disc(self, db: &dyn AnalyzerDb) -> usize {
1697        self.data(db).tag
1698    }
1699
1700    pub fn sink_diagnostics(self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1701        db.enum_variant_kind(self).sink_diagnostics(sink)
1702    }
1703
1704    pub fn parent(self, db: &dyn AnalyzerDb) -> EnumId {
1705        self.data(db).parent
1706    }
1707}
1708
1709#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1710pub enum EnumVariantKind {
1711    Unit,
1712    Tuple(SmallVec<[TypeId; 4]>),
1713}
1714
1715impl EnumVariantKind {
1716    pub fn display_name(&self) -> &'static str {
1717        match self {
1718            Self::Unit => "unit variant",
1719            Self::Tuple(..) => "tuple variant",
1720        }
1721    }
1722
1723    pub fn field_len(&self) -> usize {
1724        match self {
1725            Self::Unit => 0,
1726            Self::Tuple(elts) => elts.len(),
1727        }
1728    }
1729
1730    pub fn is_unit(&self) -> bool {
1731        matches!(self, Self::Unit)
1732    }
1733}
1734
1735impl DisplayWithDb for EnumVariantKind {
1736    fn format(&self, db: &dyn AnalyzerDb, f: &mut fmt::Formatter) -> fmt::Result {
1737        match self {
1738            Self::Unit => write!(f, "unit"),
1739            Self::Tuple(elts) => {
1740                write!(f, "(")?;
1741                let mut delim = "";
1742                for ty in elts {
1743                    write!(f, "{delim}")?;
1744                    ty.format(db, f)?;
1745                    delim = ", ";
1746                }
1747                write!(f, ")")
1748            }
1749        }
1750    }
1751}
1752
1753#[derive(Debug, PartialEq, Eq, Hash, Clone)]
1754pub struct Impl {
1755    pub trait_id: TraitId,
1756    pub receiver: TypeId,
1757    pub module: ModuleId,
1758    pub ast: Node<ast::Impl>,
1759}
1760
1761#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
1762pub struct ImplId(pub(crate) u32);
1763impl_intern_key!(ImplId);
1764impl ImplId {
1765    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<Impl> {
1766        db.lookup_intern_impl(*self)
1767    }
1768    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
1769        self.data(db).ast.span
1770    }
1771
1772    pub fn module(&self, db: &dyn AnalyzerDb) -> ModuleId {
1773        self.data(db).module
1774    }
1775
1776    pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Rc<[FunctionId]> {
1777        db.impl_all_functions(*self)
1778    }
1779
1780    pub fn trait_id(&self, db: &dyn AnalyzerDb) -> TraitId {
1781        self.data(db).trait_id
1782    }
1783
1784    pub fn receiver(&self, db: &dyn AnalyzerDb) -> TypeId {
1785        self.data(db).receiver
1786    }
1787
1788    /// Returns `true` if `other` either is `Self` or the type of the receiver
1789    pub fn is_receiver_type(&self, other: TypeId, db: &dyn AnalyzerDb) -> bool {
1790        other == self.receiver(db)
1791            || other == Type::SelfType(TraitOrType::TypeId(self.receiver(db))).id(db)
1792    }
1793
1794    /// Returns `true` if the `type_in_impl` can stand in for the `type_in_trait` as a type used
1795    /// for a parameter or as a return type
1796    pub fn can_stand_in_for(
1797        &self,
1798        db: &dyn AnalyzerDb,
1799        type_in_impl: TypeId,
1800        type_in_trait: TypeId,
1801    ) -> bool {
1802        if type_in_impl == type_in_trait {
1803            true
1804        } else {
1805            self.is_receiver_type(type_in_impl, db)
1806                && (type_in_trait.is_self_ty(db) || type_in_trait == self.receiver(db))
1807        }
1808    }
1809
1810    pub fn ast(&self, db: &dyn AnalyzerDb) -> Node<ast::Impl> {
1811        self.data(db).ast.clone()
1812    }
1813
1814    pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1815        db.impl_function_map(*self).value
1816    }
1817    pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionId> {
1818        self.functions(db).get(name).copied()
1819    }
1820    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
1821        Item::Module(self.data(db).module)
1822    }
1823    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
1824        format!(
1825            "{}_{}",
1826            self.trait_id(db).name(db),
1827            self.receiver(db).display(db)
1828        )
1829        .into()
1830    }
1831
1832    fn validate_type_or_trait_is_in_ingot(
1833        &self,
1834        db: &dyn AnalyzerDb,
1835        sink: &mut impl DiagnosticSink,
1836        type_ingot: Option<IngotId>,
1837    ) {
1838        let impl_ingot = self.data(db).module.ingot(db);
1839        let is_allowed = match type_ingot {
1840            None => impl_ingot == self.data(db).trait_id.module(db).ingot(db),
1841            Some(val) => {
1842                val == impl_ingot || self.data(db).trait_id.module(db).ingot(db) == impl_ingot
1843            }
1844        };
1845
1846        if !is_allowed {
1847            sink.push(&errors::fancy_error(
1848                "illegal `impl`. Either type or trait must be in the same ingot as the `impl`",
1849                vec![Label::primary(
1850                    self.data(db).ast.span,
1851                    format!(
1852                        "Neither `{}` nor `{}` are in the ingot of the `impl` block",
1853                        self.data(db).receiver.display(db),
1854                        self.data(db).trait_id.name(db)
1855                    ),
1856                )],
1857                vec![],
1858            ))
1859        }
1860    }
1861
1862    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
1863        match &self.data(db).receiver.typ(db) {
1864            Type::Contract(_)
1865            | Type::Map(_)
1866            | Type::SelfContract(_)
1867            | Type::Generic(_)
1868            | Type::SelfType(_) => sink.push(&errors::fancy_error(
1869                format!(
1870                    "`impl` blocks aren't allowed for {}",
1871                    self.data(db).receiver.display(db)
1872                ),
1873                vec![Label::primary(
1874                    self.data(db).ast.span,
1875                    "illegal `impl` block",
1876                )],
1877                vec![],
1878            )),
1879            Type::Struct(id) => {
1880                self.validate_type_or_trait_is_in_ingot(db, sink, Some(id.module(db).ingot(db)))
1881            }
1882            Type::Enum(id) => {
1883                self.validate_type_or_trait_is_in_ingot(db, sink, Some(id.module(db).ingot(db)))
1884            }
1885            Type::Base(_) | Type::Array(_) | Type::Tuple(_) | Type::String(_) => {
1886                self.validate_type_or_trait_is_in_ingot(db, sink, None)
1887            }
1888            Type::SPtr(_) | Type::Mut(_) => unreachable!(),
1889        }
1890
1891        if !self.trait_id(db).is_public(db) && self.trait_id(db).module(db) != self.module(db) {
1892            let trait_module_name = self.trait_id(db).module(db).name(db);
1893            let trait_name = self.trait_id(db).name(db);
1894            sink.push(&errors::fancy_error(
1895                     format!(
1896                         "the trait `{trait_name}` is private",
1897                     ),
1898                     vec![
1899                         Label::primary(self.trait_id(db).data(db).ast.kind.name.span, "this trait is not `pub`"),
1900                     ],
1901                     vec![
1902                         format!("`{trait_name}` can only be used within `{trait_module_name}`"),
1903                         format!("Hint: use `pub trait {trait_name}` to make `{trait_name}` visible from outside of `{trait_module_name}`"),
1904                     ],
1905                 ));
1906        }
1907
1908        for impl_fn in self.all_functions(db).iter() {
1909            impl_fn.sink_diagnostics(db, sink);
1910
1911            if let Some(trait_fn) = self.trait_id(db).function(db, &impl_fn.name(db)) {
1912                for (impl_param, trait_param) in impl_fn
1913                    .signature(db)
1914                    .params
1915                    .iter()
1916                    .zip(trait_fn.signature(db).params.iter())
1917                {
1918                    let impl_param_ty = impl_param.typ.clone().unwrap();
1919                    let trait_param_ty = trait_param.typ.clone().unwrap();
1920                    if self.can_stand_in_for(db, impl_param_ty, trait_param_ty) {
1921                        continue;
1922                    } else {
1923                        sink.push(&errors::fancy_error(
1924                            format!(
1925                                "method `{}` has incompatible parameters for `{}` of trait `{}`",
1926                                impl_fn.name(db),
1927                                trait_fn.name(db),
1928                                self.trait_id(db).name(db)
1929                            ),
1930                            vec![
1931                                Label::primary(
1932                                    impl_fn.data(db).ast.kind.sig.span,
1933                                    "signature of method in `impl` block",
1934                                ),
1935                                Label::primary(
1936                                    trait_fn.data(db).ast.span,
1937                                    format!(
1938                                        "signature of method in trait `{}`",
1939                                        self.trait_id(db).name(db)
1940                                    ),
1941                                ),
1942                            ],
1943                            vec![],
1944                        ));
1945                        break;
1946                    }
1947                }
1948
1949                let impl_fn_return_ty = impl_fn.signature(db).return_type.clone().unwrap();
1950                let trait_fn_return_ty = trait_fn.signature(db).return_type.clone().unwrap();
1951
1952                if !self.can_stand_in_for(db, impl_fn_return_ty, trait_fn_return_ty) {
1953                    // TODO: This could be a nicer, more detailed report
1954                    sink.push(&errors::fancy_error(
1955                        format!(
1956                            "method `{}` has an incompatible return type for `{}` of trait `{}`",
1957                            impl_fn.name(db),
1958                            trait_fn.name(db),
1959                            self.trait_id(db).name(db)
1960                        ),
1961                        vec![
1962                            Label::primary(
1963                                impl_fn.data(db).ast.kind.sig.span,
1964                                "signature of method in `impl` block",
1965                            ),
1966                            Label::primary(
1967                                trait_fn.data(db).ast.span,
1968                                format!(
1969                                    "signature of method in trait `{}`",
1970                                    self.trait_id(db).name(db)
1971                                ),
1972                            ),
1973                        ],
1974                        vec![],
1975                    ));
1976                }
1977
1978                if impl_fn.takes_self(db) != trait_fn.takes_self(db) {
1979                    let ((selfy_thing, selfy_span), (non_selfy_thing, non_selfy_span)) =
1980                        if impl_fn.takes_self(db) {
1981                            (
1982                                ("impl", impl_fn.name_span(db)),
1983                                ("trait", trait_fn.name_span(db)),
1984                            )
1985                        } else {
1986                            (
1987                                ("trait", trait_fn.name_span(db)),
1988                                ("impl", impl_fn.name_span(db)),
1989                            )
1990                        };
1991                    sink.push(&errors::fancy_error(
1992                        format!(
1993                            "method `{}` has a `self` declaration in the {}, but not in the `{}`",
1994                            impl_fn.name(db),
1995                            selfy_thing,
1996                            non_selfy_thing
1997                        ),
1998                        vec![
1999                            Label::primary(
2000                                selfy_span,
2001                                format!("`self` declared on the `{selfy_thing}`"),
2002                            ),
2003                            Label::primary(
2004                                non_selfy_span,
2005                                format!("no `self` declared on the `{non_selfy_thing}`"),
2006                            ),
2007                        ],
2008                        vec![],
2009                    ));
2010                }
2011            } else {
2012                sink.push(&errors::fancy_error(
2013                    format!(
2014                        "method `{}` is not a member of trait `{}`",
2015                        impl_fn.name(db),
2016                        self.trait_id(db).name(db)
2017                    ),
2018                    vec![Label::primary(
2019                        impl_fn.data(db).ast.span,
2020                        format!("not a member of trait `{}`", self.trait_id(db).name(db)),
2021                    )],
2022                    vec![],
2023                ))
2024            }
2025        }
2026
2027        for trait_fn in self.trait_id(db).all_functions(db).iter() {
2028            if self.function(db, &trait_fn.name(db)).is_none() {
2029                sink.push(&errors::fancy_error(
2030                    format!(
2031                        "not all members of trait `{}` implemented, missing: `{}`",
2032                        self.trait_id(db).name(db),
2033                        trait_fn.name(db)
2034                    ),
2035                    vec![Label::primary(
2036                        trait_fn.data(db).ast.span,
2037                        "this trait function is missing in `impl` block",
2038                    )],
2039                    vec![],
2040                ))
2041            }
2042        }
2043    }
2044}
2045
2046#[derive(Debug, PartialEq, Eq, Hash, Clone)]
2047pub struct Trait {
2048    pub ast: Node<ast::Trait>,
2049    pub module: ModuleId,
2050}
2051
2052#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Clone)]
2053pub struct TraitId(pub(crate) u32);
2054impl_intern_key!(TraitId);
2055impl TraitId {
2056    pub fn data(&self, db: &dyn AnalyzerDb) -> Rc<Trait> {
2057        db.lookup_intern_trait(*self)
2058    }
2059    pub fn span(&self, db: &dyn AnalyzerDb) -> Span {
2060        self.data(db).ast.span
2061    }
2062    pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
2063        self.data(db).ast.name().into()
2064    }
2065    pub fn name_span(&self, db: &dyn AnalyzerDb) -> Span {
2066        self.data(db).ast.kind.name.span
2067    }
2068
2069    pub fn is_public(&self, db: &dyn AnalyzerDb) -> bool {
2070        self.data(db).ast.kind.pub_qual.is_some()
2071    }
2072
2073    pub fn module(&self, db: &dyn AnalyzerDb) -> ModuleId {
2074        self.data(db).module
2075    }
2076    pub fn as_trait_or_type(&self) -> TraitOrType {
2077        TraitOrType::TraitId(*self)
2078    }
2079    pub fn is_implemented_for(&self, db: &dyn AnalyzerDb, ty: TypeId) -> bool {
2080        // All encodable structs automagically implement the Emittable trait
2081        // TODO: Remove this when we have the `Encode / Decode` trait.
2082        if self.is_std_trait(db, EMITTABLE_TRAIT_NAME) && ty.is_emittable(db) {
2083            return true;
2084        }
2085
2086        db.all_impls(ty).iter().any(|val| &val.trait_id(db) == self)
2087    }
2088
2089    pub fn is_in_std(&self, db: &dyn AnalyzerDb) -> bool {
2090        self.module(db).is_in_std(db)
2091    }
2092
2093    pub fn is_std_trait(&self, db: &dyn AnalyzerDb, name: &str) -> bool {
2094        self.is_in_std(db) && self.name(db).to_lowercase() == name.to_lowercase()
2095    }
2096
2097    pub fn parent(&self, db: &dyn AnalyzerDb) -> Item {
2098        Item::Module(self.data(db).module)
2099    }
2100    pub fn all_functions(&self, db: &dyn AnalyzerDb) -> Rc<[FunctionSigId]> {
2101        db.trait_all_functions(*self)
2102    }
2103
2104    pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionSigId>> {
2105        db.trait_function_map(*self).value
2106    }
2107
2108    pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
2109        self.functions(db).get(name).copied()
2110    }
2111
2112    pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
2113        db.trait_all_functions(*self)
2114            .iter()
2115            .for_each(|id| id.sink_diagnostics(db, sink));
2116    }
2117}
2118
2119pub trait DiagnosticSink {
2120    fn push(&mut self, diag: &Diagnostic);
2121    fn push_all<'a>(&mut self, iter: impl Iterator<Item = &'a Diagnostic>) {
2122        iter.for_each(|diag| self.push(diag))
2123    }
2124}
2125
2126impl DiagnosticSink for Vec<Diagnostic> {
2127    fn push(&mut self, diag: &Diagnostic) {
2128        self.push(diag.clone())
2129    }
2130    fn push_all<'a>(&mut self, iter: impl Iterator<Item = &'a Diagnostic>) {
2131        self.extend(iter.cloned())
2132    }
2133}
2134
2135pub type DepGraph = petgraph::graphmap::DiGraphMap<Item, DepLocality>;
2136#[derive(Debug, Clone)]
2137pub struct DepGraphWrapper(pub Rc<DepGraph>);
2138impl PartialEq for DepGraphWrapper {
2139    fn eq(&self, other: &DepGraphWrapper) -> bool {
2140        self.0.all_edges().eq(other.0.all_edges()) && self.0.nodes().eq(other.0.nodes())
2141    }
2142}
2143impl Eq for DepGraphWrapper {}
2144
2145/// [`DepGraph`] edge label. "Locality" refers to the deployed state;
2146/// `Local` dependencies are those that will be compiled together, while
2147/// `External` dependencies will only be reachable via an evm CALL* op.
2148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2149pub enum DepLocality {
2150    Local,
2151    External,
2152}
2153
2154pub fn walk_local_dependencies<F>(graph: &DepGraph, root: Item, mut fun: F)
2155where
2156    F: FnMut(Item),
2157{
2158    use petgraph::visit::{Bfs, EdgeFiltered};
2159
2160    let mut bfs = Bfs::new(
2161        &EdgeFiltered::from_fn(graph, |(_, _, loc)| *loc == DepLocality::Local),
2162        root,
2163    );
2164    while let Some(node) = bfs.next(graph) {
2165        fun(node)
2166    }
2167}