1use std::{
2 collections::{HashMap, HashSet},
3 fmt::Display,
4 fs,
5 sync::Arc,
6};
7
8use graph_cycles::Cycles;
9use indexmap::IndexMap;
10use itertools::Itertools;
11use sway_error::{
12 error::CompileError,
13 handler::{ErrorEmitted, Handler},
14 warning::{CompileWarning, Warning},
15};
16use sway_features::Feature;
17use sway_types::{BaseIdent, Named, SourceId, Span, Spanned};
18
19use crate::{
20 decl_engine::{DeclEngineGet, DeclId},
21 engine_threading::{DebugWithEngines, PartialEqWithEngines, PartialEqWithEnginesContext},
22 is_ty_module_cache_up_to_date,
23 language::{
24 parsed::*,
25 ty::{self, TyAstNodeContent, TyDecl, TyEnumDecl},
26 CallPath, ModName,
27 },
28 query_engine::{ModuleCacheKey, TypedModuleInfo},
29 semantic_analysis::*,
30 transform::AttributeKind,
31 BuildConfig, Engines, TypeInfo,
32};
33
34use super::{
35 declaration::auto_impl::{
36 abi_encoding::AbiEncodingAutoImplContext, debug::DebugAutoImplContext,
37 marker_traits::MarkerTraitsAutoImplContext,
38 },
39 symbol_collection_context::SymbolCollectionContext,
40};
41
42#[derive(Clone, Debug)]
43pub struct ModuleDepGraphEdge();
44
45impl Display for ModuleDepGraphEdge {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(f, "")
48 }
49}
50
51pub type ModuleDepGraphNodeId = petgraph::graph::NodeIndex;
52
53#[derive(Clone, Debug)]
54pub enum ModuleDepGraphNode {
55 Module {},
56 Submodule { name: ModName },
57}
58
59impl DebugWithEngines for ModuleDepGraphNode {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>, _engines: &Engines) -> std::fmt::Result {
61 let text = match self {
62 ModuleDepGraphNode::Module { .. } => {
63 format!("{:?}", "Root module")
64 }
65 ModuleDepGraphNode::Submodule { name: mod_name } => {
66 format!("{:?}", mod_name.as_str())
67 }
68 };
69 f.write_str(&text)
70 }
71}
72
73pub type ModuleDepNodeGraph = petgraph::graph::DiGraph<ModuleDepGraphNode, ModuleDepGraphEdge>;
75
76pub struct ModuleDepGraph {
77 dep_graph: ModuleDepNodeGraph,
78 root: ModuleDepGraphNodeId,
79 node_name_map: HashMap<String, ModuleDepGraphNodeId>,
80}
81
82impl ModuleDepGraph {
83 pub(crate) fn new() -> Self {
84 Self {
85 dep_graph: Default::default(),
86 root: Default::default(),
87 node_name_map: Default::default(),
88 }
89 }
90
91 pub fn add_node(&mut self, node: ModuleDepGraphNode) -> ModuleDepGraphNodeId {
92 let node_id = self.dep_graph.add_node(node.clone());
93 match node {
94 ModuleDepGraphNode::Module {} => {}
95 ModuleDepGraphNode::Submodule { name: mod_name } => {
96 self.node_name_map.insert(mod_name.to_string(), node_id);
97 }
98 };
99 node_id
100 }
101
102 pub fn add_root_node(&mut self) -> ModuleDepGraphNodeId {
103 self.root = self.add_node(super::module::ModuleDepGraphNode::Module {});
104 self.root
105 }
106
107 fn get_node_id_for_module(
108 &self,
109 mod_name: &sway_types::BaseIdent,
110 ) -> Option<ModuleDepGraphNodeId> {
111 self.node_name_map.get(&mod_name.to_string()).copied()
112 }
113
114 #[allow(dead_code)]
116 pub(crate) fn visualize(&self, engines: &Engines, print_graph: Option<String>) {
117 if let Some(graph_path) = print_graph {
118 use petgraph::dot::{Config, Dot};
119 let string_graph = self.dep_graph.filter_map(
120 |_idx, node| Some(format!("{:?}", engines.help_out(node))),
121 |_idx, edge| Some(format!("{}", edge)),
122 );
123
124 let output = format!(
125 "{:?}",
126 Dot::with_attr_getters(
127 &string_graph,
128 &[Config::NodeNoLabel, Config::EdgeNoLabel],
129 &|_, er| format!("label = {:?}", er.weight()),
130 &|_, nr| {
131 let _node = &self.dep_graph[nr.0];
132 let shape = "";
133 let url = "".to_string();
134 format!("{shape} label = {:?} {url}", nr.1)
135 },
136 )
137 );
138
139 if graph_path.is_empty() {
140 tracing::info!("{output}");
141 } else {
142 let result = fs::write(graph_path.clone(), output);
143 if let Some(error) = result.err() {
144 tracing::error!(
145 "There was an issue while outputting module dep analysis graph to path {graph_path:?}\n{error}"
146 );
147 }
148 }
149 }
150 }
151
152 pub(crate) fn compute_order(
156 &self,
157 handler: &Handler,
158 ) -> Result<ModuleEvaluationOrder, ErrorEmitted> {
159 let cycles = self.dep_graph.cycles();
161 if !cycles.is_empty() {
162 let mut modules = Vec::new();
163 for cycle in cycles.first().unwrap() {
164 let node = self.dep_graph.node_weight(*cycle).unwrap();
165 match node {
166 ModuleDepGraphNode::Module {} => unreachable!(),
167 ModuleDepGraphNode::Submodule { name } => modules.push(name.clone()),
168 };
169 }
170 return Err(handler.emit_err(CompileError::ModuleDepGraphCyclicReference { modules }));
171 }
172
173 let sorted = match petgraph::algo::toposort(&self.dep_graph, None) {
175 Ok(value) => value,
176 Err(_) => return Err(handler.emit_err(CompileError::ModuleDepGraphEvaluationError {})),
180 };
181
182 let sorted = sorted
183 .into_iter()
184 .filter_map(|node_index| {
185 let node = self.dep_graph.node_weight(node_index);
186 match node {
187 Some(node) => match node {
188 ModuleDepGraphNode::Module {} => None, ModuleDepGraphNode::Submodule { name: mod_name } => Some(mod_name.clone()),
190 },
191 None => None,
192 }
193 })
194 .rev()
195 .collect::<Vec<_>>();
196
197 Ok(sorted)
198 }
199}
200
201impl ty::TyModule {
202 pub fn build_dep_graph(
204 handler: &Handler,
205 parsed: &ParseModule,
206 ) -> Result<ModuleDepGraph, ErrorEmitted> {
207 let mut dep_graph = ModuleDepGraph::new();
208 dep_graph.add_root_node();
209
210 let ParseModule { submodules, .. } = parsed;
211
212 submodules.iter().for_each(|(name, _submodule)| {
214 let sub_mod_node =
215 dep_graph.add_node(ModuleDepGraphNode::Submodule { name: name.clone() });
216 dep_graph
217 .dep_graph
218 .add_edge(dep_graph.root, sub_mod_node, ModuleDepGraphEdge {});
219 });
220
221 submodules.iter().for_each(|(name, submodule)| {
223 let _ =
224 ty::TySubmodule::build_dep_graph(handler, &mut dep_graph, name.clone(), submodule);
225 });
226
227 Ok(dep_graph)
228 }
229
230 pub fn collect(
234 handler: &Handler,
235 engines: &Engines,
236 ctx: &mut SymbolCollectionContext,
237 parsed: &ParseModule,
238 ) -> Result<(), ErrorEmitted> {
239 let ParseModule {
240 submodules,
241 tree,
242 module_eval_order,
243 attributes: _,
244 span: _,
245 hash: _,
246 ..
247 } = parsed;
248
249 module_eval_order.iter().for_each(|eval_mod_name| {
251 let (name, submodule) = submodules
252 .iter()
253 .find(|(submod_name, _submodule)| eval_mod_name == submod_name)
254 .unwrap();
255 let _ = ty::TySubmodule::collect(handler, engines, ctx, name.clone(), submodule);
256 });
257
258 let _ = tree
259 .root_nodes
260 .iter()
261 .map(|node| ty::TyAstNode::collect(handler, engines, ctx, node))
262 .filter_map(|res| res.ok())
263 .collect::<Vec<_>>();
264
265 Ok(())
266 }
267
268 fn get_cached_ty_module_if_up_to_date(
273 source_id: Option<&SourceId>,
274 engines: &Engines,
275 build_config: Option<&BuildConfig>,
276 ) -> Option<(Arc<ty::TyModule>, Arc<namespace::Module>)> {
277 let source_id = source_id?;
278
279 let path = engines.se().get_path(source_id);
281 let include_tests = build_config.is_some_and(|x| x.include_tests);
282 let key = ModuleCacheKey::new(path.clone().into(), include_tests);
283 let cache = engines.qe().module_cache.read();
284 cache.get(&key).and_then(|entry| {
285 entry.typed.as_ref().and_then(|typed| {
286 let is_up_to_date = is_ty_module_cache_up_to_date(
288 engines,
289 &path.into(),
290 include_tests,
291 build_config,
292 );
293
294 if is_up_to_date {
296 Some((typed.module.clone(), typed.namespace_module.clone()))
297 } else {
298 None
299 }
300 })
301 })
302 }
303
304 pub fn type_check(
308 handler: &Handler,
309 mut ctx: TypeCheckContext,
310 engines: &Engines,
311 kind: TreeType,
312 parsed: &ParseModule,
313 build_config: Option<&BuildConfig>,
314 ) -> Result<Arc<Self>, ErrorEmitted> {
315 let ParseModule {
316 submodules,
317 tree,
318 attributes,
319 span,
320 module_eval_order,
321 ..
322 } = parsed;
323
324 if let Some((ty_module, _namespace_module)) =
326 ty::TyModule::get_cached_ty_module_if_up_to_date(
327 parsed.span.source_id(),
328 engines,
329 build_config,
330 )
331 {
332 return Ok(ty_module);
333 }
334
335 let submodules_res = module_eval_order
337 .iter()
338 .map(|eval_mod_name| {
339 let (name, submodule) = submodules
340 .iter()
341 .find(|(submod_name, _)| eval_mod_name == submod_name)
342 .unwrap();
343
344 if let Some(cached_module) = ty::TyModule::get_cached_ty_module_if_up_to_date(
346 submodule.module.span.source_id(),
347 engines,
348 build_config,
349 ) {
350 let (ty_module, namespace_module) = cached_module;
352 ctx.namespace_mut()
353 .current_module_mut()
354 .import_cached_submodule(name, (*namespace_module).clone());
355
356 let ty_submod = ty::TySubmodule {
357 module: ty_module,
358 mod_name_span: submodule.mod_name_span.clone(),
359 };
360 Ok::<(BaseIdent, ty::TySubmodule), ErrorEmitted>((name.clone(), ty_submod))
361 } else {
362 let type_checked_submodule = ty::TySubmodule::type_check(
364 handler,
365 ctx.by_ref(),
366 engines,
367 name.clone(),
368 kind,
369 submodule,
370 build_config,
371 )?;
372 Ok((name.clone(), type_checked_submodule))
373 }
374 })
375 .collect::<Result<Vec<_>, _>>();
376
377 let ordered_nodes = node_dependencies::order_ast_nodes_by_dependency(
379 handler,
380 ctx.engines(),
381 tree.root_nodes.clone(),
382 )?;
383
384 let mut all_nodes = Self::type_check_nodes(handler, ctx.by_ref(), &ordered_nodes)?;
385 let submodules = submodules_res?;
386
387 let fallback_fn = collect_fallback_fn(&all_nodes, engines, handler)?;
388 match (&kind, &fallback_fn) {
389 (TreeType::Contract, _) | (_, None) => {}
390 (_, Some(fallback_fn)) => {
391 let fallback_fn = engines.de().get(fallback_fn);
392 return Err(handler.emit_err(CompileError::FallbackFnsAreContractOnly {
393 span: fallback_fn.span.clone(),
394 }));
395 }
396 }
397
398 if ctx.experimental.new_encoding {
399 let main_decl = all_nodes.iter_mut().find_map(|x| match &mut x.content {
400 ty::TyAstNodeContent::Declaration(ty::TyDecl::FunctionDecl(decl)) => {
401 let fn_decl = engines.de().get_function(&decl.decl_id);
402 (fn_decl.name.as_str() == "main").then_some(fn_decl)
403 }
404 _ => None,
405 });
406
407 match (&kind, main_decl.is_some()) {
408 (TreeType::Predicate, true) => {
409 let mut fn_generator = AbiEncodingAutoImplContext::new(&mut ctx);
410 if let Ok(node) = fn_generator.generate_predicate_entry(
411 engines,
412 main_decl.as_ref().unwrap(),
413 handler,
414 ) {
415 all_nodes.push(node)
416 }
417 }
418 (TreeType::Script, true) => {
419 let mut fn_generator = AbiEncodingAutoImplContext::new(&mut ctx);
420 if let Ok(node) = fn_generator.generate_script_entry(
421 engines,
422 main_decl.as_ref().unwrap(),
423 handler,
424 ) {
425 all_nodes.push(node)
426 }
427 }
428 (TreeType::Contract, _) => {
429 let contract_supertrait_fns = submodules
431 .iter()
432 .flat_map(|x| x.1.module.submodules_recursive())
433 .flat_map(|x| x.1.module.contract_supertrait_fns(engines))
434 .chain(
435 all_nodes
436 .iter()
437 .flat_map(|x| x.contract_supertrait_fns(engines)),
438 )
439 .collect::<Vec<_>>();
440
441 let mut contract_fns = submodules
443 .iter()
444 .flat_map(|x| x.1.module.submodules_recursive())
445 .flat_map(|x| x.1.module.contract_fns(engines))
446 .chain(all_nodes.iter().flat_map(|x| x.contract_fns(engines)))
447 .collect::<Vec<_>>();
448
449 let partialeq_ctx = PartialEqWithEnginesContext::new(engines);
451 contract_fns.retain(|method| {
452 contract_supertrait_fns
453 .iter()
454 .all(|si| !PartialEqWithEngines::eq(method, si, &partialeq_ctx))
455 });
456
457 let mut fn_generator = AbiEncodingAutoImplContext::new(&mut ctx);
458 if let Ok(node) = fn_generator.generate_contract_entry(
459 engines,
460 parsed.span.source_id(),
461 &contract_fns,
462 fallback_fn,
463 handler,
464 ) {
465 all_nodes.push(node)
466 }
467 }
468 _ => {}
469 }
470 }
471
472 #[allow(clippy::arc_with_non_send_sync)]
473 let ty_module = Arc::new(Self {
474 span: span.clone(),
475 submodules,
476 all_nodes,
477 attributes: attributes.clone(),
478 });
479
480 if let Some(source_id) = span.source_id() {
482 let path = engines.se().get_path(source_id);
483 let version = build_config
484 .and_then(|config| config.lsp_mode.as_ref())
485 .and_then(|lsp| lsp.file_versions.get(&path).copied())
486 .flatten();
487
488 let include_tests = build_config.is_some_and(|x| x.include_tests);
489 let key = ModuleCacheKey::new(path.clone().into(), include_tests);
490 engines.qe().update_typed_module_cache_entry(
491 &key,
492 TypedModuleInfo {
493 module: ty_module.clone(),
494 namespace_module: Arc::new(ctx.namespace().current_module().clone()),
495 version,
496 },
497 );
498 }
499
500 Ok(ty_module)
501 }
502
503 fn get_all_impls(
505 ctx: TypeCheckContext<'_>,
506 nodes: &[AstNode],
507 predicate: fn(&ImplSelfOrTrait) -> bool,
508 ) -> HashMap<BaseIdent, HashSet<CallPath>> {
509 let engines = ctx.engines();
510 let mut impls = HashMap::<BaseIdent, HashSet<CallPath>>::new();
511
512 for node in nodes.iter() {
513 if let AstNodeContent::Declaration(Declaration::ImplSelfOrTrait(decl_id)) =
514 &node.content
515 {
516 let decl = &*engines.pe().get_impl_self_or_trait(decl_id);
517 let implementing_for = ctx.engines.te().get(decl.implementing_for.type_id());
518 let implementing_for = match &*implementing_for {
519 TypeInfo::Struct(decl_id) => {
520 Some(ctx.engines().de().get(decl_id).name().clone())
521 }
522 TypeInfo::Enum(decl) => Some(ctx.engines().de().get(decl).name().clone()),
523 TypeInfo::Custom {
524 qualified_call_path,
525 ..
526 } => Some(qualified_call_path.call_path.suffix.clone()),
527 _ => None,
528 };
529
530 if let Some(implementing_for) = implementing_for {
531 if predicate(decl) {
532 impls
533 .entry(implementing_for)
534 .or_default()
535 .insert(decl.trait_name.clone());
536 }
537 }
538 }
539 }
540
541 impls
542 }
543
544 fn type_check_nodes(
545 handler: &Handler,
546 mut ctx: TypeCheckContext,
547 nodes: &[AstNode],
548 ) -> Result<Vec<ty::TyAstNode>, ErrorEmitted> {
549 let engines = ctx.engines();
550
551 let all_abi_encode_impls = Self::get_all_impls(ctx.by_ref(), nodes, |decl| {
555 decl.trait_name.suffix.as_str() == "AbiEncode"
556 });
557 let all_debug_impls = Self::get_all_impls(ctx.by_ref(), nodes, |decl| {
558 decl.trait_name.suffix.as_str() == "Debug"
559 });
560
561 let mut typed_nodes = vec![];
562 for node in nodes {
563 let (auto_impl_encoding_traits, auto_impl_debug_traits) = match &node.content {
565 AstNodeContent::Declaration(Declaration::StructDeclaration(decl_id)) => {
566 let decl = ctx.engines().pe().get_struct(decl_id);
567 (
568 !all_abi_encode_impls.contains_key(&decl.name),
569 !all_debug_impls.contains_key(&decl.name),
570 )
571 }
572 AstNodeContent::Declaration(Declaration::EnumDeclaration(decl_id)) => {
573 let decl = ctx.engines().pe().get_enum(decl_id);
574 (
575 !all_abi_encode_impls.contains_key(&decl.name),
576 !all_debug_impls.contains_key(&decl.name),
577 )
578 }
579 _ => (false, false),
580 };
581
582 let Ok(node) = ty::TyAstNode::type_check(handler, ctx.by_ref(), node) else {
583 continue;
584 };
585
586 let mut generated = vec![];
588 if ctx.experimental.new_encoding {
589 if let (true, mut ctx) = (
590 auto_impl_encoding_traits,
591 AbiEncodingAutoImplContext::new(&mut ctx),
592 ) {
593 match &node.content {
594 TyAstNodeContent::Declaration(decl @ TyDecl::StructDecl(_))
595 | TyAstNodeContent::Declaration(decl @ TyDecl::EnumDecl(_)) => {
596 let (abi_encode_impl, abi_decode_impl) =
597 ctx.generate_abi_encode_and_decode_impls(engines, decl);
598 generated.extend(abi_encode_impl);
599 generated.extend(abi_decode_impl);
600 }
601 _ => {}
602 }
603 };
604 }
605
606 if auto_impl_debug_traits {
608 match &node.content {
609 TyAstNodeContent::Declaration(decl @ TyDecl::StructDecl(_))
610 | TyAstNodeContent::Declaration(decl @ TyDecl::EnumDecl(_)) => {
611 let mut ctx = DebugAutoImplContext::new(&mut ctx);
612 let a = ctx.generate_debug_impl(engines, decl);
613 generated.extend(a);
614 }
615 _ => {}
616 }
617 }
618
619 if ctx.experimental.error_type {
622 let mut ctx = MarkerTraitsAutoImplContext::new(&mut ctx);
623 if let TyAstNodeContent::Declaration(TyDecl::EnumDecl(enum_decl)) = &node.content {
624 let enum_decl = &*ctx.engines().de().get(&enum_decl.decl_id);
625
626 let enum_marker_trait_impl =
627 ctx.generate_enum_marker_trait_impl(engines, enum_decl);
628 generated.extend(enum_marker_trait_impl);
629
630 if check_is_valid_error_type_enum(handler, enum_decl).is_ok_and(|res| res) {
631 let error_type_marker_trait_impl =
632 ctx.generate_error_type_marker_trait_impl_for_enum(engines, enum_decl);
633 generated.extend(error_type_marker_trait_impl);
634 }
635 }
636 } else {
637 if let TyAstNodeContent::Declaration(TyDecl::EnumDecl(enum_decl)) = &node.content {
639 let enum_decl = &*ctx.engines().de().get(&enum_decl.decl_id);
640 for attr in enum_decl.attributes.of_kind(AttributeKind::ErrorType) {
641 handler.emit_err(CompileError::FeatureIsDisabled {
642 feature: Feature::ErrorType.name().to_string(),
643 url: Feature::ErrorType.url().to_string(),
644 span: attr.name.span(),
645 });
646 }
647
648 for attr in enum_decl
649 .variants
650 .iter()
651 .flat_map(|variant| variant.attributes.of_kind(AttributeKind::Error))
652 {
653 handler.emit_err(CompileError::FeatureIsDisabled {
654 feature: Feature::ErrorType.name().to_string(),
655 url: Feature::ErrorType.url().to_string(),
656 span: attr.name.span(),
657 });
658 }
659 }
660 }
661
662 typed_nodes.push(node);
663 typed_nodes.extend(generated);
664 }
665
666 Ok(typed_nodes)
667 }
668}
669
670fn check_is_valid_error_type_enum(
673 handler: &Handler,
674 enum_decl: &TyEnumDecl,
675) -> Result<bool, ErrorEmitted> {
676 let has_error_type_attribute = enum_decl.attributes.has_error_type();
677
678 if has_error_type_attribute && enum_decl.variants.is_empty() {
679 handler.emit_warn(CompileWarning {
680 span: enum_decl.name().span(),
681 warning_content: Warning::ErrorTypeEmptyEnum {
682 enum_name: enum_decl.name().into(),
683 },
684 });
685 }
686
687 let mut duplicated_error_messages = IndexMap::<&str, Vec<Span>>::new();
690 for (enum_variant_name, error_attr) in enum_decl.variants.iter().flat_map(|variant| {
691 variant
692 .attributes
693 .error()
694 .map(|error_attr| (&variant.name, error_attr))
695 }) {
696 error_attr.check_args_multiplicity(handler)?;
697 assert_eq!(
698 (1usize, 1usize),
699 (&error_attr.args_multiplicity()).into(),
700 "`#[error]` attribute must have argument multiplicity of exactly one"
701 );
702
703 let m_arg = &error_attr.args[0];
704 let error_msg = m_arg.get_string(handler, error_attr)?;
705
706 if error_msg.is_empty() {
707 handler.emit_warn(CompileWarning {
708 span: m_arg
709 .value
710 .as_ref()
711 .expect("`m` argument has a valid empty string value")
712 .span(),
713 warning_content: Warning::ErrorEmptyErrorMessage {
714 enum_name: enum_decl.name().clone(),
715 enum_variant_name: enum_variant_name.clone(),
716 },
717 });
718 } else {
719 duplicated_error_messages
722 .entry(error_msg)
723 .or_default()
724 .push(
725 m_arg
726 .value
727 .as_ref()
728 .expect("`m` argument has a valid empty string value")
729 .span(),
730 );
731 }
732 }
733
734 for duplicated_error_messages in duplicated_error_messages
736 .into_values()
737 .filter(|spans| spans.len() > 1)
738 {
739 let (last_occurrence, previous_occurrences) = duplicated_error_messages
740 .split_last()
741 .expect("`duplicated_error_messages` has more then one element");
742 handler.emit_warn(CompileWarning {
743 span: last_occurrence.clone(),
744 warning_content: Warning::ErrorDuplicatedErrorMessage {
745 last_occurrence: last_occurrence.clone(),
746 previous_occurrences: previous_occurrences.into(),
747 },
748 });
749 }
750
751 handler.scope(|handler| {
752 if has_error_type_attribute {
753 let non_error_variants = enum_decl
754 .variants
755 .iter()
756 .filter(|variant| !variant.attributes.has_error())
757 .collect_vec();
758 if !non_error_variants.is_empty() {
759 handler.emit_err(CompileError::ErrorTypeEnumHasNonErrorVariants {
760 enum_name: enum_decl.name().into(),
761 non_error_variants: non_error_variants
762 .iter()
763 .map(|variant| (&variant.name).into())
764 .collect(),
765 });
766 }
767 } else {
768 for variant in enum_decl
769 .variants
770 .iter()
771 .filter(|variant| variant.attributes.has_error())
772 {
773 handler.emit_err(CompileError::ErrorAttributeInNonErrorEnum {
774 enum_name: enum_decl.name().into(),
775 enum_variant_name: (&variant.name).into(),
776 });
777 }
778 }
779
780 Ok(())
781 })?;
782
783 Ok(has_error_type_attribute)
784}
785
786fn collect_fallback_fn(
787 all_nodes: &[ty::TyAstNode],
788 engines: &Engines,
789 handler: &Handler,
790) -> Result<Option<DeclId<ty::TyFunctionDecl>>, ErrorEmitted> {
791 let mut fallback_fns = all_nodes
792 .iter()
793 .filter_map(|x| match &x.content {
794 ty::TyAstNodeContent::Declaration(ty::TyDecl::FunctionDecl(decl)) => {
795 let d = engines.de().get(&decl.decl_id);
796 d.is_fallback().then_some(decl.decl_id)
797 }
798 _ => None,
799 })
800 .collect::<Vec<_>>();
801
802 let mut last_error = None;
803 for f in fallback_fns.iter().skip(1) {
804 let decl = engines.de().get(f);
805 last_error = Some(
806 handler.emit_err(CompileError::MultipleDefinitionsOfFallbackFunction {
807 name: decl.name.clone(),
808 span: decl.span.clone(),
809 }),
810 );
811 }
812
813 if let Some(last_error) = last_error {
814 return Err(last_error);
815 }
816
817 if let Some(fallback_fn) = fallback_fns.pop() {
818 let f = engines.de().get(&fallback_fn);
819 if !f.parameters.is_empty() {
820 Err(
821 handler.emit_err(CompileError::FallbackFnsCannotHaveParameters {
822 span: f.span.clone(),
823 }),
824 )
825 } else {
826 Ok(Some(fallback_fn))
827 }
828 } else {
829 Ok(None)
830 }
831}
832
833impl ty::TySubmodule {
834 pub fn build_dep_graph(
835 _handler: &Handler,
836 module_dep_graph: &mut ModuleDepGraph,
837 mod_name: ModName,
838 submodule: &ParseSubmodule,
839 ) -> Result<(), ErrorEmitted> {
840 let ParseSubmodule { module, .. } = submodule;
841 let sub_mod_node = module_dep_graph.get_node_id_for_module(&mod_name).unwrap();
842 for node in module.tree.root_nodes.iter() {
843 match &node.content {
844 AstNodeContent::UseStatement(use_stmt) => {
845 if let Some(use_mod_ident) = use_stmt.call_path.first() {
846 if let Some(mod_name_node) =
847 module_dep_graph.get_node_id_for_module(use_mod_ident)
848 {
849 if sub_mod_node != mod_name_node {
852 module_dep_graph.dep_graph.add_edge(
853 sub_mod_node,
854 mod_name_node,
855 ModuleDepGraphEdge {},
856 );
857 }
858 }
859 }
860 }
861 AstNodeContent::Declaration(_) => {}
862 AstNodeContent::Expression(_) => {}
863 AstNodeContent::IncludeStatement(_) => {}
864 AstNodeContent::Error(_, _) => {}
865 }
866 }
867 Ok(())
868 }
869
870 pub fn collect(
871 handler: &Handler,
872 engines: &Engines,
873 parent_ctx: &mut SymbolCollectionContext,
874 mod_name: ModName,
875 submodule: &ParseSubmodule,
876 ) -> Result<(), ErrorEmitted> {
877 let ParseSubmodule {
878 module,
879 mod_name_span: _,
880 visibility,
881 } = submodule;
882 parent_ctx.enter_submodule(
883 handler,
884 engines,
885 mod_name,
886 *visibility,
887 module.span.clone(),
888 |submod_ctx| ty::TyModule::collect(handler, engines, submod_ctx, module),
889 )?
890 }
891
892 pub fn type_check(
893 handler: &Handler,
894 mut parent_ctx: TypeCheckContext,
895 engines: &Engines,
896 mod_name: ModName,
897 kind: TreeType,
898 submodule: &ParseSubmodule,
899 build_config: Option<&BuildConfig>,
900 ) -> Result<Self, ErrorEmitted> {
901 let ParseSubmodule {
902 module,
903 mod_name_span,
904 visibility,
905 } = submodule;
906 parent_ctx.enter_submodule(
907 handler,
908 mod_name,
909 *visibility,
910 module.span.clone(),
911 |submod_ctx| {
912 let module_res = ty::TyModule::type_check(
913 handler,
914 submod_ctx,
915 engines,
916 kind,
917 module,
918 build_config,
919 );
920 module_res.map(|module| ty::TySubmodule {
921 module,
922 mod_name_span: mod_name_span.clone(),
923 })
924 },
925 )?
926 }
927}