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