1use crate::{
2 decl_engine::*,
3 engine_threading::*,
4 language::ty::*,
5 semantic_analysis::{
6 TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization,
7 TypeCheckFinalizationContext,
8 },
9 transform::{AllowDeprecatedState, AttributeKind},
10 type_system::*,
11 types::*,
12};
13use ast_elements::type_parameter::ConstGenericExpr;
14use serde::{Deserialize, Serialize};
15use std::{
16 fmt::{self, Debug},
17 hash::{Hash, Hasher},
18};
19use sway_error::handler::{ErrorEmitted, Handler};
20use sway_types::{Ident, Span};
21
22pub trait GetDeclIdent {
23 fn get_decl_ident(&self, engines: &Engines) -> Option<Ident>;
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct TyAstNode {
28 pub content: TyAstNodeContent,
29 pub span: Span,
30}
31
32impl EqWithEngines for TyAstNode {}
33impl PartialEqWithEngines for TyAstNode {
34 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
35 self.content.eq(&other.content, ctx)
36 }
37}
38
39impl HashWithEngines for TyAstNode {
40 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
41 let TyAstNode {
42 content,
43 span: _,
46 } = self;
47 content.hash(state, engines);
48 }
49}
50
51impl DebugWithEngines for TyAstNode {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
53 use TyAstNodeContent::*;
54 match &self.content {
55 Declaration(typed_decl) => DebugWithEngines::fmt(typed_decl, f, engines),
56 Expression(exp) => DebugWithEngines::fmt(exp, f, engines),
57 SideEffect(_) => f.write_str(""),
58 Error(_, _) => f.write_str("error"),
59 }
60 }
61}
62
63impl SubstTypes for TyAstNode {
64 fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges {
65 match self.content {
66 TyAstNodeContent::Declaration(ref mut decl) => decl.subst(ctx),
67 TyAstNodeContent::Expression(ref mut expr) => expr.subst(ctx),
68 TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => HasChanges::No,
69 }
70 }
71}
72
73impl ReplaceDecls for TyAstNode {
74 fn replace_decls_inner(
75 &mut self,
76 decl_mapping: &DeclMapping,
77 handler: &Handler,
78 ctx: &mut TypeCheckContext,
79 ) -> Result<bool, ErrorEmitted> {
80 match self.content {
81 TyAstNodeContent::Declaration(TyDecl::VariableDecl(ref mut decl)) => {
82 decl.body.replace_decls(decl_mapping, handler, ctx)
83 }
84 TyAstNodeContent::Declaration(_) => Ok(false),
85 TyAstNodeContent::Expression(ref mut expr) => {
86 expr.replace_decls(decl_mapping, handler, ctx)
87 }
88 TyAstNodeContent::SideEffect(_) => Ok(false),
89 TyAstNodeContent::Error(_, _) => Ok(false),
90 }
91 }
92}
93
94impl UpdateConstantExpression for TyAstNode {
95 fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) {
96 match self.content {
97 TyAstNodeContent::Declaration(_) => {}
98 TyAstNodeContent::Expression(ref mut expr) => {
99 expr.update_constant_expression(engines, implementing_type)
100 }
101 TyAstNodeContent::SideEffect(_) => (),
102 TyAstNodeContent::Error(_, _) => (),
103 }
104 }
105}
106
107impl TypeCheckAnalysis for TyAstNode {
108 fn type_check_analyze(
109 &self,
110 handler: &Handler,
111 ctx: &mut TypeCheckAnalysisContext,
112 ) -> Result<(), ErrorEmitted> {
113 self.content.type_check_analyze(handler, ctx)
114 }
115}
116
117impl TypeCheckFinalization for TyAstNode {
118 fn type_check_finalize(
119 &mut self,
120 handler: &Handler,
121 ctx: &mut TypeCheckFinalizationContext,
122 ) -> Result<(), ErrorEmitted> {
123 self.content.type_check_finalize(handler, ctx)
124 }
125}
126
127impl CollectTypesMetadata for TyAstNode {
128 fn collect_types_metadata(
129 &self,
130 handler: &Handler,
131 ctx: &mut CollectTypesMetadataContext,
132 ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
133 self.content.collect_types_metadata(handler, ctx)
134 }
135}
136
137impl GetDeclIdent for TyAstNode {
138 fn get_decl_ident(&self, engines: &Engines) -> Option<Ident> {
139 self.content.get_decl_ident(engines)
140 }
141}
142
143impl MaterializeConstGenerics for TyAstNode {
144 fn materialize_const_generics(
145 &mut self,
146 engines: &Engines,
147 handler: &Handler,
148 name: &str,
149 value: &TyExpression,
150 ) -> Result<(), ErrorEmitted> {
151 match &mut self.content {
152 TyAstNodeContent::Declaration(TyDecl::VariableDecl(decl)) => {
153 decl.body
154 .materialize_const_generics(engines, handler, name, value)?;
155 decl.return_type
156 .materialize_const_generics(engines, handler, name, value)?;
157 match &mut decl.type_ascription {
158 GenericArgument::Type(arg) => arg
159 .type_id
160 .materialize_const_generics(engines, handler, name, value)?,
161 GenericArgument::Const(arg) => {
162 if matches!(&arg.expr, ConstGenericExpr::AmbiguousVariableExpression { ident } if ident.as_str() == name)
163 {
164 arg.expr = ConstGenericExpr::from_ty_expression(handler, value)?;
165 }
166 }
167 }
168 Ok(())
169 }
170 TyAstNodeContent::Expression(expr) => {
171 expr.materialize_const_generics(engines, handler, name, value)
172 }
173 _ => Ok(()),
174 }
175 }
176}
177
178impl TyAstNode {
179 pub(crate) fn is_public(&self, decl_engine: &DeclEngine) -> bool {
181 match &self.content {
182 TyAstNodeContent::Declaration(decl) => decl.visibility(decl_engine).is_public(),
183 TyAstNodeContent::Expression(_)
184 | TyAstNodeContent::SideEffect(_)
185 | TyAstNodeContent::Error(_, _) => false,
186 }
187 }
188
189 pub(crate) fn is_generic_function(&self, decl_engine: &DeclEngine) -> bool {
191 match &self {
192 TyAstNode {
193 span: _,
194 content:
195 TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
196 decl_id, ..
197 })),
198 ..
199 } => {
200 let fn_decl = decl_engine.get_function(decl_id);
201 let TyFunctionDecl {
202 type_parameters, ..
203 } = &*fn_decl;
204 !type_parameters.is_empty()
205 }
206 _ => false,
207 }
208 }
209
210 pub(crate) fn is_test_function(&self, decl_engine: &DeclEngine) -> bool {
212 match &self {
213 TyAstNode {
214 span: _,
215 content:
216 TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
217 decl_id, ..
218 })),
219 ..
220 } => {
221 let fn_decl = decl_engine.get_function(decl_id);
222 let TyFunctionDecl { attributes, .. } = &*fn_decl;
223 attributes.has_any_of_kind(AttributeKind::Test)
224 }
225 _ => false,
226 }
227 }
228
229 pub(crate) fn type_info(&self, type_engine: &TypeEngine) -> TypeInfo {
230 match &self.content {
232 TyAstNodeContent::Declaration(_) => TypeInfo::Tuple(Vec::new()),
233 TyAstNodeContent::Expression(TyExpression { return_type, .. }) => {
234 (*type_engine.get(*return_type)).clone()
235 }
236 TyAstNodeContent::SideEffect(_) => TypeInfo::Tuple(Vec::new()),
237 TyAstNodeContent::Error(_, error) => TypeInfo::ErrorRecovery(*error),
238 }
239 }
240
241 pub(crate) fn check_deprecated(
242 &self,
243 engines: &Engines,
244 handler: &Handler,
245 allow_deprecated: &mut AllowDeprecatedState,
246 ) {
247 match &self.content {
248 TyAstNodeContent::Declaration(node) => match node {
249 TyDecl::VariableDecl(decl) => {
250 decl.body
251 .check_deprecated(engines, handler, allow_deprecated);
252 }
253 TyDecl::ConstantDecl(decl) => {
254 let decl = engines.de().get(&decl.decl_id);
255 if let Some(value) = &decl.value {
256 value.check_deprecated(engines, handler, allow_deprecated);
257 }
258 }
259 TyDecl::ConfigurableDecl(decl) => {
260 let decl = engines.de().get(&decl.decl_id);
261 if let Some(value) = &decl.value {
262 value.check_deprecated(engines, handler, allow_deprecated);
263 }
264 }
265 TyDecl::ConstGenericDecl(_) => {
266 todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
267 }
268 TyDecl::TraitTypeDecl(_) => {}
269 TyDecl::FunctionDecl(decl) => {
270 let decl = engines.de().get(&decl.decl_id);
271 let token = allow_deprecated.enter(decl.attributes.clone());
272 for node in decl.body.contents.iter() {
273 node.check_deprecated(engines, handler, allow_deprecated);
274 }
275 allow_deprecated.exit(token);
276 }
277 TyDecl::ImplSelfOrTrait(decl) => {
278 let decl = engines.de().get(&decl.decl_id);
279 for item in decl.items.iter() {
280 match item {
281 TyTraitItem::Fn(item) => {
282 let decl = engines.de().get(item.id());
283 let token = allow_deprecated.enter(decl.attributes.clone());
284 for node in decl.body.contents.iter() {
285 node.check_deprecated(engines, handler, allow_deprecated);
286 }
287 allow_deprecated.exit(token);
288 }
289 TyTraitItem::Constant(item) => {
290 let decl = engines.de().get(item.id());
291 if let Some(expr) = decl.value.as_ref() {
292 expr.check_deprecated(engines, handler, allow_deprecated);
293 }
294 }
295 TyTraitItem::Type(_) => {}
296 }
297 }
298 }
299 TyDecl::AbiDecl(_)
300 | TyDecl::GenericTypeForFunctionScope(_)
301 | TyDecl::ErrorRecovery(_, _)
302 | TyDecl::StorageDecl(_)
303 | TyDecl::TraitDecl(_)
304 | TyDecl::StructDecl(_)
305 | TyDecl::EnumDecl(_)
306 | TyDecl::EnumVariantDecl(_)
307 | TyDecl::TypeAliasDecl(_) => {}
308 },
309 TyAstNodeContent::Expression(node) => {
310 node.check_deprecated(engines, handler, allow_deprecated);
311 }
312 TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
313 }
314 }
315
316 pub(crate) fn check_recursive(
317 &self,
318 engines: &Engines,
319 handler: &Handler,
320 ) -> Result<(), ErrorEmitted> {
321 handler.scope(|handler| {
322 match &self.content {
323 TyAstNodeContent::Declaration(node) => match node {
324 TyDecl::VariableDecl(_decl) => {}
325 TyDecl::ConstantDecl(_decl) => {}
326 TyDecl::ConfigurableDecl(_decl) => {}
327 TyDecl::ConstGenericDecl(_decl) => {
328 todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
329 }
330 TyDecl::TraitTypeDecl(_) => {}
331 TyDecl::FunctionDecl(decl) => {
332 let fn_decl_id = decl.decl_id;
333 let mut ctx = TypeCheckAnalysisContext::new(engines);
334 let _ = fn_decl_id.type_check_analyze(handler, &mut ctx);
335 let _ = ctx.check_recursive_calls(handler);
336 }
337 TyDecl::ImplSelfOrTrait(decl) => {
338 let decl = engines.de().get(&decl.decl_id);
339 for item in decl.items.iter() {
340 let mut ctx = TypeCheckAnalysisContext::new(engines);
341 let _ = item.type_check_analyze(handler, &mut ctx);
342 let _ = ctx.check_recursive_calls(handler);
343 }
344 }
345 TyDecl::AbiDecl(_)
346 | TyDecl::GenericTypeForFunctionScope(_)
347 | TyDecl::ErrorRecovery(_, _)
348 | TyDecl::StorageDecl(_)
349 | TyDecl::TraitDecl(_)
350 | TyDecl::StructDecl(_)
351 | TyDecl::EnumDecl(_)
352 | TyDecl::EnumVariantDecl(_)
353 | TyDecl::TypeAliasDecl(_) => {}
354 },
355 TyAstNodeContent::Expression(_node) => {}
356 TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
357 };
358 Ok(())
359 })
360 }
361
362 pub fn contract_supertrait_fns(&self, engines: &Engines) -> Vec<DeclId<TyFunctionDecl>> {
363 let mut fns = vec![];
364
365 if let TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(decl)) = &self.content {
366 let decl = engines.de().get(&decl.decl_id);
367 if decl.is_impl_contract(engines.te()) {
368 for item in &decl.supertrait_items {
369 if let TyTraitItem::Fn(f) = item {
370 fns.push(*f.id());
371 }
372 }
373 }
374 }
375
376 fns
377 }
378
379 pub fn contract_fns(&self, engines: &Engines) -> Vec<DeclId<TyFunctionDecl>> {
380 let mut fns = vec![];
381
382 if let TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(decl)) = &self.content {
383 let decl = engines.de().get(&decl.decl_id);
384 if decl.is_impl_contract(engines.te()) {
385 for item in &decl.items {
386 if let TyTraitItem::Fn(f) = item {
387 fns.push(*f.id());
388 }
389 }
390 }
391 }
392
393 fns
394 }
395}
396
397#[derive(Clone, Debug, Serialize, Deserialize)]
398pub enum TyAstNodeContent {
399 Declaration(TyDecl),
400 Expression(TyExpression),
401 SideEffect(TySideEffect),
403 Error(Box<[Span]>, #[serde(skip)] ErrorEmitted),
404}
405
406impl EqWithEngines for TyAstNodeContent {}
407impl PartialEqWithEngines for TyAstNodeContent {
408 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
409 match (self, other) {
410 (Self::Declaration(x), Self::Declaration(y)) => x.eq(y, ctx),
411 (Self::Expression(x), Self::Expression(y)) => x.eq(y, ctx),
412 (Self::SideEffect(_), Self::SideEffect(_)) => true,
413 _ => false,
414 }
415 }
416}
417
418impl HashWithEngines for TyAstNodeContent {
419 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
420 use TyAstNodeContent::*;
421 std::mem::discriminant(self).hash(state);
422 match self {
423 Declaration(decl) => {
424 decl.hash(state, engines);
425 }
426 Expression(exp) => {
427 exp.hash(state, engines);
428 }
429 SideEffect(effect) => {
430 effect.hash(state);
431 }
432 Error(_, _) => {}
433 }
434 }
435}
436
437impl TypeCheckAnalysis for TyAstNodeContent {
438 fn type_check_analyze(
439 &self,
440 handler: &Handler,
441 ctx: &mut TypeCheckAnalysisContext,
442 ) -> Result<(), ErrorEmitted> {
443 match self {
444 TyAstNodeContent::Declaration(node) => node.type_check_analyze(handler, ctx)?,
445 TyAstNodeContent::Expression(node) => node.type_check_analyze(handler, ctx)?,
446 TyAstNodeContent::SideEffect(_) => {}
447 TyAstNodeContent::Error(_, _) => {}
448 }
449 Ok(())
450 }
451}
452
453impl TypeCheckFinalization for TyAstNodeContent {
454 fn type_check_finalize(
455 &mut self,
456 handler: &Handler,
457 ctx: &mut TypeCheckFinalizationContext,
458 ) -> Result<(), ErrorEmitted> {
459 match self {
460 TyAstNodeContent::Declaration(node) => node.type_check_finalize(handler, ctx)?,
461 TyAstNodeContent::Expression(node) => node.type_check_finalize(handler, ctx)?,
462 TyAstNodeContent::SideEffect(_) => {}
463 TyAstNodeContent::Error(_, _) => {}
464 }
465 Ok(())
466 }
467}
468
469impl CollectTypesMetadata for TyAstNodeContent {
470 fn collect_types_metadata(
471 &self,
472 handler: &Handler,
473 ctx: &mut CollectTypesMetadataContext,
474 ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
475 use TyAstNodeContent::*;
476 match self {
477 Declaration(decl) => decl.collect_types_metadata(handler, ctx),
478 Expression(expr) => expr.collect_types_metadata(handler, ctx),
479 SideEffect(_) => Ok(vec![]),
480 Error(_, _) => Ok(vec![]),
481 }
482 }
483}
484
485impl GetDeclIdent for TyAstNodeContent {
486 fn get_decl_ident(&self, engines: &Engines) -> Option<Ident> {
487 match self {
488 TyAstNodeContent::Declaration(decl) => decl.get_decl_ident(engines),
489 TyAstNodeContent::Expression(_expr) => None, TyAstNodeContent::SideEffect(_) => None,
491 TyAstNodeContent::Error(_, _) => None,
492 }
493 }
494}