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 query_engine;
23pub mod semantic_analysis;
24pub mod source_map;
25pub mod transform;
26pub mod type_system;
27
28use crate::ir_generation::check_function_purity;
29use crate::query_engine::ModuleCacheEntry;
30use crate::source_map::SourceMap;
31pub use asm_generation::from_ir::compile_ir_context_to_finalized_asm;
32use asm_generation::FinalizedAsm;
33pub use asm_generation::{CompiledBytecode, FinalizedEntry};
34pub use build_config::DbgGeneration;
35pub use build_config::{BuildConfig, BuildTarget, LspConfig, OptLevel, PrintAsm, PrintIr};
36use control_flow_analysis::ControlFlowGraph;
37pub use debug_generation::write_dwarf;
38use itertools::Itertools;
39use metadata::MetadataManager;
40use query_engine::{ModuleCacheKey, ModuleCommonInfo, ParsedModuleInfo, ProgramsCacheEntry};
41use semantic_analysis::program::TypeCheckFailed;
42use std::collections::hash_map::DefaultHasher;
43use std::hash::{Hash, Hasher};
44use std::path::{Path, PathBuf};
45use std::sync::atomic::{AtomicBool, Ordering};
46use std::sync::Arc;
47use sway_ast::AttributeDecl;
48use sway_error::convert_parse_tree_error::ConvertParseTreeError;
49use sway_error::handler::{ErrorEmitted, Handler};
50use sway_error::warning::{CompileWarning, Warning};
51use sway_features::ExperimentalFeatures;
52use sway_ir::{
53 create_o1_pass_group, register_known_passes, Context, Kind, Module, PassGroup, PassManager,
54 PrintPassesOpts, ARG_DEMOTION_NAME, CONST_DEMOTION_NAME, DCE_NAME, FN_DEDUP_DEBUG_PROFILE_NAME,
55 FN_INLINE_NAME, GLOBALS_DCE_NAME, MEM2REG_NAME, MEMCPYOPT_NAME, MISC_DEMOTION_NAME,
56 RET_DEMOTION_NAME, SIMPLIFY_CFG_NAME, SROA_NAME,
57};
58use sway_types::span::Source;
59use sway_types::{SourceEngine, Span};
60use sway_utils::{time_expr, PerformanceData, PerformanceMetric};
61use transform::{ArgsExpectValues, Attribute, AttributeKind, Attributes, ExpectedArgs};
62use types::{CollectTypesMetadata, CollectTypesMetadataContext, TypeMetadata};
63
64pub use semantic_analysis::namespace::{self, Namespace};
65pub mod types;
66
67use sway_error::error::CompileError;
68use sway_types::{ident::Ident, span, Spanned};
69pub use type_system::*;
70
71pub use language::Programs;
72use language::{lexed, parsed, ty, Visibility};
73use transform::to_parsed_lang::{self, convert_module_kind};
74
75pub mod fuel_prelude {
76 pub use fuel_vm::{self, fuel_asm, fuel_crypto, fuel_tx, fuel_types};
77}
78
79pub use engine_threading::Engines;
80
81pub fn parse(
95 src: Source,
96 handler: &Handler,
97 engines: &Engines,
98 config: Option<&BuildConfig>,
99 experimental: ExperimentalFeatures,
100) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
101 match config {
102 None => parse_in_memory(handler, engines, src, experimental, DbgGeneration::None),
103 Some(config) => parse_module_tree(
106 handler,
107 engines,
108 src,
109 config.canonical_root_module(),
110 None,
111 config.build_target,
112 config.dbg_generation,
113 config.include_tests,
114 experimental,
115 config.lsp_mode.as_ref(),
116 )
117 .map(
118 |ParsedModuleTree {
119 tree_type: kind,
120 lexed_module,
121 parse_module,
122 }| {
123 let lexed = lexed::LexedProgram {
124 kind,
125 root: lexed_module,
126 };
127 let parsed = parsed::ParseProgram {
128 kind,
129 root: parse_module,
130 };
131 (lexed, parsed)
132 },
133 ),
134 }
135}
136
137pub fn parse_tree_type(handler: &Handler, src: Source) -> Result<parsed::TreeType, ErrorEmitted> {
141 sway_parse::parse_module_kind(handler, src, None).map(|kind| convert_module_kind(&kind))
142}
143
144pub(crate) fn attr_decls_to_attributes(
153 attribute_decls: &[AttributeDecl],
154 can_annotate: impl Fn(&Attribute) -> bool,
155 target_friendly_name: &'static str,
156) -> (Handler, Attributes) {
157 let handler = Handler::default();
158 for attr_decl in attribute_decls
167 .iter()
168 .filter(|attr| !attr.is_doc_comment() && attr.is_inner())
169 {
170 handler.emit_err(CompileError::Unimplemented {
171 span: attr_decl.hash_kind.span(),
172 feature: "Using inner attributes (`#!`)".to_string(),
173 help: vec![],
174 });
175 }
176
177 let attributes = Attributes::new(attribute_decls);
178
179 for attribute in attributes.unknown().filter(|attr| attr.is_outer()) {
181 handler.emit_warn(CompileWarning {
182 span: attribute.name.span(),
183 warning_content: Warning::UnknownAttribute {
184 attribute: (&attribute.name).into(),
185 known_attributes: attributes.known_attribute_names(),
186 },
187 });
188 }
189
190 for ((attribute_kind, _attribute_direction), mut attributes) in &attributes
192 .all()
193 .filter(|attr| attr.is_doc_comment() || attr.is_outer())
194 .chunk_by(|attr| (attr.kind, attr.direction))
195 {
196 if attribute_kind == AttributeKind::DocComment {
199 let first_doc_line = attributes
200 .next()
201 .expect("`chunk_by` guarantees existence of at least one element in the chunk");
202 if !can_annotate(first_doc_line) {
203 let last_doc_line = match attributes.last() {
204 Some(last_attr) => last_attr,
205 None => first_doc_line,
207 };
208 handler.emit_err(
209 ConvertParseTreeError::InvalidAttributeTarget {
210 span: Span::join(
211 first_doc_line.span.clone(),
212 &last_doc_line.span.start_span(),
213 ),
214 attribute: first_doc_line.name.clone(),
215 target_friendly_name,
216 can_only_annotate_help: first_doc_line
217 .can_only_annotate_help(target_friendly_name),
218 }
219 .into(),
220 );
221 }
222 } else {
223 for attribute in attributes {
225 if !can_annotate(attribute) {
226 handler.emit_err(
227 ConvertParseTreeError::InvalidAttributeTarget {
228 span: attribute.name.span(),
229 attribute: attribute.name.clone(),
230 target_friendly_name,
231 can_only_annotate_help: attribute
232 .can_only_annotate_help(target_friendly_name),
233 }
234 .into(),
235 );
236 }
237 }
238 }
239 }
240
241 let should_be_checked =
244 |attr: &&Attribute| !attr.is_doc_comment() && attr.is_outer() && can_annotate(attr);
245
246 for (_attribute_kind, attributes_of_kind) in
248 attributes.all_by_kind(|attr| should_be_checked(attr) && !attr.kind.allows_multiple())
249 {
250 if attributes_of_kind.len() > 1 {
251 let (last_attribute, previous_attributes) = attributes_of_kind
252 .split_last()
253 .expect("`attributes_of_kind` has more then one element");
254 handler.emit_err(
255 ConvertParseTreeError::InvalidAttributeMultiplicity {
256 last_occurrence: (&last_attribute.name).into(),
257 previous_occurrences: previous_attributes
258 .iter()
259 .map(|attr| (&attr.name).into())
260 .collect(),
261 }
262 .into(),
263 );
264 }
265 }
266
267 for attribute in attributes.all().filter(should_be_checked) {
271 let _ = attribute.check_args_multiplicity(&handler);
272 }
273
274 for attribute in attributes
280 .all()
281 .filter(|attr| should_be_checked(attr) && attr.can_have_arguments())
282 {
283 match attribute.expected_args() {
284 ExpectedArgs::None => unreachable!("`attribute` can have arguments"),
285 ExpectedArgs::Any => {}
286 ExpectedArgs::MustBeIn(expected_args) => {
287 for arg in attribute.args.iter() {
288 if !expected_args.contains(&arg.name.as_str()) {
289 handler.emit_err(
290 ConvertParseTreeError::InvalidAttributeArg {
291 attribute: attribute.name.clone(),
292 arg: (&arg.name).into(),
293 expected_args: expected_args.clone(),
294 }
295 .into(),
296 );
297 }
298 }
299 }
300 ExpectedArgs::ShouldBeIn(expected_args) => {
301 for arg in attribute.args.iter() {
302 if !expected_args.contains(&arg.name.as_str()) {
303 handler.emit_warn(CompileWarning {
304 span: arg.name.span(),
305 warning_content: Warning::UnknownAttributeArg {
306 attribute: attribute.name.clone(),
307 arg: (&arg.name).into(),
308 expected_args: expected_args.clone(),
309 },
310 });
311 }
312 }
313 }
314 }
315 }
316
317 for attribute in attributes
321 .all()
322 .filter(|attr| should_be_checked(attr) && attr.can_have_arguments())
323 {
324 fn check_value_expected(handler: &Handler, attribute: &Attribute, is_value_expected: bool) {
329 for arg in attribute.args.iter() {
330 if let ExpectedArgs::MustBeIn(expected_args) = attribute.expected_args() {
331 if !expected_args.contains(&arg.name.as_str()) {
332 continue;
333 }
334 }
335
336 if (is_value_expected && arg.value.is_none())
337 || (!is_value_expected && arg.value.is_some())
338 {
339 handler.emit_err(
340 ConvertParseTreeError::InvalidAttributeArgExpectsValue {
341 attribute: attribute.name.clone(),
342 arg: (&arg.name).into(),
343 value_span: arg.value.as_ref().map(|literal| literal.span()),
344 }
345 .into(),
346 );
347 }
348 }
349 }
350
351 match attribute.args_expect_values() {
352 ArgsExpectValues::Yes => check_value_expected(&handler, attribute, true),
353 ArgsExpectValues::No => check_value_expected(&handler, attribute, false),
354 ArgsExpectValues::Maybe => {}
355 }
356 }
357
358 (handler, attributes)
359}
360
361fn parse_in_memory(
363 handler: &Handler,
364 engines: &Engines,
365 src: Source,
366 experimental: ExperimentalFeatures,
367 dbg_generation: DbgGeneration,
368) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
369 let mut hasher = DefaultHasher::new();
370 src.text.hash(&mut hasher);
371 let hash = hasher.finish();
372 let module = sway_parse::parse_file(handler, src, None)?;
373
374 let (attributes_handler, attributes) = attr_decls_to_attributes(
375 &module.attributes,
376 |attr| attr.can_annotate_module_kind(),
377 module.value.kind.friendly_name(),
378 );
379 let attributes_error_emitted = handler.append(attributes_handler);
380
381 let (kind, tree) = to_parsed_lang::convert_parse_tree(
382 &mut to_parsed_lang::Context::new(BuildTarget::EVM, dbg_generation, experimental),
383 handler,
384 engines,
385 module.value.clone(),
386 )?;
387
388 match attributes_error_emitted {
389 Some(err) => Err(err),
390 None => {
391 let root = parsed::ParseModule {
392 span: span::Span::dummy(),
393 module_kind_span: module.value.kind.span(),
394 module_eval_order: vec![],
395 tree,
396 submodules: vec![],
397 attributes,
398 hash,
399 };
400 let lexed_program = lexed::LexedProgram::new(
401 kind,
402 lexed::LexedModule {
403 tree: module,
404 submodules: vec![],
405 },
406 );
407 Ok((lexed_program, parsed::ParseProgram { kind, root }))
408 }
409 }
410}
411
412pub struct Submodule {
413 name: Ident,
414 path: Arc<PathBuf>,
415 lexed: lexed::LexedSubmodule,
416 parsed: parsed::ParseSubmodule,
417}
418
419pub type Submodules = Vec<Submodule>;
421
422#[allow(clippy::too_many_arguments)]
424fn parse_submodules(
425 handler: &Handler,
426 engines: &Engines,
427 module_name: Option<&str>,
428 module: &sway_ast::Module,
429 module_dir: &Path,
430 build_target: BuildTarget,
431 dbg_generation: DbgGeneration,
432 include_tests: bool,
433 experimental: ExperimentalFeatures,
434 lsp_mode: Option<&LspConfig>,
435) -> Submodules {
436 let mut submods = Vec::with_capacity(module.submodules().count());
438 module.submodules().for_each(|submod| {
439 let submod_path = Arc::new(module_path(module_dir, module_name, submod));
442 let submod_src: Source = match std::fs::read_to_string(&*submod_path) {
443 Ok(s) => s.as_str().into(),
444 Err(e) => {
445 handler.emit_err(CompileError::FileCouldNotBeRead {
446 span: submod.name.span(),
447 file_path: submod_path.to_string_lossy().to_string(),
448 stringified_error: e.to_string(),
449 });
450 return;
451 }
452 };
453 if let Ok(ParsedModuleTree {
454 tree_type: kind,
455 lexed_module,
456 parse_module,
457 }) = parse_module_tree(
458 handler,
459 engines,
460 submod_src.clone(),
461 submod_path.clone(),
462 Some(submod.name.as_str()),
463 build_target,
464 dbg_generation,
465 include_tests,
466 experimental,
467 lsp_mode,
468 ) {
469 if !matches!(kind, parsed::TreeType::Library) {
470 let source_id = engines.se().get_source_id(submod_path.as_ref());
471 let span = span::Span::new(submod_src, 0, 0, Some(source_id)).unwrap();
472 handler.emit_err(CompileError::ImportMustBeLibrary { span });
473 return;
474 }
475
476 let parse_submodule = parsed::ParseSubmodule {
477 module: parse_module,
478 visibility: match submod.visibility {
479 Some(..) => Visibility::Public,
480 None => Visibility::Private,
481 },
482 mod_name_span: submod.name.span(),
483 };
484 let lexed_submodule = lexed::LexedSubmodule {
485 module: lexed_module,
486 };
487 let submodule = Submodule {
488 name: submod.name.clone(),
489 path: submod_path,
490 lexed: lexed_submodule,
491 parsed: parse_submodule,
492 };
493 submods.push(submodule);
494 }
495 });
496 submods
497}
498
499pub type SourceHash = u64;
500
501#[derive(Clone, Debug)]
502pub struct ParsedModuleTree {
503 pub tree_type: parsed::TreeType,
504 pub lexed_module: lexed::LexedModule,
505 pub parse_module: parsed::ParseModule,
506}
507
508#[allow(clippy::too_many_arguments)]
511fn parse_module_tree(
512 handler: &Handler,
513 engines: &Engines,
514 src: Source,
515 path: Arc<PathBuf>,
516 module_name: Option<&str>,
517 build_target: BuildTarget,
518 dbg_generation: DbgGeneration,
519 include_tests: bool,
520 experimental: ExperimentalFeatures,
521 lsp_mode: Option<&LspConfig>,
522) -> Result<ParsedModuleTree, ErrorEmitted> {
523 let query_engine = engines.qe();
524
525 let module_dir = path.parent().expect("module file has no parent directory");
527 let source_id = engines.se().get_source_id(&path.clone());
528 let module = sway_parse::parse_file(handler, src.clone(), Some(source_id))?;
529
530 let submodules = parse_submodules(
533 handler,
534 engines,
535 module_name,
536 &module.value,
537 module_dir,
538 build_target,
539 dbg_generation,
540 include_tests,
541 experimental,
542 lsp_mode,
543 );
544
545 let (attributes_handler, attributes) = attr_decls_to_attributes(
546 &module.attributes,
547 |attr| attr.can_annotate_module_kind(),
548 module.value.kind.friendly_name(),
549 );
550 let attributes_error_emitted = handler.append(attributes_handler);
551
552 let (kind, tree) = to_parsed_lang::convert_parse_tree(
554 &mut to_parsed_lang::Context::new(build_target, dbg_generation, experimental),
555 handler,
556 engines,
557 module.value.clone(),
558 )?;
559
560 if let Some(err) = attributes_error_emitted {
561 return Err(err);
562 }
563
564 let module_kind_span = module.value.kind.span();
565 let lexed_submodules = submodules
566 .iter()
567 .map(|s| (s.name.clone(), s.lexed.clone()))
568 .collect::<Vec<_>>();
569 let lexed = lexed::LexedModule {
570 tree: module,
571 submodules: lexed_submodules,
572 };
573
574 let mut hasher = DefaultHasher::new();
575 src.text.hash(&mut hasher);
576 let hash = hasher.finish();
577
578 let parsed_submodules = submodules
579 .iter()
580 .map(|s| (s.name.clone(), s.parsed.clone()))
581 .collect::<Vec<_>>();
582 let parsed = parsed::ParseModule {
583 span: span::Span::new(src, 0, 0, Some(source_id)).unwrap(),
584 module_kind_span,
585 module_eval_order: vec![],
586 tree,
587 submodules: parsed_submodules,
588 attributes,
589 hash,
590 };
591
592 let modified_time = std::fs::metadata(path.as_path())
594 .ok()
595 .and_then(|m| m.modified().ok());
596 let dependencies = submodules.into_iter().map(|s| s.path).collect::<Vec<_>>();
597 let version = lsp_mode
598 .and_then(|lsp| lsp.file_versions.get(path.as_ref()).copied())
599 .unwrap_or(None);
600
601 let common_info = ModuleCommonInfo {
602 path: path.clone(),
603 include_tests,
604 dependencies,
605 hash,
606 };
607 let parsed_info = ParsedModuleInfo {
608 modified_time,
609 version,
610 };
611 let cache_entry = ModuleCacheEntry::new(common_info, parsed_info);
612 query_engine.update_or_insert_parsed_module_cache_entry(cache_entry);
613
614 Ok(ParsedModuleTree {
615 tree_type: kind,
616 lexed_module: lexed,
617 parse_module: parsed,
618 })
619}
620
621pub(crate) fn is_ty_module_cache_up_to_date(
629 engines: &Engines,
630 path: &Arc<PathBuf>,
631 include_tests: bool,
632 build_config: Option<&BuildConfig>,
633) -> bool {
634 let cache = engines.qe().module_cache.read();
635 let key = ModuleCacheKey::new(path.clone(), include_tests);
636 cache.get(&key).is_some_and(|entry| {
637 entry.typed.as_ref().is_some_and(|typed| {
638 let cache_up_to_date = build_config
640 .and_then(|x| x.lsp_mode.as_ref())
641 .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
642 .is_none_or(|version| {
643 version.map_or(true, |v| typed.version.is_some_and(|tv| v <= tv))
644 });
645
646 cache_up_to_date
648 && entry.common.dependencies.iter().all(|dep_path| {
649 is_ty_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
650 })
651 })
652 })
653}
654
655pub(crate) fn is_parse_module_cache_up_to_date(
660 engines: &Engines,
661 path: &Arc<PathBuf>,
662 include_tests: bool,
663 build_config: Option<&BuildConfig>,
664) -> bool {
665 let cache = engines.qe().module_cache.read();
666 let key = ModuleCacheKey::new(path.clone(), include_tests);
667 cache.get(&key).is_some_and(|entry| {
668 let cache_up_to_date = build_config
670 .and_then(|x| x.lsp_mode.as_ref())
671 .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
672 .map_or_else(
673 || {
674 let modified_time = std::fs::metadata(path.as_path())
676 .ok()
677 .and_then(|m| m.modified().ok());
678 entry.parsed.modified_time == modified_time || {
680 let src = std::fs::read_to_string(path.as_path()).unwrap();
681 let mut hasher = DefaultHasher::new();
682 src.hash(&mut hasher);
683 hasher.finish() == entry.common.hash
684 }
685 },
686 |version| {
687 version.map_or(true, |v| entry.parsed.version.is_some_and(|ev| v <= ev))
694 },
695 );
696
697 cache_up_to_date
700 && entry.common.dependencies.iter().all(|dep_path| {
701 is_parse_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
702 })
703 })
704}
705
706fn module_path(
707 parent_module_dir: &Path,
708 parent_module_name: Option<&str>,
709 submod: &sway_ast::Submodule,
710) -> PathBuf {
711 if let Some(parent_name) = parent_module_name {
712 parent_module_dir
713 .join(parent_name)
714 .join(submod.name.to_string())
715 .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
716 } else {
717 parent_module_dir
719 .join(submod.name.to_string())
720 .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
721 }
722}
723
724pub fn build_module_dep_graph(
725 handler: &Handler,
726 parse_module: &mut parsed::ParseModule,
727) -> Result<(), ErrorEmitted> {
728 let module_dep_graph = ty::TyModule::build_dep_graph(handler, parse_module)?;
729 parse_module.module_eval_order = module_dep_graph.compute_order(handler)?;
730
731 for (_, submodule) in &mut parse_module.submodules {
732 build_module_dep_graph(handler, &mut submodule.module)?;
733 }
734 Ok(())
735}
736
737pub struct CompiledAsm(pub FinalizedAsm);
738
739#[allow(clippy::too_many_arguments)]
740pub fn parsed_to_ast(
741 handler: &Handler,
742 engines: &Engines,
743 parse_program: &mut parsed::ParseProgram,
744 initial_namespace: namespace::Package,
745 build_config: Option<&BuildConfig>,
746 package_name: &str,
747 retrigger_compilation: Option<Arc<AtomicBool>>,
748 experimental: ExperimentalFeatures,
749) -> Result<ty::TyProgram, TypeCheckFailed> {
750 let lsp_config = build_config.map(|x| x.lsp_mode.clone()).unwrap_or_default();
751
752 build_module_dep_graph(handler, &mut parse_program.root).map_err(|error| TypeCheckFailed {
754 root_module: None,
755 namespace: initial_namespace.clone(),
756 error,
757 })?;
758
759 let collection_namespace = Namespace::new(handler, engines, initial_namespace.clone(), true)
760 .map_err(|error| TypeCheckFailed {
761 root_module: None,
762 namespace: initial_namespace.clone(),
763 error,
764 })?;
765 let mut collection_ctx =
768 ty::TyProgram::collect(handler, engines, parse_program, collection_namespace).map_err(
769 |error| TypeCheckFailed {
770 root_module: None,
771 namespace: initial_namespace.clone(),
772 error,
773 },
774 )?;
775
776 let typecheck_namespace =
777 Namespace::new(handler, engines, initial_namespace, true).map_err(|error| {
778 TypeCheckFailed {
779 root_module: None,
780 namespace: collection_ctx.namespace().current_package_ref().clone(),
781 error,
782 }
783 })?;
784 let typed_program_opt = ty::TyProgram::type_check(
786 handler,
787 engines,
788 parse_program,
789 &mut collection_ctx,
790 typecheck_namespace,
791 package_name,
792 build_config,
793 experimental,
794 );
795
796 let mut typed_program = typed_program_opt?;
797
798 check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
799 TypeCheckFailed {
800 root_module: Some(Arc::new(typed_program.root_module.clone())),
801 namespace: typed_program.namespace.current_package_ref().clone(),
802 error,
803 }
804 })?;
805 if lsp_config.is_none() {
809 engines.pe().clear();
810 }
811
812 typed_program.check_deprecated(engines, handler);
813
814 match typed_program.check_recursive(engines, handler) {
815 Ok(()) => {}
816 Err(error) => {
817 handler.dedup();
818 return Err(TypeCheckFailed {
819 root_module: Some(Arc::new(typed_program.root_module.clone())),
820 namespace: typed_program.namespace.current_package().clone(),
821 error,
822 });
823 }
824 };
825
826 let types_metadata = if !lsp_config.as_ref().is_some_and(|lsp| lsp.optimized_build) {
828 let types_metadata_result = typed_program.collect_types_metadata(
830 handler,
831 &mut CollectTypesMetadataContext::new(engines, experimental, package_name.to_string()),
832 );
833 let types_metadata = match types_metadata_result {
834 Ok(types_metadata) => types_metadata,
835 Err(error) => {
836 handler.dedup();
837 return Err(TypeCheckFailed {
838 root_module: Some(Arc::new(typed_program.root_module.clone())),
839 namespace: typed_program.namespace.current_package().clone(),
840 error,
841 });
842 }
843 };
844
845 typed_program
846 .logged_types
847 .extend(types_metadata.iter().filter_map(|m| match m {
848 TypeMetadata::LoggedType(log_id, type_id) => Some((*log_id, *type_id)),
849 _ => None,
850 }));
851
852 typed_program
853 .messages_types
854 .extend(types_metadata.iter().filter_map(|m| match m {
855 TypeMetadata::MessageType(message_id, type_id) => Some((*message_id, *type_id)),
856 _ => None,
857 }));
858
859 let (print_graph, print_graph_url_format) = match build_config {
860 Some(cfg) => (
861 cfg.print_dca_graph.clone(),
862 cfg.print_dca_graph_url_format.clone(),
863 ),
864 None => (None, None),
865 };
866
867 check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
868 TypeCheckFailed {
869 root_module: Some(Arc::new(typed_program.root_module.clone())),
870 namespace: typed_program.namespace.current_package_ref().clone(),
871 error,
872 }
873 })?;
874
875 let _ = perform_control_flow_analysis(
877 handler,
878 engines,
879 &typed_program,
880 print_graph,
881 print_graph_url_format,
882 );
883
884 types_metadata
885 } else {
886 vec![]
887 };
888
889 let mut ctx = Context::new(engines.se(), experimental);
891 let module = Module::new(&mut ctx, Kind::Contract);
892 if let Err(errs) = ir_generation::compile::compile_constants_for_package(
893 engines,
894 &mut ctx,
895 module,
896 &typed_program.namespace,
897 ) {
898 errs.into_iter().for_each(|err| {
899 handler.emit_err(err.clone());
900 });
901 }
902
903 let cei_analysis_warnings =
905 semantic_analysis::cei_pattern_analysis::analyze_program(engines, &typed_program);
906 for warn in cei_analysis_warnings {
907 handler.emit_warn(warn);
908 }
909
910 let mut md_mgr = MetadataManager::default();
911 typed_program
913 .get_typed_program_with_initialized_storage_slots(
914 handler,
915 engines,
916 &mut ctx,
917 &mut md_mgr,
918 module,
919 )
920 .map_err(|error: ErrorEmitted| {
921 handler.dedup();
922 TypeCheckFailed {
923 root_module: Some(Arc::new(typed_program.root_module.clone())),
924 namespace: typed_program.namespace.current_package_ref().clone(),
925 error,
926 }
927 })?;
928
929 for err in types_metadata.iter().filter_map(|m| match m {
931 TypeMetadata::UnresolvedType(name, call_site_span_opt) => {
932 Some(CompileError::UnableToInferGeneric {
933 ty: name.as_str().to_string(),
934 span: call_site_span_opt.clone().unwrap_or_else(|| name.span()),
935 })
936 }
937 _ => None,
938 }) {
939 handler.emit_err(err);
940 }
941
942 Ok(typed_program)
943}
944
945#[allow(clippy::too_many_arguments)]
946pub fn compile_to_ast(
947 handler: &Handler,
948 engines: &Engines,
949 src: Source,
950 initial_namespace: namespace::Package,
951 build_config: Option<&BuildConfig>,
952 package_name: &str,
953 retrigger_compilation: Option<Arc<AtomicBool>>,
954 experimental: ExperimentalFeatures,
955) -> Result<Programs, ErrorEmitted> {
956 check_should_abort(handler, retrigger_compilation.clone())?;
957
958 let query_engine = engines.qe();
959 let mut metrics = PerformanceData::default();
960 if let Some(config) = build_config {
961 let path = config.canonical_root_module();
962 let include_tests = config.include_tests;
963 if is_parse_module_cache_up_to_date(engines, &path, include_tests, build_config) {
965 let mut entry = query_engine.get_programs_cache_entry(&path).unwrap();
966 entry.programs.metrics.reused_programs += 1;
967
968 let (warnings, errors) = entry.handler_data;
969 let new_handler = Handler::from_parts(warnings, errors);
970 handler.append(new_handler);
971 return Ok(entry.programs);
972 };
973 }
974
975 let parse_program_opt = time_expr!(
977 package_name,
978 "parse the program to a concrete syntax tree (CST)",
979 "parse_cst",
980 parse(src, handler, engines, build_config, experimental),
981 build_config,
982 metrics
983 );
984
985 check_should_abort(handler, retrigger_compilation.clone())?;
986
987 let (lexed_program, mut parsed_program) = match parse_program_opt {
988 Ok(modules) => modules,
989 Err(e) => {
990 handler.dedup();
991 return Err(e);
992 }
993 };
994
995 if build_config.is_none_or(|config| !config.include_tests) {
997 parsed_program.exclude_tests(engines);
998 }
999
1000 let program = time_expr!(
1002 package_name,
1003 "parse the concrete syntax tree (CST) to a typed AST",
1004 "parse_ast",
1005 parsed_to_ast(
1006 handler,
1007 engines,
1008 &mut parsed_program,
1009 initial_namespace,
1010 build_config,
1011 package_name,
1012 retrigger_compilation.clone(),
1013 experimental
1014 ),
1015 build_config,
1016 metrics
1017 );
1018
1019 check_should_abort(handler, retrigger_compilation.clone())?;
1020
1021 handler.dedup();
1022
1023 let programs = Programs::new(
1024 Arc::new(lexed_program),
1025 Arc::new(parsed_program),
1026 program.map(Arc::new),
1027 metrics,
1028 );
1029
1030 if let Some(config) = build_config {
1031 let path = config.canonical_root_module();
1032 let cache_entry = ProgramsCacheEntry {
1033 path,
1034 programs: programs.clone(),
1035 handler_data: handler.clone().consume(),
1036 };
1037 query_engine.insert_programs_cache_entry(cache_entry);
1038 }
1039
1040 check_should_abort(handler, retrigger_compilation.clone())?;
1041
1042 Ok(programs)
1043}
1044
1045pub fn compile_to_asm(
1048 handler: &Handler,
1049 engines: &Engines,
1050 src: Source,
1051 initial_namespace: namespace::Package,
1052 build_config: &BuildConfig,
1053 package_name: &str,
1054 experimental: ExperimentalFeatures,
1055) -> Result<CompiledAsm, ErrorEmitted> {
1056 let ast_res = compile_to_ast(
1057 handler,
1058 engines,
1059 src,
1060 initial_namespace,
1061 Some(build_config),
1062 package_name,
1063 None,
1064 experimental,
1065 )?;
1066 ast_to_asm(handler, engines, &ast_res, build_config, experimental)
1067}
1068
1069pub fn ast_to_asm(
1072 handler: &Handler,
1073 engines: &Engines,
1074 programs: &Programs,
1075 build_config: &BuildConfig,
1076 experimental: ExperimentalFeatures,
1077) -> Result<CompiledAsm, ErrorEmitted> {
1078 let typed_program = match &programs.typed {
1079 Ok(typed_program) => typed_program,
1080 Err(err) => return Err(err.error),
1081 };
1082
1083 let asm =
1084 match compile_ast_to_ir_to_asm(handler, engines, typed_program, build_config, experimental)
1085 {
1086 Ok(res) => res,
1087 Err(err) => {
1088 handler.dedup();
1089 return Err(err);
1090 }
1091 };
1092 Ok(CompiledAsm(asm))
1093}
1094
1095pub(crate) fn compile_ast_to_ir_to_asm(
1096 handler: &Handler,
1097 engines: &Engines,
1098 program: &ty::TyProgram,
1099 build_config: &BuildConfig,
1100 experimental: ExperimentalFeatures,
1101) -> Result<FinalizedAsm, ErrorEmitted> {
1102 let mut ir = match ir_generation::compile_program(
1114 program,
1115 build_config.include_tests,
1116 engines,
1117 experimental,
1118 ) {
1119 Ok(ir) => ir,
1120 Err(errors) => {
1121 let mut last = None;
1122 for e in errors {
1123 last = Some(handler.emit_err(e));
1124 }
1125 return Err(last.unwrap());
1126 }
1127 };
1128
1129 let entry_point_functions: Vec<::sway_ir::Function> = ir
1131 .module_iter()
1132 .flat_map(|module| module.function_iter(&ir))
1133 .filter(|func| func.is_entry(&ir))
1134 .collect();
1135
1136 {
1138 let mut env = ir_generation::PurityEnv::default();
1139 let mut md_mgr = metadata::MetadataManager::default();
1140 for entry_point in &entry_point_functions {
1141 check_function_purity(handler, &mut env, &ir, &mut md_mgr, entry_point);
1142 }
1143 }
1144
1145 let mut pass_mgr = PassManager::default();
1147 register_known_passes(&mut pass_mgr);
1148 let mut pass_group = PassGroup::default();
1149
1150 match build_config.optimization_level {
1151 OptLevel::Opt1 => {
1152 pass_group.append_group(create_o1_pass_group());
1153 }
1154 OptLevel::Opt0 => {
1155 pass_group.append_pass(FN_DEDUP_DEBUG_PROFILE_NAME);
1158
1159 pass_group.append_pass(FN_INLINE_NAME);
1161
1162 pass_group.append_pass(GLOBALS_DCE_NAME);
1164 pass_group.append_pass(DCE_NAME);
1165 }
1166 }
1167
1168 if build_config.build_target == BuildTarget::Fuel {
1170 pass_group.append_pass(CONST_DEMOTION_NAME);
1175 pass_group.append_pass(ARG_DEMOTION_NAME);
1176 pass_group.append_pass(RET_DEMOTION_NAME);
1177 pass_group.append_pass(MISC_DEMOTION_NAME);
1178
1179 pass_group.append_pass(MEMCPYOPT_NAME);
1181
1182 pass_group.append_pass(DCE_NAME);
1184 pass_group.append_pass(SIMPLIFY_CFG_NAME);
1185
1186 match build_config.optimization_level {
1187 OptLevel::Opt1 => {
1188 pass_group.append_pass(SROA_NAME);
1189 pass_group.append_pass(MEM2REG_NAME);
1190 pass_group.append_pass(DCE_NAME);
1191 }
1192 OptLevel::Opt0 => {}
1193 }
1194 }
1195
1196 let print_passes_opts: PrintPassesOpts = (&build_config.print_ir).into();
1198 let res =
1199 if let Err(ir_error) = pass_mgr.run_with_print(&mut ir, &pass_group, &print_passes_opts) {
1200 Err(handler.emit_err(CompileError::InternalOwned(
1201 ir_error.to_string(),
1202 span::Span::dummy(),
1203 )))
1204 } else {
1205 Ok(())
1206 };
1207 res?;
1208
1209 compile_ir_context_to_finalized_asm(handler, &ir, Some(build_config))
1210}
1211
1212#[allow(clippy::too_many_arguments)]
1214pub fn compile_to_bytecode(
1215 handler: &Handler,
1216 engines: &Engines,
1217 src: Source,
1218 initial_namespace: namespace::Package,
1219 build_config: &BuildConfig,
1220 source_map: &mut SourceMap,
1221 package_name: &str,
1222 experimental: ExperimentalFeatures,
1223) -> Result<CompiledBytecode, ErrorEmitted> {
1224 let mut asm_res = compile_to_asm(
1225 handler,
1226 engines,
1227 src,
1228 initial_namespace,
1229 build_config,
1230 package_name,
1231 experimental,
1232 )?;
1233 asm_to_bytecode(
1234 handler,
1235 &mut asm_res,
1236 source_map,
1237 engines.se(),
1238 build_config,
1239 )
1240}
1241
1242pub const PRELUDE_CONFIGURABLES_SIZE_IN_BYTES: usize = 8;
1244pub const PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES: usize = 16;
1246pub const PRELUDE_SIZE_IN_BYTES: usize = 32;
1248
1249pub fn set_bytecode_configurables_offset(
1251 compiled_bytecode: &mut CompiledBytecode,
1252 md: &[u8; PRELUDE_CONFIGURABLES_SIZE_IN_BYTES],
1253) {
1254 assert!(
1255 compiled_bytecode.bytecode.len()
1256 >= PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES + PRELUDE_CONFIGURABLES_SIZE_IN_BYTES
1257 );
1258 let code = &mut compiled_bytecode.bytecode;
1259 for (index, byte) in md.iter().enumerate() {
1260 code[index + PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES] = *byte;
1261 }
1262}
1263
1264pub fn asm_to_bytecode(
1266 handler: &Handler,
1267 asm: &mut CompiledAsm,
1268 source_map: &mut SourceMap,
1269 source_engine: &SourceEngine,
1270 build_config: &BuildConfig,
1271) -> Result<CompiledBytecode, ErrorEmitted> {
1272 let compiled_bytecode =
1273 asm.0
1274 .to_bytecode_mut(handler, source_map, source_engine, build_config)?;
1275 Ok(compiled_bytecode)
1276}
1277
1278fn perform_control_flow_analysis(
1281 handler: &Handler,
1282 engines: &Engines,
1283 program: &ty::TyProgram,
1284 print_graph: Option<String>,
1285 print_graph_url_format: Option<String>,
1286) -> Result<(), ErrorEmitted> {
1287 let dca_res = dead_code_analysis(handler, engines, program);
1288 let rpa_errors = return_path_analysis(engines, program);
1289 let rpa_res = handler.scope(|handler| {
1290 for err in rpa_errors {
1291 handler.emit_err(err);
1292 }
1293 Ok(())
1294 });
1295
1296 if let Ok(graph) = dca_res.clone() {
1297 graph.visualize(engines, print_graph, print_graph_url_format);
1298 }
1299 dca_res?;
1300 rpa_res
1301}
1302
1303fn dead_code_analysis<'a>(
1308 handler: &Handler,
1309 engines: &'a Engines,
1310 program: &ty::TyProgram,
1311) -> Result<ControlFlowGraph<'a>, ErrorEmitted> {
1312 let decl_engine = engines.de();
1313 let mut dead_code_graph = ControlFlowGraph::new(engines);
1314 let tree_type = program.kind.tree_type();
1315 module_dead_code_analysis(
1316 handler,
1317 engines,
1318 &program.root_module,
1319 &tree_type,
1320 &mut dead_code_graph,
1321 )?;
1322 let warnings = dead_code_graph.find_dead_code(decl_engine);
1323 for warn in warnings {
1324 handler.emit_warn(warn);
1325 }
1326 Ok(dead_code_graph)
1327}
1328
1329fn module_dead_code_analysis<'eng: 'cfg, 'cfg>(
1331 handler: &Handler,
1332 engines: &'eng Engines,
1333 module: &ty::TyModule,
1334 tree_type: &parsed::TreeType,
1335 graph: &mut ControlFlowGraph<'cfg>,
1336) -> Result<(), ErrorEmitted> {
1337 module
1338 .submodules
1339 .iter()
1340 .try_fold((), |(), (_, submodule)| {
1341 let tree_type = parsed::TreeType::Library;
1342 module_dead_code_analysis(handler, engines, &submodule.module, &tree_type, graph)
1343 })?;
1344 let res = {
1345 ControlFlowGraph::append_module_to_dead_code_graph(
1346 engines,
1347 &module.all_nodes,
1348 tree_type,
1349 graph,
1350 )
1351 .map_err(|err| handler.emit_err(err))
1352 };
1353 graph.connect_pending_entry_edges();
1354 res
1355}
1356
1357fn return_path_analysis(engines: &Engines, program: &ty::TyProgram) -> Vec<CompileError> {
1358 let mut errors = vec![];
1359 module_return_path_analysis(engines, &program.root_module, &mut errors);
1360 errors
1361}
1362
1363fn module_return_path_analysis(
1364 engines: &Engines,
1365 module: &ty::TyModule,
1366 errors: &mut Vec<CompileError>,
1367) {
1368 for (_, submodule) in &module.submodules {
1369 module_return_path_analysis(engines, &submodule.module, errors);
1370 }
1371 let graph = ControlFlowGraph::construct_return_path_graph(engines, &module.all_nodes);
1372 match graph {
1373 Ok(graph) => errors.extend(graph.analyze_return_paths(engines)),
1374 Err(mut error) => errors.append(&mut error),
1375 }
1376}
1377
1378fn check_should_abort(
1381 handler: &Handler,
1382 retrigger_compilation: Option<Arc<AtomicBool>>,
1383) -> Result<(), ErrorEmitted> {
1384 if let Some(ref retrigger_compilation) = retrigger_compilation {
1385 if retrigger_compilation.load(Ordering::SeqCst) {
1386 return Err(handler.cancel());
1387 }
1388 }
1389 Ok(())
1390}
1391
1392#[test]
1393fn test_basic_prog() {
1394 let handler = Handler::default();
1395 let engines = Engines::default();
1396 let prog = parse(
1397 r#"
1398 contract;
1399
1400 enum yo
1401 <T>
1402 where
1403 T: IsAThing
1404 {
1405 x: u32,
1406 y: MyStruct<u32>
1407 }
1408
1409 enum MyOtherSumType
1410 {
1411 x: u32,
1412 y: MyStruct<u32>
1413 }
1414 struct MyStruct<T> {
1415 field_name: u64,
1416 other_field: T,
1417 }
1418
1419
1420 fn generic_function
1421 <T>
1422 (arg1: u64,
1423 arg2: T)
1424 ->
1425 T
1426 where T: Display,
1427 T: Debug {
1428 let x: MyStruct =
1429 MyStruct
1430 {
1431 field_name:
1432 5
1433 };
1434 return
1435 match
1436 arg1
1437 {
1438 1
1439 => true,
1440 _ => { return false; },
1441 };
1442 }
1443
1444 struct MyStruct {
1445 test: string,
1446 }
1447
1448
1449
1450 use stdlib::println;
1451
1452 trait MyTrait {
1453 // interface points
1454 fn myfunc(x: int) -> unit;
1455 } {
1456 // methods
1457 fn calls_interface_fn(x: int) -> unit {
1458 // declare a byte
1459 let x = 0b10101111;
1460 let mut y = 0b11111111;
1461 self.interface_fn(x);
1462 }
1463 }
1464
1465 pub fn prints_number_five() -> u8 {
1466 let x: u8 = 5;
1467 println(x);
1468 x.to_string();
1469 let some_list = [
1470 5,
1471 10 + 3 / 2,
1472 func_app(my_args, (so_many_args))];
1473 return 5;
1474 }
1475 "#
1476 .into(),
1477 &handler,
1478 &engines,
1479 None,
1480 ExperimentalFeatures::default(),
1481 );
1482 prog.unwrap();
1483}
1484#[test]
1485fn test_parenthesized() {
1486 let handler = Handler::default();
1487 let engines = Engines::default();
1488 let prog = parse(
1489 r#"
1490 contract;
1491 pub fn some_abi_func() -> unit {
1492 let x = (5 + 6 / (1 + (2 / 1) + 4));
1493 return;
1494 }
1495 "#
1496 .into(),
1497 &handler,
1498 &engines,
1499 None,
1500 ExperimentalFeatures::default(),
1501 );
1502 prog.unwrap();
1503}
1504
1505#[test]
1506fn test_unary_ordering() {
1507 use crate::language::{self, parsed};
1508 let handler = Handler::default();
1509 let engines = Engines::default();
1510 let prog = parse(
1511 r#"
1512 script;
1513 fn main() -> bool {
1514 let a = true;
1515 let b = true;
1516 !a && b;
1517 }"#
1518 .into(),
1519 &handler,
1520 &engines,
1521 None,
1522 ExperimentalFeatures::default(),
1523 );
1524 let (.., prog) = prog.unwrap();
1525 if let parsed::AstNode {
1528 content:
1529 parsed::AstNodeContent::Declaration(parsed::Declaration::FunctionDeclaration(decl_id)),
1530 ..
1531 } = &prog.root.tree.root_nodes[0]
1532 {
1533 let fn_decl = engines.pe().get_function(decl_id);
1534 if let parsed::AstNode {
1535 content:
1536 parsed::AstNodeContent::Expression(parsed::Expression {
1537 kind:
1538 parsed::ExpressionKind::LazyOperator(parsed::LazyOperatorExpression {
1539 op, ..
1540 }),
1541 ..
1542 }),
1543 ..
1544 } = &fn_decl.body.contents[2]
1545 {
1546 assert_eq!(op, &language::LazyOp::And)
1547 } else {
1548 panic!("Was not lazy operator.")
1549 }
1550 } else {
1551 panic!("Was not ast node")
1552 };
1553}
1554
1555#[test]
1556fn test_parser_recovery() {
1557 let handler = Handler::default();
1558 let engines = Engines::default();
1559 let prog = parse(
1560 r#"
1561 script;
1562 fn main() -> bool {
1563 let
1564 let a = true;
1565 true
1566 }"#
1567 .into(),
1568 &handler,
1569 &engines,
1570 None,
1571 ExperimentalFeatures::default(),
1572 );
1573 let (_, _) = prog.unwrap();
1574 assert!(handler.has_errors());
1575 dbg!(handler);
1576}