sway_core/semantic_analysis/ast_node/
mod.rs

1pub mod code_block;
2pub mod declaration;
3pub mod expression;
4pub mod modes;
5
6pub(crate) use expression::*;
7pub(crate) use modes::*;
8
9use crate::{
10    language::{parsed::*, ty},
11    semantic_analysis::*,
12    type_system::*,
13    Engines, Ident,
14};
15
16use sway_error::{
17    handler::{ErrorEmitted, Handler},
18    warning::{CompileWarning, Warning},
19};
20use sway_types::{span::Span, Spanned};
21
22use super::symbol_collection_context::SymbolCollectionContext;
23
24impl ty::TyAstNode {
25    pub(crate) fn collect(
26        handler: &Handler,
27        engines: &Engines,
28        ctx: &mut SymbolCollectionContext,
29        node: &AstNode,
30    ) -> Result<(), ErrorEmitted> {
31        match node.content.clone() {
32            AstNodeContent::UseStatement(stmt) => {
33                collect_use_statement(handler, engines, ctx, &stmt);
34            }
35            AstNodeContent::IncludeStatement(_i) => (),
36            AstNodeContent::Declaration(decl) => ty::TyDecl::collect(handler, engines, ctx, decl)?,
37            AstNodeContent::Expression(expr) => {
38                ty::TyExpression::collect(handler, engines, ctx, &expr)?
39            }
40            AstNodeContent::Error(_spans, _err) => (),
41        };
42
43        Ok(())
44    }
45
46    pub(crate) fn type_check(
47        handler: &Handler,
48        mut ctx: TypeCheckContext,
49        node: &AstNode,
50    ) -> Result<Self, ErrorEmitted> {
51        let type_engine = ctx.engines.te();
52        let decl_engine = ctx.engines.de();
53        let engines = ctx.engines();
54
55        let node = ty::TyAstNode {
56            content: match node.content.clone() {
57                AstNodeContent::UseStatement(stmt) => {
58                    handle_use_statement(&mut ctx, &stmt, handler);
59                    ty::TyAstNodeContent::SideEffect(ty::TySideEffect {
60                        side_effect: ty::TySideEffectVariant::UseStatement(ty::TyUseStatement {
61                            alias: stmt.alias,
62                            call_path: stmt.call_path,
63                            span: stmt.span,
64                            is_relative_to_package_root: stmt.is_relative_to_package_root,
65                            import_type: stmt.import_type,
66                        }),
67                    })
68                }
69                AstNodeContent::IncludeStatement(i) => {
70                    ty::TyAstNodeContent::SideEffect(ty::TySideEffect {
71                        side_effect: ty::TySideEffectVariant::IncludeStatement(
72                            ty::TyIncludeStatement {
73                                mod_name: i.mod_name,
74                                span: i.span,
75                                visibility: i.visibility,
76                            },
77                        ),
78                    })
79                }
80                AstNodeContent::Declaration(decl) => ty::TyAstNodeContent::Declaration(
81                    ty::TyDecl::type_check(handler, &mut ctx, decl)?,
82                ),
83                AstNodeContent::Expression(expr) => {
84                    let mut ctx = ctx;
85                    match expr.kind {
86                        ExpressionKind::ImplicitReturn(_) => {
87                            // Do not use any type annotation with implicit returns as that
88                            // will later cause type inference errors when matching implicit block
89                            // types.
90                        }
91                        _ => {
92                            ctx = ctx
93                                .with_help_text("")
94                                .with_type_annotation(type_engine.new_unknown());
95                        }
96                    }
97                    let inner = ty::TyExpression::type_check(handler, ctx, &expr)
98                        .unwrap_or_else(|err| ty::TyExpression::error(err, expr.span(), engines));
99                    ty::TyAstNodeContent::Expression(inner)
100                }
101                AstNodeContent::Error(spans, err) => ty::TyAstNodeContent::Error(spans, err),
102            },
103            span: node.span.clone(),
104        };
105
106        if let ty::TyAstNode {
107            content: ty::TyAstNodeContent::Expression(ty::TyExpression { expression, .. }),
108            ..
109        } = &node
110        {
111            match expression {
112                ty::TyExpressionVariant::ImplicitReturn(_) => {}
113                _ => {
114                    if !node
115                        .type_info(type_engine)
116                        .can_safely_ignore(type_engine, decl_engine)
117                    {
118                        handler.emit_warn(CompileWarning {
119                            warning_content: Warning::UnusedReturnValue {
120                                r#type: engines.help_out(node.type_info(type_engine)).to_string(),
121                            },
122                            span: node.span.clone(),
123                        })
124                    };
125                }
126            }
127        }
128
129        Ok(node)
130    }
131}
132
133fn collect_use_statement(
134    handler: &Handler,
135    engines: &Engines,
136    ctx: &mut SymbolCollectionContext,
137    stmt: &UseStatement,
138) {
139    let path = ctx.namespace.parsed_path_to_full_path(
140        engines,
141        &stmt.call_path,
142        stmt.is_relative_to_package_root,
143    );
144
145    let _ = match stmt.import_type {
146        ImportType::Star => {
147            // try a standard starimport first
148            let star_import_handler = Handler::default();
149            let import = ctx.star_import(&star_import_handler, engines, &path, stmt.reexport);
150            if import.is_ok() {
151                handler.append(star_import_handler);
152                import
153            } else if path.len() >= 2 {
154                // if it doesn't work it could be an enum star import
155                if let Some((enum_name, path)) = path.split_last() {
156                    let variant_import_handler = Handler::default();
157                    let variant_import = ctx.variant_star_import(
158                        &variant_import_handler,
159                        engines,
160                        path,
161                        enum_name,
162                        stmt.reexport,
163                    );
164                    if variant_import.is_ok() {
165                        handler.append(variant_import_handler);
166                        variant_import
167                    } else {
168                        handler.append(star_import_handler);
169                        import
170                    }
171                } else {
172                    handler.append(star_import_handler);
173                    import
174                }
175            } else {
176                handler.append(star_import_handler);
177                import
178            }
179        }
180        ImportType::SelfImport(_) => {
181            ctx.self_import(handler, engines, &path, stmt.alias.clone(), stmt.reexport)
182        }
183        ImportType::Item(ref s) => {
184            // try a standard item import first
185            let item_import_handler = Handler::default();
186            let import = ctx.item_import(
187                &item_import_handler,
188                engines,
189                &path,
190                s,
191                stmt.alias.clone(),
192                stmt.reexport,
193            );
194
195            if import.is_ok() {
196                handler.append(item_import_handler);
197                import
198            } else if path.len() >= 2 {
199                // if it doesn't work it could be an enum variant import
200                // For this to work the path must have at least 2 elements: The current package name and the enum name
201                if let Some((enum_name, path)) = path.split_last() {
202                    let variant_import_handler = Handler::default();
203                    let variant_import = ctx.variant_import(
204                        &variant_import_handler,
205                        engines,
206                        path,
207                        enum_name,
208                        s,
209                        stmt.alias.clone(),
210                        stmt.reexport,
211                    );
212
213                    if variant_import.is_ok() {
214                        handler.append(variant_import_handler);
215                        variant_import
216                    } else {
217                        handler.append(item_import_handler);
218                        import
219                    }
220                } else {
221                    handler.append(item_import_handler);
222                    import
223                }
224            } else {
225                handler.append(item_import_handler);
226                import
227            }
228        }
229    };
230}
231
232// To be removed once TypeCheckContext is ported to use SymbolCollectionContext.
233fn handle_use_statement(ctx: &mut TypeCheckContext<'_>, stmt: &UseStatement, handler: &Handler) {
234    let path = ctx.namespace.parsed_path_to_full_path(
235        ctx.engines,
236        &stmt.call_path,
237        stmt.is_relative_to_package_root,
238    );
239    let _ = match stmt.import_type {
240        ImportType::Star => {
241            // try a standard starimport first
242            let star_import_handler = Handler::default();
243            let import = ctx.star_import(&star_import_handler, &path, stmt.reexport);
244            if import.is_ok() {
245                handler.append(star_import_handler);
246                import
247            } else if path.len() >= 2 {
248                // if it doesn't work it could be an enum star import
249                if let Some((enum_name, path)) = path.split_last() {
250                    let variant_import_handler = Handler::default();
251                    let variant_import = ctx.variant_star_import(
252                        &variant_import_handler,
253                        path,
254                        enum_name,
255                        stmt.reexport,
256                    );
257                    if variant_import.is_ok() {
258                        handler.append(variant_import_handler);
259                        variant_import
260                    } else {
261                        handler.append(star_import_handler);
262                        import
263                    }
264                } else {
265                    handler.append(star_import_handler);
266                    import
267                }
268            } else {
269                handler.append(star_import_handler);
270                import
271            }
272        }
273        ImportType::SelfImport(_) => {
274            ctx.self_import(handler, &path, stmt.alias.clone(), stmt.reexport)
275        }
276        ImportType::Item(ref s) => {
277            // try a standard item import first
278            let item_import_handler = Handler::default();
279            let import = ctx.item_import(
280                &item_import_handler,
281                &path,
282                s,
283                stmt.alias.clone(),
284                stmt.reexport,
285            );
286
287            if import.is_ok() {
288                handler.append(item_import_handler);
289                import
290            } else if path.len() >= 2 {
291                // if it doesn't work it could be an enum variant import
292                // For this to work the path must have at least 2 elements: The current package name and the enum name.
293                if let Some((enum_name, path)) = path.split_last() {
294                    let variant_import_handler = Handler::default();
295                    let variant_import = ctx.variant_import(
296                        &variant_import_handler,
297                        path,
298                        enum_name,
299                        s,
300                        stmt.alias.clone(),
301                        stmt.reexport,
302                    );
303                    if variant_import.is_ok() {
304                        handler.append(variant_import_handler);
305                        variant_import
306                    } else {
307                        handler.append(item_import_handler);
308                        import
309                    }
310                } else {
311                    handler.append(item_import_handler);
312                    import
313                }
314            } else {
315                handler.append(item_import_handler);
316                import
317            }
318        }
319    };
320}