sway_core/language/ty/expression/
expression.rs

1use crate::{
2    decl_engine::*,
3    engine_threading::*,
4    has_changes,
5    language::{ty::*, Literal},
6    semantic_analysis::{
7        TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization,
8        TypeCheckFinalizationContext,
9    },
10    transform::{AllowDeprecatedState, AttributeKind, AttributesMap},
11    type_system::*,
12    types::*,
13};
14use serde::{Deserialize, Serialize};
15use std::{fmt, hash::Hasher};
16use sway_error::{
17    error::CompileError,
18    handler::{ErrorEmitted, Handler},
19    type_error::TypeError,
20    warning::{CompileWarning, Warning},
21};
22use sway_types::{Span, Spanned};
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct TyExpression {
26    pub expression: TyExpressionVariant,
27    pub return_type: TypeId,
28    pub span: Span,
29}
30
31impl EqWithEngines for TyExpression {}
32impl PartialEqWithEngines for TyExpression {
33    fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
34        let type_engine = ctx.engines().te();
35        self.expression.eq(&other.expression, ctx)
36            && type_engine
37                .get(self.return_type)
38                .eq(&type_engine.get(other.return_type), ctx)
39    }
40}
41
42impl HashWithEngines for TyExpression {
43    fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
44        let TyExpression {
45            expression,
46            return_type,
47            // these fields are not hashed because they aren't relevant/a
48            // reliable source of obj v. obj distinction
49            span: _,
50        } = self;
51        let type_engine = engines.te();
52        expression.hash(state, engines);
53        type_engine.get(*return_type).hash(state, engines);
54    }
55}
56
57impl SubstTypes for TyExpression {
58    fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
59        has_changes! {
60            self.return_type.subst(ctx);
61            self.expression.subst(ctx);
62        }
63    }
64}
65
66impl ReplaceDecls for TyExpression {
67    fn replace_decls_inner(
68        &mut self,
69        decl_mapping: &DeclMapping,
70        handler: &Handler,
71        ctx: &mut TypeCheckContext,
72    ) -> Result<bool, ErrorEmitted> {
73        self.expression.replace_decls(decl_mapping, handler, ctx)
74    }
75}
76
77impl UpdateConstantExpression for TyExpression {
78    fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
79        self.expression
80            .update_constant_expression(engines, implementing_type)
81    }
82}
83
84impl DisplayWithEngines for TyExpression {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
86        write!(
87            f,
88            "{} ({})",
89            engines.help_out(&self.expression),
90            engines.help_out(self.return_type)
91        )
92    }
93}
94
95impl DebugWithEngines for TyExpression {
96    fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
97        write!(
98            f,
99            "{:?} ({:?})",
100            engines.help_out(&self.expression),
101            engines.help_out(self.return_type)
102        )
103    }
104}
105
106impl TypeCheckAnalysis for TyExpression {
107    fn type_check_analyze(
108        &self,
109        handler: &Handler,
110        ctx: &mut TypeCheckAnalysisContext,
111    ) -> Result<(), ErrorEmitted> {
112        match &self.expression {
113            // Check literal "fits" into assigned typed.
114            TyExpressionVariant::Literal(Literal::Numeric(literal_value)) => {
115                let t = ctx.engines.te().get(self.return_type);
116                if let TypeInfo::UnsignedInteger(bits) = &*t {
117                    if bits.would_overflow(*literal_value) {
118                        handler.emit_err(CompileError::TypeError(TypeError::LiteralOverflow {
119                            expected: format!("{:?}", ctx.engines.help_out(t)),
120                            span: self.span.clone(),
121                        }));
122                    }
123                }
124            }
125            TyExpressionVariant::ArrayExplicit { .. } => {
126                self.as_array_unify_elements(handler, ctx.engines);
127            }
128            _ => {}
129        }
130        self.expression.type_check_analyze(handler, ctx)
131    }
132}
133
134impl TypeCheckFinalization for TyExpression {
135    fn type_check_finalize(
136        &mut self,
137        handler: &Handler,
138        ctx: &mut TypeCheckFinalizationContext,
139    ) -> Result<(), ErrorEmitted> {
140        let res = self.expression.type_check_finalize(handler, ctx);
141        if let TyExpressionVariant::FunctionApplication { fn_ref, .. } = &self.expression {
142            let method = ctx.engines.de().get_function(fn_ref);
143            self.return_type = method.return_type.type_id;
144        }
145        res
146    }
147}
148
149impl CollectTypesMetadata for TyExpression {
150    fn collect_types_metadata(
151        &self,
152        handler: &Handler,
153        ctx: &mut CollectTypesMetadataContext,
154    ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
155        use TyExpressionVariant::*;
156        let decl_engine = ctx.engines.de();
157        let mut res = self.return_type.collect_types_metadata(handler, ctx)?;
158        match &self.expression {
159            FunctionApplication {
160                arguments,
161                fn_ref,
162                call_path,
163                type_binding,
164                ..
165            } => {
166                for arg in arguments.iter() {
167                    res.append(&mut arg.1.collect_types_metadata(handler, ctx)?);
168                }
169                let function_decl = decl_engine.get_function(fn_ref);
170
171                ctx.call_site_push();
172                for (idx, type_parameter) in function_decl.type_parameters.iter().enumerate() {
173                    ctx.call_site_insert(type_parameter.type_id, call_path.span());
174
175                    // Verify type arguments are concrete
176                    res.extend(
177                        type_parameter
178                            .type_id
179                            .collect_types_metadata(handler, ctx)?
180                            .into_iter()
181                            // try to use the caller span for better error messages
182                            .map(|x| match x {
183                                TypeMetadata::UnresolvedType(ident, original_span) => {
184                                    let span = type_binding
185                                        .as_ref()
186                                        .and_then(|type_binding| {
187                                            type_binding.type_arguments.as_slice().get(idx)
188                                        })
189                                        .map(|type_argument| Some(type_argument.span.clone()))
190                                        .unwrap_or(original_span);
191                                    TypeMetadata::UnresolvedType(ident, span)
192                                }
193                                x => x,
194                            }),
195                    );
196                }
197
198                for content in function_decl.body.contents.iter() {
199                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
200                }
201                ctx.call_site_pop();
202            }
203            Tuple { fields } => {
204                for field in fields.iter() {
205                    res.append(&mut field.collect_types_metadata(handler, ctx)?);
206                }
207            }
208            AsmExpression { registers, .. } => {
209                for register in registers.iter() {
210                    if let Some(init) = register.initializer.as_ref() {
211                        res.append(&mut init.collect_types_metadata(handler, ctx)?);
212                    }
213                }
214            }
215            StructExpression {
216                fields,
217                instantiation_span,
218                struct_id,
219                ..
220            } => {
221                let struct_decl = decl_engine.get_struct(struct_id);
222                for type_parameter in &struct_decl.type_parameters {
223                    ctx.call_site_insert(type_parameter.type_id, instantiation_span.clone());
224                }
225                if let TypeInfo::Struct(decl_ref) = &*ctx.engines.te().get(self.return_type) {
226                    let decl = decl_engine.get_struct(decl_ref);
227                    for type_parameter in &decl.type_parameters {
228                        ctx.call_site_insert(type_parameter.type_id, instantiation_span.clone());
229                    }
230                }
231                for field in fields.iter() {
232                    res.append(&mut field.value.collect_types_metadata(handler, ctx)?);
233                }
234            }
235            LazyOperator { lhs, rhs, .. } => {
236                res.append(&mut lhs.collect_types_metadata(handler, ctx)?);
237                res.append(&mut rhs.collect_types_metadata(handler, ctx)?);
238            }
239            ArrayExplicit {
240                elem_type: _,
241                contents,
242            } => {
243                for content in contents.iter() {
244                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
245                }
246            }
247            ArrayRepeat {
248                elem_type: _,
249                value,
250                length,
251            } => {
252                res.append(&mut value.collect_types_metadata(handler, ctx)?);
253                res.append(&mut length.collect_types_metadata(handler, ctx)?);
254            }
255            ArrayIndex { prefix, index } => {
256                res.append(&mut (**prefix).collect_types_metadata(handler, ctx)?);
257                res.append(&mut (**index).collect_types_metadata(handler, ctx)?);
258            }
259            CodeBlock(block) => {
260                for content in block.contents.iter() {
261                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
262                }
263            }
264            MatchExp { desugared, .. } => {
265                res.append(&mut desugared.collect_types_metadata(handler, ctx)?)
266            }
267            IfExp {
268                condition,
269                then,
270                r#else,
271            } => {
272                res.append(&mut condition.collect_types_metadata(handler, ctx)?);
273                res.append(&mut then.collect_types_metadata(handler, ctx)?);
274                if let Some(r#else) = r#else {
275                    res.append(&mut r#else.collect_types_metadata(handler, ctx)?);
276                }
277            }
278            StructFieldAccess {
279                prefix,
280                resolved_type_of_parent,
281                ..
282            } => {
283                res.append(&mut prefix.collect_types_metadata(handler, ctx)?);
284                res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?);
285            }
286            TupleElemAccess {
287                prefix,
288                resolved_type_of_parent,
289                ..
290            } => {
291                res.append(&mut prefix.collect_types_metadata(handler, ctx)?);
292                res.append(&mut resolved_type_of_parent.collect_types_metadata(handler, ctx)?);
293            }
294            EnumInstantiation {
295                enum_ref,
296                contents,
297                call_path_binding,
298                ..
299            } => {
300                let enum_decl = decl_engine.get_enum(enum_ref);
301                for type_param in enum_decl.type_parameters.iter() {
302                    ctx.call_site_insert(type_param.type_id, call_path_binding.inner.suffix.span())
303                }
304                if let Some(contents) = contents {
305                    res.append(&mut contents.collect_types_metadata(handler, ctx)?);
306                }
307                for variant in enum_decl.variants.iter() {
308                    res.append(
309                        &mut variant
310                            .type_argument
311                            .type_id
312                            .collect_types_metadata(handler, ctx)?,
313                    );
314                }
315                for type_param in enum_decl.type_parameters.iter() {
316                    res.append(&mut type_param.type_id.collect_types_metadata(handler, ctx)?);
317                }
318            }
319            AbiCast { address, .. } => {
320                res.append(&mut address.collect_types_metadata(handler, ctx)?);
321            }
322            IntrinsicFunction(kind) => {
323                res.append(&mut kind.collect_types_metadata(handler, ctx)?);
324            }
325            EnumTag { exp } => {
326                res.append(&mut exp.collect_types_metadata(handler, ctx)?);
327            }
328            UnsafeDowncast {
329                exp,
330                variant,
331                call_path_decl: _,
332            } => {
333                res.append(&mut exp.collect_types_metadata(handler, ctx)?);
334                res.append(
335                    &mut variant
336                        .type_argument
337                        .type_id
338                        .collect_types_metadata(handler, ctx)?,
339                );
340            }
341            WhileLoop { condition, body } => {
342                res.append(&mut condition.collect_types_metadata(handler, ctx)?);
343                for content in body.contents.iter() {
344                    res.append(&mut content.collect_types_metadata(handler, ctx)?);
345                }
346            }
347            ForLoop { desugared } => {
348                res.append(&mut desugared.collect_types_metadata(handler, ctx)?);
349            }
350            ImplicitReturn(exp) | Return(exp) => {
351                res.append(&mut exp.collect_types_metadata(handler, ctx)?)
352            }
353            Ref(exp) | Deref(exp) => res.append(&mut exp.collect_types_metadata(handler, ctx)?),
354            // storage access can never be generic
355            // variable expressions don't ever have return types themselves, they're stored in
356            // `TyExpression::return_type`. Variable expressions are just names of variables.
357            VariableExpression { .. }
358            | ConstantExpression { .. }
359            | ConfigurableExpression { .. }
360            | ConstGenericExpression { .. }
361            | StorageAccess { .. }
362            | Literal(_)
363            | AbiName(_)
364            | Break
365            | Continue
366            | FunctionParameter => {}
367            Reassignment(reassignment) => {
368                res.append(&mut reassignment.rhs.collect_types_metadata(handler, ctx)?);
369            }
370        }
371        Ok(res)
372    }
373}
374
375impl MaterializeConstGenerics for TyExpression {
376    fn materialize_const_generics(
377        &mut self,
378        engines: &Engines,
379        handler: &Handler,
380        name: &str,
381        value: &TyExpression,
382    ) -> Result<(), ErrorEmitted> {
383        self.return_type
384            .materialize_const_generics(engines, handler, name, value)?;
385        match &mut self.expression {
386            TyExpressionVariant::ConstGenericExpression { decl, .. } => {
387                decl.materialize_const_generics(engines, handler, name, value)
388            }
389            TyExpressionVariant::ImplicitReturn(expr) => {
390                expr.materialize_const_generics(engines, handler, name, value)
391            }
392            TyExpressionVariant::FunctionApplication { arguments, .. } => {
393                for (_, expr) in arguments {
394                    expr.materialize_const_generics(engines, handler, name, value)?;
395                }
396
397                Ok(())
398            }
399            TyExpressionVariant::WhileLoop { condition, body } => {
400                condition.materialize_const_generics(engines, handler, name, value)?;
401                body.materialize_const_generics(engines, handler, name, value)
402            }
403            TyExpressionVariant::Reassignment(expr) => expr
404                .rhs
405                .materialize_const_generics(engines, handler, name, value),
406            TyExpressionVariant::ArrayIndex { prefix, index } => {
407                prefix.materialize_const_generics(engines, handler, name, value)?;
408                index.materialize_const_generics(engines, handler, name, value)
409            }
410            TyExpressionVariant::IntrinsicFunction(kind) => {
411                for expr in kind.arguments.iter_mut() {
412                    expr.materialize_const_generics(engines, handler, name, value)?;
413                }
414                Ok(())
415            }
416            TyExpressionVariant::Literal(_) | TyExpressionVariant::VariableExpression { .. } => {
417                Ok(())
418            }
419            _ => Err(handler.emit_err(
420                sway_error::error::CompileError::ConstGenericNotSupportedHere {
421                    span: self.span.clone(),
422                },
423            )),
424        }
425    }
426}
427
428impl TyExpression {
429    pub(crate) fn error(err: ErrorEmitted, span: Span, engines: &Engines) -> TyExpression {
430        let type_engine = engines.te();
431        TyExpression {
432            expression: TyExpressionVariant::Tuple { fields: vec![] },
433            return_type: type_engine.id_of_error_recovery(err),
434            span,
435        }
436    }
437
438    /// gathers the mutability of the expressions within
439    pub(crate) fn gather_mutability(&self) -> VariableMutability {
440        match &self.expression {
441            TyExpressionVariant::VariableExpression { mutability, .. } => *mutability,
442            _ => VariableMutability::Immutable,
443        }
444    }
445
446    /// Returns `self` as a literal, if possible.
447    pub(crate) fn extract_literal_value(&self) -> Option<Literal> {
448        self.expression.extract_literal_value()
449    }
450
451    // Checks if this expression references a deprecated item
452    // TODO: Change this fn for more deprecated checks.
453    pub(crate) fn check_deprecated(
454        &self,
455        engines: &Engines,
456        handler: &Handler,
457        allow_deprecated: &mut AllowDeprecatedState,
458    ) {
459        fn emit_warning_if_deprecated(
460            attributes: &AttributesMap,
461            span: &Span,
462            handler: &Handler,
463            message: &str,
464            allow_deprecated: &mut AllowDeprecatedState,
465        ) {
466            if allow_deprecated.is_allowed() {
467                return;
468            }
469
470            if let Some(v) = attributes
471                .get(&AttributeKind::Deprecated)
472                .and_then(|x| x.last())
473            {
474                let mut message = message.to_string();
475
476                if let Some(sway_ast::Literal::String(s)) = v
477                    .args
478                    .iter()
479                    .find(|x| x.name.as_str() == "note")
480                    .and_then(|x| x.value.as_ref())
481                {
482                    message.push_str(": ");
483                    message.push_str(s.parsed.as_str());
484                }
485
486                handler.emit_warn(CompileWarning {
487                    span: span.clone(),
488                    warning_content: Warning::UsingDeprecated { message },
489                })
490            }
491        }
492
493        match &self.expression {
494            TyExpressionVariant::Literal(..) => {}
495            TyExpressionVariant::FunctionApplication {
496                call_path,
497                fn_ref,
498                arguments,
499                ..
500            } => {
501                for (_, expr) in arguments.iter() {
502                    expr.check_deprecated(engines, handler, allow_deprecated);
503                }
504
505                let fn_ty = engines.de().get(fn_ref);
506                if let Some(TyDecl::ImplSelfOrTrait(t)) = &fn_ty.implementing_type {
507                    let t = &engines.de().get(&t.decl_id).implementing_for;
508                    if let TypeInfo::Struct(struct_id) = &*engines.te().get(t.type_id) {
509                        let s = engines.de().get(struct_id);
510                        emit_warning_if_deprecated(
511                            &s.attributes,
512                            &call_path.span(),
513                            handler,
514                            "deprecated struct",
515                            allow_deprecated,
516                        );
517                    }
518                }
519
520                emit_warning_if_deprecated(
521                    &fn_ty.attributes,
522                    &call_path.span(),
523                    handler,
524                    "deprecated function",
525                    allow_deprecated,
526                );
527            }
528            TyExpressionVariant::LazyOperator { lhs, rhs, .. } => {
529                lhs.check_deprecated(engines, handler, allow_deprecated);
530                rhs.check_deprecated(engines, handler, allow_deprecated);
531            }
532            TyExpressionVariant::ConstantExpression { span, decl, .. } => {
533                emit_warning_if_deprecated(
534                    &decl.attributes,
535                    span,
536                    handler,
537                    "deprecated constant",
538                    allow_deprecated,
539                );
540            }
541            TyExpressionVariant::ConfigurableExpression { span, decl, .. } => {
542                emit_warning_if_deprecated(
543                    &decl.attributes,
544                    span,
545                    handler,
546                    "deprecated configurable",
547                    allow_deprecated,
548                );
549            }
550            TyExpressionVariant::ConstGenericExpression { span, .. } => {
551                // Const generics don“t have attributes,
552                // so deprecation warnings cannot be turned off
553                emit_warning_if_deprecated(
554                    &AttributesMap::default(),
555                    span,
556                    handler,
557                    "deprecated configurable",
558                    allow_deprecated,
559                );
560            }
561            TyExpressionVariant::VariableExpression { .. } => {}
562            TyExpressionVariant::Tuple { fields } => {
563                for e in fields.iter() {
564                    e.check_deprecated(engines, handler, allow_deprecated);
565                }
566            }
567            TyExpressionVariant::ArrayExplicit { contents, .. } => {
568                for e in contents.iter() {
569                    e.check_deprecated(engines, handler, allow_deprecated);
570                }
571            }
572            TyExpressionVariant::ArrayRepeat { value, length, .. } => {
573                value.check_deprecated(engines, handler, allow_deprecated);
574                length.check_deprecated(engines, handler, allow_deprecated);
575            }
576            TyExpressionVariant::ArrayIndex { prefix, index } => {
577                prefix.check_deprecated(engines, handler, allow_deprecated);
578                index.check_deprecated(engines, handler, allow_deprecated);
579            }
580            TyExpressionVariant::StructExpression {
581                struct_id,
582                instantiation_span,
583                ..
584            } => {
585                let struct_decl = engines.de().get(struct_id);
586                emit_warning_if_deprecated(
587                    &struct_decl.attributes,
588                    instantiation_span,
589                    handler,
590                    "deprecated struct",
591                    allow_deprecated,
592                );
593            }
594            TyExpressionVariant::CodeBlock(block) => {
595                block.check_deprecated(engines, handler, allow_deprecated);
596            }
597            TyExpressionVariant::FunctionParameter => {}
598            TyExpressionVariant::MatchExp {
599                desugared,
600                //scrutinees,
601                ..
602            } => {
603                desugared.check_deprecated(engines, handler, allow_deprecated);
604                // TODO: check scrutinees if necessary
605            }
606            TyExpressionVariant::IfExp {
607                condition,
608                then,
609                r#else,
610            } => {
611                condition.check_deprecated(engines, handler, allow_deprecated);
612                then.check_deprecated(engines, handler, allow_deprecated);
613                if let Some(e) = r#else {
614                    e.check_deprecated(engines, handler, allow_deprecated);
615                }
616            }
617            TyExpressionVariant::AsmExpression { .. } => {}
618            TyExpressionVariant::StructFieldAccess {
619                prefix,
620                field_to_access,
621                field_instantiation_span,
622                ..
623            } => {
624                prefix.check_deprecated(engines, handler, allow_deprecated);
625                emit_warning_if_deprecated(
626                    &field_to_access.attributes,
627                    field_instantiation_span,
628                    handler,
629                    "deprecated struct field",
630                    allow_deprecated,
631                );
632            }
633            TyExpressionVariant::TupleElemAccess { prefix, .. } => {
634                prefix.check_deprecated(engines, handler, allow_deprecated);
635            }
636            TyExpressionVariant::EnumInstantiation {
637                enum_ref,
638                tag,
639                contents,
640                variant_instantiation_span,
641                ..
642            } => {
643                let enum_ty = engines.de().get(enum_ref);
644                emit_warning_if_deprecated(
645                    &enum_ty.attributes,
646                    variant_instantiation_span,
647                    handler,
648                    "deprecated enum",
649                    allow_deprecated,
650                );
651                if let Some(variant_decl) = enum_ty.variants.get(*tag) {
652                    emit_warning_if_deprecated(
653                        &variant_decl.attributes,
654                        variant_instantiation_span,
655                        handler,
656                        "deprecated enum variant",
657                        allow_deprecated,
658                    );
659                }
660                if let Some(expr) = contents {
661                    expr.check_deprecated(engines, handler, allow_deprecated);
662                }
663            }
664            TyExpressionVariant::AbiCast { address, .. } => {
665                // TODO: check abi name?
666                address.check_deprecated(engines, handler, allow_deprecated);
667            }
668            TyExpressionVariant::StorageAccess(access) => {
669                // TODO: check storage access?
670                if let Some(expr) = &access.key_expression {
671                    expr.check_deprecated(engines, handler, allow_deprecated);
672                }
673            }
674            TyExpressionVariant::IntrinsicFunction(kind) => {
675                for arg in kind.arguments.iter() {
676                    arg.check_deprecated(engines, handler, allow_deprecated);
677                }
678            }
679            TyExpressionVariant::AbiName(..) => {}
680            TyExpressionVariant::EnumTag { exp } => {
681                exp.check_deprecated(engines, handler, allow_deprecated);
682            }
683            TyExpressionVariant::UnsafeDowncast {
684                exp,
685                //variant,
686                ..
687            } => {
688                exp.check_deprecated(engines, handler, allow_deprecated);
689                // TODO: maybe check variant?
690            }
691            TyExpressionVariant::WhileLoop { condition, body } => {
692                condition.check_deprecated(engines, handler, allow_deprecated);
693                body.check_deprecated(engines, handler, allow_deprecated);
694            }
695            TyExpressionVariant::ForLoop { desugared } => {
696                desugared.check_deprecated(engines, handler, allow_deprecated);
697            }
698            TyExpressionVariant::Break => {}
699            TyExpressionVariant::Continue => {}
700            TyExpressionVariant::Reassignment(reass) => {
701                if let TyReassignmentTarget::Deref(expr) = &reass.lhs {
702                    expr.check_deprecated(engines, handler, allow_deprecated);
703                }
704                reass
705                    .rhs
706                    .check_deprecated(engines, handler, allow_deprecated);
707            }
708            TyExpressionVariant::ImplicitReturn(expr) => {
709                expr.check_deprecated(engines, handler, allow_deprecated);
710            }
711            TyExpressionVariant::Return(expr) => {
712                expr.check_deprecated(engines, handler, allow_deprecated);
713            }
714            TyExpressionVariant::Ref(expr) => {
715                expr.check_deprecated(engines, handler, allow_deprecated);
716            }
717            TyExpressionVariant::Deref(expr) => {
718                expr.check_deprecated(engines, handler, allow_deprecated);
719            }
720        }
721    }
722
723    pub fn as_array(&self) -> Option<(&TypeId, &[TyExpression])> {
724        match &self.expression {
725            TyExpressionVariant::ArrayExplicit {
726                elem_type,
727                contents,
728            } => Some((elem_type, contents)),
729            _ => None,
730        }
731    }
732
733    pub(crate) fn as_literal_u64(&self) -> Option<u64> {
734        match &self.expression {
735            TyExpressionVariant::Literal(Literal::U64(v)) => Some(*v),
736            _ => None,
737        }
738    }
739
740    pub fn as_intrinsic(&self) -> Option<&TyIntrinsicFunctionKind> {
741        match &self.expression {
742            TyExpressionVariant::IntrinsicFunction(v) => Some(v),
743            _ => None,
744        }
745    }
746
747    /// Unify elem_type with each element return type.
748    /// Must be called on arrays.
749    pub fn as_array_unify_elements(&self, handler: &Handler, engines: &Engines) {
750        let TyExpressionVariant::ArrayExplicit {
751            elem_type,
752            contents,
753        } = &self.expression
754        else {
755            unreachable!("Should only be called on Arrays")
756        };
757
758        let array_elem_type = engines.te().get(*elem_type);
759        if !matches!(&*array_elem_type, TypeInfo::Never) {
760            let unify = crate::type_system::unify::unifier::Unifier::new(
761                engines,
762                "",
763                unify::unifier::UnifyKind::Default,
764            );
765            for element in contents {
766                let element_type = engines.te().get(element.return_type);
767
768                // If the element is never, we do not need to check
769                if matches!(&*element_type, TypeInfo::Never) {
770                    continue;
771                }
772
773                let h = Handler::default();
774                unify.unify(&h, element.return_type, *elem_type, &element.span, true);
775
776                // unification error points to type that failed
777                // we want to report the element type instead
778                if h.has_errors() {
779                    handler.emit_err(CompileError::TypeError(TypeError::MismatchedType {
780                        expected: format!("{:?}", engines.help_out(&array_elem_type)),
781                        received: format!("{:?}", engines.help_out(element_type)),
782                        help_text: String::new(),
783                        span: element.span.clone(),
784                    }));
785                }
786            }
787        }
788    }
789}