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#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, Copy)]
29pub enum Item {
30 Ingot(IngotId),
31 Module(ModuleId),
32 Type(TypeDef),
33 GenericType(GenericType),
37 Trait(TraitId),
38 Impl(ImplId),
39 Function(FunctionId),
40 Constant(ModuleConstantId),
41 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 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 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 Main,
309 Lib,
311 StandaloneModule,
313}
314
315#[derive(Debug, PartialEq, Eq, Hash, Clone)]
319pub struct Ingot {
320 pub name: SmolStr,
321 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 let file_path_prefix = if files.len() == 1 {
395 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 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 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!(), };
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 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#[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 pub fn all_items(&self, db: &dyn AnalyzerDb) -> Rc<[Item]> {
575 db.module_all_items(*self)
576 }
577
578 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 pub fn items(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, Item>> {
589 db.module_item_map(*self).value
590 }
591
592 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 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 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 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 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 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 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 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 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 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 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 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 sink.push_all(db.module_item_map(*self).diagnostics.iter());
815
816 sink.push_all(db.module_impl_map(*self).diagnostics.iter());
818
819 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 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 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 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 pub fn functions(&self, db: &dyn AnalyzerDb) -> Rc<IndexMap<SmolStr, FunctionId>> {
1106 db.contract_function_map(*self).value
1107 }
1108
1109 pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionId> {
1112 self.functions(db).get(name).copied()
1113 }
1114
1115 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 pub fn dependency_graph(&self, db: &dyn AnalyzerDb) -> Rc<DepGraph> {
1129 db.contract_dependency_graph(*self).0
1130 }
1131
1132 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 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 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 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 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 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 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 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#[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}