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
89pub 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 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
154pub fn parse_tree_type(handler: &Handler, src: Source) -> Result<parsed::TreeType, ErrorEmitted> {
158 let experimental = ExperimentalFeatures::default();
162 sway_parse::parse_module_kind(handler, src, None, experimental)
163 .map(|kind| convert_module_kind(&kind))
164}
165
166pub(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 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 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 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 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 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 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 let should_be_checked =
266 |attr: &&Attribute| !attr.is_doc_comment() && attr.is_outer() && can_annotate(attr);
267
268 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 for attribute in attributes.all().filter(should_be_checked) {
293 let _ = attribute.check_args_multiplicity(&handler);
294 }
295
296 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 for attribute in attributes
343 .all()
344 .filter(|attr| should_be_checked(attr) && attr.can_have_arguments())
345 {
346 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
383fn 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
447pub type Submodules = Vec<Submodule>;
449
450#[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 let mut submods = Vec::with_capacity(module.submodules().count());
467 module.submodules().for_each(|submod| {
468 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#[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 let module_dir = path.parent().expect("module file has no parent directory");
558 let source_id = engines.se().get_source_id(&path.clone());
559 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 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 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 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
655pub(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 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 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
689pub(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 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 let modified_time = std::fs::metadata(path.as_path())
710 .ok()
711 .and_then(|m| m.modified().ok());
712 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 version.is_none_or(|v| entry.parsed.version.is_some_and(|ev| v <= ev))
728 },
729 );
730
731 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 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#[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
788pub 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_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 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 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 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 let types_metadata = if !lsp_config.as_ref().is_some_and(|lsp| lsp.optimized_build) {
886 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 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 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 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 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 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 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 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 build_config.is_none_or(|config| !config.include_tests) {
1062 parsed_program.exclude_tests(engines);
1063 }
1064
1065 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
1110pub 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
1135pub 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 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 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 {
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 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 pass_group.append_pass(FN_DEDUP_DEBUG_PROFILE_NAME);
1237
1238 pass_group.append_pass(FN_INLINE_NAME);
1240
1241 pass_group.append_pass(GLOBALS_DCE_NAME);
1243 pass_group.append_pass(DCE_NAME);
1244 }
1245 }
1246
1247 if build_config.build_target == BuildTarget::Fuel {
1249 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 pass_group.append_pass(ARG_POINTEE_MUTABILITY_TAGGER_NAME);
1260 pass_group.append_pass(MEMCPYOPT_NAME);
1261
1262 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 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#[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
1322pub const PRELUDE_CONFIGURABLES_SIZE_IN_BYTES: usize = 8;
1324pub const PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES: usize = 16;
1326pub const PRELUDE_SIZE_IN_BYTES: usize = 32;
1328
1329pub 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
1344pub 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
1358fn 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
1383fn 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
1409fn 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
1458fn 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 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}