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 self.content {
151 TyAstNodeContent::Declaration(_) => Ok(()),
152 TyAstNodeContent::Expression(ref mut expr) => {
153 expr.materialize_const_generics(engines, handler, name, value)
154 }
155 TyAstNodeContent::SideEffect(_) => Ok(()),
156 TyAstNodeContent::Error(_, _) => Ok(()),
157 }
158 }
159}
160
161impl TyAstNode {
162 pub(crate) fn is_public(&self, decl_engine: &DeclEngine) -> bool {
164 match &self.content {
165 TyAstNodeContent::Declaration(decl) => decl.visibility(decl_engine).is_public(),
166 TyAstNodeContent::Expression(_)
167 | TyAstNodeContent::SideEffect(_)
168 | TyAstNodeContent::Error(_, _) => false,
169 }
170 }
171
172 pub(crate) fn is_generic_function(&self, decl_engine: &DeclEngine) -> bool {
174 match &self {
175 TyAstNode {
176 span: _,
177 content:
178 TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
179 decl_id, ..
180 })),
181 ..
182 } => {
183 let fn_decl = decl_engine.get_function(decl_id);
184 let TyFunctionDecl {
185 type_parameters, ..
186 } = &*fn_decl;
187 !type_parameters.is_empty()
188 }
189 _ => false,
190 }
191 }
192
193 pub(crate) fn is_test_function(&self, decl_engine: &DeclEngine) -> bool {
195 match &self {
196 TyAstNode {
197 span: _,
198 content:
199 TyAstNodeContent::Declaration(TyDecl::FunctionDecl(FunctionDecl {
200 decl_id, ..
201 })),
202 ..
203 } => {
204 let fn_decl = decl_engine.get_function(decl_id);
205 let TyFunctionDecl { attributes, .. } = &*fn_decl;
206 attributes.contains_key(&AttributeKind::Test)
207 }
208 _ => false,
209 }
210 }
211
212 pub(crate) fn type_info(&self, type_engine: &TypeEngine) -> TypeInfo {
213 match &self.content {
215 TyAstNodeContent::Declaration(_) => TypeInfo::Tuple(Vec::new()),
216 TyAstNodeContent::Expression(TyExpression { return_type, .. }) => {
217 (*type_engine.get(*return_type)).clone()
218 }
219 TyAstNodeContent::SideEffect(_) => TypeInfo::Tuple(Vec::new()),
220 TyAstNodeContent::Error(_, error) => TypeInfo::ErrorRecovery(*error),
221 }
222 }
223
224 pub(crate) fn check_deprecated(
225 &self,
226 engines: &Engines,
227 handler: &Handler,
228 allow_deprecated: &mut AllowDeprecatedState,
229 ) {
230 match &self.content {
231 TyAstNodeContent::Declaration(node) => match node {
232 TyDecl::VariableDecl(decl) => {
233 decl.body
234 .check_deprecated(engines, handler, allow_deprecated);
235 }
236 TyDecl::ConstantDecl(decl) => {
237 let decl = engines.de().get(&decl.decl_id);
238 if let Some(value) = &decl.value {
239 value.check_deprecated(engines, handler, allow_deprecated);
240 }
241 }
242 TyDecl::ConfigurableDecl(decl) => {
243 let decl = engines.de().get(&decl.decl_id);
244 if let Some(value) = &decl.value {
245 value.check_deprecated(engines, handler, allow_deprecated);
246 }
247 }
248 TyDecl::ConstGenericDecl(_) => {
249 todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
250 }
251 TyDecl::TraitTypeDecl(_) => {}
252 TyDecl::FunctionDecl(decl) => {
253 let decl = engines.de().get(&decl.decl_id);
254 let token = allow_deprecated.enter(decl.attributes.clone());
255 for node in decl.body.contents.iter() {
256 node.check_deprecated(engines, handler, allow_deprecated);
257 }
258 allow_deprecated.exit(token);
259 }
260 TyDecl::ImplSelfOrTrait(decl) => {
261 let decl = engines.de().get(&decl.decl_id);
262 for item in decl.items.iter() {
263 match item {
264 TyTraitItem::Fn(item) => {
265 let decl = engines.de().get(item.id());
266 let token = allow_deprecated.enter(decl.attributes.clone());
267 for node in decl.body.contents.iter() {
268 node.check_deprecated(engines, handler, allow_deprecated);
269 }
270 allow_deprecated.exit(token);
271 }
272 TyTraitItem::Constant(item) => {
273 let decl = engines.de().get(item.id());
274 if let Some(expr) = decl.value.as_ref() {
275 expr.check_deprecated(engines, handler, allow_deprecated);
276 }
277 }
278 TyTraitItem::Type(_) => {}
279 }
280 }
281 }
282 TyDecl::AbiDecl(_)
283 | TyDecl::GenericTypeForFunctionScope(_)
284 | TyDecl::ErrorRecovery(_, _)
285 | TyDecl::StorageDecl(_)
286 | TyDecl::TraitDecl(_)
287 | TyDecl::StructDecl(_)
288 | TyDecl::EnumDecl(_)
289 | TyDecl::EnumVariantDecl(_)
290 | TyDecl::TypeAliasDecl(_) => {}
291 },
292 TyAstNodeContent::Expression(node) => {
293 node.check_deprecated(engines, handler, allow_deprecated);
294 }
295 TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
296 }
297 }
298
299 pub(crate) fn check_recursive(
300 &self,
301 engines: &Engines,
302 handler: &Handler,
303 ) -> Result<(), ErrorEmitted> {
304 handler.scope(|handler| {
305 match &self.content {
306 TyAstNodeContent::Declaration(node) => match node {
307 TyDecl::VariableDecl(_decl) => {}
308 TyDecl::ConstantDecl(_decl) => {}
309 TyDecl::ConfigurableDecl(_decl) => {}
310 TyDecl::ConstGenericDecl(_decl) => {
311 todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
312 }
313 TyDecl::TraitTypeDecl(_) => {}
314 TyDecl::FunctionDecl(decl) => {
315 let fn_decl_id = decl.decl_id;
316 let mut ctx = TypeCheckAnalysisContext::new(engines);
317 let _ = fn_decl_id.type_check_analyze(handler, &mut ctx);
318 let _ = ctx.check_recursive_calls(handler);
319 }
320 TyDecl::ImplSelfOrTrait(decl) => {
321 let decl = engines.de().get(&decl.decl_id);
322 for item in decl.items.iter() {
323 let mut ctx = TypeCheckAnalysisContext::new(engines);
324 let _ = item.type_check_analyze(handler, &mut ctx);
325 let _ = ctx.check_recursive_calls(handler);
326 }
327 }
328 TyDecl::AbiDecl(_)
329 | TyDecl::GenericTypeForFunctionScope(_)
330 | TyDecl::ErrorRecovery(_, _)
331 | TyDecl::StorageDecl(_)
332 | TyDecl::TraitDecl(_)
333 | TyDecl::StructDecl(_)
334 | TyDecl::EnumDecl(_)
335 | TyDecl::EnumVariantDecl(_)
336 | TyDecl::TypeAliasDecl(_) => {}
337 },
338 TyAstNodeContent::Expression(_node) => {}
339 TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {}
340 };
341 Ok(())
342 })
343 }
344
345 pub fn contract_supertrait_fns(&self, engines: &Engines) -> Vec<DeclId<TyFunctionDecl>> {
346 let mut fns = vec![];
347
348 if let TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait(decl)) = &self.content {
349 let decl = engines.de().get(&decl.decl_id);
350 if decl.is_impl_contract(engines.te()) {
351 for item in &decl.supertrait_items {
352 if let TyTraitItem::Fn(f) = item {
353 fns.push(*f.id());
354 }
355 }
356 }
357 }
358
359 fns
360 }
361
362 pub fn contract_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.items {
369 if let TyTraitItem::Fn(f) = item {
370 fns.push(*f.id());
371 }
372 }
373 }
374 }
375
376 fns
377 }
378}
379
380#[derive(Clone, Debug, Serialize, Deserialize)]
381pub enum TyAstNodeContent {
382 Declaration(TyDecl),
383 Expression(TyExpression),
384 SideEffect(TySideEffect),
386 Error(Box<[Span]>, #[serde(skip)] ErrorEmitted),
387}
388
389impl EqWithEngines for TyAstNodeContent {}
390impl PartialEqWithEngines for TyAstNodeContent {
391 fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
392 match (self, other) {
393 (Self::Declaration(x), Self::Declaration(y)) => x.eq(y, ctx),
394 (Self::Expression(x), Self::Expression(y)) => x.eq(y, ctx),
395 (Self::SideEffect(_), Self::SideEffect(_)) => true,
396 _ => false,
397 }
398 }
399}
400
401impl HashWithEngines for TyAstNodeContent {
402 fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
403 use TyAstNodeContent::*;
404 std::mem::discriminant(self).hash(state);
405 match self {
406 Declaration(decl) => {
407 decl.hash(state, engines);
408 }
409 Expression(exp) => {
410 exp.hash(state, engines);
411 }
412 SideEffect(effect) => {
413 effect.hash(state);
414 }
415 Error(_, _) => {}
416 }
417 }
418}
419
420impl TypeCheckAnalysis for TyAstNodeContent {
421 fn type_check_analyze(
422 &self,
423 handler: &Handler,
424 ctx: &mut TypeCheckAnalysisContext,
425 ) -> Result<(), ErrorEmitted> {
426 match self {
427 TyAstNodeContent::Declaration(node) => node.type_check_analyze(handler, ctx)?,
428 TyAstNodeContent::Expression(node) => node.type_check_analyze(handler, ctx)?,
429 TyAstNodeContent::SideEffect(_) => {}
430 TyAstNodeContent::Error(_, _) => {}
431 }
432 Ok(())
433 }
434}
435
436impl TypeCheckFinalization for TyAstNodeContent {
437 fn type_check_finalize(
438 &mut self,
439 handler: &Handler,
440 ctx: &mut TypeCheckFinalizationContext,
441 ) -> Result<(), ErrorEmitted> {
442 match self {
443 TyAstNodeContent::Declaration(node) => node.type_check_finalize(handler, ctx)?,
444 TyAstNodeContent::Expression(node) => node.type_check_finalize(handler, ctx)?,
445 TyAstNodeContent::SideEffect(_) => {}
446 TyAstNodeContent::Error(_, _) => {}
447 }
448 Ok(())
449 }
450}
451
452impl CollectTypesMetadata for TyAstNodeContent {
453 fn collect_types_metadata(
454 &self,
455 handler: &Handler,
456 ctx: &mut CollectTypesMetadataContext,
457 ) -> Result<Vec<TypeMetadata>, ErrorEmitted> {
458 use TyAstNodeContent::*;
459 match self {
460 Declaration(decl) => decl.collect_types_metadata(handler, ctx),
461 Expression(expr) => expr.collect_types_metadata(handler, ctx),
462 SideEffect(_) => Ok(vec![]),
463 Error(_, _) => Ok(vec![]),
464 }
465 }
466}
467
468impl GetDeclIdent for TyAstNodeContent {
469 fn get_decl_ident(&self, engines: &Engines) -> Option<Ident> {
470 match self {
471 TyAstNodeContent::Declaration(decl) => decl.get_decl_ident(engines),
472 TyAstNodeContent::Expression(_expr) => None, TyAstNodeContent::SideEffect(_) => None,
474 TyAstNodeContent::Error(_, _) => None,
475 }
476 }
477}