Skip to main content

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