sway_core/language/ty/expression/
intrinsic_function.rs

1use crate::{
2    abi_generation::abi_str::AbiStrContext, engine_threading::*, has_changes, language::ty::*,
3    type_system::*, types::*,
4};
5use itertools::Itertools;
6use serde::{Deserialize, Serialize};
7use std::{
8    fmt,
9    hash::{Hash, Hasher},
10};
11use sway_ast::Intrinsic;
12use sway_error::handler::{ErrorEmitted, Handler};
13use sway_types::Span;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct TyIntrinsicFunctionKind {
17    pub kind: Intrinsic,
18    pub arguments: Vec<TyExpression>,
19    pub type_arguments: Vec<GenericArgument>,
20    pub span: Span,
21}
22
23impl TyIntrinsicFunctionKind {
24    /// Returns the actual type being logged. When the "new_encoding" is off,
25    /// this is just the `__log` argument; but when it is on, it is actually the
26    /// type of the argument to fn `encode`.
27    pub fn get_logged_type(&self, new_encoding: bool) -> Option<TypeId> {
28        if new_encoding {
29            if matches!(self.kind, Intrinsic::Log) {
30                match &self.arguments[0].expression {
31                    TyExpressionVariant::FunctionApplication {
32                        call_path,
33                        arguments,
34                        ..
35                    } => {
36                        assert!(call_path.suffix.as_str() == "encode");
37                        Some(arguments[0].1.return_type)
38                    }
39                    _ => None,
40                }
41            } else {
42                None
43            }
44        } else {
45            Some(self.arguments[0].return_type)
46        }
47    }
48}
49
50impl EqWithEngines for TyIntrinsicFunctionKind {}
51impl PartialEqWithEngines for TyIntrinsicFunctionKind {
52    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
53        self.kind == other.kind
54            && self.arguments.eq(&other.arguments, ctx)
55            && self.type_arguments.eq(&other.type_arguments, ctx)
56    }
57}
58
59impl HashWithEngines for TyIntrinsicFunctionKind {
60    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
61        let TyIntrinsicFunctionKind {
62            kind,
63            arguments,
64            type_arguments,
65            // these fields are not hashed because they aren't relevant/a
66            // reliable source of obj v. obj distinction
67            span: _,
68        } = self;
69        kind.hash(state);
70        arguments.hash(state, engines);
71        type_arguments.hash(state, engines);
72    }
73}
74
75impl SubstTypes for TyIntrinsicFunctionKind {
76    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
77        has_changes! {
78            self.arguments.subst(ctx);
79            self.type_arguments.subst(ctx);
80        }
81    }
82}
83
84impl DebugWithEngines for TyIntrinsicFunctionKind {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
86        let targs = self
87            .type_arguments
88            .iter()
89            .map(|targ| format!("{:?}", engines.help_out(targ.type_id())))
90            .join(", ");
91        let args = self
92            .arguments
93            .iter()
94            .map(|e| format!("{:?}", engines.help_out(e)))
95            .join(", ");
96
97        write!(f, "{}::<{}>::({})", self.kind, targs, args)
98    }
99}
100
101impl CollectTypesMetadata for TyIntrinsicFunctionKind {
102    fn collect_types_metadata(
103        &self,
104        handler: &Handler,
105        ctx: &mut CollectTypesMetadataContext,
106    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
107        let mut types_metadata = vec![];
108        for type_arg in self.type_arguments.iter() {
109            types_metadata.append(&mut type_arg.type_id().collect_types_metadata(handler, ctx)?);
110        }
111        for arg in self.arguments.iter() {
112            types_metadata.append(&mut arg.collect_types_metadata(handler, ctx)?);
113        }
114
115        match self.kind {
116            Intrinsic::Log => {
117                let logged_type = self.get_logged_type(ctx.experimental.new_encoding).unwrap();
118                types_metadata.push(TypeMetadata::LoggedType(
119                    LogId::new(logged_type.get_abi_type_str(
120                        &AbiStrContext {
121                            program_name: ctx.program_name.clone(),
122                            abi_with_callpaths: true,
123                            abi_with_fully_specified_types: true,
124                            abi_root_type_without_generic_type_parameters: false,
125                        },
126                        ctx.engines,
127                        logged_type,
128                    )),
129                    logged_type,
130                ));
131            }
132            Intrinsic::Smo => {
133                types_metadata.push(TypeMetadata::MessageType(
134                    MessageId::new(ctx.message_id_counter()),
135                    self.arguments[1].return_type,
136                ));
137                *ctx.message_id_counter_mut() += 1;
138            }
139            _ => {}
140        }
141
142        Ok(types_metadata)
143    }
144}