1#![recursion_limit = "256"]
2
3#[macro_use]
4pub mod error;
5
6#[macro_use]
7pub mod engine_threading;
8
9pub mod abi_generation;
10pub mod asm_generation;
11mod asm_lang;
12mod build_config;
13pub mod compiler_generated;
14mod concurrent_slab;
15mod control_flow_analysis;
16mod debug_generation;
17pub mod decl_engine;
18pub mod ir_generation;
19pub mod language;
20pub mod marker_traits;
21mod metadata;
22pub mod obs_engine;
23pub mod query_engine;
24pub mod semantic_analysis;
25pub mod source_map;
26pub mod transform;
27pub mod type_system;
28
29use crate::decl_engine::DeclEngineGet as _;
30use crate::engine_threading::SpannedWithEngines;
31use crate::ir_generation::check_function_purity;
32use crate::ir_generation::compile::CheckDecl;
33use crate::language::ty::{
34 generate_is_decode_trivial_table, TyAstNodeContent, TyDecl, TyTraitInterfaceItem,
35};
36use crate::language::{CallPath, CallPathType};
37use crate::query_engine::ModuleCacheEntry;
38use crate::semantic_analysis::namespace::ResolvedDeclaration;
39use crate::semantic_analysis::type_resolve::{resolve_call_path, VisibilityCheck};
40use crate::semantic_analysis::TypeCheckContext;
41use crate::source_map::SourceMap;
42pub use asm_generation::from_ir::compile_ir_context_to_finalized_asm;
43use asm_generation::FinalizedAsm;
44pub use asm_generation::{CompiledBytecode, FinalizedEntry};
45pub use build_config::DbgGeneration;
46pub use build_config::{Backtrace, BuildConfig, BuildTarget, IrCli, LspConfig, OptLevel, PrintAsm};
47use control_flow_analysis::ControlFlowGraph;
48pub use debug_generation::write_dwarf;
49use itertools::Itertools;
50use metadata::MetadataManager;
51use query_engine::{ModuleCacheKey, ModuleCommonInfo, ParsedModuleInfo, ProgramsCacheEntry};
52use semantic_analysis::program::TypeCheckFailed;
53use std::collections::hash_map::DefaultHasher;
54use std::collections::HashMap;
55use std::hash::{Hash, Hasher};
56use std::path::{Path, PathBuf};
57use std::sync::atomic::{AtomicBool, Ordering};
58use std::sync::Arc;
59use sway_ast::attribute::REQUIRE_ARG_NAME_TRIVIALLY_DECODABLE;
60use sway_ast::AttributeDecl;
61use sway_error::convert_parse_tree_error::ConvertParseTreeError;
62use sway_error::handler::{ErrorEmitted, Handler};
63use sway_error::warning::{CollectedTraitImpl, CompileInfo, CompileWarning, Info, Warning};
64use sway_features::ExperimentalFeatures;
65use sway_ir::{
66 create_o1_pass_group, register_known_passes, Context, Kind, Module, PassGroup, PassManager,
67 PrintPassesOpts, VerifyPassesOpts, ARG_DEMOTION_NAME, ARG_POINTEE_MUTABILITY_TAGGER_NAME,
68 CONST_DEMOTION_NAME, DCE_NAME, FN_DEDUP_DEBUG_PROFILE_NAME, FN_INLINE_NAME, GLOBALS_DCE_NAME,
69 INIT_AGGR_LOWERING_NAME, MEM2REG_NAME, MEMCPYOPT_NAME, MEMCPYPROP_REVERSE_NAME,
70 MISC_DEMOTION_NAME, RET_DEMOTION_NAME, SIMPLIFY_CFG_NAME, SROA_NAME,
71};
72use sway_types::integer_bits::IntegerBits;
73use sway_types::span::Source;
74use sway_types::{SourceEngine, SourceLocation, Span};
75use sway_utils::{time_expr, PerformanceData, PerformanceMetric};
76use transform::{ArgsExpectValues, Attribute, AttributeKind, Attributes, ExpectedArgs};
77use types::{CollectTypesMetadata, CollectTypesMetadataContext, LogId, TypeMetadata};
78
79pub use semantic_analysis::namespace::{self, Namespace};
80pub mod types;
81
82use sway_error::error::{CompileError, TrivialCheckDiagType};
83use sway_types::{ident::Ident, span, Spanned};
84pub use type_system::*;
85
86pub use language::Programs;
87use language::{lexed, parsed, ty, Visibility};
88use transform::to_parsed_lang::{self, convert_module_kind};
89
90pub mod fuel_prelude {
91 pub use fuel_vm::{self, fuel_asm, fuel_crypto, fuel_tx, fuel_types};
92}
93
94pub use engine_threading::Engines;
95pub use obs_engine::{ObservabilityEngine, Observer};
96
97pub fn parse(
111 src: Source,
112 handler: &Handler,
113 engines: &Engines,
114 config: Option<&BuildConfig>,
115 experimental: ExperimentalFeatures,
116 package_name: &str,
117) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
118 match config {
119 None => parse_in_memory(
120 handler,
121 engines,
122 src,
123 experimental,
124 DbgGeneration::None,
125 package_name,
126 ),
127 Some(config) => parse_module_tree(
130 handler,
131 engines,
132 src,
133 config.canonical_root_module(),
134 None,
135 config.build_target,
136 config.dbg_generation,
137 config.include_tests,
138 experimental,
139 config.lsp_mode.as_ref(),
140 package_name,
141 )
142 .map(
143 |ParsedModuleTree {
144 tree_type: kind,
145 lexed_module,
146 parse_module,
147 }| {
148 let lexed = lexed::LexedProgram {
149 kind,
150 root: lexed_module,
151 };
152 let parsed = parsed::ParseProgram {
153 kind,
154 root: parse_module,
155 };
156 (lexed, parsed)
157 },
158 ),
159 }
160}
161
162pub fn parse_tree_type(handler: &Handler, src: Source) -> Result<parsed::TreeType, ErrorEmitted> {
166 let experimental = ExperimentalFeatures::default();
170 sway_parse::parse_module_kind(handler, src, None, experimental)
171 .map(|kind| convert_module_kind(&kind))
172}
173
174pub(crate) fn attr_decls_to_attributes(
183 attribute_decls: &[AttributeDecl],
184 can_annotate: impl Fn(&Attribute) -> bool,
185 target_friendly_name: &'static str,
186) -> (Handler, Attributes) {
187 let handler = Handler::default();
188 for attr_decl in attribute_decls
197 .iter()
198 .filter(|attr| !attr.is_doc_comment() && attr.is_inner())
199 {
200 handler.emit_err(CompileError::Unimplemented {
201 span: attr_decl.hash_kind.span(),
202 feature: "Using inner attributes (`#!`)".to_string(),
203 help: vec![],
204 });
205 }
206
207 let attributes = Attributes::new(attribute_decls);
208
209 for attribute in attributes.unknown().filter(|attr| attr.is_outer()) {
211 handler.emit_warn(CompileWarning {
212 span: attribute.name.span(),
213 warning_content: Warning::UnknownAttribute {
214 attribute: (&attribute.name).into(),
215 known_attributes: attributes.known_attribute_names(),
216 },
217 });
218 }
219
220 for ((attribute_kind, _attribute_direction), mut attributes) in &attributes
222 .all()
223 .filter(|attr| attr.is_doc_comment() || attr.is_outer())
224 .chunk_by(|attr| (attr.kind, attr.direction))
225 {
226 if attribute_kind == AttributeKind::DocComment {
229 let first_doc_line = attributes
230 .next()
231 .expect("`chunk_by` guarantees existence of at least one element in the chunk");
232 if !can_annotate(first_doc_line) {
233 let last_doc_line = match attributes.last() {
234 Some(last_attr) => last_attr,
235 None => first_doc_line,
237 };
238 handler.emit_err(
239 ConvertParseTreeError::InvalidAttributeTarget {
240 span: Span::join(
241 first_doc_line.span.clone(),
242 &last_doc_line.span.start_span(),
243 ),
244 attribute: first_doc_line.name.clone(),
245 target_friendly_name,
246 can_only_annotate_help: first_doc_line
247 .can_only_annotate_help(target_friendly_name),
248 }
249 .into(),
250 );
251 }
252 } else {
253 for attribute in attributes {
255 if !can_annotate(attribute) {
256 handler.emit_err(
257 ConvertParseTreeError::InvalidAttributeTarget {
258 span: attribute.name.span(),
259 attribute: attribute.name.clone(),
260 target_friendly_name,
261 can_only_annotate_help: attribute
262 .can_only_annotate_help(target_friendly_name),
263 }
264 .into(),
265 );
266 }
267 }
268 }
269 }
270
271 let should_be_checked =
274 |attr: &&Attribute| !attr.is_doc_comment() && attr.is_outer() && can_annotate(attr);
275
276 for (_attribute_kind, attributes_of_kind) in
278 attributes.all_by_kind(|attr| should_be_checked(attr) && !attr.kind.allows_multiple())
279 {
280 if attributes_of_kind.len() > 1 {
281 let (last_attribute, previous_attributes) = attributes_of_kind
282 .split_last()
283 .expect("`attributes_of_kind` has more than one element");
284 handler.emit_err(
285 ConvertParseTreeError::InvalidAttributeMultiplicity {
286 last_occurrence: (&last_attribute.name).into(),
287 previous_occurrences: previous_attributes
288 .iter()
289 .map(|attr| (&attr.name).into())
290 .collect(),
291 }
292 .into(),
293 );
294 }
295 }
296
297 for attribute in attributes.all().filter(should_be_checked) {
301 let _ = attribute.check_args_multiplicity(&handler);
302 }
303
304 for attribute in attributes
310 .all()
311 .filter(|attr| should_be_checked(attr) && attr.can_have_arguments())
312 {
313 match attribute.expected_args() {
314 ExpectedArgs::None => unreachable!("`attribute` can have arguments"),
315 ExpectedArgs::Any => {}
316 ExpectedArgs::MustBeIn(expected_args) => {
317 for arg in attribute.args.iter() {
318 if !expected_args.contains(&arg.name.as_str()) {
319 handler.emit_err(
320 ConvertParseTreeError::InvalidAttributeArg {
321 attribute: attribute.name.clone(),
322 arg: (&arg.name).into(),
323 expected_args: expected_args.clone(),
324 }
325 .into(),
326 );
327 }
328 }
329 }
330 ExpectedArgs::ShouldBeIn(expected_args) => {
331 for arg in attribute.args.iter() {
332 if !expected_args.contains(&arg.name.as_str()) {
333 handler.emit_warn(CompileWarning {
334 span: arg.name.span(),
335 warning_content: Warning::UnknownAttributeArg {
336 attribute: attribute.name.clone(),
337 arg: (&arg.name).into(),
338 expected_args: expected_args.clone(),
339 },
340 });
341 }
342 }
343 }
344 }
345 }
346
347 for attribute in attributes
351 .all()
352 .filter(|attr| should_be_checked(attr) && attr.can_have_arguments())
353 {
354 fn check_value_expected(handler: &Handler, attribute: &Attribute, is_value_expected: bool) {
359 for arg in attribute.args.iter() {
360 if let ExpectedArgs::MustBeIn(expected_args) = attribute.expected_args() {
361 if !expected_args.contains(&arg.name.as_str()) {
362 continue;
363 }
364 }
365
366 if (is_value_expected && arg.value.is_none())
367 || (!is_value_expected && arg.value.is_some())
368 {
369 handler.emit_err(
370 ConvertParseTreeError::InvalidAttributeArgExpectsValue {
371 attribute: attribute.name.clone(),
372 arg: (&arg.name).into(),
373 value_span: arg.value.as_ref().map(|literal| literal.span()),
374 }
375 .into(),
376 );
377 }
378 }
379 }
380
381 match attribute.args_expect_values() {
382 ArgsExpectValues::Yes => check_value_expected(&handler, attribute, true),
383 ArgsExpectValues::No => check_value_expected(&handler, attribute, false),
384 ArgsExpectValues::Maybe => {}
385 }
386 }
387
388 (handler, attributes)
389}
390
391fn parse_in_memory(
393 handler: &Handler,
394 engines: &Engines,
395 src: Source,
396 experimental: ExperimentalFeatures,
397 dbg_generation: DbgGeneration,
398 package_name: &str,
399) -> Result<(lexed::LexedProgram, parsed::ParseProgram), ErrorEmitted> {
400 let mut hasher = DefaultHasher::new();
401 src.text.hash(&mut hasher);
402 let hash = hasher.finish();
403 let module = sway_parse::parse_file(handler, src, None, experimental)?;
404
405 let (attributes_handler, attributes) = attr_decls_to_attributes(
406 &module.attributes,
407 |attr| attr.can_annotate_module_kind(),
408 module.value.kind.friendly_name(),
409 );
410 let attributes_error_emitted = handler.append(attributes_handler);
411
412 let (kind, tree) = to_parsed_lang::convert_parse_tree(
413 &mut to_parsed_lang::Context::new(
414 BuildTarget::EVM,
415 dbg_generation,
416 experimental,
417 package_name,
418 ),
419 handler,
420 engines,
421 module.value.clone(),
422 )?;
423
424 match attributes_error_emitted {
425 Some(err) => Err(err),
426 None => {
427 let root = parsed::ParseModule {
428 span: span::Span::dummy(),
429 module_kind_span: module.value.kind.span(),
430 module_eval_order: vec![],
431 tree,
432 submodules: vec![],
433 attributes,
434 hash,
435 };
436 let lexed_program = lexed::LexedProgram::new(
437 kind,
438 lexed::LexedModule {
439 tree: module,
440 submodules: vec![],
441 },
442 );
443 Ok((lexed_program, parsed::ParseProgram { kind, root }))
444 }
445 }
446}
447
448pub struct Submodule {
449 name: Ident,
450 path: Arc<PathBuf>,
451 lexed: lexed::LexedSubmodule,
452 parsed: parsed::ParseSubmodule,
453}
454
455pub type Submodules = Vec<Submodule>;
457
458#[allow(clippy::too_many_arguments)]
460fn parse_submodules(
461 handler: &Handler,
462 engines: &Engines,
463 module_name: Option<&str>,
464 module: &sway_ast::Module,
465 module_dir: &Path,
466 build_target: BuildTarget,
467 dbg_generation: DbgGeneration,
468 include_tests: bool,
469 experimental: ExperimentalFeatures,
470 lsp_mode: Option<&LspConfig>,
471 package_name: &str,
472) -> Submodules {
473 let mut submods = Vec::with_capacity(module.submodules().count());
475 module.submodules().for_each(|submod| {
476 let submod_path = Arc::new(module_path(module_dir, module_name, submod));
479 let submod_src: Source = match std::fs::read_to_string(&*submod_path) {
480 Ok(s) => s.as_str().into(),
481 Err(e) => {
482 handler.emit_err(CompileError::FileCouldNotBeRead {
483 span: submod.name.span(),
484 file_path: submod_path.to_string_lossy().to_string(),
485 stringified_error: e.to_string(),
486 });
487 return;
488 }
489 };
490 if let Ok(ParsedModuleTree {
491 tree_type: kind,
492 lexed_module,
493 parse_module,
494 }) = parse_module_tree(
495 handler,
496 engines,
497 submod_src.clone(),
498 submod_path.clone(),
499 Some(submod.name.as_str()),
500 build_target,
501 dbg_generation,
502 include_tests,
503 experimental,
504 lsp_mode,
505 package_name,
506 ) {
507 if !matches!(kind, parsed::TreeType::Library) {
508 let source_id = engines.se().get_source_id(submod_path.as_ref());
509 let span = span::Span::new(submod_src, 0, 0, Some(source_id)).unwrap();
510 handler.emit_err(CompileError::ImportMustBeLibrary { span });
511 return;
512 }
513
514 let parse_submodule = parsed::ParseSubmodule {
515 module: parse_module,
516 visibility: match submod.visibility {
517 Some(..) => Visibility::Public,
518 None => Visibility::Private,
519 },
520 mod_name_span: submod.name.span(),
521 };
522 let lexed_submodule = lexed::LexedSubmodule {
523 module: lexed_module,
524 };
525 let submodule = Submodule {
526 name: submod.name.clone(),
527 path: submod_path,
528 lexed: lexed_submodule,
529 parsed: parse_submodule,
530 };
531 submods.push(submodule);
532 }
533 });
534 submods
535}
536
537pub type SourceHash = u64;
538
539#[derive(Clone, Debug)]
540pub struct ParsedModuleTree {
541 pub tree_type: parsed::TreeType,
542 pub lexed_module: lexed::LexedModule,
543 pub parse_module: parsed::ParseModule,
544}
545
546#[allow(clippy::too_many_arguments)]
549fn parse_module_tree(
550 handler: &Handler,
551 engines: &Engines,
552 src: Source,
553 path: Arc<PathBuf>,
554 module_name: Option<&str>,
555 build_target: BuildTarget,
556 dbg_generation: DbgGeneration,
557 include_tests: bool,
558 experimental: ExperimentalFeatures,
559 lsp_mode: Option<&LspConfig>,
560 package_name: &str,
561) -> Result<ParsedModuleTree, ErrorEmitted> {
562 let query_engine = engines.qe();
563
564 let module_dir = path.parent().expect("module file has no parent directory");
566 let source_id = engines.se().get_source_id(&path.clone());
567 let src = engines.se().get_or_create_source_buffer(&source_id, src);
569 let module = sway_parse::parse_file(handler, src.clone(), Some(source_id), experimental)?;
570
571 let submodules = parse_submodules(
574 handler,
575 engines,
576 module_name,
577 &module.value,
578 module_dir,
579 build_target,
580 dbg_generation,
581 include_tests,
582 experimental,
583 lsp_mode,
584 package_name,
585 );
586
587 let (attributes_handler, attributes) = attr_decls_to_attributes(
588 &module.attributes,
589 |attr| attr.can_annotate_module_kind(),
590 module.value.kind.friendly_name(),
591 );
592 let attributes_error_emitted = handler.append(attributes_handler);
593
594 let (kind, tree) = to_parsed_lang::convert_parse_tree(
596 &mut to_parsed_lang::Context::new(build_target, dbg_generation, experimental, package_name),
597 handler,
598 engines,
599 module.value.clone(),
600 )?;
601
602 if let Some(err) = attributes_error_emitted {
603 return Err(err);
604 }
605
606 let module_kind_span = module.value.kind.span();
607 let lexed_submodules = submodules
608 .iter()
609 .map(|s| (s.name.clone(), s.lexed.clone()))
610 .collect::<Vec<_>>();
611 let lexed = lexed::LexedModule {
612 tree: module,
613 submodules: lexed_submodules,
614 };
615
616 let mut hasher = DefaultHasher::new();
617 src.text.hash(&mut hasher);
618 let hash = hasher.finish();
619
620 let parsed_submodules = submodules
621 .iter()
622 .map(|s| (s.name.clone(), s.parsed.clone()))
623 .collect::<Vec<_>>();
624 let parsed = parsed::ParseModule {
625 span: span::Span::new(src, 0, 0, Some(source_id)).unwrap(),
626 module_kind_span,
627 module_eval_order: vec![],
628 tree,
629 submodules: parsed_submodules,
630 attributes,
631 hash,
632 };
633
634 let modified_time = std::fs::metadata(path.as_path())
636 .ok()
637 .and_then(|m| m.modified().ok());
638 let dependencies = submodules.into_iter().map(|s| s.path).collect::<Vec<_>>();
639 let version = lsp_mode
640 .and_then(|lsp| lsp.file_versions.get(path.as_ref()).copied())
641 .unwrap_or(None);
642
643 let common_info = ModuleCommonInfo {
644 path: path.clone(),
645 include_tests,
646 dependencies,
647 hash,
648 };
649 let parsed_info = ParsedModuleInfo {
650 modified_time,
651 version,
652 };
653 let cache_entry = ModuleCacheEntry::new(common_info, parsed_info);
654 query_engine.update_or_insert_parsed_module_cache_entry(cache_entry);
655
656 Ok(ParsedModuleTree {
657 tree_type: kind,
658 lexed_module: lexed,
659 parse_module: parsed,
660 })
661}
662
663pub(crate) fn is_ty_module_cache_up_to_date(
671 engines: &Engines,
672 path: &Arc<PathBuf>,
673 include_tests: bool,
674 build_config: Option<&BuildConfig>,
675) -> bool {
676 let cache = engines.qe().module_cache.read();
677 let key = ModuleCacheKey::new(path.clone(), include_tests);
678 cache.get(&key).is_some_and(|entry| {
679 entry.typed.as_ref().is_some_and(|typed| {
680 let cache_up_to_date = build_config
682 .and_then(|x| x.lsp_mode.as_ref())
683 .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
684 .is_none_or(|version| {
685 version.is_none_or(|v| typed.version.is_some_and(|tv| v <= tv))
686 });
687
688 cache_up_to_date
690 && entry.common.dependencies.iter().all(|dep_path| {
691 is_ty_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
692 })
693 })
694 })
695}
696
697pub(crate) fn is_parse_module_cache_up_to_date(
702 engines: &Engines,
703 path: &Arc<PathBuf>,
704 include_tests: bool,
705 build_config: Option<&BuildConfig>,
706) -> bool {
707 let cache = engines.qe().module_cache.read();
708 let key = ModuleCacheKey::new(path.clone(), include_tests);
709 cache.get(&key).is_some_and(|entry| {
710 let cache_up_to_date = build_config
712 .and_then(|x| x.lsp_mode.as_ref())
713 .and_then(|lsp| lsp.file_versions.get(path.as_ref()))
714 .map_or_else(
715 || {
716 let modified_time = std::fs::metadata(path.as_path())
718 .ok()
719 .and_then(|m| m.modified().ok());
720 entry.parsed.modified_time == modified_time || {
722 let src = std::fs::read_to_string(path.as_path()).unwrap();
723 let mut hasher = DefaultHasher::new();
724 src.hash(&mut hasher);
725 hasher.finish() == entry.common.hash
726 }
727 },
728 |version| {
729 version.is_none_or(|v| entry.parsed.version.is_some_and(|ev| v <= ev))
736 },
737 );
738
739 cache_up_to_date
742 && entry.common.dependencies.iter().all(|dep_path| {
743 is_parse_module_cache_up_to_date(engines, dep_path, include_tests, build_config)
744 })
745 })
746}
747
748fn module_path(
749 parent_module_dir: &Path,
750 parent_module_name: Option<&str>,
751 submod: &sway_ast::Submodule,
752) -> PathBuf {
753 if let Some(parent_name) = parent_module_name {
754 parent_module_dir
755 .join(parent_name)
756 .join(submod.name.to_string())
757 .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
758 } else {
759 parent_module_dir
761 .join(submod.name.to_string())
762 .with_extension(sway_types::constants::DEFAULT_FILE_EXTENSION)
763 }
764}
765
766pub fn build_module_dep_graph(
767 handler: &Handler,
768 parse_module: &mut parsed::ParseModule,
769) -> Result<(), ErrorEmitted> {
770 let module_dep_graph = ty::TyModule::build_dep_graph(handler, parse_module)?;
771 parse_module.module_eval_order = module_dep_graph.compute_order(handler)?;
772
773 for (_, submodule) in &mut parse_module.submodules {
774 build_module_dep_graph(handler, &mut submodule.module)?;
775 }
776 Ok(())
777}
778
779#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
790pub struct PanicOccurrence {
791 pub function: String,
792 pub loc: SourceLocation,
793 pub log_id: Option<LogId>,
794 pub msg: Option<String>,
795}
796
797#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
836pub struct PanickingCallOccurrence {
837 pub function: String,
838 pub caller_function: String,
839 pub loc: SourceLocation,
840}
841
842pub type PanicOccurrences = HashMap<PanicOccurrence, u64>;
844
845pub type PanickingCallOccurrences = HashMap<PanickingCallOccurrence, u64>;
847
848pub struct CompiledAsm {
849 pub finalized_asm: FinalizedAsm,
850 pub panic_occurrences: PanicOccurrences,
851 pub panicking_call_occurrences: PanickingCallOccurrences,
852}
853
854#[allow(clippy::result_large_err)]
855#[allow(clippy::too_many_arguments)]
856pub fn parsed_to_ast(
857 handler: &Handler,
858 engines: &Engines,
859 parse_program: &mut parsed::ParseProgram,
860 initial_namespace: namespace::Package,
861 build_config: Option<&BuildConfig>,
862 package_name: &str,
863 retrigger_compilation: Option<Arc<AtomicBool>>,
864 experimental: ExperimentalFeatures,
865 backtrace: Backtrace,
866) -> Result<ty::TyProgram, TypeCheckFailed> {
867 let lsp_config = build_config.map(|x| x.lsp_mode.clone()).unwrap_or_default();
868
869 build_module_dep_graph(handler, &mut parse_program.root).map_err(|error| TypeCheckFailed {
871 root_module: None,
872 namespace: initial_namespace.clone(),
873 error,
874 })?;
875
876 let collection_namespace = Namespace::new(handler, engines, initial_namespace.clone(), true)
877 .map_err(|error| TypeCheckFailed {
878 root_module: None,
879 namespace: initial_namespace.clone(),
880 error,
881 })?;
882 let mut collection_ctx =
885 ty::TyProgram::collect(handler, engines, parse_program, collection_namespace).map_err(
886 |error| TypeCheckFailed {
887 root_module: None,
888 namespace: initial_namespace.clone(),
889 error,
890 },
891 )?;
892
893 let mut typecheck_namespace = Namespace::new(handler, engines, initial_namespace, true)
894 .map_err(|error| TypeCheckFailed {
895 root_module: None,
896 namespace: collection_ctx.namespace().current_package_ref().clone(),
897 error,
898 })?;
899
900 let mut type_check_ctx = TypeCheckContext::from_root(
902 &mut typecheck_namespace,
903 &mut collection_ctx,
904 engines,
905 experimental,
906 )
907 .with_kind(parse_program.kind);
908
909 let typed_program_opt = ty::TyProgram::type_check(
910 handler,
911 engines,
912 parse_program,
913 package_name,
914 build_config,
915 &mut type_check_ctx,
916 );
917
918 let mut typed_program = typed_program_opt?;
919
920 check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
921 TypeCheckFailed {
922 root_module: Some(Arc::new(typed_program.root_module.clone())),
923 namespace: typed_program.namespace.current_package_ref().clone(),
924 error,
925 }
926 })?;
927
928 if lsp_config.is_none() {
932 engines.pe().clear();
933 }
934
935 typed_program.check_deprecated(engines, handler);
936
937 match typed_program.check_recursive(engines, handler) {
938 Ok(()) => {}
939 Err(error) => {
940 handler.dedup();
941 return Err(TypeCheckFailed {
942 root_module: Some(Arc::new(typed_program.root_module.clone())),
943 namespace: typed_program.namespace.current_package().clone(),
944 error,
945 });
946 }
947 };
948
949 let mut ctx = Context::new(engines.se(), experimental, backtrace.into());
950 let module = Module::new(&mut ctx, Kind::Contract);
951 let mut md_mgr = MetadataManager::default();
952
953 let checks = run_decl_checks(
955 handler,
956 &typed_program,
957 &mut type_check_ctx,
958 &mut ctx,
959 &mut md_mgr,
960 module,
961 );
962 match checks {
963 Ok(()) => {}
964 Err(error) => {
965 handler.dedup();
966 return Err(TypeCheckFailed {
967 root_module: Some(Arc::new(typed_program.root_module.clone())),
968 namespace: typed_program.namespace.current_package().clone(),
969 error,
970 });
971 }
972 };
973
974 let types_metadata = if !lsp_config.as_ref().is_some_and(|lsp| lsp.optimized_build) {
976 let mut collect_ctx =
978 CollectTypesMetadataContext::new(engines, experimental, package_name.to_string());
979
980 let types_metadata_result = typed_program.collect_types_metadata(handler, &mut collect_ctx);
981
982 let types_metadata = match types_metadata_result {
983 Ok(types_metadata) => types_metadata,
984 Err(error) => {
985 handler.dedup();
986 return Err(TypeCheckFailed {
987 root_module: Some(Arc::new(typed_program.root_module.clone())),
988 namespace: typed_program.namespace.current_package().clone(),
989 error,
990 });
991 }
992 };
993
994 typed_program
995 .logged_types
996 .extend(types_metadata.iter().filter_map(|m| match m {
997 TypeMetadata::LoggedType(log_id, type_id) => Some((*log_id, *type_id)),
998 _ => None,
999 }));
1000
1001 typed_program
1002 .messages_types
1003 .extend(types_metadata.iter().filter_map(|m| match m {
1004 TypeMetadata::MessageType(message_id, type_id) => Some((*message_id, *type_id)),
1005 _ => None,
1006 }));
1007
1008 let (print_graph, print_graph_url_format) = match build_config {
1009 Some(cfg) => (
1010 cfg.print_dca_graph.clone(),
1011 cfg.print_dca_graph_url_format.clone(),
1012 ),
1013 None => (None, None),
1014 };
1015
1016 check_should_abort(handler, retrigger_compilation.clone()).map_err(|error| {
1017 TypeCheckFailed {
1018 root_module: Some(Arc::new(typed_program.root_module.clone())),
1019 namespace: typed_program.namespace.current_package_ref().clone(),
1020 error,
1021 }
1022 })?;
1023
1024 let _ = perform_control_flow_analysis(
1026 handler,
1027 engines,
1028 &typed_program,
1029 print_graph,
1030 print_graph_url_format,
1031 );
1032
1033 types_metadata
1034 } else {
1035 vec![]
1036 };
1037
1038 if let Err(errs) = ir_generation::compile::compile_constants_for_package(
1041 engines,
1042 &mut ctx,
1043 module,
1044 &typed_program.namespace,
1045 ) {
1046 errs.into_iter().for_each(|err| {
1047 handler.emit_err(err.clone());
1048 });
1049 }
1050
1051 let cei_analysis_warnings =
1053 semantic_analysis::cei_pattern_analysis::analyze_program(engines, &typed_program);
1054 for warn in cei_analysis_warnings {
1055 handler.emit_warn(warn);
1056 }
1057
1058 typed_program
1060 .get_typed_program_with_initialized_storage_slots(
1061 handler,
1062 engines,
1063 &mut ctx,
1064 &mut md_mgr,
1065 module,
1066 )
1067 .map_err(|error: ErrorEmitted| {
1068 handler.dedup();
1069 TypeCheckFailed {
1070 root_module: Some(Arc::new(typed_program.root_module.clone())),
1071 namespace: typed_program.namespace.current_package_ref().clone(),
1072 error,
1073 }
1074 })?;
1075
1076 for err in types_metadata.iter().filter_map(|m| match m {
1078 TypeMetadata::UnresolvedType(name, call_site_span_opt) => {
1079 Some(CompileError::UnableToInferGeneric {
1080 ty: name.as_str().to_string(),
1081 span: call_site_span_opt.clone().unwrap_or_else(|| name.span()),
1082 })
1083 }
1084 _ => None,
1085 }) {
1086 handler.emit_err(err);
1087 }
1088
1089 Ok(typed_program)
1090}
1091
1092fn run_decl_checks(
1093 handler: &Handler,
1094 typed_program: &ty::TyProgram,
1095 type_check_ctx: &mut TypeCheckContext<'_>,
1096 ir_ctx: &mut Context<'_>,
1097 md_mgr: &mut MetadataManager,
1098 module: Module,
1099) -> Result<(), ErrorEmitted> {
1100 let mut decl_checks = vec![];
1101
1102 let nodes = std::iter::once(&typed_program.root_module)
1103 .chain(
1104 typed_program
1105 .root_module
1106 .submodules_recursive()
1107 .map(|(_, submod)| &*submod.module),
1108 )
1109 .flat_map(|x| x.all_nodes.iter());
1110
1111 let has_require_att = |atts: &Attributes| -> Result<TrivialCheckDiagType, ErrorEmitted> {
1113 let atts = atts.all_by_kind(|att| matches!(att.kind, AttributeKind::Require));
1114 for (_, atts) in atts {
1115 for att in atts.iter() {
1116 for arg in att.args.iter() {
1117 if arg.name.as_str() == REQUIRE_ARG_NAME_TRIVIALLY_DECODABLE {
1118 if let Some(v) = arg.value.as_ref() {
1119 match v.as_string() {
1120 Some("yes") => return Ok(TrivialCheckDiagType::Error),
1121 Some("no") => return Ok(TrivialCheckDiagType::Nothing),
1122 Some("as_warning") => return Ok(TrivialCheckDiagType::Warning),
1123 Some(_) => {
1124 let err = ConvertParseTreeError::InvalidAttributeArgValue {
1125 span: v.span(),
1126 arg: arg.name.clone(),
1127 expected_values: vec!["yes", "no", "as_warning"],
1128 };
1129 return Err(handler.emit_err(err.into()));
1130 }
1131 None => unreachable!(),
1132 }
1133 } else {
1134 unreachable!();
1135 }
1136 }
1137 }
1138 }
1139 }
1140 Ok(TrivialCheckDiagType::Nothing)
1141 };
1142
1143 let check_type = |ctx: &mut TypeCheckContext<'_>,
1144 is_decl: bool,
1145 tid: TypeId,
1146 type_name_span: Option<Span>,
1147 diag_type: TrivialCheckDiagType|
1148 -> Option<CheckDecl> {
1149 let is_decode_trivial_table = match ctx.engines.te().get(tid).as_ref() {
1150 TypeInfo::Struct(decl_id) => {
1151 let struct_decl = ctx.engines.de().get(decl_id);
1152
1153 let check = matches!(
1154 (is_decl, has_require_att(&struct_decl.attributes)),
1155 (
1156 true,
1157 Ok(TrivialCheckDiagType::Error | TrivialCheckDiagType::Warning)
1158 ) | (false, _)
1159 );
1160
1161 if check {
1162 let types = struct_decl
1163 .fields
1164 .iter()
1165 .map(|field| field.type_argument.type_id)
1166 .chain([tid]);
1167 Some(generate_is_decode_trivial_table(ctx, types))
1168 } else {
1169 None
1170 }
1171 }
1172 TypeInfo::Enum(decl_id) => {
1173 let enum_decl = ctx.engines.de().get(decl_id);
1174
1175 let check = matches!(
1176 (is_decl, has_require_att(&enum_decl.attributes)),
1177 (
1178 true,
1179 Ok(TrivialCheckDiagType::Error | TrivialCheckDiagType::Warning)
1180 ) | (false, _)
1181 );
1182
1183 if check {
1184 let types = enum_decl
1185 .variants
1186 .iter()
1187 .map(|variant| variant.type_argument.type_id)
1188 .chain([tid]);
1189
1190 Some(generate_is_decode_trivial_table(ctx, types))
1191 } else {
1192 None
1193 }
1194 }
1195 TypeInfo::UnsignedInteger(IntegerBits::Eight)
1196 | TypeInfo::UnsignedInteger(IntegerBits::SixtyFour)
1197 | TypeInfo::UnsignedInteger(IntegerBits::V256)
1198 | TypeInfo::B256 => None,
1199 TypeInfo::Boolean
1200 | TypeInfo::UnsignedInteger(IntegerBits::Sixteen)
1201 | TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo)
1202 | TypeInfo::Tuple(..)
1203 | TypeInfo::Array(..) => Some(generate_is_decode_trivial_table(ctx, [tid])),
1204 type_info => {
1205 let type_info = ctx.engines.help_out(type_info);
1206 handler.emit_err(CompileError::InternalOwned(
1207 format!("Unexpected type: {:?}", type_info),
1208 type_name_span.clone().unwrap_or(Span::dummy()),
1209 ));
1210 None
1211 }
1212 };
1213
1214 is_decode_trivial_table.map(|is_decode_trivial_table| {
1215 if is_decl {
1216 CheckDecl::Decl {
1217 tid,
1218 is_decode_trivial_table,
1219 diag: diag_type,
1220 }
1221 } else {
1222 CheckDecl::Ref {
1223 tid,
1224 is_decode_trivial_table,
1225 type_name_span: type_name_span.unwrap(),
1226 diag: diag_type,
1227 }
1228 }
1229 })
1230 };
1231
1232 for node in nodes {
1233 match &node.content {
1234 TyAstNodeContent::Declaration(TyDecl::StructDecl(struct_decl)) => {
1235 let id = struct_decl.decl_id;
1239 let struct_decl = type_check_ctx.engines.de().get(&id);
1240 let diag_type = has_require_att(&struct_decl.attributes)?;
1241
1242 decl_checks.extend(check_type(
1243 type_check_ctx,
1244 true,
1245 type_check_ctx.engines.te().insert(
1246 type_check_ctx.engines,
1247 TypeInfo::Struct(id),
1248 None,
1249 ),
1250 None,
1251 diag_type,
1252 ));
1253 }
1254 TyAstNodeContent::Declaration(TyDecl::AbiDecl(abi_decl)) => {
1255 let decl = type_check_ctx.engines.de().get(&abi_decl.decl_id);
1256 for item in decl.interface_surface.iter() {
1257 if let TyTraitInterfaceItem::TraitFn(decl_ref) = item {
1258 let decl = type_check_ctx.engines.de().get(decl_ref.id());
1259
1260 let diag_type = has_require_att(&decl.attributes)?;
1263 if matches!(
1264 diag_type,
1265 TrivialCheckDiagType::Error | TrivialCheckDiagType::Warning
1266 ) {
1267 let types = decl
1268 .parameters
1269 .iter()
1270 .map(|parameter| {
1271 (
1272 parameter.type_argument.type_id,
1273 parameter.type_argument.span.clone(),
1274 )
1275 })
1276 .chain([(decl.return_type.type_id, decl.return_type.span.clone())]);
1277
1278 for (tid, reason_being_checked) in types {
1279 decl_checks.extend(check_type(
1280 type_check_ctx,
1281 false,
1282 tid,
1283 Some(reason_being_checked),
1284 diag_type,
1285 ));
1286 }
1287 }
1288 }
1289 }
1290 }
1291 _ => {}
1292 }
1293 }
1294
1295 let workspace_pid = typed_program
1296 .declarations
1297 .first()
1298 .and_then(|x| x.span(type_check_ctx.engines).source_id().cloned())
1299 .map(|x| x.program_id());
1300
1301 let problems = ir_generation::compile::run_ir_decl_checks(
1302 handler,
1303 type_check_ctx.engines,
1304 ir_ctx,
1305 md_mgr,
1306 module,
1307 &decl_checks,
1308 workspace_pid,
1309 )?;
1310
1311 for err in problems {
1312 match err.diag {
1313 TrivialCheckDiagType::Nothing => {}
1314 TrivialCheckDiagType::Error => {
1315 handler.emit_err(CompileError::TrivialCheckFailed(err));
1316 }
1317 TrivialCheckDiagType::Warning => {
1318 handler.emit_warn(CompileWarning {
1319 span: Span::dummy(),
1320 warning_content: Warning::TrivialCheckFailed(err),
1321 });
1322 }
1323 };
1324 }
1325
1326 Ok(())
1327}
1328
1329#[allow(clippy::too_many_arguments)]
1330pub fn compile_to_ast(
1331 handler: &Handler,
1332 engines: &Engines,
1333 src: Source,
1334 initial_namespace: namespace::Package,
1335 build_config: Option<&BuildConfig>,
1336 package_name: &str,
1337 retrigger_compilation: Option<Arc<AtomicBool>>,
1338 experimental: ExperimentalFeatures,
1339) -> Result<Programs, ErrorEmitted> {
1340 check_should_abort(handler, retrigger_compilation.clone())?;
1341
1342 let query_engine = engines.qe();
1343 let mut metrics = PerformanceData::default();
1344 if let Some(config) = build_config {
1345 let path = config.canonical_root_module();
1346 let include_tests = config.include_tests;
1347 if is_parse_module_cache_up_to_date(engines, &path, include_tests, build_config) {
1349 let mut entry = query_engine.get_programs_cache_entry(&path).unwrap();
1350 entry.programs.metrics.reused_programs += 1;
1351
1352 let (warnings, errors, infos) = entry.handler_data;
1353 let new_handler = Handler::from_parts(warnings, errors, infos);
1354 handler.append(new_handler);
1355 return Ok(entry.programs);
1356 };
1357 }
1358
1359 let parse_program_opt = time_expr!(
1361 package_name,
1362 "parse the program to a concrete syntax tree (CST)",
1363 "parse_cst",
1364 parse(
1365 src,
1366 handler,
1367 engines,
1368 build_config,
1369 experimental,
1370 package_name
1371 ),
1372 build_config,
1373 metrics
1374 );
1375
1376 check_should_abort(handler, retrigger_compilation.clone())?;
1377
1378 let (lexed_program, mut parsed_program) = match parse_program_opt {
1379 Ok(modules) => modules,
1380 Err(e) => {
1381 handler.dedup();
1382 return Err(e);
1383 }
1384 };
1385
1386 if build_config.is_none_or(|config| !config.include_tests) {
1388 parsed_program.exclude_tests(engines);
1389 }
1390
1391 let program = time_expr!(
1393 package_name,
1394 "parse the concrete syntax tree (CST) to a typed AST",
1395 "parse_ast",
1396 parsed_to_ast(
1397 handler,
1398 engines,
1399 &mut parsed_program,
1400 initial_namespace,
1401 build_config,
1402 package_name,
1403 retrigger_compilation.clone(),
1404 experimental,
1405 build_config.map(|cfg| cfg.backtrace).unwrap_or_default()
1406 ),
1407 build_config,
1408 metrics
1409 );
1410
1411 check_should_abort(handler, retrigger_compilation.clone())?;
1412
1413 handler.dedup();
1414
1415 let programs = Programs::new(
1416 Arc::new(lexed_program),
1417 Arc::new(parsed_program),
1418 program.map(Arc::new),
1419 metrics,
1420 );
1421
1422 if let Some(config) = build_config {
1423 let path = config.canonical_root_module();
1424 let cache_entry = ProgramsCacheEntry {
1425 path,
1426 programs: programs.clone(),
1427 handler_data: handler.clone().consume(),
1428 };
1429 query_engine.insert_programs_cache_entry(cache_entry);
1430 }
1431
1432 check_should_abort(handler, retrigger_compilation.clone())?;
1433
1434 Ok(programs)
1435}
1436
1437pub fn compile_to_asm(
1440 handler: &Handler,
1441 engines: &Engines,
1442 src: Source,
1443 initial_namespace: namespace::Package,
1444 build_config: &BuildConfig,
1445 package_name: &str,
1446 experimental: ExperimentalFeatures,
1447) -> Result<CompiledAsm, ErrorEmitted> {
1448 let ast_res = compile_to_ast(
1449 handler,
1450 engines,
1451 src,
1452 initial_namespace,
1453 Some(build_config),
1454 package_name,
1455 None,
1456 experimental,
1457 )?;
1458
1459 ast_to_asm(handler, engines, &ast_res, build_config, experimental)
1460}
1461
1462pub fn ast_to_asm(
1465 handler: &Handler,
1466 engines: &Engines,
1467 programs: &Programs,
1468 build_config: &BuildConfig,
1469 experimental: ExperimentalFeatures,
1470) -> Result<CompiledAsm, ErrorEmitted> {
1471 let typed_program = match &programs.typed {
1472 Ok(typed_program) => typed_program,
1473 Err(err) => return Err(err.error),
1474 };
1475
1476 let mut panic_occurrences = PanicOccurrences::default();
1477 let mut panicking_call_occurrences = PanickingCallOccurrences::default();
1478
1479 let asm = match compile_ast_to_ir_to_asm(
1480 handler,
1481 engines,
1482 typed_program,
1483 &mut panic_occurrences,
1484 &mut panicking_call_occurrences,
1485 build_config,
1486 experimental,
1487 ) {
1488 Ok(res) => res,
1489 Err(err) => {
1490 handler.dedup();
1491 return Err(err);
1492 }
1493 };
1494
1495 Ok(CompiledAsm {
1496 finalized_asm: asm,
1497 panic_occurrences,
1498 panicking_call_occurrences,
1499 })
1500}
1501
1502pub(crate) fn compile_ast_to_ir_to_asm(
1503 handler: &Handler,
1504 engines: &Engines,
1505 program: &ty::TyProgram,
1506 panic_occurrences: &mut PanicOccurrences,
1507 panicking_call_occurrences: &mut PanickingCallOccurrences,
1508 build_config: &BuildConfig,
1509 experimental: ExperimentalFeatures,
1510) -> Result<FinalizedAsm, ErrorEmitted> {
1511 let mut ir = match ir_generation::compile_program(
1523 program,
1524 panic_occurrences,
1525 panicking_call_occurrences,
1526 build_config.include_tests,
1527 engines,
1528 experimental,
1529 build_config.backtrace.into(),
1530 ) {
1531 Ok(ir) => ir,
1532 Err(errors) => {
1533 let mut last = None;
1534 for e in errors {
1535 last = Some(handler.emit_err(e));
1536 }
1537 return Err(last.unwrap());
1538 }
1539 };
1540
1541 let entry_point_functions: Vec<::sway_ir::Function> = ir
1543 .module_iter()
1544 .flat_map(|module| module.function_iter(&ir))
1545 .filter(|func| func.is_entry(&ir))
1546 .collect();
1547
1548 {
1550 let mut env = ir_generation::PurityEnv::default();
1551 let mut md_mgr = metadata::MetadataManager::default();
1552 for entry_point in &entry_point_functions {
1553 check_function_purity(handler, &mut env, &ir, &mut md_mgr, entry_point);
1554 }
1555 }
1556
1557 let mut pass_mgr = PassManager::default();
1559 register_known_passes(&mut pass_mgr);
1560
1561 let mut pass_group = PassGroup::default();
1562
1563 pass_group.append_pass(INIT_AGGR_LOWERING_NAME);
1565
1566 match build_config.optimization_level {
1567 OptLevel::Opt1 => {
1568 pass_group.append_group(create_o1_pass_group());
1569 }
1570 OptLevel::Opt0 => {
1571 pass_group.append_pass(FN_DEDUP_DEBUG_PROFILE_NAME);
1574
1575 pass_group.append_pass(FN_INLINE_NAME);
1577
1578 pass_group.append_pass(GLOBALS_DCE_NAME);
1580 pass_group.append_pass(DCE_NAME);
1581 }
1582 }
1583
1584 if build_config.build_target == BuildTarget::Fuel {
1586 pass_group.append_pass(CONST_DEMOTION_NAME);
1591 pass_group.append_pass(ARG_DEMOTION_NAME);
1592 pass_group.append_pass(RET_DEMOTION_NAME);
1593 pass_group.append_pass(MISC_DEMOTION_NAME);
1594
1595 pass_group.append_pass(ARG_POINTEE_MUTABILITY_TAGGER_NAME);
1597 pass_group.append_pass(MEMCPYOPT_NAME);
1598
1599 pass_group.append_pass(DCE_NAME);
1601 pass_group.append_pass(SIMPLIFY_CFG_NAME);
1602
1603 match build_config.optimization_level {
1604 OptLevel::Opt1 => {
1605 pass_group.append_pass(MEMCPYPROP_REVERSE_NAME);
1606 pass_group.append_pass(SROA_NAME);
1607 pass_group.append_pass(MEM2REG_NAME);
1608 pass_group.append_pass(DCE_NAME);
1609 }
1610 OptLevel::Opt0 => {}
1611 }
1612 }
1613
1614 let print_passes_opts: PrintPassesOpts = (&build_config.print_ir).into();
1616 let verify_passes_opts: VerifyPassesOpts = (&build_config.verify_ir).into();
1617 let res = if let Err(ir_error) = pass_mgr.run_with_print_verify(
1618 &mut ir,
1619 &pass_group,
1620 &print_passes_opts,
1621 &verify_passes_opts,
1622 ) {
1623 Err(handler.emit_err(CompileError::InternalOwned(
1624 ir_error.to_string(),
1625 span::Span::dummy(),
1626 )))
1627 } else {
1628 Ok(())
1629 };
1630 res?;
1631
1632 compile_ir_context_to_finalized_asm(handler, &ir, Some(build_config))
1633}
1634
1635#[allow(clippy::too_many_arguments)]
1637pub fn compile_to_bytecode(
1638 handler: &Handler,
1639 engines: &Engines,
1640 src: Source,
1641 initial_namespace: namespace::Package,
1642 build_config: &BuildConfig,
1643 source_map: &mut SourceMap,
1644 package_name: &str,
1645 experimental: ExperimentalFeatures,
1646) -> Result<CompiledBytecode, ErrorEmitted> {
1647 let mut asm_res = compile_to_asm(
1648 handler,
1649 engines,
1650 src,
1651 initial_namespace,
1652 build_config,
1653 package_name,
1654 experimental,
1655 )?;
1656 asm_to_bytecode(
1657 handler,
1658 &mut asm_res,
1659 source_map,
1660 engines.se(),
1661 build_config,
1662 )
1663}
1664
1665pub const PRELUDE_CONFIGURABLES_SIZE_IN_BYTES: usize = 8;
1667pub const PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES: usize = 16;
1669pub const PRELUDE_SIZE_IN_BYTES: usize = 32;
1671
1672pub fn set_bytecode_configurables_offset(
1674 compiled_bytecode: &mut CompiledBytecode,
1675 md: &[u8; PRELUDE_CONFIGURABLES_SIZE_IN_BYTES],
1676) {
1677 assert!(
1678 compiled_bytecode.bytecode.len()
1679 >= PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES + PRELUDE_CONFIGURABLES_SIZE_IN_BYTES
1680 );
1681 let code = &mut compiled_bytecode.bytecode;
1682 for (index, byte) in md.iter().enumerate() {
1683 code[index + PRELUDE_CONFIGURABLES_OFFSET_IN_BYTES] = *byte;
1684 }
1685}
1686
1687pub fn asm_to_bytecode(
1689 handler: &Handler,
1690 asm: &mut CompiledAsm,
1691 source_map: &mut SourceMap,
1692 source_engine: &SourceEngine,
1693 build_config: &BuildConfig,
1694) -> Result<CompiledBytecode, ErrorEmitted> {
1695 let compiled_bytecode =
1696 asm.finalized_asm
1697 .to_bytecode_mut(handler, source_map, source_engine, build_config)?;
1698 Ok(compiled_bytecode)
1699}
1700
1701fn perform_control_flow_analysis(
1704 handler: &Handler,
1705 engines: &Engines,
1706 program: &ty::TyProgram,
1707 print_graph: Option<String>,
1708 print_graph_url_format: Option<String>,
1709) -> Result<(), ErrorEmitted> {
1710 let dca_res = dead_code_analysis(handler, engines, program);
1711 let rpa_errors = return_path_analysis(engines, program);
1712 let rpa_res = handler.scope(|handler| {
1713 for err in rpa_errors {
1714 handler.emit_err(err);
1715 }
1716 Ok(())
1717 });
1718
1719 if let Ok(graph) = dca_res.clone() {
1720 graph.visualize(engines, print_graph, print_graph_url_format);
1721 }
1722 dca_res?;
1723 rpa_res
1724}
1725
1726fn dead_code_analysis<'a>(
1731 handler: &Handler,
1732 engines: &'a Engines,
1733 program: &ty::TyProgram,
1734) -> Result<ControlFlowGraph<'a>, ErrorEmitted> {
1735 let decl_engine = engines.de();
1736 let mut dead_code_graph = ControlFlowGraph::new(engines);
1737 let tree_type = program.kind.tree_type();
1738 module_dead_code_analysis(
1739 handler,
1740 engines,
1741 &program.root_module,
1742 &tree_type,
1743 &mut dead_code_graph,
1744 )?;
1745 let warnings = dead_code_graph.find_dead_code(decl_engine);
1746 for warn in warnings {
1747 handler.emit_warn(warn);
1748 }
1749 Ok(dead_code_graph)
1750}
1751
1752fn module_dead_code_analysis<'eng: 'cfg, 'cfg>(
1754 handler: &Handler,
1755 engines: &'eng Engines,
1756 module: &ty::TyModule,
1757 tree_type: &parsed::TreeType,
1758 graph: &mut ControlFlowGraph<'cfg>,
1759) -> Result<(), ErrorEmitted> {
1760 module
1761 .submodules
1762 .iter()
1763 .try_fold((), |(), (_, submodule)| {
1764 let tree_type = parsed::TreeType::Library;
1765 module_dead_code_analysis(handler, engines, &submodule.module, &tree_type, graph)
1766 })?;
1767 let res = {
1768 ControlFlowGraph::append_module_to_dead_code_graph(
1769 engines,
1770 &module.all_nodes,
1771 tree_type,
1772 graph,
1773 )
1774 .map_err(|err| handler.emit_err(err))
1775 };
1776 graph.connect_pending_entry_edges();
1777 res
1778}
1779
1780fn return_path_analysis(engines: &Engines, program: &ty::TyProgram) -> Vec<CompileError> {
1781 let mut errors = vec![];
1782 module_return_path_analysis(engines, &program.root_module, &mut errors);
1783 errors
1784}
1785
1786fn module_return_path_analysis(
1787 engines: &Engines,
1788 module: &ty::TyModule,
1789 errors: &mut Vec<CompileError>,
1790) {
1791 for (_, submodule) in &module.submodules {
1792 module_return_path_analysis(engines, &submodule.module, errors);
1793 }
1794 let graph = ControlFlowGraph::construct_return_path_graph(engines, &module.all_nodes);
1795 match graph {
1796 Ok(graph) => errors.extend(graph.analyze_return_paths(engines)),
1797 Err(mut error) => errors.append(&mut error),
1798 }
1799}
1800
1801fn check_should_abort(
1804 handler: &Handler,
1805 retrigger_compilation: Option<Arc<AtomicBool>>,
1806) -> Result<(), ErrorEmitted> {
1807 if let Some(ref retrigger_compilation) = retrigger_compilation {
1808 if retrigger_compilation.load(Ordering::SeqCst) {
1809 return Err(handler.cancel());
1810 }
1811 }
1812 Ok(())
1813}
1814
1815pub fn dump_trait_impls_for_typename(
1816 handler: &Handler,
1817 engines: &Engines,
1818 namespace: &namespace::Namespace,
1819 typename: &str,
1820) -> Result<(), ErrorEmitted> {
1821 let path: Vec<&str> = typename.split("::").collect();
1822 let mut call_path = CallPath::fullpath(&path);
1823 call_path.callpath_type = CallPathType::Ambiguous;
1824
1825 let pkg_namespace = namespace.current_package_ref();
1826 let mod_path = [pkg_namespace.root_module().name().clone()];
1827
1828 let resolve_handler = Handler::default();
1829 let resolved = resolve_call_path(
1830 &resolve_handler,
1831 engines,
1832 namespace,
1833 &mod_path,
1834 &call_path,
1835 None,
1836 VisibilityCheck::No,
1837 );
1838
1839 if let Ok(resolved) = resolved {
1840 let module = &pkg_namespace.root_module();
1841
1842 let mut impls = Vec::new();
1843 find_trait_impls_for_type(engines, namespace, &resolved, module, &mut impls);
1844
1845 for ext_pkg in pkg_namespace.external_packages.iter() {
1846 let ext_module = ext_pkg.1.root_module();
1847 find_trait_impls_for_type(engines, namespace, &resolved, ext_module, &mut impls);
1848 }
1849
1850 let unique_impls = impls
1851 .iter()
1852 .unique_by(|i| i.impl_span.clone())
1853 .cloned()
1854 .collect::<Vec<_>>();
1855 handler.emit_info(CompileInfo {
1856 span: resolved.span(engines).subset_first_of("{").unwrap(),
1857 content: Info::ImplTraitsForType {
1858 impls: unique_impls,
1859 },
1860 });
1861 }
1862
1863 Ok(())
1864}
1865
1866fn find_trait_impls_for_type(
1867 engines: &Engines,
1868 namespace: &namespace::Namespace,
1869 resolved_decl: &ResolvedDeclaration,
1870 module: &namespace::Module,
1871 impls: &mut Vec<CollectedTraitImpl>,
1872) {
1873 let handler = Handler::default();
1874 let struct_decl_source_id = resolved_decl
1875 .to_struct_decl(&handler, engines)
1876 .map(|d| d.expect_typed())
1877 .and_then(|decl| decl.to_struct_decl(&handler, engines))
1878 .map(|decl_id| engines.de().get_struct(&decl_id).span.source_id().cloned())
1879 .ok()
1880 .flatten();
1881
1882 let enum_decl_source_id = resolved_decl
1883 .to_enum_decl(&handler, engines)
1884 .map(|d| d.expect_typed())
1885 .and_then(|decl| decl.to_enum_id(&handler, engines))
1886 .map(|decl_id| engines.de().get_enum(&decl_id).span.source_id().cloned())
1887 .ok()
1888 .flatten();
1889
1890 module.walk_scope_chain(|lexical_scope| {
1891 module.submodules().iter().for_each(|(_, sub)| {
1892 find_trait_impls_for_type(engines, namespace, resolved_decl, sub, impls);
1893 });
1894
1895 let trait_map = &lexical_scope.items.implemented_traits;
1896
1897 for key in trait_map.trait_impls.keys() {
1898 for trait_entry in trait_map.trait_impls[key].iter() {
1899 let trait_type = engines.te().get(trait_entry.inner.key.type_id);
1900
1901 let matched = match *trait_type {
1902 TypeInfo::Enum(decl_id) => {
1903 let trait_enum = engines.de().get_enum(&decl_id);
1904 enum_decl_source_id == trait_enum.span.source_id().cloned()
1905 }
1906 TypeInfo::Struct(decl_id) => {
1907 let trait_struct = engines.de().get_struct(&decl_id);
1908 struct_decl_source_id == trait_struct.span.source_id().cloned()
1909 }
1910 _ => false,
1911 };
1912
1913 if matched {
1914 let trait_callpath = trait_entry.inner.key.name.to_fullpath(engines, namespace);
1915 impls.push(CollectedTraitImpl {
1916 impl_span: trait_entry
1917 .inner
1918 .value
1919 .impl_span
1920 .subset_first_of("{")
1921 .unwrap(),
1922 trait_name: engines.help_out(trait_callpath).to_string(),
1923 });
1924 }
1925 }
1926 }
1927 });
1928}
1929
1930#[test]
1931fn test_basic_prog() {
1932 let handler = Handler::default();
1933 let engines = Engines::default();
1934 let prog = parse(
1935 r#"
1936 contract;
1937
1938 enum yo
1939 <T>
1940 where
1941 T: IsAThing
1942 {
1943 x: u32,
1944 y: MyStruct<u32>
1945 }
1946
1947 enum MyOtherSumType
1948 {
1949 x: u32,
1950 y: MyStruct<u32>
1951 }
1952 struct MyStruct<T> {
1953 field_name: u64,
1954 other_field: T,
1955 }
1956
1957
1958 fn generic_function
1959 <T>
1960 (arg1: u64,
1961 arg2: T)
1962 ->
1963 T
1964 where T: Display,
1965 T: Debug {
1966 let x: MyStruct =
1967 MyStruct
1968 {
1969 field_name:
1970 5
1971 };
1972 return
1973 match
1974 arg1
1975 {
1976 1
1977 => true,
1978 _ => { return false; },
1979 };
1980 }
1981
1982 struct MyStruct {
1983 test: string,
1984 }
1985
1986
1987
1988 use stdlib::println;
1989
1990 trait MyTrait {
1991 // interface points
1992 fn myfunc(x: int) -> unit;
1993 } {
1994 // methods
1995 fn calls_interface_fn(x: int) -> unit {
1996 // declare a byte
1997 let x = 0b10101111;
1998 let mut y = 0b11111111;
1999 self.interface_fn(x);
2000 }
2001 }
2002
2003 pub fn prints_number_five() -> u8 {
2004 let x: u8 = 5;
2005 println(x);
2006 x.to_string();
2007 let some_list = [
2008 5,
2009 10 + 3 / 2,
2010 func_app(my_args, (so_many_args))];
2011 return 5;
2012 }
2013 "#
2014 .into(),
2015 &handler,
2016 &engines,
2017 None,
2018 ExperimentalFeatures::default(),
2019 "test",
2020 );
2021 prog.unwrap();
2022}
2023#[test]
2024fn test_parenthesized() {
2025 let handler = Handler::default();
2026 let engines = Engines::default();
2027 let prog = parse(
2028 r#"
2029 contract;
2030 pub fn some_abi_func() -> unit {
2031 let x = (5 + 6 / (1 + (2 / 1) + 4));
2032 return;
2033 }
2034 "#
2035 .into(),
2036 &handler,
2037 &engines,
2038 None,
2039 ExperimentalFeatures::default(),
2040 "test",
2041 );
2042 prog.unwrap();
2043}
2044
2045#[test]
2046fn test_unary_ordering() {
2047 use crate::language::{self, parsed};
2048 let handler = Handler::default();
2049 let engines = Engines::default();
2050 let prog = parse(
2051 r#"
2052 script;
2053 fn main() -> bool {
2054 let a = true;
2055 let b = true;
2056 !a && b;
2057 }"#
2058 .into(),
2059 &handler,
2060 &engines,
2061 None,
2062 ExperimentalFeatures::default(),
2063 "test",
2064 );
2065 let (.., prog) = prog.unwrap();
2066 if let parsed::AstNode {
2069 content:
2070 parsed::AstNodeContent::Declaration(parsed::Declaration::FunctionDeclaration(decl_id)),
2071 ..
2072 } = &prog.root.tree.root_nodes[0]
2073 {
2074 let fn_decl = engines.pe().get_function(decl_id);
2075 if let parsed::AstNode {
2076 content:
2077 parsed::AstNodeContent::Expression(parsed::Expression {
2078 kind:
2079 parsed::ExpressionKind::LazyOperator(parsed::LazyOperatorExpression {
2080 op, ..
2081 }),
2082 ..
2083 }),
2084 ..
2085 } = &fn_decl.body.contents[2]
2086 {
2087 assert_eq!(op, &language::LazyOp::And)
2088 } else {
2089 panic!("Was not lazy operator.")
2090 }
2091 } else {
2092 panic!("Was not ast node")
2093 };
2094}
2095
2096#[test]
2097fn test_parser_recovery() {
2098 let handler = Handler::default();
2099 let engines = Engines::default();
2100 let prog = parse(
2101 r#"
2102 script;
2103 fn main() -> bool {
2104 let
2105 let a = true;
2106 true
2107 }"#
2108 .into(),
2109 &handler,
2110 &engines,
2111 None,
2112 ExperimentalFeatures::default(),
2113 "test",
2114 );
2115 let (_, _) = prog.unwrap();
2116 assert!(handler.has_errors());
2117 dbg!(handler);
2118}