sway_core/
lib.rs

1#![recursion_limit = "256"]
2
3#[macro_use]
4pub mod error;
5
6#[macro_use]
7pub mod engine_threading;
8
9pub mod abi_generation;
10pub mod asm_generation;
11mod asm_lang;
12mod build_config;
13pub mod compiler_generated;
14mod concurrent_slab;
15mod control_flow_analysis;
16mod debug_generation;
17pub mod decl_engine;
18pub mod ir_generation;
19pub mod language;
20pub mod marker_traits;
21mod metadata;
22pub mod obs_engine;
23pub mod query_engine;
24pub mod semantic_analysis;
25pub mod source_map;
26pub mod transform;
27pub mod type_system;
28
29use crate::ir_generation::check_function_purity;
30use crate::language::{CallPath, CallPathType};
31use crate::query_engine::ModuleCacheEntry;
32use crate::semantic_analysis::namespace::ResolvedDeclaration;
33use crate::semantic_analysis::type_resolve::{resolve_call_path, VisibilityCheck};
34use crate::source_map::SourceMap;
35pub use asm_generation::from_ir::compile_ir_context_to_finalized_asm;
36use asm_generation::FinalizedAsm;
37pub use asm_generation::{CompiledBytecode, FinalizedEntry};
38pub use build_config::DbgGeneration;
39pub use build_config::{
40    Backtrace, BuildConfig, BuildTarget, LspConfig, OptLevel, PrintAsm, PrintIr,
41};
42use control_flow_analysis::ControlFlowGraph;
43pub use debug_generation::write_dwarf;
44use itertools::Itertools;
45use metadata::MetadataManager;
46use query_engine::{ModuleCacheKey, ModuleCommonInfo, ParsedModuleInfo, ProgramsCacheEntry};
47use semantic_analysis::program::TypeCheckFailed;
48use std::collections::hash_map::DefaultHasher;
49use std::collections::HashMap;
50use std::hash::{Hash, Hasher};
51use std::path::{Path, PathBuf};
52use std::sync::atomic::{AtomicBool, Ordering};
53use std::sync::Arc;
54use sway_ast::AttributeDecl;
55use sway_error::convert_parse_tree_error::ConvertParseTreeError;
56use sway_error::handler::{ErrorEmitted, Handler};
57use sway_error::warning::{CollectedTraitImpl, CompileInfo, CompileWarning, Info, Warning};
58use sway_features::ExperimentalFeatures;
59use sway_ir::{
60    create_o1_pass_group, register_known_passes, Context, Kind, Module, PassGroup, PassManager,
61    PrintPassesOpts, ARG_DEMOTION_NAME, ARG_POINTEE_MUTABILITY_TAGGER_NAME, CONST_DEMOTION_NAME,
62    DCE_NAME, FN_DEDUP_DEBUG_PROFILE_NAME, FN_INLINE_NAME, GLOBALS_DCE_NAME, MEM2REG_NAME,
63    MEMCPYOPT_NAME, MISC_DEMOTION_NAME, RET_DEMOTION_NAME, SIMPLIFY_CFG_NAME, SROA_NAME,
64};
65use sway_types::span::Source;
66use sway_types::{SourceEngine, SourceLocation, Span};
67use sway_utils::{time_expr, PerformanceData, PerformanceMetric};
68use transform::{ArgsExpectValues, Attribute, AttributeKind, Attributes, ExpectedArgs};
69use types::{CollectTypesMetadata, CollectTypesMetadataContext, LogId, TypeMetadata};
70
71pub use semantic_analysis::namespace::{self, Namespace};
72pub mod types;
73
74use sway_error::error::CompileError;
75use sway_types::{ident::Ident, span, Spanned};
76pub use type_system::*;
77
78pub use language::Programs;
79use language::{lexed, parsed, ty, Visibility};
80use transform::to_parsed_lang::{self, convert_module_kind};
81
82pub mod fuel_prelude {
83    pub use fuel_vm::{self, fuel_asm, fuel_crypto, fuel_tx, fuel_types};
84}
85
86pub use engine_threading::Engines;
87pub use obs_engine::{ObservabilityEngine, Observer};
88
89/// Given an input `Arc<str>` and an optional [BuildConfig], parse the input into a [lexed::LexedProgram] and [parsed::ParseProgram].
90///
91/// # Example
92/// ```ignore
93/// # use sway_core::parse;
94/// # fn main() {
95///     let input = "script; fn main() -> bool { true }";
96///     let result = parse(input.into(), <_>::default(), None);
97/// # }
98/// ```
99///
100/// # Panics
101/// Panics if the parser panics.
102pub fn parse(
103    src: Source,
104    handler: &Handler,
105    engines: &Engines,
106    config: Option<&BuildConfig>,
107    experimental: ExperimentalFeatures,
108    package_name: &str,
109) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
110    match config {
111        None => parse_in_memory(
112            handler,
113            engines,
114            src,
115            experimental,
116            DbgGeneration::None,
117            package_name,
118        ),
119        // When a `BuildConfig` is given,
120        // the module source may declare `mod`s that must be parsed from other files.
121        Some(config) => parse_module_tree(
122            handler,
123            engines,
124            src,
125            config.canonical_root_module(),
126            None,
127            config.build_target,
128            config.dbg_generation,
129            config.include_tests,
130            experimental,
131            config.lsp_mode.as_ref(),
132            package_name,
133        )
134        .map(
135            |ParsedModuleTree {
136                 tree_type: kind,
137                 lexed_module,
138                 parse_module,
139             }| {
140                let lexed = lexed::LexedProgram {
141                    kind,
142                    root: lexed_module,
143                };
144                let parsed = parsed::ParseProgram {
145                    kind,
146                    root: parse_module,
147                };
148                (lexed, parsed)
149            },
150        ),
151    }
152}
153
154/// Parses the tree kind in the input provided.
155///
156/// This will lex the entire input, but parses only the module kind.
157pub fn parse_tree_type(handler: &Handler, src: Source) -> Result<parsed::TreeType, ErrorEmitted> {
158    // Parsing only the module kind does not depend on any
159    // experimental feature. So, we can just pass the default
160    // experimental features here.
161    let experimental = ExperimentalFeatures::default();
162    sway_parse::parse_module_kind(handler, src, None, experimental)
163        .map(|kind| convert_module_kind(&kind))
164}
165
166/// Converts `attribute_decls` to [Attributes].
167///
168/// This function always returns [Attributes], even if the attributes are erroneous.
169/// Errors and warnings are returned via [Handler]. The callers should ignore eventual errors
170/// in attributes and proceed with the compilation. [Attributes] are tolerant to erroneous
171/// attributes and follows the last-wins principle, which allows annotated elements to
172/// proceed with compilation. After their successful compilation, callers need to inspect
173/// the [Handler] and still emit errors if there were any.
174pub(crate) fn attr_decls_to_attributes(
175    attribute_decls: &[AttributeDecl],
176    can_annotate: impl Fn(&Attribute) -> bool,
177    target_friendly_name: &'static str,
178) -> (Handler, Attributes) {
179    let handler = Handler::default();
180    // Check if attribute is an unsupported inner attribute (`#!`).
181    // Note that we are doing that before creating the flattened `attributes`,
182    // because we want the error to point at the `#!` token.
183    // Note also that we will still include those attributes into
184    // the `attributes`. There are cases, like e.g., LSP, where
185    // having complete list of attributes is needed.
186    // In the below analysis, though, we will be ignoring inner attributes,
187    // means not checking their content.
188    for attr_decl in attribute_decls
189        .iter()
190        .filter(|attr| !attr.is_doc_comment() && attr.is_inner())
191    {
192        handler.emit_err(CompileError::Unimplemented {
193            span: attr_decl.hash_kind.span(),
194            feature: "Using inner attributes (`#!`)".to_string(),
195            help: vec![],
196        });
197    }
198
199    let attributes = Attributes::new(attribute_decls);
200
201    // Check for unknown attributes.
202    for attribute in attributes.unknown().filter(|attr| attr.is_outer()) {
203        handler.emit_warn(CompileWarning {
204            span: attribute.name.span(),
205            warning_content: Warning::UnknownAttribute {
206                attribute: (&attribute.name).into(),
207                known_attributes: attributes.known_attribute_names(),
208            },
209        });
210    }
211
212    // Check for attributes annotating invalid targets.
213    for ((attribute_kind, _attribute_direction), mut attributes) in &attributes
214        .all()
215        .filter(|attr| attr.is_doc_comment() || attr.is_outer())
216        .chunk_by(|attr| (attr.kind, attr.direction))
217    {
218        // For doc comments, we want to show the error on a complete doc comment,
219        // and not on every documentation line.
220        if attribute_kind == AttributeKind::DocComment {
221            let first_doc_line = attributes
222                .next()
223                .expect("`chunk_by` guarantees existence of at least one element in the chunk");
224            if !can_annotate(first_doc_line) {
225                let last_doc_line = match attributes.last() {
226                    Some(last_attr) => last_attr,
227                    // There is only one doc line in the complete doc comment.
228                    None => first_doc_line,
229                };
230                handler.emit_err(
231                    ConvertParseTreeError::InvalidAttributeTarget {
232                        span: Span::join(
233                            first_doc_line.span.clone(),
234                            &last_doc_line.span.start_span(),
235                        ),
236                        attribute: first_doc_line.name.clone(),
237                        target_friendly_name,
238                        can_only_annotate_help: first_doc_line
239                            .can_only_annotate_help(target_friendly_name),
240                    }
241                    .into(),
242                );
243            }
244        } else {
245            // For other attributes, the error is shown for every individual attribute.
246            for attribute in attributes {
247                if !can_annotate(attribute) {
248                    handler.emit_err(
249                        ConvertParseTreeError::InvalidAttributeTarget {
250                            span: attribute.name.span(),
251                            attribute: attribute.name.clone(),
252                            target_friendly_name,
253                            can_only_annotate_help: attribute
254                                .can_only_annotate_help(target_friendly_name),
255                        }
256                        .into(),
257                    );
258                }
259            }
260        }
261    }
262
263    // In all the subsequent test we are checking only non-doc-comment attributes
264    // and only those that didn't produce invalid target or unsupported inner attributes errors.
265    let should_be_checked =
266        |attr: &&Attribute| !attr.is_doc_comment() && attr.is_outer() && can_annotate(attr);
267
268    // Check for attributes multiplicity.
269    for (_attribute_kind, attributes_of_kind) in
270        attributes.all_by_kind(|attr| should_be_checked(attr) && !attr.kind.allows_multiple())
271    {
272        if attributes_of_kind.len() > 1 {
273            let (last_attribute, previous_attributes) = attributes_of_kind
274                .split_last()
275                .expect("`attributes_of_kind` has more than one element");
276            handler.emit_err(
277                ConvertParseTreeError::InvalidAttributeMultiplicity {
278                    last_occurrence: (&last_attribute.name).into(),
279                    previous_occurrences: previous_attributes
280                        .iter()
281                        .map(|attr| (&attr.name).into())
282                        .collect(),
283                }
284                .into(),
285            );
286        }
287    }
288
289    // Check for arguments multiplicity.
290    // For attributes that can be applied only once but are applied several times
291    // we will still check arguments in every attribute occurrence.
292    for attribute in attributes.all().filter(should_be_checked) {
293        let _ = attribute.check_args_multiplicity(&handler);
294    }
295
296    // Check for expected arguments.
297    // For attributes that can be applied only once but are applied more times
298    // we will check arguments of every attribute occurrence.
299    // If an attribute does not expect any arguments, we will not check them,
300    // but emit only the above error about invalid number of arguments.
301    for attribute in attributes
302        .all()
303        .filter(|attr| should_be_checked(attr) && attr.can_have_arguments())
304    {
305        match attribute.expected_args() {
306            ExpectedArgs::None => unreachable!("`attribute` can have arguments"),
307            ExpectedArgs::Any => {}
308            ExpectedArgs::MustBeIn(expected_args) => {
309                for arg in attribute.args.iter() {
310                    if !expected_args.contains(&arg.name.as_str()) {
311                        handler.emit_err(
312                            ConvertParseTreeError::InvalidAttributeArg {
313                                attribute: attribute.name.clone(),
314                                arg: (&arg.name).into(),
315                                expected_args: expected_args.clone(),
316                            }
317                            .into(),
318                        );
319                    }
320                }
321            }
322            ExpectedArgs::ShouldBeIn(expected_args) => {
323                for arg in attribute.args.iter() {
324                    if !expected_args.contains(&arg.name.as_str()) {
325                        handler.emit_warn(CompileWarning {
326                            span: arg.name.span(),
327                            warning_content: Warning::UnknownAttributeArg {
328                                attribute: attribute.name.clone(),
329                                arg: (&arg.name).into(),
330                                expected_args: expected_args.clone(),
331                            },
332                        });
333                    }
334                }
335            }
336        }
337    }
338
339    // Check for expected argument values.
340    // We use here the same logic for what to check, as in the above check
341    // for expected arguments.
342    for attribute in attributes
343        .all()
344        .filter(|attr| should_be_checked(attr) && attr.can_have_arguments())
345    {
346        // In addition, if an argument **must** be in expected args but is not,
347        // we will not be checking it, but only emit the error above.
348        // But if it **should** be in expected args and is not,
349        // we still impose on it the expectation coming from its attribute.
350        fn check_value_expected(handler: &Handler, attribute: &Attribute, is_value_expected: bool) {
351            for arg in attribute.args.iter() {
352                if let ExpectedArgs::MustBeIn(expected_args) = attribute.expected_args() {
353                    if !expected_args.contains(&arg.name.as_str()) {
354                        continue;
355                    }
356                }
357
358                if (is_value_expected && arg.value.is_none())
359                    || (!is_value_expected && arg.value.is_some())
360                {
361                    handler.emit_err(
362                        ConvertParseTreeError::InvalidAttributeArgExpectsValue {
363                            attribute: attribute.name.clone(),
364                            arg: (&arg.name).into(),
365                            value_span: arg.value.as_ref().map(|literal| literal.span()),
366                        }
367                        .into(),
368                    );
369                }
370            }
371        }
372
373        match attribute.args_expect_values() {
374            ArgsExpectValues::Yes => check_value_expected(&handler, attribute, true),
375            ArgsExpectValues::No => check_value_expected(&handler, attribute, false),
376            ArgsExpectValues::Maybe => {}
377        }
378    }
379
380    (handler, attributes)
381}
382
383/// When no `BuildConfig` is given, we're assumed to be parsing in-memory with no submodules.
384fn parse_in_memory(
385    handler: &Handler,
386    engines: &Engines,
387    src: Source,
388    experimental: ExperimentalFeatures,
389    dbg_generation: DbgGeneration,
390    package_name: &str,
391) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
392    let mut hasher = DefaultHasher::new();
393    src.text.hash(&mut hasher);
394    let hash = hasher.finish();
395    let module = sway_parse::parse_file(handler, src, None, experimental)?;
396
397    let (attributes_handler, attributes) = attr_decls_to_attributes(
398        &module.attributes,
399        |attr| attr.can_annotate_module_kind(),
400        module.value.kind.friendly_name(),
401    );
402    let attributes_error_emitted = handler.append(attributes_handler);
403
404    let (kind, tree) = to_parsed_lang::convert_parse_tree(
405        &mut to_parsed_lang::Context::new(
406            BuildTarget::EVM,
407            dbg_generation,
408            experimental,
409            package_name,
410        ),
411        handler,
412        engines,
413        module.value.clone(),
414    )?;
415
416    match attributes_error_emitted {
417        Some(err) => Err(err),
418        None => {
419            let root = parsed::ParseModule {
420                span: span::Span::dummy(),
421                module_kind_span: module.value.kind.span(),
422                module_eval_order: vec![],
423                tree,
424                submodules: vec![],
425                attributes,
426                hash,
427            };
428            let lexed_program = lexed::LexedProgram::new(
429                kind,
430                lexed::LexedModule {
431                    tree: module,
432                    submodules: vec![],
433                },
434            );
435            Ok((lexed_program, parsed::ParseProgram { kind, root }))
436        }
437    }
438}
439
440pub struct Submodule {
441    name: Ident,
442    path: Arc<PathBuf>,
443    lexed: lexed::LexedSubmodule,
444    parsed: parsed::ParseSubmodule,
445}
446
447/// Contains the lexed and parsed submodules 'deps' of a module.
448pub type Submodules = Vec<Submodule>;
449
450/// Parse all dependencies `deps` as submodules.
451#[allow(clippy::too_many_arguments)]
452fn parse_submodules(
453    handler: &Handler,
454    engines: &Engines,
455    module_name: Option<&str>,
456    module: &sway_ast::Module,
457    module_dir: &Path,
458    build_target: BuildTarget,
459    dbg_generation: DbgGeneration,
460    include_tests: bool,
461    experimental: ExperimentalFeatures,
462    lsp_mode: Option<&LspConfig>,
463    package_name: &str,
464) -> Submodules {
465    // Assume the happy path, so there'll be as many submodules as dependencies, but no more.
466    let mut submods = Vec::with_capacity(module.submodules().count());
467    module.submodules().for_each(|submod| {
468        // Read the source code from the dependency.
469        // If we cannot, record as an error, but continue with other files.
470        let submod_path = Arc::new(module_path(module_dir, module_name, submod));
471        let submod_src: Source = match std::fs::read_to_string(&*submod_path) {
472            Ok(s) => s.as_str().into(),
473            Err(e) => {
474                handler.emit_err(CompileError::FileCouldNotBeRead {
475                    span: submod.name.span(),
476                    file_path: submod_path.to_string_lossy().to_string(),
477                    stringified_error: e.to_string(),
478                });
479                return;
480            }
481        };
482        if let Ok(ParsedModuleTree {
483            tree_type: kind,
484            lexed_module,
485            parse_module,
486        }) = parse_module_tree(
487            handler,
488            engines,
489            submod_src.clone(),
490            submod_path.clone(),
491            Some(submod.name.as_str()),
492            build_target,
493            dbg_generation,
494            include_tests,
495            experimental,
496            lsp_mode,
497            package_name,
498        ) {
499            if !matches!(kind, parsed::TreeType::Library) {
500                let source_id = engines.se().get_source_id(submod_path.as_ref());
501                let span = span::Span::new(submod_src, 0, 0, Some(source_id)).unwrap();
502                handler.emit_err(CompileError::ImportMustBeLibrary { span });
503                return;
504            }
505
506            let parse_submodule = parsed::ParseSubmodule {
507                module: parse_module,
508                visibility: match submod.visibility {
509                    Some(..) => Visibility::Public,
510                    None => Visibility::Private,
511                },
512                mod_name_span: submod.name.span(),
513            };
514            let lexed_submodule = lexed::LexedSubmodule {
515                module: lexed_module,
516            };
517            let submodule = Submodule {
518                name: submod.name.clone(),
519                path: submod_path,
520                lexed: lexed_submodule,
521                parsed: parse_submodule,
522            };
523            submods.push(submodule);
524        }
525    });
526    submods
527}
528
529pub type SourceHash = u64;
530
531#[derive(Clone, Debug)]
532pub struct ParsedModuleTree {
533    pub tree_type: parsed::TreeType,
534    pub lexed_module: lexed::LexedModule,
535    pub parse_module: parsed::ParseModule,
536}
537
538/// Given the source of the module along with its path,
539/// parse this module including all of its submodules.
540#[allow(clippy::too_many_arguments)]
541fn parse_module_tree(
542    handler: &Handler,
543    engines: &Engines,
544    src: Source,
545    path: Arc<PathBuf>,
546    module_name: Option<&str>,
547    build_target: BuildTarget,
548    dbg_generation: DbgGeneration,
549    include_tests: bool,
550    experimental: ExperimentalFeatures,
551    lsp_mode: Option<&LspConfig>,
552    package_name: &str,
553) -> Result<ParsedModuleTree, ErrorEmitted> {
554    let query_engine = engines.qe();
555
556    // Parse this module first.
557    let module_dir = path.parent().expect("module file has no parent directory");
558    let source_id = engines.se().get_source_id(&path.clone());
559    // don't use reloaded file if we already have it in memory, that way new spans will still point to the same string
560    let src = engines.se().get_or_create_source_buffer(&source_id, src);
561    let module = sway_parse::parse_file(handler, src.clone(), Some(source_id), experimental)?;
562
563    // Parse all submodules before converting to the `ParseTree`.
564    // This always recovers on parse errors for the file itself by skipping that file.
565    let submodules = parse_submodules(
566        handler,
567        engines,
568        module_name,
569        &module.value,
570        module_dir,
571        build_target,
572        dbg_generation,
573        include_tests,
574        experimental,
575        lsp_mode,
576        package_name,
577    );
578
579    let (attributes_handler, attributes) = attr_decls_to_attributes(
580        &module.attributes,
581        |attr| attr.can_annotate_module_kind(),
582        module.value.kind.friendly_name(),
583    );
584    let attributes_error_emitted = handler.append(attributes_handler);
585
586    // Convert from the raw parsed module to the `ParseTree` ready for type-check.
587    let (kind, tree) = to_parsed_lang::convert_parse_tree(
588        &mut to_parsed_lang::Context::new(build_target, dbg_generation, experimental, package_name),
589        handler,
590        engines,
591        module.value.clone(),
592    )?;
593
594    if let Some(err) = attributes_error_emitted {
595        return Err(err);
596    }
597
598    let module_kind_span = module.value.kind.span();
599    let lexed_submodules = submodules
600        .iter()
601        .map(|s| (s.name.clone(), s.lexed.clone()))
602        .collect::<Vec<_>>();
603    let lexed = lexed::LexedModule {
604        tree: module,
605        submodules: lexed_submodules,
606    };
607
608    let mut hasher = DefaultHasher::new();
609    src.text.hash(&mut hasher);
610    let hash = hasher.finish();
611
612    let parsed_submodules = submodules
613        .iter()
614        .map(|s| (s.name.clone(), s.parsed.clone()))
615        .collect::<Vec<_>>();
616    let parsed = parsed::ParseModule {
617        span: span::Span::new(src, 0, 0, Some(source_id)).unwrap(),
618        module_kind_span,
619        module_eval_order: vec![],
620        tree,
621        submodules: parsed_submodules,
622        attributes,
623        hash,
624    };
625
626    // Let's prime the cache with the module dependency and hash data.
627    let modified_time = std::fs::metadata(path.as_path())
628        .ok()
629        .and_then(|m| m.modified().ok());
630    let dependencies = submodules.into_iter().map(|s| s.path).collect::<Vec<_>>();
631    let version = lsp_mode
632        .and_then(|lsp| lsp.file_versions.get(path.as_ref()).copied())
633        .unwrap_or(None);
634
635    let common_info = ModuleCommonInfo {
636        path: path.clone(),
637        include_tests,
638        dependencies,
639        hash,
640    };
641    let parsed_info = ParsedModuleInfo {
642        modified_time,
643        version,
644    };
645    let cache_entry = ModuleCacheEntry::new(common_info, parsed_info);
646    query_engine.update_or_insert_parsed_module_cache_entry(cache_entry);
647
648    Ok(ParsedModuleTree {
649        tree_type: kind,
650        lexed_module: lexed,
651        parse_module: parsed,
652    })
653}
654
655/// Checks if the typed module cache for a given path is up to date.
656///
657/// This function determines whether the cached typed representation of a module
658/// is still valid based on file versions and dependencies.
659///
660/// Note: This functionality is currently only supported when the compiler is
661/// initiated from the language server.
662pub(crate) fn is_ty_module_cache_up_to_date(
663    engines: &Engines,
664    path: &Arc<PathBuf>,
665    include_tests: bool,
666    build_config: Option<&BuildConfig>,
667) -> bool {
668    let cache = engines.qe().module_cache.read();
669    let key = ModuleCacheKey::new(path.clone(), include_tests);
670    cache.get(&key).is_some_and(|entry| {
671        entry.typed.as_ref().is_some_and(|typed| {
672            // Check if the cache is up to date based on file versions
673            let cache_up_to_date = build_config
674                .and_then(|x| x.lsp_mode.as_ref())
675                .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
676                .is_none_or(|version| {
677                    version.is_none_or(|v| typed.version.is_some_and(|tv| v <= tv))
678                });
679
680            // If the cache is up to date, recursively check all dependencies
681            cache_up_to_date
682                && entry.common.dependencies.iter().all(|dep_path| {
683                    is_ty_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
684                })
685        })
686    })
687}
688
689/// Checks if the parsed module cache for a given path is up to date.
690///
691/// This function determines whether the cached parsed representation of a module
692/// is still valid based on file versions, modification times, or content hashes.
693pub(crate) fn is_parse_module_cache_up_to_date(
694    engines: &Engines,
695    path: &Arc<PathBuf>,
696    include_tests: bool,
697    build_config: Option<&BuildConfig>,
698) -> bool {
699    let cache = engines.qe().module_cache.read();
700    let key = ModuleCacheKey::new(path.clone(), include_tests);
701    cache.get(&key).is_some_and(|entry| {
702        // Determine if the cached dependency information is still valid
703        let cache_up_to_date = build_config
704            .and_then(|x| x.lsp_mode.as_ref())
705            .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
706            .map_or_else(
707                || {
708                    // If LSP mode is not active or file version is unavailable, fall back to filesystem checks.
709                    let modified_time = std::fs::metadata(path.as_path())
710                        .ok()
711                        .and_then(|m| m.modified().ok());
712                    // Check if modification time matches, or if not, compare file content hash
713                    entry.parsed.modified_time == modified_time || {
714                        let src = std::fs::read_to_string(path.as_path()).unwrap();
715                        let mut hasher = DefaultHasher::new();
716                        src.hash(&mut hasher);
717                        hasher.finish() == entry.common.hash
718                    }
719                },
720                |version| {
721                    // Determine if the parse cache is up-to-date in LSP mode:
722                    // - If there's no LSP file version (version is None), consider the cache up-to-date.
723                    // - If there is an LSP file version:
724                    //   - If there's no cached version (entry.parsed.version is None), the cache is outdated.
725                    //   - If there's a cached version, compare them: cache is up-to-date if the LSP file version
726                    //     is not greater than the cached version.
727                    version.is_none_or(|v| entry.parsed.version.is_some_and(|ev| v <= ev))
728                },
729            );
730
731        // Checks if the typed module cache for a given path is up to date// If the cache is up to date, recursively check all dependencies to make sure they have not been
732        // modified either.
733        cache_up_to_date
734            && entry.common.dependencies.iter().all(|dep_path| {
735                is_parse_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
736            })
737    })
738}
739
740fn module_path(
741    parent_module_dir: &Path,
742    parent_module_name: Option<&str>,
743    submod: &sway_ast::Submodule,
744) -> PathBuf {
745    if let Some(parent_name) = parent_module_name {
746        parent_module_dir
747            .join(parent_name)
748            .join(submod.name.to_string())
749            .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
750    } else {
751        // top level module
752        parent_module_dir
753            .join(submod.name.to_string())
754            .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
755    }
756}
757
758pub fn build_module_dep_graph(
759    handler: &Handler,
760    parse_module: &mut parsed::ParseModule,
761) -> Result<(), ErrorEmitted> {
762    let module_dep_graph = ty::TyModule::build_dep_graph(handler, parse_module)?;
763    parse_module.module_eval_order = module_dep_graph.compute_order(handler)?;
764
765    for (_, submodule) in &mut parse_module.submodules {
766        build_module_dep_graph(handler, &mut submodule.module)?;
767    }
768    Ok(())
769}
770
771/// A possible occurrence of a `panic` expression that is located in code at [PanicOccurrence::loc].
772///
773/// Note that a single `panic` expression can have multiple [PanicOccurrence]s related to it.
774///
775/// For example:
776/// - `panic "Some message.";` will have just a single occurrence, with `msg` containing the message.
777/// - `panic some_value_of_a_concrete_type;` will have just a single occurrence, with `log_id` containing the [LogId] of the concrete type.
778/// - `panic some_value_of_a_generic_type;` will have multiple occurrences, one with `log_id` for every monomorphized type.
779///
780/// **Every [PanicOccurrence] has exactly one revert code assigned to it.**
781#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
782pub struct PanicOccurrence {
783    pub loc: SourceLocation,
784    pub log_id: Option<LogId>,
785    pub msg: Option<String>,
786}
787
788/// [PanicOccurrence]s mapped to their corresponding revert codes.
789pub type PanicOccurrences = HashMap<PanicOccurrence, u64>;
790
791pub struct CompiledAsm {
792    pub finalized_asm: FinalizedAsm,
793    pub panic_occurrences: PanicOccurrences,
794}
795
796#[allow(clippy::result_large_err)]
797#[allow(clippy::too_many_arguments)]
798pub fn parsed_to_ast(
799    handler: &Handler,
800    engines: &Engines,
801    parse_program: &mut parsed::ParseProgram,
802    initial_namespace: namespace::Package,
803    build_config: Option<&BuildConfig>,
804    package_name: &str,
805    retrigger_compilation: Option<Arc<AtomicBool>>,
806    experimental: ExperimentalFeatures,
807) -> Result<ty::TyProgram, TypeCheckFailed> {
808    let lsp_config = build_config.map(|x| x.lsp_mode.clone()).unwrap_or_default();
809
810    // Build the dependency graph for the submodules.
811    build_module_dep_graph(handler, &mut parse_program.root).map_err(|error| TypeCheckFailed {
812        root_module: None,
813        namespace: initial_namespace.clone(),
814        error,
815    })?;
816
817    let collection_namespace = Namespace::new(handler, engines, initial_namespace.clone(), true)
818        .map_err(|error| TypeCheckFailed {
819            root_module: None,
820            namespace: initial_namespace.clone(),
821            error,
822        })?;
823    // Collect the program symbols.
824
825    let mut collection_ctx =
826        ty::TyProgram::collect(handler, engines, parse_program, collection_namespace).map_err(
827            |error| TypeCheckFailed {
828                root_module: None,
829                namespace: initial_namespace.clone(),
830                error,
831            },
832        )?;
833
834    let typecheck_namespace =
835        Namespace::new(handler, engines, initial_namespace, true).map_err(|error| {
836            TypeCheckFailed {
837                root_module: None,
838                namespace: collection_ctx.namespace().current_package_ref().clone(),
839                error,
840            }
841        })?;
842    // Type check the program.
843    let typed_program_opt = ty::TyProgram::type_check(
844        handler,
845        engines,
846        parse_program,
847        &mut collection_ctx,
848        typecheck_namespace,
849        package_name,
850        build_config,
851        experimental,
852    );
853
854    let mut typed_program = typed_program_opt?;
855
856    check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
857        TypeCheckFailed {
858            root_module: Some(Arc::new(typed_program.root_module.clone())),
859            namespace: typed_program.namespace.current_package_ref().clone(),
860            error,
861        }
862    })?;
863    // Only clear the parsed AST nodes if we are running a regular compilation pipeline.
864    // LSP needs these to build its token map, and they are cleared by `clear_program` as
865    // part of the LSP garbage collection functionality instead.
866    if lsp_config.is_none() {
867        engines.pe().clear();
868    }
869
870    typed_program.check_deprecated(engines, handler);
871
872    match typed_program.check_recursive(engines, handler) {
873        Ok(()) => {}
874        Err(error) => {
875            handler.dedup();
876            return Err(TypeCheckFailed {
877                root_module: Some(Arc::new(typed_program.root_module.clone())),
878                namespace: typed_program.namespace.current_package().clone(),
879                error,
880            });
881        }
882    };
883
884    // Skip collecting metadata if we triggered an optimised build from LSP.
885    let types_metadata = if !lsp_config.as_ref().is_some_and(|lsp| lsp.optimized_build) {
886        // Collect information about the types used in this program
887        let types_metadata_result = typed_program.collect_types_metadata(
888            handler,
889            &mut CollectTypesMetadataContext::new(engines, experimental, package_name.to_string()),
890        );
891        let types_metadata = match types_metadata_result {
892            Ok(types_metadata) => types_metadata,
893            Err(error) => {
894                handler.dedup();
895                return Err(TypeCheckFailed {
896                    root_module: Some(Arc::new(typed_program.root_module.clone())),
897                    namespace: typed_program.namespace.current_package().clone(),
898                    error,
899                });
900            }
901        };
902
903        typed_program
904            .logged_types
905            .extend(types_metadata.iter().filter_map(|m| match m {
906                TypeMetadata::LoggedType(log_id, type_id) => Some((*log_id, *type_id)),
907                _ => None,
908            }));
909
910        typed_program
911            .messages_types
912            .extend(types_metadata.iter().filter_map(|m| match m {
913                TypeMetadata::MessageType(message_id, type_id) => Some((*message_id, *type_id)),
914                _ => None,
915            }));
916
917        let (print_graph, print_graph_url_format) = match build_config {
918            Some(cfg) => (
919                cfg.print_dca_graph.clone(),
920                cfg.print_dca_graph_url_format.clone(),
921            ),
922            None => (None, None),
923        };
924
925        check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
926            TypeCheckFailed {
927                root_module: Some(Arc::new(typed_program.root_module.clone())),
928                namespace: typed_program.namespace.current_package_ref().clone(),
929                error,
930            }
931        })?;
932
933        // Perform control flow analysis and extend with any errors.
934        let _ = perform_control_flow_analysis(
935            handler,
936            engines,
937            &typed_program,
938            print_graph,
939            print_graph_url_format,
940        );
941
942        types_metadata
943    } else {
944        vec![]
945    };
946
947    // Evaluate const declarations, to allow storage slots initialization with consts.
948    let mut ctx = Context::new(engines.se(), experimental);
949    let module = Module::new(&mut ctx, Kind::Contract);
950    if let Err(errs) = ir_generation::compile::compile_constants_for_package(
951        engines,
952        &mut ctx,
953        module,
954        &typed_program.namespace,
955    ) {
956        errs.into_iter().for_each(|err| {
957            handler.emit_err(err.clone());
958        });
959    }
960
961    // CEI pattern analysis
962    let cei_analysis_warnings =
963        semantic_analysis::cei_pattern_analysis::analyze_program(engines, &typed_program);
964    for warn in cei_analysis_warnings {
965        handler.emit_warn(warn);
966    }
967
968    let mut md_mgr = MetadataManager::default();
969    // Check that all storage initializers can be evaluated at compile time.
970    typed_program
971        .get_typed_program_with_initialized_storage_slots(
972            handler,
973            engines,
974            &mut ctx,
975            &mut md_mgr,
976            module,
977        )
978        .map_err(|error: ErrorEmitted| {
979            handler.dedup();
980            TypeCheckFailed {
981                root_module: Some(Arc::new(typed_program.root_module.clone())),
982                namespace: typed_program.namespace.current_package_ref().clone(),
983                error,
984            }
985        })?;
986
987    // All unresolved types lead to compile errors.
988    for err in types_metadata.iter().filter_map(|m| match m {
989        TypeMetadata::UnresolvedType(name, call_site_span_opt) => {
990            Some(CompileError::UnableToInferGeneric {
991                ty: name.as_str().to_string(),
992                span: call_site_span_opt.clone().unwrap_or_else(|| name.span()),
993            })
994        }
995        _ => None,
996    }) {
997        handler.emit_err(err);
998    }
999
1000    Ok(typed_program)
1001}
1002
1003#[allow(clippy::too_many_arguments)]
1004pub fn compile_to_ast(
1005    handler: &Handler,
1006    engines: &Engines,
1007    src: Source,
1008    initial_namespace: namespace::Package,
1009    build_config: Option<&BuildConfig>,
1010    package_name: &str,
1011    retrigger_compilation: Option<Arc<AtomicBool>>,
1012    experimental: ExperimentalFeatures,
1013) -> Result<Programs, ErrorEmitted> {
1014    check_should_abort(handler, retrigger_compilation.clone())?;
1015
1016    let query_engine = engines.qe();
1017    let mut metrics = PerformanceData::default();
1018    if let Some(config) = build_config {
1019        let path = config.canonical_root_module();
1020        let include_tests = config.include_tests;
1021        // Check if we can re-use the data in the cache.
1022        if is_parse_module_cache_up_to_date(engines, &path, include_tests, build_config) {
1023            let mut entry = query_engine.get_programs_cache_entry(&path).unwrap();
1024            entry.programs.metrics.reused_programs += 1;
1025
1026            let (warnings, errors, infos) = entry.handler_data;
1027            let new_handler = Handler::from_parts(warnings, errors, infos);
1028            handler.append(new_handler);
1029            return Ok(entry.programs);
1030        };
1031    }
1032
1033    // Parse the program to a concrete syntax tree (CST).
1034    let parse_program_opt = time_expr!(
1035        package_name,
1036        "parse the program to a concrete syntax tree (CST)",
1037        "parse_cst",
1038        parse(
1039            src,
1040            handler,
1041            engines,
1042            build_config,
1043            experimental,
1044            package_name
1045        ),
1046        build_config,
1047        metrics
1048    );
1049
1050    check_should_abort(handler, retrigger_compilation.clone())?;
1051
1052    let (lexed_program, mut parsed_program) = match parse_program_opt {
1053        Ok(modules) => modules,
1054        Err(e) => {
1055            handler.dedup();
1056            return Err(e);
1057        }
1058    };
1059
1060    // If tests are not enabled, exclude them from `parsed_program`.
1061    if build_config.is_none_or(|config| !config.include_tests) {
1062        parsed_program.exclude_tests(engines);
1063    }
1064
1065    // Type check (+ other static analysis) the CST to a typed AST.
1066    let program = time_expr!(
1067        package_name,
1068        "parse the concrete syntax tree (CST) to a typed AST",
1069        "parse_ast",
1070        parsed_to_ast(
1071            handler,
1072            engines,
1073            &mut parsed_program,
1074            initial_namespace,
1075            build_config,
1076            package_name,
1077            retrigger_compilation.clone(),
1078            experimental
1079        ),
1080        build_config,
1081        metrics
1082    );
1083
1084    check_should_abort(handler, retrigger_compilation.clone())?;
1085
1086    handler.dedup();
1087
1088    let programs = Programs::new(
1089        Arc::new(lexed_program),
1090        Arc::new(parsed_program),
1091        program.map(Arc::new),
1092        metrics,
1093    );
1094
1095    if let Some(config) = build_config {
1096        let path = config.canonical_root_module();
1097        let cache_entry = ProgramsCacheEntry {
1098            path,
1099            programs: programs.clone(),
1100            handler_data: handler.clone().consume(),
1101        };
1102        query_engine.insert_programs_cache_entry(cache_entry);
1103    }
1104
1105    check_should_abort(handler, retrigger_compilation.clone())?;
1106
1107    Ok(programs)
1108}
1109
1110/// Given input Sway source code, try compiling to a `CompiledAsm`,
1111/// containing the asm in opcode form (not raw bytes/bytecode).
1112pub fn compile_to_asm(
1113    handler: &Handler,
1114    engines: &Engines,
1115    src: Source,
1116    initial_namespace: namespace::Package,
1117    build_config: &BuildConfig,
1118    package_name: &str,
1119    experimental: ExperimentalFeatures,
1120) -> Result<CompiledAsm, ErrorEmitted> {
1121    let ast_res = compile_to_ast(
1122        handler,
1123        engines,
1124        src,
1125        initial_namespace,
1126        Some(build_config),
1127        package_name,
1128        None,
1129        experimental,
1130    )?;
1131
1132    ast_to_asm(handler, engines, &ast_res, build_config, experimental)
1133}
1134
1135/// Given an AST compilation result, try compiling to a `CompiledAsm`,
1136/// containing the asm in opcode form (not raw bytes/bytecode).
1137pub fn ast_to_asm(
1138    handler: &Handler,
1139    engines: &Engines,
1140    programs: &Programs,
1141    build_config: &BuildConfig,
1142    experimental: ExperimentalFeatures,
1143) -> Result<CompiledAsm, ErrorEmitted> {
1144    let typed_program = match &programs.typed {
1145        Ok(typed_program) => typed_program,
1146        Err(err) => return Err(err.error),
1147    };
1148
1149    let mut panic_occurrences = PanicOccurrences::default();
1150
1151    let asm = match compile_ast_to_ir_to_asm(
1152        handler,
1153        engines,
1154        typed_program,
1155        &mut panic_occurrences,
1156        build_config,
1157        experimental,
1158    ) {
1159        Ok(res) => res,
1160        Err(err) => {
1161            handler.dedup();
1162            return Err(err);
1163        }
1164    };
1165
1166    Ok(CompiledAsm {
1167        finalized_asm: asm,
1168        panic_occurrences,
1169    })
1170}
1171
1172pub(crate) fn compile_ast_to_ir_to_asm(
1173    handler: &Handler,
1174    engines: &Engines,
1175    program: &ty::TyProgram,
1176    panic_occurrences: &mut PanicOccurrences,
1177    build_config: &BuildConfig,
1178    experimental: ExperimentalFeatures,
1179) -> Result<FinalizedAsm, ErrorEmitted> {
1180    // The IR pipeline relies on type information being fully resolved.
1181    // If type information is found to still be generic or unresolved inside of
1182    // IR, this is considered an internal compiler error. To resolve this situation,
1183    // we need to explicitly ensure all types are resolved before going into IR.
1184    //
1185    // We _could_ introduce a new type here that uses TypeInfo instead of TypeId and throw away
1186    // the engine, since we don't need inference for IR. That'd be a _lot_ of copy-pasted code,
1187    // though, so instead, we are just going to do a pass and throw any unresolved generics as
1188    // errors and then hold as a runtime invariant that none of the types will be unresolved in the
1189    // IR phase.
1190
1191    let mut ir = match ir_generation::compile_program(
1192        program,
1193        panic_occurrences,
1194        build_config.include_tests,
1195        engines,
1196        experimental,
1197    ) {
1198        Ok(ir) => ir,
1199        Err(errors) => {
1200            let mut last = None;
1201            for e in errors {
1202                last = Some(handler.emit_err(e));
1203            }
1204            return Err(last.unwrap());
1205        }
1206    };
1207
1208    // Find all the entry points for purity checking and DCE.
1209    let entry_point_functions: Vec<::sway_ir::Function> = ir
1210        .module_iter()
1211        .flat_map(|module| module.function_iter(&ir))
1212        .filter(|func| func.is_entry(&ir))
1213        .collect();
1214
1215    // Do a purity check on the _unoptimised_ IR.
1216    {
1217        let mut env = ir_generation::PurityEnv::default();
1218        let mut md_mgr = metadata::MetadataManager::default();
1219        for entry_point in &entry_point_functions {
1220            check_function_purity(handler, &mut env, &ir, &mut md_mgr, entry_point);
1221        }
1222    }
1223
1224    // Initialize the pass manager and register known passes.
1225    let mut pass_mgr = PassManager::default();
1226    register_known_passes(&mut pass_mgr);
1227    let mut pass_group = PassGroup::default();
1228
1229    match build_config.optimization_level {
1230        OptLevel::Opt1 => {
1231            pass_group.append_group(create_o1_pass_group());
1232        }
1233        OptLevel::Opt0 => {
1234            // We run a function deduplication pass that only removes duplicate
1235            // functions when everything, including the metadata are identical.
1236            pass_group.append_pass(FN_DEDUP_DEBUG_PROFILE_NAME);
1237
1238            // Inlining is necessary until #4899 is resolved.
1239            pass_group.append_pass(FN_INLINE_NAME);
1240
1241            // Do DCE so other optimizations run faster.
1242            pass_group.append_pass(GLOBALS_DCE_NAME);
1243            pass_group.append_pass(DCE_NAME);
1244        }
1245    }
1246
1247    // Target specific transforms should be moved into something more configured.
1248    if build_config.build_target == BuildTarget::Fuel {
1249        // FuelVM target specific transforms.
1250        //
1251        // Demote large by-value constants, arguments and return values to by-reference values
1252        // using temporaries.
1253        pass_group.append_pass(CONST_DEMOTION_NAME);
1254        pass_group.append_pass(ARG_DEMOTION_NAME);
1255        pass_group.append_pass(RET_DEMOTION_NAME);
1256        pass_group.append_pass(MISC_DEMOTION_NAME);
1257
1258        // Convert loads and stores to mem_copies where possible.
1259        pass_group.append_pass(ARG_POINTEE_MUTABILITY_TAGGER_NAME);
1260        pass_group.append_pass(MEMCPYOPT_NAME);
1261
1262        // Run a DCE and simplify-cfg to clean up any obsolete instructions.
1263        pass_group.append_pass(DCE_NAME);
1264        pass_group.append_pass(SIMPLIFY_CFG_NAME);
1265
1266        match build_config.optimization_level {
1267            OptLevel::Opt1 => {
1268                pass_group.append_pass(SROA_NAME);
1269                pass_group.append_pass(MEM2REG_NAME);
1270                pass_group.append_pass(DCE_NAME);
1271            }
1272            OptLevel::Opt0 => {}
1273        }
1274    }
1275
1276    // Run the passes.
1277    let print_passes_opts: PrintPassesOpts = (&build_config.print_ir).into();
1278    let res =
1279        if let Err(ir_error) = pass_mgr.run_with_print(&mut ir, &pass_group, &print_passes_opts) {
1280            Err(handler.emit_err(CompileError::InternalOwned(
1281                ir_error.to_string(),
1282                span::Span::dummy(),
1283            )))
1284        } else {
1285            Ok(())
1286        };
1287    res?;
1288
1289    compile_ir_context_to_finalized_asm(handler, &ir, Some(build_config))
1290}
1291
1292/// Given input Sway source code, compile to [CompiledBytecode], containing the asm in bytecode form.
1293#[allow(clippy::too_many_arguments)]
1294pub fn compile_to_bytecode(
1295    handler: &Handler,
1296    engines: &Engines,
1297    src: Source,
1298    initial_namespace: namespace::Package,
1299    build_config: &BuildConfig,
1300    source_map: &mut SourceMap,
1301    package_name: &str,
1302    experimental: ExperimentalFeatures,
1303) -> Result<CompiledBytecode, ErrorEmitted> {
1304    let mut asm_res = compile_to_asm(
1305        handler,
1306        engines,
1307        src,
1308        initial_namespace,
1309        build_config,
1310        package_name,
1311        experimental,
1312    )?;
1313    asm_to_bytecode(
1314        handler,
1315        &mut asm_res,
1316        source_map,
1317        engines.se(),
1318        build_config,
1319    )
1320}
1321
1322/// Size of the prelude's CONFIGURABLES_OFFSET section, in bytes.
1323pub const PRELUDE_CONFIGURABLES_SIZE_IN_BYTES: usize = 8;
1324/// Offset (in bytes) of the CONFIGURABLES_OFFSET section in the prelude.
1325pub const PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES: usize = 16;
1326/// Total size of the prelude in bytes. Instructions start right after.
1327pub const PRELUDE_SIZE_IN_BYTES: usize = 32;
1328
1329/// Given bytecode, overwrite the existing offset to configurables offset in the prelude with the given one.
1330pub fn set_bytecode_configurables_offset(
1331    compiled_bytecode: &mut CompiledBytecode,
1332    md: &[u8; PRELUDE_CONFIGURABLES_SIZE_IN_BYTES],
1333) {
1334    assert!(
1335        compiled_bytecode.bytecode.len()
1336            >= PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES + PRELUDE_CONFIGURABLES_SIZE_IN_BYTES
1337    );
1338    let code = &mut compiled_bytecode.bytecode;
1339    for (index, byte) in md.iter().enumerate() {
1340        code[index + PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES] = *byte;
1341    }
1342}
1343
1344/// Given the assembly (opcodes), compile to [CompiledBytecode], containing the asm in bytecode form.
1345pub fn asm_to_bytecode(
1346    handler: &Handler,
1347    asm: &mut CompiledAsm,
1348    source_map: &mut SourceMap,
1349    source_engine: &SourceEngine,
1350    build_config: &BuildConfig,
1351) -> Result<CompiledBytecode, ErrorEmitted> {
1352    let compiled_bytecode =
1353        asm.finalized_asm
1354            .to_bytecode_mut(handler, source_map, source_engine, build_config)?;
1355    Ok(compiled_bytecode)
1356}
1357
1358/// Given a [ty::TyProgram], which is type-checked Sway source, construct a graph to analyze
1359/// control flow and determine if it is valid.
1360fn perform_control_flow_analysis(
1361    handler: &Handler,
1362    engines: &Engines,
1363    program: &ty::TyProgram,
1364    print_graph: Option<String>,
1365    print_graph_url_format: Option<String>,
1366) -> Result<(), ErrorEmitted> {
1367    let dca_res = dead_code_analysis(handler, engines, program);
1368    let rpa_errors = return_path_analysis(engines, program);
1369    let rpa_res = handler.scope(|handler| {
1370        for err in rpa_errors {
1371            handler.emit_err(err);
1372        }
1373        Ok(())
1374    });
1375
1376    if let Ok(graph) = dca_res.clone() {
1377        graph.visualize(engines, print_graph, print_graph_url_format);
1378    }
1379    dca_res?;
1380    rpa_res
1381}
1382
1383/// Constructs a dead code graph from all modules within the graph and then attempts to find dead
1384/// code.
1385///
1386/// Returns the graph that was used for analysis.
1387fn dead_code_analysis<'a>(
1388    handler: &Handler,
1389    engines: &'a Engines,
1390    program: &ty::TyProgram,
1391) -> Result<ControlFlowGraph<'a>, ErrorEmitted> {
1392    let decl_engine = engines.de();
1393    let mut dead_code_graph = ControlFlowGraph::new(engines);
1394    let tree_type = program.kind.tree_type();
1395    module_dead_code_analysis(
1396        handler,
1397        engines,
1398        &program.root_module,
1399        &tree_type,
1400        &mut dead_code_graph,
1401    )?;
1402    let warnings = dead_code_graph.find_dead_code(decl_engine);
1403    for warn in warnings {
1404        handler.emit_warn(warn);
1405    }
1406    Ok(dead_code_graph)
1407}
1408
1409/// Recursively collect modules into the given `ControlFlowGraph` ready for dead code analysis.
1410fn module_dead_code_analysis<'eng: 'cfg, 'cfg>(
1411    handler: &Handler,
1412    engines: &'eng Engines,
1413    module: &ty::TyModule,
1414    tree_type: &parsed::TreeType,
1415    graph: &mut ControlFlowGraph<'cfg>,
1416) -> Result<(), ErrorEmitted> {
1417    module
1418        .submodules
1419        .iter()
1420        .try_fold((), |(), (_, submodule)| {
1421            let tree_type = parsed::TreeType::Library;
1422            module_dead_code_analysis(handler, engines, &submodule.module, &tree_type, graph)
1423        })?;
1424    let res = {
1425        ControlFlowGraph::append_module_to_dead_code_graph(
1426            engines,
1427            &module.all_nodes,
1428            tree_type,
1429            graph,
1430        )
1431        .map_err(|err| handler.emit_err(err))
1432    };
1433    graph.connect_pending_entry_edges();
1434    res
1435}
1436
1437fn return_path_analysis(engines: &Engines, program: &ty::TyProgram) -> Vec<CompileError> {
1438    let mut errors = vec![];
1439    module_return_path_analysis(engines, &program.root_module, &mut errors);
1440    errors
1441}
1442
1443fn module_return_path_analysis(
1444    engines: &Engines,
1445    module: &ty::TyModule,
1446    errors: &mut Vec<CompileError>,
1447) {
1448    for (_, submodule) in &module.submodules {
1449        module_return_path_analysis(engines, &submodule.module, errors);
1450    }
1451    let graph = ControlFlowGraph::construct_return_path_graph(engines, &module.all_nodes);
1452    match graph {
1453        Ok(graph) => errors.extend(graph.analyze_return_paths(engines)),
1454        Err(mut error) => errors.append(&mut error),
1455    }
1456}
1457
1458/// Check if the retrigger compilation flag has been set to true in the language server.
1459/// If it has, there is a new compilation request, so we should abort the current compilation.
1460fn check_should_abort(
1461    handler: &Handler,
1462    retrigger_compilation: Option<Arc<AtomicBool>>,
1463) -> Result<(), ErrorEmitted> {
1464    if let Some(ref retrigger_compilation) = retrigger_compilation {
1465        if retrigger_compilation.load(Ordering::SeqCst) {
1466            return Err(handler.cancel());
1467        }
1468    }
1469    Ok(())
1470}
1471
1472pub fn dump_trait_impls_for_typename(
1473    handler: &Handler,
1474    engines: &Engines,
1475    namespace: &namespace::Namespace,
1476    typename: &str,
1477) -> Result<(), ErrorEmitted> {
1478    let path: Vec<&str> = typename.split("::").collect();
1479    let mut call_path = CallPath::fullpath(&path);
1480    call_path.callpath_type = CallPathType::Ambiguous;
1481
1482    let pkg_namespace = namespace.current_package_ref();
1483    let mod_path = [pkg_namespace.root_module().name().clone()];
1484
1485    let resolve_handler = Handler::default();
1486    let resolved = resolve_call_path(
1487        &resolve_handler,
1488        engines,
1489        namespace,
1490        &mod_path,
1491        &call_path,
1492        None,
1493        VisibilityCheck::No,
1494    );
1495
1496    if let Ok(resolved) = resolved {
1497        let module = &pkg_namespace.root_module();
1498
1499        let mut impls = Vec::new();
1500        find_trait_impls_for_type(engines, namespace, &resolved, module, &mut impls);
1501
1502        for ext_pkg in pkg_namespace.external_packages.iter() {
1503            let ext_module = ext_pkg.1.root_module();
1504            find_trait_impls_for_type(engines, namespace, &resolved, ext_module, &mut impls);
1505        }
1506
1507        let unique_impls = impls
1508            .iter()
1509            .unique_by(|i| i.impl_span.clone())
1510            .cloned()
1511            .collect::<Vec<_>>();
1512        handler.emit_info(CompileInfo {
1513            span: resolved.span(engines).subset_first_of("{").unwrap(),
1514            content: Info::ImplTraitsForType {
1515                impls: unique_impls,
1516            },
1517        });
1518    }
1519
1520    Ok(())
1521}
1522
1523fn find_trait_impls_for_type(
1524    engines: &Engines,
1525    namespace: &namespace::Namespace,
1526    resolved_decl: &ResolvedDeclaration,
1527    module: &namespace::Module,
1528    impls: &mut Vec<CollectedTraitImpl>,
1529) {
1530    let handler = Handler::default();
1531    let struct_decl_source_id = resolved_decl
1532        .to_struct_decl(&handler, engines)
1533        .map(|d| d.expect_typed())
1534        .and_then(|decl| decl.to_struct_decl(&handler, engines))
1535        .map(|decl_id| engines.de().get_struct(&decl_id).span.source_id().cloned())
1536        .ok()
1537        .flatten();
1538
1539    let enum_decl_source_id = resolved_decl
1540        .to_enum_decl(&handler, engines)
1541        .map(|d| d.expect_typed())
1542        .and_then(|decl| decl.to_enum_id(&handler, engines))
1543        .map(|decl_id| engines.de().get_enum(&decl_id).span.source_id().cloned())
1544        .ok()
1545        .flatten();
1546
1547    module.walk_scope_chain(|lexical_scope| {
1548        module.submodules().iter().for_each(|(_, sub)| {
1549            find_trait_impls_for_type(engines, namespace, resolved_decl, sub, impls);
1550        });
1551
1552        let trait_map = &lexical_scope.items.implemented_traits;
1553
1554        for key in trait_map.trait_impls.keys() {
1555            for trait_entry in trait_map.trait_impls[key].iter() {
1556                let trait_type = engines.te().get(trait_entry.inner.key.type_id);
1557
1558                let matched = match *trait_type {
1559                    TypeInfo::Enum(decl_id) => {
1560                        let trait_enum = engines.de().get_enum(&decl_id);
1561                        enum_decl_source_id == trait_enum.span.source_id().cloned()
1562                    }
1563                    TypeInfo::Struct(decl_id) => {
1564                        let trait_struct = engines.de().get_struct(&decl_id);
1565                        struct_decl_source_id == trait_struct.span.source_id().cloned()
1566                    }
1567                    _ => false,
1568                };
1569
1570                if matched {
1571                    let trait_callpath = trait_entry.inner.key.name.to_fullpath(engines, namespace);
1572                    impls.push(CollectedTraitImpl {
1573                        impl_span: trait_entry
1574                            .inner
1575                            .value
1576                            .impl_span
1577                            .subset_first_of("{")
1578                            .unwrap(),
1579                        trait_name: engines.help_out(trait_callpath).to_string(),
1580                    });
1581                }
1582            }
1583        }
1584    });
1585}
1586
1587#[test]
1588fn test_basic_prog() {
1589    let handler = Handler::default();
1590    let engines = Engines::default();
1591    let prog = parse(
1592        r#"
1593        contract;
1594
1595    enum yo
1596    <T>
1597    where
1598    T: IsAThing
1599    {
1600        x: u32,
1601        y: MyStruct<u32>
1602    }
1603
1604    enum  MyOtherSumType
1605    {
1606        x: u32,
1607        y: MyStruct<u32>
1608    }
1609        struct MyStruct<T> {
1610            field_name: u64,
1611            other_field: T,
1612        }
1613
1614
1615    fn generic_function
1616    <T>
1617    (arg1: u64,
1618    arg2: T)
1619    ->
1620    T
1621    where T: Display,
1622          T: Debug {
1623          let x: MyStruct =
1624          MyStruct
1625          {
1626              field_name:
1627              5
1628          };
1629          return
1630          match
1631            arg1
1632          {
1633               1
1634               => true,
1635               _ => { return false; },
1636          };
1637    }
1638
1639    struct MyStruct {
1640        test: string,
1641    }
1642
1643
1644
1645    use stdlib::println;
1646
1647    trait MyTrait {
1648        // interface points
1649        fn myfunc(x: int) -> unit;
1650        } {
1651        // methods
1652        fn calls_interface_fn(x: int) -> unit {
1653            // declare a byte
1654            let x = 0b10101111;
1655            let mut y = 0b11111111;
1656            self.interface_fn(x);
1657        }
1658    }
1659
1660    pub fn prints_number_five() -> u8 {
1661        let x: u8 = 5;
1662        println(x);
1663         x.to_string();
1664         let some_list = [
1665         5,
1666         10 + 3 / 2,
1667         func_app(my_args, (so_many_args))];
1668        return 5;
1669    }
1670    "#
1671        .into(),
1672        &handler,
1673        &engines,
1674        None,
1675        ExperimentalFeatures::default(),
1676        "test",
1677    );
1678    prog.unwrap();
1679}
1680#[test]
1681fn test_parenthesized() {
1682    let handler = Handler::default();
1683    let engines = Engines::default();
1684    let prog = parse(
1685        r#"
1686        contract;
1687        pub fn some_abi_func() -> unit {
1688            let x = (5 + 6 / (1 + (2 / 1) + 4));
1689            return;
1690        }
1691    "#
1692        .into(),
1693        &handler,
1694        &engines,
1695        None,
1696        ExperimentalFeatures::default(),
1697        "test",
1698    );
1699    prog.unwrap();
1700}
1701
1702#[test]
1703fn test_unary_ordering() {
1704    use crate::language::{self, parsed};
1705    let handler = Handler::default();
1706    let engines = Engines::default();
1707    let prog = parse(
1708        r#"
1709    script;
1710    fn main() -> bool {
1711        let a = true;
1712        let b = true;
1713        !a && b;
1714    }"#
1715        .into(),
1716        &handler,
1717        &engines,
1718        None,
1719        ExperimentalFeatures::default(),
1720        "test",
1721    );
1722    let (.., prog) = prog.unwrap();
1723    // this should parse as `(!a) && b`, not `!(a && b)`. So, the top level
1724    // expression should be `&&`
1725    if let parsed::AstNode {
1726        content:
1727            parsed::AstNodeContent::Declaration(parsed::Declaration::FunctionDeclaration(decl_id)),
1728        ..
1729    } = &prog.root.tree.root_nodes[0]
1730    {
1731        let fn_decl = engines.pe().get_function(decl_id);
1732        if let parsed::AstNode {
1733            content:
1734                parsed::AstNodeContent::Expression(parsed::Expression {
1735                    kind:
1736                        parsed::ExpressionKind::LazyOperator(parsed::LazyOperatorExpression {
1737                            op, ..
1738                        }),
1739                    ..
1740                }),
1741            ..
1742        } = &fn_decl.body.contents[2]
1743        {
1744            assert_eq!(op, &language::LazyOp::And)
1745        } else {
1746            panic!("Was not lazy operator.")
1747        }
1748    } else {
1749        panic!("Was not ast node")
1750    };
1751}
1752
1753#[test]
1754fn test_parser_recovery() {
1755    let handler = Handler::default();
1756    let engines = Engines::default();
1757    let prog = parse(
1758        r#"
1759    script;
1760    fn main() -> bool {
1761        let
1762        let a = true;
1763        true
1764    }"#
1765        .into(),
1766        &handler,
1767        &engines,
1768        None,
1769        ExperimentalFeatures::default(),
1770        "test",
1771    );
1772    let (_, _) = prog.unwrap();
1773    assert!(handler.has_errors());
1774    dbg!(handler);
1775}