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::{BuildConfig, BuildTarget, LspConfig, OptLevel, PrintAsm, PrintIr};
35use control_flow_analysis::ControlFlowGraph;
36pub use debug_generation::write_dwarf;
37use indexmap::IndexMap;
38use metadata::MetadataManager;
39use query_engine::{ModuleCacheKey, ModuleCommonInfo, ParsedModuleInfo, ProgramsCacheEntry};
40use semantic_analysis::program::TypeCheckFailed;
41use std::collections::hash_map::DefaultHasher;
42use std::hash::{Hash, Hasher};
43use std::path::{Path, PathBuf};
44use std::sync::atomic::{AtomicBool, Ordering};
45use std::sync::Arc;
46use sway_ast::AttributeDecl;
47use sway_error::handler::{ErrorEmitted, Handler};
48use sway_features::ExperimentalFeatures;
49use sway_ir::{
50 create_o1_pass_group, register_known_passes, Context, Kind, Module, PassGroup, PassManager,
51 PrintPassesOpts, ARG_DEMOTION_NAME, CONST_DEMOTION_NAME, DCE_NAME, FN_DEDUP_DEBUG_PROFILE_NAME,
52 FN_INLINE_NAME, GLOBALS_DCE_NAME, MEM2REG_NAME, MEMCPYOPT_NAME, MISC_DEMOTION_NAME,
53 RET_DEMOTION_NAME, SIMPLIFY_CFG_NAME, SROA_NAME,
54};
55use sway_types::constants::DOC_COMMENT_ATTRIBUTE_NAME;
56use sway_types::SourceEngine;
57use sway_utils::{time_expr, PerformanceData, PerformanceMetric};
58use transform::{Attribute, AttributeArg, AttributeKind, AttributesMap};
59use types::{CollectTypesMetadata, CollectTypesMetadataContext, TypeMetadata};
60
61pub use semantic_analysis::namespace::{self, Namespace};
62pub mod types;
63
64use sway_error::error::CompileError;
65use sway_types::{ident::Ident, span, Spanned};
66pub use type_system::*;
67
68pub use language::Programs;
69use language::{lexed, parsed, ty, Visibility};
70use transform::to_parsed_lang::{self, convert_module_kind};
71
72pub mod fuel_prelude {
73 pub use fuel_vm::{self, fuel_asm, fuel_crypto, fuel_tx, fuel_types};
74}
75
76pub use engine_threading::Engines;
77
78pub fn parse(
92 input: Arc<str>,
93 handler: &Handler,
94 engines: &Engines,
95 config: Option<&BuildConfig>,
96 experimental: ExperimentalFeatures,
97) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
98 match config {
99 None => parse_in_memory(handler, engines, input, experimental),
100 Some(config) => parse_module_tree(
103 handler,
104 engines,
105 input,
106 config.canonical_root_module(),
107 None,
108 config.build_target,
109 config.include_tests,
110 experimental,
111 config.lsp_mode.as_ref(),
112 )
113 .map(
114 |ParsedModuleTree {
115 tree_type: kind,
116 lexed_module,
117 parse_module,
118 }| {
119 let lexed = lexed::LexedProgram {
120 kind,
121 root: lexed_module,
122 };
123 let parsed = parsed::ParseProgram {
124 kind,
125 root: parse_module,
126 };
127 (lexed, parsed)
128 },
129 ),
130 }
131}
132
133pub fn parse_tree_type(
137 handler: &Handler,
138 input: Arc<str>,
139) -> Result<parsed::TreeType, ErrorEmitted> {
140 sway_parse::parse_module_kind(handler, input, None).map(|kind| convert_module_kind(&kind))
141}
142
143fn module_attrs_to_map(
145 handler: &Handler,
146 attribute_list: &[AttributeDecl],
147) -> Result<AttributesMap, ErrorEmitted> {
148 let mut attrs_map: IndexMap<_, Vec<Attribute>> = IndexMap::new();
149 for attr_decl in attribute_list {
150 let attrs = attr_decl.attribute.get().into_iter();
151 for attr in attrs {
152 let name = attr.name.as_str();
153 if name != DOC_COMMENT_ATTRIBUTE_NAME {
154 handler.emit_err(CompileError::ExpectedModuleDocComment {
156 span: attr.name.span(),
157 });
158 }
159
160 let args = attr
161 .args
162 .as_ref()
163 .map(|parens| {
164 parens
165 .get()
166 .into_iter()
167 .cloned()
168 .map(|arg| AttributeArg {
169 name: arg.name.clone(),
170 value: arg.value.clone(),
171 span: arg.span(),
172 })
173 .collect()
174 })
175 .unwrap_or_else(Vec::new);
176
177 let attribute = Attribute {
178 name: attr.name.clone(),
179 args,
180 span: attr_decl.span(),
181 };
182
183 if let Some(attr_kind) = match name {
184 DOC_COMMENT_ATTRIBUTE_NAME => Some(AttributeKind::DocComment),
185 _ => None,
186 } {
187 attrs_map.entry(attr_kind).or_default().push(attribute);
188 }
189 }
190 }
191 Ok(AttributesMap::new(Arc::new(attrs_map)))
192}
193
194fn parse_in_memory(
196 handler: &Handler,
197 engines: &Engines,
198 src: Arc<str>,
199 experimental: ExperimentalFeatures,
200) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
201 let mut hasher = DefaultHasher::new();
202 src.hash(&mut hasher);
203 let hash = hasher.finish();
204 let module = sway_parse::parse_file(handler, src, None)?;
205
206 let (kind, tree) = to_parsed_lang::convert_parse_tree(
207 &mut to_parsed_lang::Context::new(BuildTarget::EVM, experimental),
208 handler,
209 engines,
210 module.value.clone(),
211 )?;
212 let module_kind_span = module.value.kind.span();
213 let submodules = Vec::default();
214 let attributes = module_attrs_to_map(handler, &module.attribute_list)?;
215 let root = parsed::ParseModule {
216 span: span::Span::dummy(),
217 module_kind_span,
218 module_eval_order: vec![],
219 tree,
220 submodules,
221 attributes,
222 hash,
223 };
224 let lexed_program = lexed::LexedProgram::new(
225 kind,
226 lexed::LexedModule {
227 tree: module,
228 submodules: Vec::default(),
229 },
230 );
231
232 Ok((lexed_program, parsed::ParseProgram { kind, root }))
233}
234
235pub struct Submodule {
236 name: Ident,
237 path: Arc<PathBuf>,
238 lexed: lexed::LexedSubmodule,
239 parsed: parsed::ParseSubmodule,
240}
241
242pub type Submodules = Vec<Submodule>;
244
245#[allow(clippy::too_many_arguments)]
247fn parse_submodules(
248 handler: &Handler,
249 engines: &Engines,
250 module_name: Option<&str>,
251 module: &sway_ast::Module,
252 module_dir: &Path,
253 build_target: BuildTarget,
254 include_tests: bool,
255 experimental: ExperimentalFeatures,
256 lsp_mode: Option<&LspConfig>,
257) -> Submodules {
258 let mut submods = Vec::with_capacity(module.submodules().count());
260 module.submodules().for_each(|submod| {
261 let submod_path = Arc::new(module_path(module_dir, module_name, submod));
264 let submod_str: Arc<str> = match std::fs::read_to_string(&*submod_path) {
265 Ok(s) => Arc::from(s),
266 Err(e) => {
267 handler.emit_err(CompileError::FileCouldNotBeRead {
268 span: submod.name.span(),
269 file_path: submod_path.to_string_lossy().to_string(),
270 stringified_error: e.to_string(),
271 });
272 return;
273 }
274 };
275 if let Ok(ParsedModuleTree {
276 tree_type: kind,
277 lexed_module,
278 parse_module,
279 }) = parse_module_tree(
280 handler,
281 engines,
282 submod_str.clone(),
283 submod_path.clone(),
284 Some(submod.name.as_str()),
285 build_target,
286 include_tests,
287 experimental,
288 lsp_mode,
289 ) {
290 if !matches!(kind, parsed::TreeType::Library) {
291 let source_id = engines.se().get_source_id(submod_path.as_ref());
292 let span = span::Span::new(submod_str, 0, 0, Some(source_id)).unwrap();
293 handler.emit_err(CompileError::ImportMustBeLibrary { span });
294 return;
295 }
296
297 let parse_submodule = parsed::ParseSubmodule {
298 module: parse_module,
299 visibility: match submod.visibility {
300 Some(..) => Visibility::Public,
301 None => Visibility::Private,
302 },
303 mod_name_span: submod.name.span(),
304 };
305 let lexed_submodule = lexed::LexedSubmodule {
306 module: lexed_module,
307 };
308 let submodule = Submodule {
309 name: submod.name.clone(),
310 path: submod_path,
311 lexed: lexed_submodule,
312 parsed: parse_submodule,
313 };
314 submods.push(submodule);
315 }
316 });
317 submods
318}
319
320pub type SourceHash = u64;
321
322#[derive(Clone, Debug)]
323pub struct ParsedModuleTree {
324 pub tree_type: parsed::TreeType,
325 pub lexed_module: lexed::LexedModule,
326 pub parse_module: parsed::ParseModule,
327}
328
329#[allow(clippy::too_many_arguments)]
332fn parse_module_tree(
333 handler: &Handler,
334 engines: &Engines,
335 src: Arc<str>,
336 path: Arc<PathBuf>,
337 module_name: Option<&str>,
338 build_target: BuildTarget,
339 include_tests: bool,
340 experimental: ExperimentalFeatures,
341 lsp_mode: Option<&LspConfig>,
342) -> Result<ParsedModuleTree, ErrorEmitted> {
343 let query_engine = engines.qe();
344
345 let module_dir = path.parent().expect("module file has no parent directory");
347 let source_id = engines.se().get_source_id(&path.clone());
348 let module = sway_parse::parse_file(handler, src.clone(), Some(source_id))?;
349
350 let submodules = parse_submodules(
353 handler,
354 engines,
355 module_name,
356 &module.value,
357 module_dir,
358 build_target,
359 include_tests,
360 experimental,
361 lsp_mode,
362 );
363
364 let (kind, tree) = to_parsed_lang::convert_parse_tree(
366 &mut to_parsed_lang::Context::new(build_target, experimental),
367 handler,
368 engines,
369 module.value.clone(),
370 )?;
371 let module_kind_span = module.value.kind.span();
372 let attributes = module_attrs_to_map(handler, &module.attribute_list)?;
373
374 let lexed_submodules = submodules
375 .iter()
376 .map(|s| (s.name.clone(), s.lexed.clone()))
377 .collect::<Vec<_>>();
378 let lexed = lexed::LexedModule {
379 tree: module,
380 submodules: lexed_submodules,
381 };
382
383 let mut hasher = DefaultHasher::new();
384 src.hash(&mut hasher);
385 let hash = hasher.finish();
386
387 let parsed_submodules = submodules
388 .iter()
389 .map(|s| (s.name.clone(), s.parsed.clone()))
390 .collect::<Vec<_>>();
391 let parsed = parsed::ParseModule {
392 span: span::Span::new(src, 0, 0, Some(source_id)).unwrap(),
393 module_kind_span,
394 module_eval_order: vec![],
395 tree,
396 submodules: parsed_submodules,
397 attributes,
398 hash,
399 };
400
401 let modified_time = std::fs::metadata(path.as_path())
403 .ok()
404 .and_then(|m| m.modified().ok());
405 let dependencies = submodules.into_iter().map(|s| s.path).collect::<Vec<_>>();
406 let version = lsp_mode
407 .and_then(|lsp| lsp.file_versions.get(path.as_ref()).copied())
408 .unwrap_or(None);
409
410 let common_info = ModuleCommonInfo {
411 path: path.clone(),
412 include_tests,
413 dependencies,
414 hash,
415 };
416 let parsed_info = ParsedModuleInfo {
417 modified_time,
418 version,
419 };
420 let cache_entry = ModuleCacheEntry::new(common_info, parsed_info);
421 query_engine.update_or_insert_parsed_module_cache_entry(cache_entry);
422
423 Ok(ParsedModuleTree {
424 tree_type: kind,
425 lexed_module: lexed,
426 parse_module: parsed,
427 })
428}
429
430pub(crate) fn is_ty_module_cache_up_to_date(
438 engines: &Engines,
439 path: &Arc<PathBuf>,
440 include_tests: bool,
441 build_config: Option<&BuildConfig>,
442) -> bool {
443 let cache = engines.qe().module_cache.read();
444 let key = ModuleCacheKey::new(path.clone(), include_tests);
445 cache.get(&key).is_some_and(|entry| {
446 entry.typed.as_ref().is_some_and(|typed| {
447 let cache_up_to_date = build_config
449 .and_then(|x| x.lsp_mode.as_ref())
450 .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
451 .is_none_or(|version| {
452 version.map_or(true, |v| typed.version.is_some_and(|tv| v <= tv))
453 });
454
455 cache_up_to_date
457 && entry.common.dependencies.iter().all(|dep_path| {
458 is_ty_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
459 })
460 })
461 })
462}
463
464pub(crate) fn is_parse_module_cache_up_to_date(
469 engines: &Engines,
470 path: &Arc<PathBuf>,
471 include_tests: bool,
472 build_config: Option<&BuildConfig>,
473) -> bool {
474 let cache = engines.qe().module_cache.read();
475 let key = ModuleCacheKey::new(path.clone(), include_tests);
476 cache.get(&key).is_some_and(|entry| {
477 let cache_up_to_date = build_config
479 .and_then(|x| x.lsp_mode.as_ref())
480 .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
481 .map_or_else(
482 || {
483 let modified_time = std::fs::metadata(path.as_path())
485 .ok()
486 .and_then(|m| m.modified().ok());
487 entry.parsed.modified_time == modified_time || {
489 let src = std::fs::read_to_string(path.as_path()).unwrap();
490 let mut hasher = DefaultHasher::new();
491 src.hash(&mut hasher);
492 hasher.finish() == entry.common.hash
493 }
494 },
495 |version| {
496 version.map_or(true, |v| entry.parsed.version.is_some_and(|ev| v <= ev))
503 },
504 );
505
506 cache_up_to_date
509 && entry.common.dependencies.iter().all(|dep_path| {
510 is_parse_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
511 })
512 })
513}
514
515fn module_path(
516 parent_module_dir: &Path,
517 parent_module_name: Option<&str>,
518 submod: &sway_ast::Submodule,
519) -> PathBuf {
520 if let Some(parent_name) = parent_module_name {
521 parent_module_dir
522 .join(parent_name)
523 .join(submod.name.to_string())
524 .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
525 } else {
526 parent_module_dir
528 .join(submod.name.to_string())
529 .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
530 }
531}
532
533pub fn build_module_dep_graph(
534 handler: &Handler,
535 parse_module: &mut parsed::ParseModule,
536) -> Result<(), ErrorEmitted> {
537 let module_dep_graph = ty::TyModule::build_dep_graph(handler, parse_module)?;
538 parse_module.module_eval_order = module_dep_graph.compute_order(handler)?;
539
540 for (_, submodule) in &mut parse_module.submodules {
541 build_module_dep_graph(handler, &mut submodule.module)?;
542 }
543 Ok(())
544}
545
546pub struct CompiledAsm(pub FinalizedAsm);
547
548#[allow(clippy::too_many_arguments)]
549pub fn parsed_to_ast(
550 handler: &Handler,
551 engines: &Engines,
552 parse_program: &mut parsed::ParseProgram,
553 initial_namespace: namespace::Root,
554 build_config: Option<&BuildConfig>,
555 package_name: &str,
556 retrigger_compilation: Option<Arc<AtomicBool>>,
557 experimental: ExperimentalFeatures,
558) -> Result<ty::TyProgram, TypeCheckFailed> {
559 let lsp_config = build_config.map(|x| x.lsp_mode.clone()).unwrap_or_default();
560
561 build_module_dep_graph(handler, &mut parse_program.root).map_err(|error| TypeCheckFailed {
563 root_module: None,
564 namespace: initial_namespace.clone(),
565 error,
566 })?;
567
568 let collection_namespace = Namespace::new(handler, engines, initial_namespace.clone(), true)
569 .map_err(|error| TypeCheckFailed {
570 root_module: None,
571 namespace: initial_namespace.clone(),
572 error,
573 })?;
574 let mut collection_ctx =
577 ty::TyProgram::collect(handler, engines, parse_program, collection_namespace).map_err(
578 |error| TypeCheckFailed {
579 root_module: None,
580 namespace: initial_namespace.clone(),
581 error,
582 },
583 )?;
584
585 let typecheck_namespace =
586 Namespace::new(handler, engines, initial_namespace, true).map_err(|error| {
587 TypeCheckFailed {
588 root_module: None,
589 namespace: collection_ctx.namespace().root_ref().clone(),
590 error,
591 }
592 })?;
593 let typed_program_opt = ty::TyProgram::type_check(
595 handler,
596 engines,
597 parse_program,
598 &mut collection_ctx,
599 typecheck_namespace,
600 package_name,
601 build_config,
602 experimental,
603 );
604
605 let mut typed_program = typed_program_opt?;
606
607 check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
608 TypeCheckFailed {
609 root_module: Some(Arc::new(typed_program.root_module.clone())),
610 namespace: typed_program.namespace.root_ref().clone(),
611 error,
612 }
613 })?;
614 if lsp_config.is_none() {
618 engines.pe().clear();
619 }
620
621 typed_program.check_deprecated(engines, handler);
622
623 match typed_program.check_recursive(engines, handler) {
624 Ok(()) => {}
625 Err(error) => {
626 handler.dedup();
627 return Err(TypeCheckFailed {
628 root_module: Some(Arc::new(typed_program.root_module.clone())),
629 namespace: typed_program.namespace.root().clone(),
630 error,
631 });
632 }
633 };
634
635 let types_metadata = if !lsp_config.as_ref().is_some_and(|lsp| lsp.optimized_build) {
637 let types_metadata_result = typed_program.collect_types_metadata(
639 handler,
640 &mut CollectTypesMetadataContext::new(engines, experimental, package_name.to_string()),
641 );
642 let types_metadata = match types_metadata_result {
643 Ok(types_metadata) => types_metadata,
644 Err(error) => {
645 handler.dedup();
646 return Err(TypeCheckFailed {
647 root_module: Some(Arc::new(typed_program.root_module.clone())),
648 namespace: typed_program.namespace.root().clone(),
649 error,
650 });
651 }
652 };
653
654 typed_program
655 .logged_types
656 .extend(types_metadata.iter().filter_map(|m| match m {
657 TypeMetadata::LoggedType(log_id, type_id) => Some((*log_id, *type_id)),
658 _ => None,
659 }));
660
661 typed_program
662 .messages_types
663 .extend(types_metadata.iter().filter_map(|m| match m {
664 TypeMetadata::MessageType(message_id, type_id) => Some((*message_id, *type_id)),
665 _ => None,
666 }));
667
668 let (print_graph, print_graph_url_format) = match build_config {
669 Some(cfg) => (
670 cfg.print_dca_graph.clone(),
671 cfg.print_dca_graph_url_format.clone(),
672 ),
673 None => (None, None),
674 };
675
676 check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
677 TypeCheckFailed {
678 root_module: Some(Arc::new(typed_program.root_module.clone())),
679 namespace: typed_program.namespace.root_ref().clone(),
680 error,
681 }
682 })?;
683
684 let _ = perform_control_flow_analysis(
686 handler,
687 engines,
688 &typed_program,
689 print_graph,
690 print_graph_url_format,
691 );
692
693 types_metadata
694 } else {
695 vec![]
696 };
697
698 let mut ctx = Context::new(engines.se(), experimental);
700 let module = Module::new(&mut ctx, Kind::Contract);
701 if let Err(errs) = ir_generation::compile::compile_constants_for_package(
702 engines,
703 &mut ctx,
704 module,
705 typed_program.namespace.root_ref(),
706 ) {
707 errs.into_iter().for_each(|err| {
708 handler.emit_err(err.clone());
709 });
710 }
711
712 let cei_analysis_warnings =
714 semantic_analysis::cei_pattern_analysis::analyze_program(engines, &typed_program);
715 for warn in cei_analysis_warnings {
716 handler.emit_warn(warn);
717 }
718
719 let mut md_mgr = MetadataManager::default();
720 typed_program
722 .get_typed_program_with_initialized_storage_slots(
723 handler,
724 engines,
725 &mut ctx,
726 &mut md_mgr,
727 module,
728 )
729 .map_err(|error: ErrorEmitted| {
730 handler.dedup();
731 TypeCheckFailed {
732 root_module: Some(Arc::new(typed_program.root_module.clone())),
733 namespace: typed_program.namespace.root_ref().clone(),
734 error,
735 }
736 })?;
737
738 for err in types_metadata.iter().filter_map(|m| match m {
740 TypeMetadata::UnresolvedType(name, call_site_span_opt) => {
741 Some(CompileError::UnableToInferGeneric {
742 ty: name.as_str().to_string(),
743 span: call_site_span_opt.clone().unwrap_or_else(|| name.span()),
744 })
745 }
746 _ => None,
747 }) {
748 handler.emit_err(err);
749 }
750
751 Ok(typed_program)
752}
753
754#[allow(clippy::too_many_arguments)]
755pub fn compile_to_ast(
756 handler: &Handler,
757 engines: &Engines,
758 input: Arc<str>,
759 initial_namespace: namespace::Root,
760 build_config: Option<&BuildConfig>,
761 package_name: &str,
762 retrigger_compilation: Option<Arc<AtomicBool>>,
763 experimental: ExperimentalFeatures,
764) -> Result<Programs, ErrorEmitted> {
765 check_should_abort(handler, retrigger_compilation.clone())?;
766
767 let query_engine = engines.qe();
768 let mut metrics = PerformanceData::default();
769 if let Some(config) = build_config {
770 let path = config.canonical_root_module();
771 let include_tests = config.include_tests;
772 if is_parse_module_cache_up_to_date(engines, &path, include_tests, build_config) {
774 let mut entry = query_engine.get_programs_cache_entry(&path).unwrap();
775 entry.programs.metrics.reused_programs += 1;
776
777 let (warnings, errors) = entry.handler_data;
778 let new_handler = Handler::from_parts(warnings, errors);
779 handler.append(new_handler);
780 return Ok(entry.programs);
781 };
782 }
783
784 let parse_program_opt = time_expr!(
786 package_name,
787 "parse the program to a concrete syntax tree (CST)",
788 "parse_cst",
789 parse(input, handler, engines, build_config, experimental),
790 build_config,
791 metrics
792 );
793
794 check_should_abort(handler, retrigger_compilation.clone())?;
795
796 let (lexed_program, mut parsed_program) = match parse_program_opt {
797 Ok(modules) => modules,
798 Err(e) => {
799 handler.dedup();
800 return Err(e);
801 }
802 };
803
804 if build_config.is_none_or(|config| !config.include_tests) {
806 parsed_program.exclude_tests(engines);
807 }
808
809 let program = time_expr!(
811 package_name,
812 "parse the concrete syntax tree (CST) to a typed AST",
813 "parse_ast",
814 parsed_to_ast(
815 handler,
816 engines,
817 &mut parsed_program,
818 initial_namespace,
819 build_config,
820 package_name,
821 retrigger_compilation.clone(),
822 experimental
823 ),
824 build_config,
825 metrics
826 );
827
828 check_should_abort(handler, retrigger_compilation.clone())?;
829
830 handler.dedup();
831
832 let programs = Programs::new(lexed_program, parsed_program, program, metrics);
833
834 if let Some(config) = build_config {
835 let path = config.canonical_root_module();
836 let cache_entry = ProgramsCacheEntry {
837 path,
838 programs: programs.clone(),
839 handler_data: handler.clone().consume(),
840 };
841 query_engine.insert_programs_cache_entry(cache_entry);
842 }
843
844 check_should_abort(handler, retrigger_compilation.clone())?;
845
846 Ok(programs)
847}
848
849pub fn compile_to_asm(
852 handler: &Handler,
853 engines: &Engines,
854 input: Arc<str>,
855 initial_namespace: namespace::Root,
856 build_config: &BuildConfig,
857 package_name: &str,
858 experimental: ExperimentalFeatures,
859) -> Result<CompiledAsm, ErrorEmitted> {
860 let ast_res = compile_to_ast(
861 handler,
862 engines,
863 input,
864 initial_namespace,
865 Some(build_config),
866 package_name,
867 None,
868 experimental,
869 )?;
870 ast_to_asm(handler, engines, &ast_res, build_config, experimental)
871}
872
873pub fn ast_to_asm(
876 handler: &Handler,
877 engines: &Engines,
878 programs: &Programs,
879 build_config: &BuildConfig,
880 experimental: ExperimentalFeatures,
881) -> Result<CompiledAsm, ErrorEmitted> {
882 let typed_program = match &programs.typed {
883 Ok(typed_program) => typed_program,
884 Err(err) => return Err(err.error),
885 };
886
887 let asm =
888 match compile_ast_to_ir_to_asm(handler, engines, typed_program, build_config, experimental)
889 {
890 Ok(res) => res,
891 Err(err) => {
892 handler.dedup();
893 return Err(err);
894 }
895 };
896 Ok(CompiledAsm(asm))
897}
898
899pub(crate) fn compile_ast_to_ir_to_asm(
900 handler: &Handler,
901 engines: &Engines,
902 program: &ty::TyProgram,
903 build_config: &BuildConfig,
904 experimental: ExperimentalFeatures,
905) -> Result<FinalizedAsm, ErrorEmitted> {
906 let mut ir = match ir_generation::compile_program(
918 program,
919 build_config.include_tests,
920 engines,
921 experimental,
922 ) {
923 Ok(ir) => ir,
924 Err(errors) => {
925 let mut last = None;
926 for e in errors {
927 last = Some(handler.emit_err(e));
928 }
929 return Err(last.unwrap());
930 }
931 };
932
933 let entry_point_functions: Vec<::sway_ir::Function> = ir
935 .module_iter()
936 .flat_map(|module| module.function_iter(&ir))
937 .filter(|func| func.is_entry(&ir))
938 .collect();
939
940 {
942 let mut env = ir_generation::PurityEnv::default();
943 let mut md_mgr = metadata::MetadataManager::default();
944 for entry_point in &entry_point_functions {
945 check_function_purity(handler, &mut env, &ir, &mut md_mgr, entry_point);
946 }
947 }
948
949 let mut pass_mgr = PassManager::default();
951 register_known_passes(&mut pass_mgr);
952 let mut pass_group = PassGroup::default();
953
954 match build_config.optimization_level {
955 OptLevel::Opt1 => {
956 pass_group.append_group(create_o1_pass_group());
957 }
958 OptLevel::Opt0 => {
959 pass_group.append_pass(FN_DEDUP_DEBUG_PROFILE_NAME);
962
963 pass_group.append_pass(FN_INLINE_NAME);
965
966 pass_group.append_pass(GLOBALS_DCE_NAME);
968 pass_group.append_pass(DCE_NAME);
969 }
970 }
971
972 if build_config.build_target == BuildTarget::Fuel {
974 pass_group.append_pass(CONST_DEMOTION_NAME);
979 pass_group.append_pass(ARG_DEMOTION_NAME);
980 pass_group.append_pass(RET_DEMOTION_NAME);
981 pass_group.append_pass(MISC_DEMOTION_NAME);
982
983 pass_group.append_pass(MEMCPYOPT_NAME);
985
986 pass_group.append_pass(DCE_NAME);
988 pass_group.append_pass(SIMPLIFY_CFG_NAME);
989
990 match build_config.optimization_level {
991 OptLevel::Opt1 => {
992 pass_group.append_pass(SROA_NAME);
993 pass_group.append_pass(MEM2REG_NAME);
994 pass_group.append_pass(DCE_NAME);
995 }
996 OptLevel::Opt0 => {}
997 }
998 }
999
1000 let print_passes_opts: PrintPassesOpts = (&build_config.print_ir).into();
1002 let res =
1003 if let Err(ir_error) = pass_mgr.run_with_print(&mut ir, &pass_group, &print_passes_opts) {
1004 Err(handler.emit_err(CompileError::InternalOwned(
1005 ir_error.to_string(),
1006 span::Span::dummy(),
1007 )))
1008 } else {
1009 Ok(())
1010 };
1011 res?;
1012
1013 compile_ir_context_to_finalized_asm(handler, &ir, Some(build_config))
1014}
1015
1016#[allow(clippy::too_many_arguments)]
1018pub fn compile_to_bytecode(
1019 handler: &Handler,
1020 engines: &Engines,
1021 input: Arc<str>,
1022 initial_namespace: namespace::Root,
1023 build_config: &BuildConfig,
1024 source_map: &mut SourceMap,
1025 package_name: &str,
1026 experimental: ExperimentalFeatures,
1027) -> Result<CompiledBytecode, ErrorEmitted> {
1028 let mut asm_res = compile_to_asm(
1029 handler,
1030 engines,
1031 input,
1032 initial_namespace,
1033 build_config,
1034 package_name,
1035 experimental,
1036 )?;
1037 asm_to_bytecode(
1038 handler,
1039 &mut asm_res,
1040 source_map,
1041 engines.se(),
1042 build_config,
1043 )
1044}
1045
1046pub const PRELUDE_CONFIGURABLES_SIZE_IN_BYTES: usize = 8;
1048pub const PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES: usize = 16;
1050pub const PRELUDE_SIZE_IN_BYTES: usize = 32;
1052
1053pub fn set_bytecode_configurables_offset(
1055 compiled_bytecode: &mut CompiledBytecode,
1056 md: &[u8; PRELUDE_CONFIGURABLES_SIZE_IN_BYTES],
1057) {
1058 assert!(
1059 compiled_bytecode.bytecode.len()
1060 >= PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES + PRELUDE_CONFIGURABLES_SIZE_IN_BYTES
1061 );
1062 let code = &mut compiled_bytecode.bytecode;
1063 for (index, byte) in md.iter().enumerate() {
1064 code[index + PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES] = *byte;
1065 }
1066}
1067
1068pub fn asm_to_bytecode(
1070 handler: &Handler,
1071 asm: &mut CompiledAsm,
1072 source_map: &mut SourceMap,
1073 source_engine: &SourceEngine,
1074 build_config: &BuildConfig,
1075) -> Result<CompiledBytecode, ErrorEmitted> {
1076 let compiled_bytecode =
1077 asm.0
1078 .to_bytecode_mut(handler, source_map, source_engine, build_config)?;
1079 Ok(compiled_bytecode)
1080}
1081
1082fn perform_control_flow_analysis(
1085 handler: &Handler,
1086 engines: &Engines,
1087 program: &ty::TyProgram,
1088 print_graph: Option<String>,
1089 print_graph_url_format: Option<String>,
1090) -> Result<(), ErrorEmitted> {
1091 let dca_res = dead_code_analysis(handler, engines, program);
1092 let rpa_errors = return_path_analysis(engines, program);
1093 let rpa_res = handler.scope(|handler| {
1094 for err in rpa_errors {
1095 handler.emit_err(err);
1096 }
1097 Ok(())
1098 });
1099
1100 if let Ok(graph) = dca_res.clone() {
1101 graph.visualize(engines, print_graph, print_graph_url_format);
1102 }
1103 dca_res?;
1104 rpa_res
1105}
1106
1107fn dead_code_analysis<'a>(
1112 handler: &Handler,
1113 engines: &'a Engines,
1114 program: &ty::TyProgram,
1115) -> Result<ControlFlowGraph<'a>, ErrorEmitted> {
1116 let decl_engine = engines.de();
1117 let mut dead_code_graph = ControlFlowGraph::new(engines);
1118 let tree_type = program.kind.tree_type();
1119 module_dead_code_analysis(
1120 handler,
1121 engines,
1122 &program.root_module,
1123 &tree_type,
1124 &mut dead_code_graph,
1125 )?;
1126 let warnings = dead_code_graph.find_dead_code(decl_engine);
1127 for warn in warnings {
1128 handler.emit_warn(warn);
1129 }
1130 Ok(dead_code_graph)
1131}
1132
1133fn module_dead_code_analysis<'eng: 'cfg, 'cfg>(
1135 handler: &Handler,
1136 engines: &'eng Engines,
1137 module: &ty::TyModule,
1138 tree_type: &parsed::TreeType,
1139 graph: &mut ControlFlowGraph<'cfg>,
1140) -> Result<(), ErrorEmitted> {
1141 module
1142 .submodules
1143 .iter()
1144 .try_fold((), |(), (_, submodule)| {
1145 let tree_type = parsed::TreeType::Library;
1146 module_dead_code_analysis(handler, engines, &submodule.module, &tree_type, graph)
1147 })?;
1148 let res = {
1149 ControlFlowGraph::append_module_to_dead_code_graph(
1150 engines,
1151 &module.all_nodes,
1152 tree_type,
1153 graph,
1154 )
1155 .map_err(|err| handler.emit_err(err))
1156 };
1157 graph.connect_pending_entry_edges();
1158 res
1159}
1160
1161fn return_path_analysis(engines: &Engines, program: &ty::TyProgram) -> Vec<CompileError> {
1162 let mut errors = vec![];
1163 module_return_path_analysis(engines, &program.root_module, &mut errors);
1164 errors
1165}
1166
1167fn module_return_path_analysis(
1168 engines: &Engines,
1169 module: &ty::TyModule,
1170 errors: &mut Vec<CompileError>,
1171) {
1172 for (_, submodule) in &module.submodules {
1173 module_return_path_analysis(engines, &submodule.module, errors);
1174 }
1175 let graph = ControlFlowGraph::construct_return_path_graph(engines, &module.all_nodes);
1176 match graph {
1177 Ok(graph) => errors.extend(graph.analyze_return_paths(engines)),
1178 Err(mut error) => errors.append(&mut error),
1179 }
1180}
1181
1182fn check_should_abort(
1185 handler: &Handler,
1186 retrigger_compilation: Option<Arc<AtomicBool>>,
1187) -> Result<(), ErrorEmitted> {
1188 if let Some(ref retrigger_compilation) = retrigger_compilation {
1189 if retrigger_compilation.load(Ordering::SeqCst) {
1190 return Err(handler.cancel());
1191 }
1192 }
1193 Ok(())
1194}
1195
1196#[test]
1197fn test_basic_prog() {
1198 let handler = Handler::default();
1199 let engines = Engines::default();
1200 let prog = parse(
1201 r#"
1202 contract;
1203
1204 enum yo
1205 <T>
1206 where
1207 T: IsAThing
1208 {
1209 x: u32,
1210 y: MyStruct<u32>
1211 }
1212
1213 enum MyOtherSumType
1214 {
1215 x: u32,
1216 y: MyStruct<u32>
1217 }
1218 struct MyStruct<T> {
1219 field_name: u64,
1220 other_field: T,
1221 }
1222
1223
1224 fn generic_function
1225 <T>
1226 (arg1: u64,
1227 arg2: T)
1228 ->
1229 T
1230 where T: Display,
1231 T: Debug {
1232 let x: MyStruct =
1233 MyStruct
1234 {
1235 field_name:
1236 5
1237 };
1238 return
1239 match
1240 arg1
1241 {
1242 1
1243 => true,
1244 _ => { return false; },
1245 };
1246 }
1247
1248 struct MyStruct {
1249 test: string,
1250 }
1251
1252
1253
1254 use stdlib::println;
1255
1256 trait MyTrait {
1257 // interface points
1258 fn myfunc(x: int) -> unit;
1259 } {
1260 // methods
1261 fn calls_interface_fn(x: int) -> unit {
1262 // declare a byte
1263 let x = 0b10101111;
1264 let mut y = 0b11111111;
1265 self.interface_fn(x);
1266 }
1267 }
1268
1269 pub fn prints_number_five() -> u8 {
1270 let x: u8 = 5;
1271 println(x);
1272 x.to_string();
1273 let some_list = [
1274 5,
1275 10 + 3 / 2,
1276 func_app(my_args, (so_many_args))];
1277 return 5;
1278 }
1279 "#
1280 .into(),
1281 &handler,
1282 &engines,
1283 None,
1284 ExperimentalFeatures::default(),
1285 );
1286 prog.unwrap();
1287}
1288#[test]
1289fn test_parenthesized() {
1290 let handler = Handler::default();
1291 let engines = Engines::default();
1292 let prog = parse(
1293 r#"
1294 contract;
1295 pub fn some_abi_func() -> unit {
1296 let x = (5 + 6 / (1 + (2 / 1) + 4));
1297 return;
1298 }
1299 "#
1300 .into(),
1301 &handler,
1302 &engines,
1303 None,
1304 ExperimentalFeatures::default(),
1305 );
1306 prog.unwrap();
1307}
1308
1309#[test]
1310fn test_unary_ordering() {
1311 use crate::language::{self, parsed};
1312 let handler = Handler::default();
1313 let engines = Engines::default();
1314 let prog = parse(
1315 r#"
1316 script;
1317 fn main() -> bool {
1318 let a = true;
1319 let b = true;
1320 !a && b;
1321 }"#
1322 .into(),
1323 &handler,
1324 &engines,
1325 None,
1326 ExperimentalFeatures::default(),
1327 );
1328 let (.., prog) = prog.unwrap();
1329 if let parsed::AstNode {
1332 content:
1333 parsed::AstNodeContent::Declaration(parsed::Declaration::FunctionDeclaration(decl_id)),
1334 ..
1335 } = &prog.root.tree.root_nodes[0]
1336 {
1337 let fn_decl = engines.pe().get_function(decl_id);
1338 if let parsed::AstNode {
1339 content:
1340 parsed::AstNodeContent::Expression(parsed::Expression {
1341 kind:
1342 parsed::ExpressionKind::LazyOperator(parsed::LazyOperatorExpression {
1343 op, ..
1344 }),
1345 ..
1346 }),
1347 ..
1348 } = &fn_decl.body.contents[2]
1349 {
1350 assert_eq!(op, &language::LazyOp::And)
1351 } else {
1352 panic!("Was not lazy operator.")
1353 }
1354 } else {
1355 panic!("Was not ast node")
1356 };
1357}
1358
1359#[test]
1360fn test_parser_recovery() {
1361 let handler = Handler::default();
1362 let engines = Engines::default();
1363 let prog = parse(
1364 r#"
1365 script;
1366 fn main() -> bool {
1367 let
1368 let a = true;
1369 true
1370 }"#
1371 .into(),
1372 &handler,
1373 &engines,
1374 None,
1375 ExperimentalFeatures::default(),
1376 );
1377 let (_, _) = prog.unwrap();
1378 assert!(handler.has_errors());
1379 dbg!(handler);
1380}