1use std::sync::Arc;
2
3use crate::{
4 decl_engine::*,
5 fuel_prelude::fuel_tx::StorageSlot,
6 language::{parsed, ty::*, Purity, Visibility},
7 namespace::{check_impls_for_overlap, check_orphan_rules_for_impls, TraitMap},
8 semantic_analysis::namespace,
9 transform::AllowDeprecatedState,
10 type_system::*,
11 types::*,
12 Engines,
13};
14
15use sway_error::{
16 error::{CompileError, TypeNotAllowedReason},
17 handler::{ErrorEmitted, Handler},
18};
19use sway_features::ExperimentalFeatures;
20use sway_types::*;
21
22#[derive(Debug, Clone)]
23pub struct TyProgram {
24 pub kind: TyProgramKind,
25 pub root_module: TyModule,
26 pub namespace: namespace::Namespace,
27 pub declarations: Vec<TyDecl>,
28 pub configurables: Vec<TyConfigurableDecl>,
29 pub storage_slots: Vec<StorageSlot>,
30 pub logged_types: Vec<(LogId, TypeId)>,
31 pub messages_types: Vec<(MessageId, TypeId)>,
32}
33
34fn get_type_not_allowed_error(
35 engines: &Engines,
36 type_id: TypeId,
37 spanned: &impl Spanned,
38 f: impl Fn(&TypeInfo) -> Option<TypeNotAllowedReason>,
39) -> Option<CompileError> {
40 let types = type_id.extract_any_including_self(engines, &|t| f(t).is_some(), vec![], 0);
41
42 let (id, _) = types.into_iter().next()?;
43 let t = engines.te().get(id);
44
45 Some(CompileError::TypeNotAllowed {
46 reason: f(&t)?,
47 span: spanned.span(),
48 })
49}
50
51fn check_no_ref_main(engines: &Engines, handler: &Handler, main_function: &DeclId<TyFunctionDecl>) {
52 let main_function = engines.de().get_function(main_function);
53 for param in main_function.parameters.iter() {
54 if param.is_reference && param.is_mutable {
55 handler.emit_err(CompileError::RefMutableNotAllowedInMain {
56 param_name: param.name.clone(),
57 span: param.name.span(),
58 });
59 }
60 }
61}
62
63impl TyProgram {
64 pub fn validate_coherence(
65 handler: &Handler,
66 engines: &Engines,
67 root: &TyModule,
68 root_namespace: &mut namespace::Namespace,
69 ) -> Result<(), ErrorEmitted> {
70 check_orphan_rules_for_impls(handler, engines, root_namespace.current_package_ref())?;
72
73 let mut unified_trait_map = root_namespace
75 .current_package_ref()
76 .root_module()
77 .root_lexical_scope()
78 .items
79 .implemented_traits
80 .clone();
81
82 Self::validate_coherence_overlap(
83 handler,
84 engines,
85 root,
86 root_namespace,
87 &mut unified_trait_map,
88 )?;
89
90 Ok(())
91 }
92
93 pub fn validate_coherence_overlap(
94 handler: &Handler,
95 engines: &Engines,
96 module: &TyModule,
97 root_namespace: &mut namespace::Namespace,
98 unified_trait_map: &mut TraitMap,
99 ) -> Result<(), ErrorEmitted> {
100 let other_trait_map = unified_trait_map.clone();
101 check_impls_for_overlap(unified_trait_map, handler, other_trait_map, engines)?;
102
103 for (submod_name, submodule) in module.submodules.iter() {
104 root_namespace.push_submodule(
105 handler,
106 engines,
107 submod_name.clone(),
108 Visibility::Public,
109 submodule.mod_name_span.clone(),
110 false,
111 )?;
112
113 Self::validate_coherence_overlap(
114 handler,
115 engines,
116 &submodule.module,
117 root_namespace,
118 unified_trait_map,
119 )?;
120
121 root_namespace.pop_submodule();
122 }
123
124 Ok(())
125 }
126
127 pub fn validate_root(
129 handler: &Handler,
130 engines: &Engines,
131 root: &TyModule,
132 kind: parsed::TreeType,
133 package_name: &str,
134 experimental: ExperimentalFeatures,
135 ) -> Result<(TyProgramKind, Vec<TyDecl>, Vec<TyConfigurableDecl>), ErrorEmitted> {
136 let ty_engine = engines.te();
139 let decl_engine = engines.de();
140
141 let mut configurables = vec![];
143 for (_, submodule) in &root.submodules {
144 let _ = Self::validate_root(
145 handler,
146 engines,
147 &submodule.module,
148 parsed::TreeType::Library,
149 package_name,
150 experimental,
151 );
152 }
153
154 let mut entries = Vec::new();
155 let mut mains = Vec::new();
156 let mut declarations = Vec::<TyDecl>::new();
157 let mut abi_entries = Vec::new();
158 let mut fn_declarations = std::collections::HashSet::new();
159
160 for node in &root.all_nodes {
161 match &node.content {
162 TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl { decl_id })) => {
163 let func = decl_engine.get_function(decl_id);
164
165 match func.kind {
166 TyFunctionDeclKind::Main => mains.push(*decl_id),
167 TyFunctionDeclKind::Entry => entries.push(*decl_id),
168 _ => {}
169 }
170
171 if !fn_declarations.insert(func.name.clone()) {
172 handler.emit_err(CompileError::MultipleDefinitionsOfFunction {
173 name: func.name.clone(),
174 span: func.name.span(),
175 });
176 }
177
178 declarations.push(TyDecl::FunctionDecl(FunctionDecl { decl_id: *decl_id }));
179 }
180 TyAstNodeContent::Declaration(TyDecl::ConfigurableDecl(ConfigurableDecl {
181 decl_id,
182 ..
183 })) => {
184 let decl = (*decl_engine.get_configurable(decl_id)).clone();
185 configurables.push(decl);
186 }
187 TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(ImplSelfOrTrait {
191 decl_id,
192 ..
193 })) => {
194 let impl_trait_decl = decl_engine.get_impl_self_or_trait(decl_id);
195 let TyImplSelfOrTrait {
196 items,
197 implementing_for,
198 trait_decl_ref,
199 ..
200 } = &*impl_trait_decl;
201 if matches!(
202 &*ty_engine.get(implementing_for.type_id()),
203 TypeInfo::Contract
204 ) {
205 if let Some(trait_decl_ref) = trait_decl_ref {
208 if matches!(*trait_decl_ref.id(), InterfaceDeclId::Abi(_)) {
209 for item in items {
210 match item {
211 TyImplItem::Fn(method_ref) => {
212 abi_entries.push(*method_ref.id());
213 }
214 TyImplItem::Constant(const_ref) => {
215 declarations.push(TyDecl::ConstantDecl(ConstantDecl {
216 decl_id: *const_ref.id(),
217 }));
218 }
219 TyImplItem::Type(type_ref) => {
220 declarations.push(TyDecl::TraitTypeDecl(
221 TraitTypeDecl {
222 decl_id: *type_ref.id(),
223 },
224 ));
225 }
226 }
227 }
228 }
229 }
230 }
231 }
232 TyAstNodeContent::Declaration(decl) => {
234 declarations.push(decl.clone());
235 }
236 _ => {}
237 };
238 }
239
240 if kind != parsed::TreeType::Contract {
242 if !matches!(kind, parsed::TreeType::Library) {
244 for err in disallow_impure_functions(decl_engine, &declarations, &entries) {
245 handler.emit_err(err);
246 }
247 }
248
249 let storage_decl = declarations
251 .iter()
252 .find(|decl| matches!(decl, TyDecl::StorageDecl { .. }));
253
254 if let Some(TyDecl::StorageDecl(StorageDecl { decl_id })) = storage_decl {
255 handler.emit_err(CompileError::StorageDeclarationInNonContract {
256 program_kind: format!("{kind}"),
257 span: engines.de().get(decl_id).span.clone(),
258 });
259 }
260 }
261
262 let typed_program_kind = match kind {
264 parsed::TreeType::Contract => {
265 for decl in declarations.iter() {
267 if let TyDecl::StorageDecl(StorageDecl { decl_id }) = decl {
268 let storage_decl = decl_engine.get_storage(decl_id);
269 for field in storage_decl.fields.iter() {
270 if let Some(error) = get_type_not_allowed_error(
271 engines,
272 field.type_argument.type_id(),
273 &field.type_argument,
274 |t| match t {
275 TypeInfo::StringSlice => {
276 Some(TypeNotAllowedReason::StringSliceInConfigurables)
277 }
278 TypeInfo::RawUntypedPtr => Some(
279 TypeNotAllowedReason::TypeNotAllowedInContractStorage {
280 ty: engines.help_out(t).to_string(),
281 },
282 ),
283 _ => None,
284 },
285 ) {
286 handler.emit_err(error);
287 }
288 }
289 }
290 }
291
292 TyProgramKind::Contract {
293 entry_function: if experimental.new_encoding {
294 if entries.len() != 1 {
295 return Err(handler.emit_err(CompileError::CouldNotGenerateEntry {
296 span: Span::dummy(),
297 }));
298 }
299 Some(entries[0])
300 } else {
301 None
302 },
303 abi_entries,
304 }
305 }
306 parsed::TreeType::Library => {
307 if !configurables.is_empty() {
308 handler.emit_err(CompileError::ConfigurableInLibrary {
309 span: configurables[0].call_path.suffix.span(),
310 });
311 }
312 TyProgramKind::Library {
313 name: package_name.to_string(),
314 }
315 }
316 parsed::TreeType::Predicate => {
317 if mains.is_empty() {
318 return Err(
319 handler.emit_err(CompileError::NoPredicateMainFunction(root.span.clone()))
320 );
321 }
322
323 if mains.len() > 1 {
324 let mut last_error = None;
325 for m in mains.iter().skip(1) {
326 let mains_last = decl_engine.get_function(m);
327 last_error = Some(handler.emit_err(
328 CompileError::MultipleDefinitionsOfFunction {
329 name: mains_last.name.clone(),
330 span: mains_last.name.span(),
331 },
332 ));
333 }
334 return Err(last_error.unwrap());
335 }
336
337 check_no_ref_main(engines, handler, &mains[0]);
339
340 let (entry_fn_id, main_fn_id) = if experimental.new_encoding {
341 if entries.len() != 1 {
342 return Err(handler.emit_err(CompileError::CouldNotGenerateEntry {
343 span: Span::dummy(),
344 }));
345 }
346 (entries[0], mains[0])
347 } else {
348 assert!(entries.is_empty());
349 (mains[0], mains[0])
350 };
351
352 let main_fn = decl_engine.get(&main_fn_id);
353 if !ty_engine.get(main_fn.return_type.type_id()).is_bool() {
354 handler.emit_err(CompileError::PredicateMainDoesNotReturnBool(
355 main_fn.span.clone(),
356 ));
357 }
358
359 TyProgramKind::Predicate {
360 entry_function: entry_fn_id,
361 main_function: main_fn_id,
362 }
363 }
364 parsed::TreeType::Script => {
365 if mains.is_empty() {
367 return Err(
368 handler.emit_err(CompileError::NoScriptMainFunction(root.span.clone()))
369 );
370 }
371
372 if mains.len() > 1 {
373 let mut last_error = None;
374 for m in mains.iter().skip(1) {
375 let mains_last = decl_engine.get_function(m);
376 last_error = Some(handler.emit_err(
377 CompileError::MultipleDefinitionsOfFunction {
378 name: mains_last.name.clone(),
379 span: mains_last.name.span(),
380 },
381 ));
382 }
383 return Err(last_error.unwrap());
384 }
385
386 check_no_ref_main(engines, handler, &mains[0]);
388
389 let (entry_fn_id, main_fn_id) = if experimental.new_encoding {
390 if entries.len() != 1 {
391 return Err(handler.emit_err(CompileError::CouldNotGenerateEntry {
392 span: Span::dummy(),
393 }));
394 }
395 (entries[0], mains[0])
396 } else {
397 assert!(entries.is_empty());
398 (mains[0], mains[0])
399 };
400
401 if !experimental.new_encoding {
403 let main_fn = decl_engine.get(&main_fn_id);
404 for p in main_fn.parameters() {
405 if let Some(error) = get_type_not_allowed_error(
406 engines,
407 p.type_argument.type_id(),
408 &p.type_argument,
409 |t| match t {
410 TypeInfo::StringSlice => {
411 Some(TypeNotAllowedReason::StringSliceInMainParameters)
412 }
413 TypeInfo::RawUntypedSlice => {
414 Some(TypeNotAllowedReason::NestedSliceReturnNotAllowedInMain)
415 }
416 _ => None,
417 },
418 ) {
419 handler.emit_err(error);
420 }
421 }
422
423 if let Some(error) = get_type_not_allowed_error(
425 engines,
426 main_fn.return_type.type_id(),
427 &main_fn.return_type,
428 |t| match t {
429 TypeInfo::StringSlice => {
430 Some(TypeNotAllowedReason::StringSliceInMainReturn)
431 }
432 TypeInfo::RawUntypedSlice => {
433 Some(TypeNotAllowedReason::NestedSliceReturnNotAllowedInMain)
434 }
435 _ => None,
436 },
437 ) {
438 if !matches!(
440 &*engines.te().get(main_fn.return_type.type_id()),
441 TypeInfo::RawUntypedSlice
442 ) {
443 handler.emit_err(error);
444 }
445 }
446 }
447
448 TyProgramKind::Script {
449 entry_function: entry_fn_id,
450 main_function: main_fn_id,
451 }
452 }
453 };
454
455 for c in configurables.iter() {
457 if let Some(error) = get_type_not_allowed_error(
458 engines,
459 c.return_type,
460 &c.type_ascription,
461 |t| match t {
462 TypeInfo::StringSlice => Some(TypeNotAllowedReason::StringSliceInConfigurables),
463 TypeInfo::Slice(_) => Some(TypeNotAllowedReason::SliceInConst),
464 _ => None,
465 },
466 ) {
467 handler.emit_err(error);
468 }
469 }
470
471 for decl in root.iter_constants(decl_engine).iter() {
473 let decl = decl_engine.get_constant(&decl.decl_id);
474 let e =
475 get_type_not_allowed_error(engines, decl.return_type, &decl.type_ascription, |t| {
476 match t {
477 TypeInfo::StringSlice => Some(TypeNotAllowedReason::StringSliceInConst),
478 TypeInfo::Slice(_) => Some(TypeNotAllowedReason::SliceInConst),
479 _ => None,
480 }
481 });
482 if let Some(error) = e {
483 handler.emit_err(error);
484 }
485 }
486
487 Ok((typed_program_kind, declarations, configurables))
488 }
489
490 pub fn test_fns<'a: 'b, 'b>(
492 &'b self,
493 decl_engine: &'a DeclEngine,
494 ) -> impl 'b + Iterator<Item = (Arc<TyFunctionDecl>, DeclRefFunction)> {
495 self.root_module.test_fns_recursive(decl_engine)
496 }
497
498 pub fn check_deprecated(&self, engines: &Engines, handler: &Handler) {
499 let mut allow_deprecated = AllowDeprecatedState::default();
500 self.root_module
501 .check_deprecated(engines, handler, &mut allow_deprecated);
502 }
503
504 pub fn check_recursive(
505 &self,
506 engines: &Engines,
507 handler: &Handler,
508 ) -> Result<(), ErrorEmitted> {
509 self.root_module.check_recursive(engines, handler)
510 }
511}
512
513impl CollectTypesMetadata for TyProgram {
514 fn collect_types_metadata(
516 &self,
517 handler: &Handler,
518 ctx: &mut CollectTypesMetadataContext,
519 ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
520 let decl_engine = ctx.engines.de();
521 let mut metadata = vec![];
522
523 match &self.kind {
525 TyProgramKind::Script {
528 entry_function: main_function,
529 ..
530 }
531 | TyProgramKind::Predicate {
532 entry_function: main_function,
533 ..
534 } => {
535 let main_function = decl_engine.get_function(main_function);
536 metadata.append(&mut main_function.collect_types_metadata(handler, ctx)?);
537 }
538 TyProgramKind::Contract {
541 abi_entries,
542 entry_function: main_function,
543 } => {
544 if let Some(main_function) = main_function {
545 let entry = decl_engine.get_function(main_function);
546 metadata.append(&mut entry.collect_types_metadata(handler, ctx)?);
547 }
548
549 for entry in abi_entries.iter() {
550 let entry = decl_engine.get_function(entry);
551 metadata.append(&mut entry.collect_types_metadata(handler, ctx)?);
552 }
553 }
554 TyProgramKind::Library { .. } => {
558 for module in std::iter::once(&self.root_module).chain(
559 self.root_module
560 .submodules_recursive()
561 .map(|(_, submod)| &*submod.module),
562 ) {
563 for node in module.all_nodes.iter() {
564 let is_generic_function = node.is_generic_function(decl_engine);
565 if node.is_public(decl_engine) {
566 let node_metadata = node.collect_types_metadata(handler, ctx)?;
567 metadata.append(
568 &mut node_metadata
569 .iter()
570 .filter(|m| {
571 !(is_generic_function
574 && matches!(m, TypeMetadata::UnresolvedType(..)))
575 })
576 .cloned()
577 .collect::<Vec<TypeMetadata>>(),
578 );
579 }
580 }
581 }
582 }
583 }
584
585 for module in std::iter::once(&self.root_module).chain(
588 self.root_module
589 .submodules_recursive()
590 .map(|(_, submod)| &*submod.module),
591 ) {
592 for node in module.all_nodes.iter() {
593 if node.is_test_function(decl_engine) {
594 metadata.append(&mut node.collect_types_metadata(handler, ctx)?);
595 }
596 }
597 }
598
599 Ok(metadata)
600 }
601}
602
603#[derive(Clone, Debug)]
604pub enum TyProgramKind {
605 Contract {
606 entry_function: Option<DeclId<TyFunctionDecl>>,
607 abi_entries: Vec<DeclId<TyFunctionDecl>>,
608 },
609 Library {
610 name: String,
611 },
612 Predicate {
613 entry_function: DeclId<TyFunctionDecl>,
614 main_function: DeclId<TyFunctionDecl>,
615 },
616 Script {
617 entry_function: DeclId<TyFunctionDecl>,
618 main_function: DeclId<TyFunctionDecl>,
619 },
620}
621
622impl TyProgramKind {
623 pub fn tree_type(&self) -> parsed::TreeType {
625 match self {
626 TyProgramKind::Contract { .. } => parsed::TreeType::Contract,
627 TyProgramKind::Library { .. } => parsed::TreeType::Library,
628 TyProgramKind::Predicate { .. } => parsed::TreeType::Predicate,
629 TyProgramKind::Script { .. } => parsed::TreeType::Script,
630 }
631 }
632 pub fn as_title_str(&self) -> &str {
634 match self {
635 TyProgramKind::Contract { .. } => "Contract",
636 TyProgramKind::Library { .. } => "Library",
637 TyProgramKind::Predicate { .. } => "Predicate",
638 TyProgramKind::Script { .. } => "Script",
639 }
640 }
641}
642
643fn disallow_impure_functions(
644 decl_engine: &DeclEngine,
645 declarations: &[TyDecl],
646 mains: &[DeclId<TyFunctionDecl>],
647) -> Vec<CompileError> {
648 let mut errs: Vec<CompileError> = vec![];
649 let fn_decls = declarations
650 .iter()
651 .filter_map(|decl| match decl {
652 TyDecl::FunctionDecl(FunctionDecl { decl_id, .. }) => Some(*decl_id),
653 _ => None,
654 })
655 .chain(mains.to_owned());
656 let mut err_purity = fn_decls
657 .filter_map(|decl_id| {
658 let fn_decl = decl_engine.get_function(&decl_id);
659 let TyFunctionDecl { purity, name, .. } = &*fn_decl;
660 if *purity != Purity::Pure {
661 Some(CompileError::ImpureInNonContract { span: name.span() })
662 } else {
663 None
664 }
665 })
666 .collect::<Vec<_>>();
667 errs.append(&mut err_purity);
668 errs
669}