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