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