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 let enum_codec_values_impl = ctx.generate_tables(engines, decl);
600 generated.extend(enum_codec_values_impl);
601 }
602 _ => {}
603 }
604 };
605 }
606
607 if auto_impl_debug_traits {
609 match &node.content {
610 TyAstNodeContent::Declaration(decl @ TyDecl::StructDecl(_))
611 | TyAstNodeContent::Declaration(decl @ TyDecl::EnumDecl(_)) => {
612 let mut ctx = DebugAutoImplContext::new(&mut ctx);
613 let a = ctx.generate_debug_impl(engines, decl);
614 generated.extend(a);
615 }
616 _ => {}
617 }
618 }
619
620 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
637 typed_nodes.push(node);
638 typed_nodes.extend(generated);
639 }
640
641 Ok(typed_nodes)
642 }
643}
644
645fn check_is_valid_error_type_enum(
648 handler: &Handler,
649 enum_decl: &TyEnumDecl,
650) -> Result<bool, ErrorEmitted> {
651 let has_error_type_attribute = enum_decl.attributes.has_error_type();
652
653 if has_error_type_attribute && enum_decl.variants.is_empty() {
654 handler.emit_warn(CompileWarning {
655 span: enum_decl.name().span(),
656 warning_content: Warning::ErrorTypeEmptyEnum {
657 enum_name: enum_decl.name().into(),
658 },
659 });
660 }
661
662 let mut duplicated_error_messages = IndexMap::<&str, Vec<Span>>::new();
665 for (enum_variant_name, error_attr) in enum_decl.variants.iter().flat_map(|variant| {
666 variant
667 .attributes
668 .error()
669 .map(|error_attr| (&variant.name, error_attr))
670 }) {
671 error_attr.check_args_multiplicity(handler)?;
672 assert_eq!(
673 (1usize, 1usize),
674 (&error_attr.args_multiplicity()).into(),
675 "`#[error]` attribute must have argument multiplicity of exactly one"
676 );
677
678 let m_arg = &error_attr.args[0];
679 let error_msg = m_arg.get_string(handler, error_attr)?;
680
681 if error_msg.is_empty() {
682 handler.emit_warn(CompileWarning {
683 span: m_arg
684 .value
685 .as_ref()
686 .expect("`m` argument has a valid empty string value")
687 .span(),
688 warning_content: Warning::ErrorEmptyErrorMessage {
689 enum_name: enum_decl.name().clone(),
690 enum_variant_name: enum_variant_name.clone(),
691 },
692 });
693 } else {
694 duplicated_error_messages
697 .entry(error_msg)
698 .or_default()
699 .push(
700 m_arg
701 .value
702 .as_ref()
703 .expect("`m` argument has a valid empty string value")
704 .span(),
705 );
706 }
707 }
708
709 for duplicated_error_messages in duplicated_error_messages
711 .into_values()
712 .filter(|spans| spans.len() > 1)
713 {
714 let (last_occurrence, previous_occurrences) = duplicated_error_messages
715 .split_last()
716 .expect("`duplicated_error_messages` has more than one element");
717 handler.emit_warn(CompileWarning {
718 span: last_occurrence.clone(),
719 warning_content: Warning::ErrorDuplicatedErrorMessage {
720 last_occurrence: last_occurrence.clone(),
721 previous_occurrences: previous_occurrences.into(),
722 },
723 });
724 }
725
726 handler.scope(|handler| {
727 if has_error_type_attribute {
728 let non_error_variants = enum_decl
729 .variants
730 .iter()
731 .filter(|variant| !variant.attributes.has_error())
732 .collect_vec();
733 if !non_error_variants.is_empty() {
734 handler.emit_err(CompileError::ErrorTypeEnumHasNonErrorVariants {
735 enum_name: enum_decl.name().into(),
736 non_error_variants: non_error_variants
737 .iter()
738 .map(|variant| (&variant.name).into())
739 .collect(),
740 });
741 }
742 } else {
743 for variant in enum_decl
744 .variants
745 .iter()
746 .filter(|variant| variant.attributes.has_error())
747 {
748 handler.emit_err(CompileError::ErrorAttributeInNonErrorEnum {
749 enum_name: enum_decl.name().into(),
750 enum_variant_name: (&variant.name).into(),
751 });
752 }
753 }
754
755 Ok(())
756 })?;
757
758 Ok(has_error_type_attribute)
759}
760
761fn collect_fallback_fn(
762 all_nodes: &[ty::TyAstNode],
763 engines: &Engines,
764 handler: &Handler,
765) -> Result<Option<DeclId<ty::TyFunctionDecl>>, ErrorEmitted> {
766 let mut fallback_fns = all_nodes
767 .iter()
768 .filter_map(|x| match &x.content {
769 ty::TyAstNodeContent::Declaration(ty::TyDecl::FunctionDecl(decl)) => {
770 let d = engines.de().get(&decl.decl_id);
771 d.is_fallback().then_some(decl.decl_id)
772 }
773 _ => None,
774 })
775 .collect::<Vec<_>>();
776
777 let mut last_error = None;
778 for f in fallback_fns.iter().skip(1) {
779 let decl = engines.de().get(f);
780 last_error = Some(
781 handler.emit_err(CompileError::MultipleDefinitionsOfFallbackFunction {
782 name: decl.name.clone(),
783 span: decl.span.clone(),
784 }),
785 );
786 }
787
788 if let Some(last_error) = last_error {
789 return Err(last_error);
790 }
791
792 if let Some(fallback_fn) = fallback_fns.pop() {
793 let f = engines.de().get(&fallback_fn);
794 if !f.parameters.is_empty() {
795 Err(
796 handler.emit_err(CompileError::FallbackFnsCannotHaveParameters {
797 span: f.span.clone(),
798 }),
799 )
800 } else {
801 Ok(Some(fallback_fn))
802 }
803 } else {
804 Ok(None)
805 }
806}
807
808impl ty::TySubmodule {
809 pub fn build_dep_graph(
810 _handler: &Handler,
811 module_dep_graph: &mut ModuleDepGraph,
812 mod_name: ModName,
813 submodule: &ParseSubmodule,
814 ) -> Result<(), ErrorEmitted> {
815 let ParseSubmodule { module, .. } = submodule;
816 let sub_mod_node = module_dep_graph.get_node_id_for_module(&mod_name).unwrap();
817 for node in module.tree.root_nodes.iter() {
818 match &node.content {
819 AstNodeContent::UseStatement(use_stmt) => {
820 if let Some(use_mod_ident) = use_stmt.call_path.first() {
821 if let Some(mod_name_node) =
822 module_dep_graph.get_node_id_for_module(use_mod_ident)
823 {
824 if sub_mod_node != mod_name_node {
827 module_dep_graph.dep_graph.add_edge(
828 sub_mod_node,
829 mod_name_node,
830 ModuleDepGraphEdge {},
831 );
832 }
833 }
834 }
835 }
836 AstNodeContent::Declaration(_) => {}
837 AstNodeContent::Expression(_) => {}
838 AstNodeContent::IncludeStatement(_) => {}
839 AstNodeContent::Error(_, _) => {}
840 }
841 }
842 Ok(())
843 }
844
845 pub fn collect(
846 handler: &Handler,
847 engines: &Engines,
848 parent_ctx: &mut SymbolCollectionContext,
849 mod_name: ModName,
850 submodule: &ParseSubmodule,
851 ) -> Result<(), ErrorEmitted> {
852 let ParseSubmodule {
853 module,
854 mod_name_span: _,
855 visibility,
856 } = submodule;
857 parent_ctx.enter_submodule(
858 handler,
859 engines,
860 mod_name,
861 *visibility,
862 module.span.clone(),
863 |submod_ctx| ty::TyModule::collect(handler, engines, submod_ctx, module),
864 )?
865 }
866
867 pub fn type_check(
868 handler: &Handler,
869 mut parent_ctx: TypeCheckContext,
870 engines: &Engines,
871 mod_name: ModName,
872 kind: TreeType,
873 submodule: &ParseSubmodule,
874 build_config: Option<&BuildConfig>,
875 ) -> Result<Self, ErrorEmitted> {
876 let ParseSubmodule {
877 module,
878 mod_name_span,
879 visibility,
880 } = submodule;
881 parent_ctx.enter_submodule(
882 handler,
883 mod_name,
884 *visibility,
885 module.span.clone(),
886 |submod_ctx| {
887 let module_res = ty::TyModule::type_check(
888 handler,
889 submod_ctx,
890 engines,
891 kind,
892 module,
893 build_config,
894 );
895 module_res.map(|module| ty::TySubmodule {
896 module,
897 mod_name_span: mod_name_span.clone(),
898 })
899 },
900 )?
901 }
902}