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