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