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