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