diff --git a/forc-plugins/forc-migrate/src/visiting/mod.rs b/forc-plugins/forc-migrate/src/visiting/mod.rs index 3f493ac06ee..bba2c5683c0 100644 --- a/forc-plugins/forc-migrate/src/visiting/mod.rs +++ b/forc-plugins/forc-migrate/src/visiting/mod.rs @@ -23,8 +23,8 @@ use sway_core::{ ty::{ TyAbiDecl, TyAstNodeContent, TyCodeBlock, TyDecl, TyExpression, TyExpressionVariant, TyFunctionDecl, TyImplSelfOrTrait, TyIntrinsicFunctionKind, TyModule, - TyReassignmentTarget, TySideEffect, TySideEffectVariant, TyStorageDecl, TyStorageField, - TyStructDecl, TyTraitDecl, TyTraitItem, TyUseStatement, TyVariableDecl, + TyReassignmentTarget, TyStatement, TyStorageDecl, TyStorageField, TyStructDecl, + TyTraitDecl, TyTraitItem, TyUseStatement, TyVariableDecl, }, CallPath, }, @@ -369,9 +369,11 @@ impl __ProgramVisitor { .all_nodes .iter() .find_map(|node| match &node.content { - TyAstNodeContent::SideEffect(TySideEffect { - side_effect: TySideEffectVariant::UseStatement(ty_use), - }) if ty_use.span == item_use.span() => Some(ty_use), + TyAstNodeContent::Statement(TyStatement::Use(ty_use)) + if ty_use.span == item_use.span() => + { + Some(ty_use) + } _ => None, }) }); @@ -818,15 +820,19 @@ impl __ProgramVisitor { // TODO: Implement visiting `annotations`. match __ref([annotated.value]) { ItemKind::Use(item_use) => { - let ty_use = ty_node.map(|ty_node| - match &ty_node.content { - TyAstNodeContent::SideEffect(ty_side_effect) => match &ty_side_effect.side_effect { - TySideEffectVariant::UseStatement(ty_use) => Ok(ty_use), - _ => bail!(internal_error("`ItemKind::Use` must correspond to a `TySideEffectVariant::UseStatement`.")), - }, - _ => bail!(internal_error("`ItemKind::Use` must correspond to a `TyAstNodeContent::SideEffect`.")), - } - ).transpose()?; + let ty_use = ty_node + .map(|ty_node| match &ty_node.content { + TyAstNodeContent::Statement(TyStatement::Use(ty_use)) => { + Ok(ty_use) + } + TyAstNodeContent::Statement(_) => bail!(internal_error( + "`ItemKind::Use` must correspond to a `TyStatement::Use`.", + )), + _ => bail!(internal_error( + "`ItemKind::Use` must correspond to a `TyAstNodeContent::Statement`.", + )), + }) + .transpose()?; visitor.visit_use(ctx, item_use, ty_use, output)?; } diff --git a/sway-core/src/control_flow_analysis/analyze_return_paths.rs b/sway-core/src/control_flow_analysis/analyze_return_paths.rs index 4186bc91b26..7987490f073 100644 --- a/sway-core/src/control_flow_analysis/analyze_return_paths.rs +++ b/sway-core/src/control_flow_analysis/analyze_return_paths.rs @@ -191,7 +191,7 @@ fn connect_node<'eng: 'cfg, 'cfg>( } Ok(NodeConnection::NextStep(Some(entry))) } - ty::TyAstNodeContent::SideEffect(_) => Ok(NodeConnection::NextStep(leaf_opt)), + ty::TyAstNodeContent::Statement(_) => Ok(NodeConnection::NextStep(leaf_opt)), ty::TyAstNodeContent::Declaration(decl) => Ok(NodeConnection::NextStep( connect_declaration(engines, node, decl, graph, leaf_opt)?, )), diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index f0f5e60460c..65051fd56e9 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -465,7 +465,7 @@ fn connect_node<'eng: 'cfg, 'cfg>( }, ) } - ty::TyAstNodeContent::SideEffect(_) => (leaves.to_vec(), exit_node), + ty::TyAstNodeContent::Statement(_) => (leaves.to_vec(), exit_node), ty::TyAstNodeContent::Declaration(decl) => { // all leaves connect to this node, then this node is the singular leaf let cfg_node: ControlFlowGraphNode = @@ -2435,6 +2435,10 @@ fn construct_dead_code_warning_from_node( content: ty::TyAstNodeContent::Declaration(ty::TyDecl::AbiDecl(_)), .. } => return None, + ty::TyAstNode { + content: ty::TyAstNodeContent::Statement(ty::TyStatement::Let(_)), + .. + } => return None, // We handle storage fields individually. There is no need to emit any warnings for the // storage declaration itself. ty::TyAstNode { @@ -2456,7 +2460,7 @@ fn construct_dead_code_warning_from_node( // Otherwise, this is unreachable. ty::TyAstNode { span, - content: ty::TyAstNodeContent::Expression(_) | ty::TyAstNodeContent::SideEffect(_), + content: ty::TyAstNodeContent::Expression(_) | ty::TyAstNodeContent::Statement(_), } => CompileWarning { span: span.clone(), warning_content: Warning::UnreachableCode, @@ -2629,7 +2633,7 @@ fn allow_dead_code_ast_node(decl_engine: &DeclEngine, node: &ty::TyAstNode) -> b ty::TyDecl::StorageDecl { .. } => false, }, ty::TyAstNodeContent::Expression(_) => false, - ty::TyAstNodeContent::SideEffect(_) => false, + ty::TyAstNodeContent::Statement(_) => false, ty::TyAstNodeContent::Error(_, _) => false, } } diff --git a/sway-core/src/ir_generation/const_eval.rs b/sway-core/src/ir_generation/const_eval.rs index ac9fc35f657..7dce4bce626 100644 --- a/sway-core/src/ir_generation/const_eval.rs +++ b/sway-core/src/ir_generation/const_eval.rs @@ -875,7 +875,7 @@ fn const_eval_codeblock( } } }, - ty::TyAstNodeContent::SideEffect(_) => Err(ConstEvalError::CannotBeEvaluatedToConst { + ty::TyAstNodeContent::Statement(_) => Err(ConstEvalError::CannotBeEvaluatedToConst { span: ast_node.span.clone(), }), ty::TyAstNodeContent::Error(_, _) => Err(ConstEvalError::CannotBeEvaluatedToConst { diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index 374895a2559..db134f85c26 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -387,6 +387,7 @@ impl<'a> FnCompiler<'a> { ty::TyDecl::EnumVariantDecl { .. } => unexpected_decl("enum variant"), ty::TyDecl::TraitTypeDecl { .. } => unexpected_decl("trait type"), }, + ty::TyAstNodeContent::Statement(_) => Ok(None), ty::TyAstNodeContent::Expression(te) => { match &te.expression { TyExpressionVariant::ImplicitReturn(exp) => self @@ -404,9 +405,6 @@ impl<'a> FnCompiler<'a> { } } } - // a side effect can be () because it just impacts the type system/namespacing. - // There should be no new IR generated. - ty::TyAstNodeContent::SideEffect(_) => Ok(None), ty::TyAstNodeContent::Error(_, _) => { unreachable!("error node found when generating IR"); } diff --git a/sway-core/src/language/parsed/mod.rs b/sway-core/src/language/parsed/mod.rs index bf19ed600c3..0bf7bedd6a9 100644 --- a/sway-core/src/language/parsed/mod.rs +++ b/sway-core/src/language/parsed/mod.rs @@ -2,7 +2,7 @@ mod code_block; pub mod declaration; mod expression; -mod include_statement; +mod mod_statement; mod module; mod program; mod use_statement; @@ -10,7 +10,7 @@ mod use_statement; pub use code_block::*; pub use declaration::*; pub use expression::*; -pub use include_statement::IncludeStatement; +pub use mod_statement::ModStatement; pub use module::{ModuleEvaluationOrder, ParseModule, ParseSubmodule}; pub use program::{ParseProgram, TreeType}; use sway_error::handler::ErrorEmitted; @@ -54,15 +54,13 @@ impl PartialEqWithEngines for AstNode { #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone)] pub enum AstNodeContent { - /// A statement of the form `use foo::bar;` or `use ::foo::bar;` - UseStatement(UseStatement), + /// Any statement node. + Statement(Statement), /// Any type of declaration, of which there are quite a few. See [Declaration] for more details /// on the possible variants. Declaration(Declaration), /// Any type of expression, of which there are quite a few. See [Expression] for more details. Expression(Expression), - /// A statement of the form `mod foo::bar;` which imports/includes another source file. - IncludeStatement(IncludeStatement), /// A malformed statement. /// /// Used for parser recovery when we cannot form a more specific node. @@ -75,20 +73,37 @@ impl EqWithEngines for AstNodeContent {} impl PartialEqWithEngines for AstNodeContent { fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { match (self, other) { - (AstNodeContent::UseStatement(lhs), AstNodeContent::UseStatement(rhs)) => lhs.eq(rhs), + (AstNodeContent::Statement(lhs), AstNodeContent::Statement(rhs)) => lhs.eq(rhs, ctx), (AstNodeContent::Declaration(lhs), AstNodeContent::Declaration(rhs)) => { lhs.eq(rhs, ctx) } (AstNodeContent::Expression(lhs), AstNodeContent::Expression(rhs)) => lhs.eq(rhs, ctx), - (AstNodeContent::IncludeStatement(lhs), AstNodeContent::IncludeStatement(rhs)) => { - lhs.eq(rhs) - } (AstNodeContent::Error(lhs, ..), AstNodeContent::Error(rhs, ..)) => lhs.eq(rhs), _ => false, } } } +/// Statements that can appear in the parse tree. +#[derive(Debug, Clone)] +pub enum Statement { + /// A statement of the form `use foo::bar;` or `use ::foo::bar;` + Use(UseStatement), + /// A statement of the form `mod foo::bar;` which imports/includes another source file. + Mod(ModStatement), +} + +impl EqWithEngines for Statement {} +impl PartialEqWithEngines for Statement { + fn eq(&self, other: &Self, _ctx: &PartialEqWithEnginesContext) -> bool { + match (self, other) { + (Statement::Use(lhs), Statement::Use(rhs)) => lhs.eq(rhs), + (Statement::Mod(lhs), Statement::Mod(rhs)) => lhs.eq(rhs), + _ => false, + } + } +} + impl ParseTree { /// Excludes all test functions from the parse tree. pub(crate) fn exclude_tests(&mut self, engines: &Engines) { diff --git a/sway-core/src/language/parsed/include_statement.rs b/sway-core/src/language/parsed/mod_statement.rs similarity index 90% rename from sway-core/src/language/parsed/include_statement.rs rename to sway-core/src/language/parsed/mod_statement.rs index c52ce3d3269..2925723b050 100644 --- a/sway-core/src/language/parsed/include_statement.rs +++ b/sway-core/src/language/parsed/mod_statement.rs @@ -3,7 +3,7 @@ use sway_types::{span::Span, Ident}; use crate::language::Visibility; #[derive(Clone, Debug, PartialEq)] -pub struct IncludeStatement { +pub struct ModStatement { // this span may be used for errors in the future, although it is not right now. pub span: Span, pub mod_name: Ident, diff --git a/sway-core/src/language/ty/ast_node.rs b/sway-core/src/language/ty/ast_node.rs index 416328f3512..398cc803a5c 100644 --- a/sway-core/src/language/ty/ast_node.rs +++ b/sway-core/src/language/ty/ast_node.rs @@ -53,8 +53,8 @@ impl DebugWithEngines for TyAstNode { use TyAstNodeContent::*; match &self.content { Declaration(typed_decl) => DebugWithEngines::fmt(typed_decl, f, engines), + Statement(stmt) => Debug::fmt(stmt, f), Expression(exp) => DebugWithEngines::fmt(exp, f, engines), - SideEffect(_) => f.write_str(""), Error(_, _) => f.write_str("error"), } } @@ -64,8 +64,9 @@ impl SubstTypes for TyAstNode { fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges { match self.content { TyAstNodeContent::Declaration(ref mut decl) => decl.subst(ctx), + TyAstNodeContent::Statement(ref mut statement) => statement.subst(ctx), TyAstNodeContent::Expression(ref mut expr) => expr.subst(ctx), - TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => HasChanges::No, + TyAstNodeContent::Error(_, _) => HasChanges::No, } } } @@ -82,10 +83,12 @@ impl ReplaceDecls for TyAstNode { decl.body.replace_decls(decl_mapping, handler, ctx) } TyAstNodeContent::Declaration(_) => Ok(false), + TyAstNodeContent::Statement(ref mut statement) => { + statement.replace_decls(decl_mapping, handler, ctx) + } TyAstNodeContent::Expression(ref mut expr) => { expr.replace_decls(decl_mapping, handler, ctx) } - TyAstNodeContent::SideEffect(_) => Ok(false), TyAstNodeContent::Error(_, _) => Ok(false), } } @@ -95,10 +98,17 @@ impl UpdateConstantExpression for TyAstNode { fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl) { match self.content { TyAstNodeContent::Declaration(_) => {} + TyAstNodeContent::Statement(ref mut statement) => match statement { + TyStatement::Let(binding) => { + binding + .value + .update_constant_expression(engines, implementing_type); + } + TyStatement::Use(_) | TyStatement::Mod(_) => {} + }, TyAstNodeContent::Expression(ref mut expr) => { expr.update_constant_expression(engines, implementing_type) } - TyAstNodeContent::SideEffect(_) => (), TyAstNodeContent::Error(_, _) => (), } } @@ -178,6 +188,9 @@ impl MaterializeConstGenerics for TyAstNode { } Ok(()) } + TyAstNodeContent::Statement(statement) => { + statement.materialize_const_generics(engines, handler, name, value) + } TyAstNodeContent::Expression(expr) => { expr.materialize_const_generics(engines, handler, name, value) } @@ -192,7 +205,7 @@ impl TyAstNode { match &self.content { TyAstNodeContent::Declaration(decl) => decl.visibility(decl_engine).is_public(), TyAstNodeContent::Expression(_) - | TyAstNodeContent::SideEffect(_) + | TyAstNodeContent::Statement(_) | TyAstNodeContent::Error(_, _) => false, } } @@ -244,7 +257,7 @@ impl TyAstNode { TyAstNodeContent::Expression(TyExpression { return_type, .. }) => { (*type_engine.get(*return_type)).clone() } - TyAstNodeContent::SideEffect(_) => TypeInfo::Tuple(Vec::new()), + TyAstNodeContent::Statement(_) => TypeInfo::Tuple(Vec::new()), TyAstNodeContent::Error(_, error) => TypeInfo::ErrorRecovery(*error), } } @@ -320,7 +333,15 @@ impl TyAstNode { TyAstNodeContent::Expression(node) => { node.check_deprecated(engines, handler, allow_deprecated); } - TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {} + TyAstNodeContent::Statement(statement) => match statement { + TyStatement::Let(binding) => { + binding + .value + .check_deprecated(engines, handler, allow_deprecated); + } + TyStatement::Use(_) | TyStatement::Mod(_) => {} + }, + TyAstNodeContent::Error(_, _) => {} } } @@ -364,7 +385,8 @@ impl TyAstNode { | TyDecl::TypeAliasDecl(_) => {} }, TyAstNodeContent::Expression(_node) => {} - TyAstNodeContent::SideEffect(_) | TyAstNodeContent::Error(_, _) => {} + TyAstNodeContent::Statement(_) => {} + TyAstNodeContent::Error(_, _) => {} }; Ok(()) }) @@ -409,9 +431,8 @@ impl TyAstNode { #[allow(clippy::large_enum_variant)] pub enum TyAstNodeContent { Declaration(TyDecl), + Statement(TyStatement), Expression(TyExpression), - // a no-op node used for something that just issues a side effect, like an import statement. - SideEffect(TySideEffect), Error(Box<[Span]>, #[serde(skip)] ErrorEmitted), } @@ -420,8 +441,8 @@ impl PartialEqWithEngines for TyAstNodeContent { fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { match (self, other) { (Self::Declaration(x), Self::Declaration(y)) => x.eq(y, ctx), + (Self::Statement(x), Self::Statement(y)) => x.eq(y, ctx), (Self::Expression(x), Self::Expression(y)) => x.eq(y, ctx), - (Self::SideEffect(_), Self::SideEffect(_)) => true, _ => false, } } @@ -435,12 +456,12 @@ impl HashWithEngines for TyAstNodeContent { Declaration(decl) => { decl.hash(state, engines); } + Statement(stmt) => { + stmt.hash(state, engines); + } Expression(exp) => { exp.hash(state, engines); } - SideEffect(effect) => { - effect.hash(state); - } Error(_, _) => {} } } @@ -454,8 +475,8 @@ impl TypeCheckAnalysis for TyAstNodeContent { ) -> Result<(), ErrorEmitted> { match self { TyAstNodeContent::Declaration(node) => node.type_check_analyze(handler, ctx)?, + TyAstNodeContent::Statement(node) => node.type_check_analyze(handler, ctx)?, TyAstNodeContent::Expression(node) => node.type_check_analyze(handler, ctx)?, - TyAstNodeContent::SideEffect(_) => {} TyAstNodeContent::Error(_, _) => {} } Ok(()) @@ -470,8 +491,8 @@ impl TypeCheckFinalization for TyAstNodeContent { ) -> Result<(), ErrorEmitted> { match self { TyAstNodeContent::Declaration(node) => node.type_check_finalize(handler, ctx)?, + TyAstNodeContent::Statement(node) => node.type_check_finalize(handler, ctx)?, TyAstNodeContent::Expression(node) => node.type_check_finalize(handler, ctx)?, - TyAstNodeContent::SideEffect(_) => {} TyAstNodeContent::Error(_, _) => {} } Ok(()) @@ -487,8 +508,8 @@ impl CollectTypesMetadata for TyAstNodeContent { use TyAstNodeContent::*; match self { Declaration(decl) => decl.collect_types_metadata(handler, ctx), + Statement(stmt) => stmt.collect_types_metadata(handler, ctx), Expression(expr) => expr.collect_types_metadata(handler, ctx), - SideEffect(_) => Ok(vec![]), Error(_, _) => Ok(vec![]), } } @@ -499,7 +520,7 @@ impl GetDeclIdent for TyAstNodeContent { match self { TyAstNodeContent::Declaration(decl) => decl.get_decl_ident(engines), TyAstNodeContent::Expression(_expr) => None, //expr.get_decl_ident(), - TyAstNodeContent::SideEffect(_) => None, + TyAstNodeContent::Statement(_) => None, TyAstNodeContent::Error(_, _) => None, } } diff --git a/sway-core/src/language/ty/mod.rs b/sway-core/src/language/ty/mod.rs index f48713d6656..f0650aa1000 100644 --- a/sway-core/src/language/ty/mod.rs +++ b/sway-core/src/language/ty/mod.rs @@ -4,7 +4,7 @@ mod declaration; mod expression; mod module; mod program; -mod side_effect; +mod statement; mod variable_mutability; pub use ast_node::*; @@ -13,5 +13,5 @@ pub use declaration::*; pub use expression::*; pub use module::*; pub use program::*; -pub use side_effect::*; +pub use statement::*; pub use variable_mutability::*; diff --git a/sway-core/src/language/ty/side_effect/include_statement.rs b/sway-core/src/language/ty/side_effect/include_statement.rs deleted file mode 100644 index 666e5b63a58..00000000000 --- a/sway-core/src/language/ty/side_effect/include_statement.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::language::Visibility; -use serde::{Deserialize, Serialize}; -use sway_types::{ident::Ident, Span, Spanned}; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct TyIncludeStatement { - pub span: Span, - pub visibility: Visibility, - pub mod_name: Ident, -} - -impl Spanned for TyIncludeStatement { - fn span(&self) -> Span { - self.span.clone() - } -} diff --git a/sway-core/src/language/ty/side_effect/mod.rs b/sway-core/src/language/ty/side_effect/mod.rs deleted file mode 100644 index e70b040de37..00000000000 --- a/sway-core/src/language/ty/side_effect/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod include_statement; -#[allow(clippy::module_inception)] -mod side_effect; -mod use_statement; - -pub use include_statement::*; -pub use side_effect::*; -pub use use_statement::*; diff --git a/sway-core/src/language/ty/side_effect/side_effect.rs b/sway-core/src/language/ty/side_effect/side_effect.rs deleted file mode 100644 index 9e8e672c5fa..00000000000 --- a/sway-core/src/language/ty/side_effect/side_effect.rs +++ /dev/null @@ -1,13 +0,0 @@ -use super::{TyIncludeStatement, TyUseStatement}; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct TySideEffect { - pub side_effect: TySideEffectVariant, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum TySideEffectVariant { - IncludeStatement(TyIncludeStatement), - UseStatement(TyUseStatement), -} diff --git a/sway-core/src/language/ty/side_effect/use_statement.rs b/sway-core/src/language/ty/side_effect/use_statement.rs deleted file mode 100644 index 9e1cfc554a3..00000000000 --- a/sway-core/src/language/ty/side_effect/use_statement.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::language::parsed; -use serde::{Deserialize, Serialize}; -use sway_types::{ident::Ident, Span, Spanned}; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct TyUseStatement { - pub call_path: Vec, - pub span: Span, - pub import_type: parsed::ImportType, - // If `is_relative_to_package_root` is true, then this use statement is a path relative to the - // project root. For example, if the path is `::X::Y` and occurs in package `P`, then the path - // refers to the full path `P::X::Y`. - // If `is_relative_to_package_root` is false, then there are two options: - // - The path refers to a path relative to the current namespace. For example, if the path is - // `X::Y` and it occurs in a module whose path is `P::M`, then the path refers to the full - // path `P::M::X::Y`. - // - The path refers to a path in an external package. For example, the path `X::Y` refers to an - // entity `Y` in the external package `X`. - pub is_relative_to_package_root: bool, - pub alias: Option, -} - -impl Spanned for TyUseStatement { - fn span(&self) -> Span { - self.span.clone() - } -} diff --git a/sway-core/src/language/ty/statement/mod.rs b/sway-core/src/language/ty/statement/mod.rs new file mode 100644 index 00000000000..cc96b723d40 --- /dev/null +++ b/sway-core/src/language/ty/statement/mod.rs @@ -0,0 +1,290 @@ +use crate::{ + decl_engine::{DeclMapping, MaterializeConstGenerics, ReplaceDecls}, + engine_threading::*, + language::{ + parsed, + ty::{TyExpression, TyVariableDecl, VariableMutability}, + Visibility, + }, + semantic_analysis::{ + TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization, + TypeCheckFinalizationContext, + }, + type_system::*, + types::*, + GenericArgument, +}; +use ast_elements::type_parameter::ConstGenericExpr; +use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::{ident::Ident as BaseIdent, Ident, Named, Span, Spanned}; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct TyModStatement { + pub span: Span, + pub visibility: Visibility, + pub mod_name: BaseIdent, +} + +impl Spanned for TyModStatement { + fn span(&self) -> Span { + self.span.clone() + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct TyUseStatement { + pub call_path: Vec, + pub span: Span, + pub import_type: parsed::ImportType, + // If `is_relative_to_package_root` is true, then this use statement is a path relative to the + // project root. For example, if the path is `::X::Y` and occurs in package `P`, then the path + // refers to the full path `P::X::Y`. + // If `is_relative_to_package_root` is false, then there are two options: + // - The path refers to a path relative to the current namespace. For example, if the path is + // `X::Y` and it occurs in a module whose path is `P::M`, then the path refers to the full + // path `P::M::X::Y`. + // - The path refers to a path in an external package. For example, the path `X::Y` refers to an + // entity `Y` in the external package `X`. + pub is_relative_to_package_root: bool, + pub alias: Option, +} + +impl Spanned for TyUseStatement { + fn span(&self) -> Span { + self.span.clone() + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[allow(clippy::large_enum_variant)] +pub enum TyStatement { + Let(TyLetBinding), + Use(TyUseStatement), + Mod(TyModStatement), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TyLetBinding { + pub name: Ident, + pub value: TyExpression, + pub mutability: VariableMutability, + pub return_type: TypeId, + pub type_ascription: GenericArgument, +} + +impl Named for TyLetBinding { + fn name(&self) -> &sway_types::BaseIdent { + &self.name + } +} + +impl Spanned for TyLetBinding { + fn span(&self) -> Span { + self.name.span() + } +} + +impl EqWithEngines for TyStatement {} +impl PartialEqWithEngines for TyStatement { + fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { + match (self, other) { + (TyStatement::Let(lhs), TyStatement::Let(rhs)) => lhs.eq(rhs, ctx), + (TyStatement::Use(lhs), TyStatement::Use(rhs)) => lhs == rhs, + (TyStatement::Mod(lhs), TyStatement::Mod(rhs)) => lhs == rhs, + _ => false, + } + } +} + +impl HashWithEngines for TyStatement { + fn hash(&self, state: &mut H, engines: &Engines) { + match self { + TyStatement::Let(binding) => binding.hash(state, engines), + TyStatement::Use(stmt) => stmt.hash(state), + TyStatement::Mod(stmt) => stmt.hash(state), + } + } +} + +impl SubstTypes for TyStatement { + fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges { + match self { + TyStatement::Let(binding) => binding.subst(ctx), + TyStatement::Use(_) | TyStatement::Mod(_) => HasChanges::No, + } + } +} + +impl ReplaceDecls for TyStatement { + fn replace_decls_inner( + &mut self, + decl_mapping: &DeclMapping, + handler: &Handler, + ctx: &mut TypeCheckContext, + ) -> Result { + match self { + TyStatement::Let(binding) => binding.value.replace_decls(decl_mapping, handler, ctx), + TyStatement::Use(_) | TyStatement::Mod(_) => Ok(false), + } + } +} + +impl TypeCheckAnalysis for TyStatement { + fn type_check_analyze( + &self, + handler: &Handler, + ctx: &mut TypeCheckAnalysisContext, + ) -> Result<(), ErrorEmitted> { + match self { + TyStatement::Let(binding) => binding.value.type_check_analyze(handler, ctx)?, + TyStatement::Use(_) | TyStatement::Mod(_) => {} + } + Ok(()) + } +} + +impl TypeCheckFinalization for TyStatement { + fn type_check_finalize( + &mut self, + handler: &Handler, + ctx: &mut TypeCheckFinalizationContext, + ) -> Result<(), ErrorEmitted> { + match self { + TyStatement::Let(binding) => binding.value.type_check_finalize(handler, ctx)?, + TyStatement::Use(_) | TyStatement::Mod(_) => {} + } + Ok(()) + } +} + +impl CollectTypesMetadata for TyStatement { + fn collect_types_metadata( + &self, + handler: &Handler, + ctx: &mut CollectTypesMetadataContext, + ) -> Result, ErrorEmitted> { + match self { + TyStatement::Let(binding) => { + let mut metadata = binding.value.collect_types_metadata(handler, ctx)?; + metadata.append( + &mut binding + .type_ascription + .type_id() + .collect_types_metadata(handler, ctx)?, + ); + Ok(metadata) + } + TyStatement::Use(_) | TyStatement::Mod(_) => Ok(vec![]), + } + } +} + +impl MaterializeConstGenerics for TyStatement { + fn materialize_const_generics( + &mut self, + engines: &Engines, + handler: &Handler, + name: &str, + value: &TyExpression, + ) -> Result<(), ErrorEmitted> { + match self { + TyStatement::Let(binding) => { + binding + .value + .materialize_const_generics(engines, handler, name, value)?; + binding + .return_type + .materialize_const_generics(engines, handler, name, value)?; + match &mut binding.type_ascription { + GenericArgument::Type(arg) => arg + .type_id + .materialize_const_generics(engines, handler, name, value)?, + GenericArgument::Const(arg) => { + if matches!( + &arg.expr, + ConstGenericExpr::AmbiguousVariableExpression { ident, .. } + if ident.as_str() == name + ) { + arg.expr = ConstGenericExpr::from_ty_expression(handler, value)?; + } + } + } + Ok(()) + } + TyStatement::Use(_) | TyStatement::Mod(_) => Ok(()), + } + } +} + +impl EqWithEngines for TyLetBinding {} +impl PartialEqWithEngines for TyLetBinding { + fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool { + let type_engine = ctx.engines().te(); + self.name == other.name + && self.value.eq(&other.value, ctx) + && self.mutability == other.mutability + && type_engine + .get(self.return_type) + .eq(&type_engine.get(other.return_type), ctx) + && self.type_ascription.eq(&other.type_ascription, ctx) + } +} + +impl HashWithEngines for TyLetBinding { + fn hash(&self, state: &mut H, engines: &Engines) { + let TyLetBinding { + name, + value, + mutability, + return_type, + type_ascription, + } = self; + let type_engine = engines.te(); + name.hash(state); + value.hash(state, engines); + type_engine.get(*return_type).hash(state, engines); + type_ascription.hash(state, engines); + mutability.hash(state); + } +} + +impl SubstTypes for TyLetBinding { + fn subst_inner(&mut self, ctx: &SubstTypesContext) -> HasChanges { + self.return_type.subst(ctx); + self.type_ascription.subst(ctx); + self.value.subst(ctx) + } +} + +impl From for TyLetBinding { + fn from(decl: TyVariableDecl) -> Self { + let TyVariableDecl { + name, + body, + mutability, + return_type, + type_ascription, + } = decl; + TyLetBinding { + name, + value: body, + mutability, + return_type, + type_ascription, + } + } +} + +impl TyLetBinding { + pub fn to_variable_decl(&self) -> TyVariableDecl { + TyVariableDecl { + name: self.name.clone(), + body: self.value.clone(), + mutability: self.mutability, + return_type: self.return_type, + type_ascription: self.type_ascription.clone(), + } + } +} diff --git a/sway-core/src/semantic_analysis/ast_node/mod.rs b/sway-core/src/semantic_analysis/ast_node/mod.rs index 81262068cb6..4d26c43de7f 100644 --- a/sway-core/src/semantic_analysis/ast_node/mod.rs +++ b/sway-core/src/semantic_analysis/ast_node/mod.rs @@ -29,10 +29,12 @@ impl ty::TyAstNode { node: &AstNode, ) -> Result<(), ErrorEmitted> { match node.content.clone() { - AstNodeContent::UseStatement(stmt) => { - collect_use_statement(handler, engines, ctx, &stmt); - } - AstNodeContent::IncludeStatement(_i) => (), + AstNodeContent::Statement(statement) => match statement { + Statement::Use(stmt) => { + collect_use_statement(handler, engines, ctx, &stmt); + } + Statement::Mod(_mod_stmt) => (), + }, AstNodeContent::Declaration(decl) => ty::TyDecl::collect(handler, engines, ctx, decl)?, AstNodeContent::Expression(expr) => { ty::TyExpression::collect(handler, engines, ctx, &expr)? @@ -54,29 +56,25 @@ impl ty::TyAstNode { let node = ty::TyAstNode { content: match node.content.clone() { - AstNodeContent::UseStatement(stmt) => { - handle_use_statement(&mut ctx, &stmt, handler); - ty::TyAstNodeContent::SideEffect(ty::TySideEffect { - side_effect: ty::TySideEffectVariant::UseStatement(ty::TyUseStatement { + AstNodeContent::Statement(statement) => match statement { + Statement::Use(stmt) => { + handle_use_statement(&mut ctx, &stmt, handler); + ty::TyAstNodeContent::Statement(ty::TyStatement::Use(ty::TyUseStatement { alias: stmt.alias, call_path: stmt.call_path, span: stmt.span, is_relative_to_package_root: stmt.is_relative_to_package_root, import_type: stmt.import_type, - }), - }) - } - AstNodeContent::IncludeStatement(i) => { - ty::TyAstNodeContent::SideEffect(ty::TySideEffect { - side_effect: ty::TySideEffectVariant::IncludeStatement( - ty::TyIncludeStatement { - mod_name: i.mod_name, - span: i.span, - visibility: i.visibility, - }, - ), - }) - } + })) + } + Statement::Mod(i) => { + ty::TyAstNodeContent::Statement(ty::TyStatement::Mod(ty::TyModStatement { + mod_name: i.mod_name, + span: i.span, + visibility: i.visibility, + })) + } + }, AstNodeContent::Declaration(decl) => ty::TyAstNodeContent::Declaration( ty::TyDecl::type_check(handler, &mut ctx, decl)?, ), diff --git a/sway-core/src/semantic_analysis/ast_node/statement/let_binding.rs b/sway-core/src/semantic_analysis/ast_node/statement/let_binding.rs new file mode 100644 index 00000000000..99abe10450f --- /dev/null +++ b/sway-core/src/semantic_analysis/ast_node/statement/let_binding.rs @@ -0,0 +1,52 @@ +use crate::{ + decl_engine::parsed_id::ParsedDeclId, + language::{ + parsed::{Declaration, VariableDeclaration}, + ty::{self, TyLetBinding, TyStatement, TyVariableDecl}, + }, + semantic_analysis::{ + symbol_collection_context::SymbolCollectionContext, TypeCheckContext, + }, + type_system::*, + Engines, +}; +use sway_error::handler::{ErrorEmitted, Handler}; +use sway_types::Spanned; + +impl TyLetBinding { + pub(crate) fn collect( + handler: &Handler, + engines: &Engines, + ctx: &mut SymbolCollectionContext, + decl_id: &ParsedDeclId, + ) -> Result<(), ErrorEmitted> { + TyVariableDecl::collect(handler, engines, ctx, decl_id) + } + + pub(crate) fn type_check( + handler: &Handler, + ctx: &mut TypeCheckContext, + var_decl: VariableDeclaration, + ) -> Result<(TyStatement, ty::TyDecl), ErrorEmitted> { + let span = var_decl.name.span(); + let name = var_decl.name.clone(); + let typed_var_decl = TyVariableDecl::type_check(handler, ctx.by_ref(), var_decl)?; + let ty_decl = ty::TyDecl::VariableDecl(Box::new(typed_var_decl.clone())); + ctx.insert_symbol(handler, name, ty_decl.clone())?; + let statement = TyStatement::Let(typed_var_decl.into()); + Ok((statement, ty_decl)) + } +} + +pub(crate) fn parsed_statement_from_decl( + engines: &Engines, + decl_id: &ParsedDeclId, +) -> VariableDeclaration { + engines.pe().get_variable(decl_id).as_ref().clone() +} + +pub(crate) fn declaration_from_statement(statement: &TyStatement) -> Option { + match statement { + TyStatement::Let(binding) => Some(binding.to_variable_decl()), + } +} diff --git a/sway-core/src/semantic_analysis/ast_node/statement/mod.rs b/sway-core/src/semantic_analysis/ast_node/statement/mod.rs new file mode 100644 index 00000000000..b7c432d708c --- /dev/null +++ b/sway-core/src/semantic_analysis/ast_node/statement/mod.rs @@ -0,0 +1,3 @@ +mod let_binding; + +pub(crate) use let_binding::*; diff --git a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs index 9cc4dc7a736..a4a77604b93 100644 --- a/sway-core/src/semantic_analysis/cei_pattern_analysis.rs +++ b/sway-core/src/semantic_analysis/cei_pattern_analysis.rs @@ -193,7 +193,7 @@ fn analyze_code_block_entry( ty::TyAstNodeContent::Expression(expr) => { analyze_expression(engines, expr, block_name, warnings) } - ty::TyAstNodeContent::SideEffect(_) | ty::TyAstNodeContent::Error(_, _) => HashSet::new(), + ty::TyAstNodeContent::Statement(_) | ty::TyAstNodeContent::Error(_, _) => HashSet::new(), } } @@ -495,7 +495,7 @@ fn effects_of_codeblock_entry(engines: &Engines, ast_node: &ty::TyAstNode) -> Ha match &ast_node.content { ty::TyAstNodeContent::Declaration(decl) => effects_of_codeblock_decl(engines, decl), ty::TyAstNodeContent::Expression(expr) => effects_of_expression(engines, expr), - ty::TyAstNodeContent::SideEffect(_) | ty::TyAstNodeContent::Error(_, _) => HashSet::new(), + ty::TyAstNodeContent::Statement(_) | ty::TyAstNodeContent::Error(_, _) => HashSet::new(), } } diff --git a/sway-core/src/semantic_analysis/module.rs b/sway-core/src/semantic_analysis/module.rs index fa635a57cd7..e203461c98f 100644 --- a/sway-core/src/semantic_analysis/module.rs +++ b/sway-core/src/semantic_analysis/module.rs @@ -813,26 +813,27 @@ impl ty::TySubmodule { let sub_mod_node = module_dep_graph.get_node_id_for_module(&mod_name).unwrap(); for node in module.tree.root_nodes.iter() { match &node.content { - AstNodeContent::UseStatement(use_stmt) => { - if let Some(use_mod_ident) = use_stmt.call_path.first() { - if let Some(mod_name_node) = - module_dep_graph.get_node_id_for_module(use_mod_ident) - { - // Prevent adding edge loops between the same node as that will throw off - // the cyclic dependency analysis. - if sub_mod_node != mod_name_node { - module_dep_graph.dep_graph.add_edge( - sub_mod_node, - mod_name_node, - ModuleDepGraphEdge {}, - ); + AstNodeContent::Statement(statement) => { + if let Statement::Use(use_stmt) = statement { + if let Some(use_mod_ident) = use_stmt.call_path.first() { + if let Some(mod_name_node) = + module_dep_graph.get_node_id_for_module(use_mod_ident) + { + // Prevent adding edge loops between the same node as that will throw off + // the cyclic dependency analysis. + if sub_mod_node != mod_name_node { + module_dep_graph.dep_graph.add_edge( + sub_mod_node, + mod_name_node, + ModuleDepGraphEdge {}, + ); + } } } } } AstNodeContent::Declaration(_) => {} AstNodeContent::Expression(_) => {} - AstNodeContent::IncludeStatement(_) => {} AstNodeContent::Error(_, _) => {} } } diff --git a/sway-core/src/semantic_analysis/node_dependencies.rs b/sway-core/src/semantic_analysis/node_dependencies.rs index 8e34d58d685..173ad20bd08 100644 --- a/sway-core/src/semantic_analysis/node_dependencies.rs +++ b/sway-core/src/semantic_analysis/node_dependencies.rs @@ -268,17 +268,26 @@ fn depends_on( ) -> bool { match (&dependant_node.content, &dependee_node.content) { // Include statements first. - (AstNodeContent::IncludeStatement(_), AstNodeContent::IncludeStatement(_)) => false, - (_, AstNodeContent::IncludeStatement(_)) => true, + ( + AstNodeContent::Statement(Statement::Mod(_)), + AstNodeContent::Statement(Statement::Mod(_)), + ) => false, + (_, AstNodeContent::Statement(Statement::Mod(_))) => true, // Use statements next. - (AstNodeContent::IncludeStatement(_), AstNodeContent::UseStatement(_)) => false, - (AstNodeContent::UseStatement(_), AstNodeContent::UseStatement(_)) => false, - (_, AstNodeContent::UseStatement(_)) => true, + ( + AstNodeContent::Statement(Statement::Mod(_)), + AstNodeContent::Statement(Statement::Use(_)), + ) => false, + ( + AstNodeContent::Statement(Statement::Use(_)), + AstNodeContent::Statement(Statement::Use(_)), + ) => false, + (_, AstNodeContent::Statement(Statement::Use(_))) => true, // Then declarations, ordered using the dependencies list. - (AstNodeContent::IncludeStatement(_), AstNodeContent::Declaration(_)) => false, - (AstNodeContent::UseStatement(_), AstNodeContent::Declaration(_)) => false, + (AstNodeContent::Statement(Statement::Mod(_)), AstNodeContent::Declaration(_)) => false, + (AstNodeContent::Statement(Statement::Use(_)), AstNodeContent::Declaration(_)) => false, (AstNodeContent::Declaration(dependant), AstNodeContent::Declaration(dependee)) => { match (decl_name(engines, dependant), decl_name(engines, dependee)) { (Some(dependant_name), Some(dependee_name)) => decl_dependencies @@ -768,9 +777,7 @@ impl Dependencies { AstNodeContent::Declaration(decl) => self.gather_from_decl(engines, decl), // No deps from these guys. - AstNodeContent::UseStatement(_) - | AstNodeContent::IncludeStatement(_) - | AstNodeContent::Error(_, _) => self, + AstNodeContent::Statement(_) | AstNodeContent::Error(_, _) => self, } } diff --git a/sway-core/src/semantic_analysis/symbol_resolve.rs b/sway-core/src/semantic_analysis/symbol_resolve.rs index 8dd038066de..6c41ca7e9fb 100644 --- a/sway-core/src/semantic_analysis/symbol_resolve.rs +++ b/sway-core/src/semantic_analysis/symbol_resolve.rs @@ -61,10 +61,9 @@ impl ResolveSymbols for ParseModule { impl ResolveSymbols for AstNode { fn resolve_symbols(&mut self, handler: &Handler, ctx: SymbolResolveContext) { match &mut self.content { - AstNodeContent::UseStatement(_) => {} + AstNodeContent::Statement(_) => {} AstNodeContent::Declaration(decl) => decl.resolve_symbols(handler, ctx), AstNodeContent::Expression(expr) => expr.resolve_symbols(handler, ctx), - AstNodeContent::IncludeStatement(_) => {} AstNodeContent::Error(_, _) => {} } } diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 8ef4662e9ef..db8f04f1f24 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -6,7 +6,10 @@ use crate::{ generate_tuple_var_name, }, decl_engine::{parsed_engine::ParsedDeclEngineInsert, parsed_id::ParsedDeclId}, - language::{parsed::*, *}, + language::{ + parsed::{self, *}, + *, + }, transform::{attribute::*, to_parsed_lang::context::Context}, type_system::*, BuildTarget, Engines, @@ -122,12 +125,12 @@ pub fn item_to_ast_nodes( )); } - let incl_stmt = submodule_to_include_statement(&submodule); - vec![AstNodeContent::IncludeStatement(incl_stmt)] + let mod_stmt = submodule_to_mod_statement(&submodule); + vec![AstNodeContent::Statement(parsed::Statement::Mod(mod_stmt))] } ItemKind::Use(item_use) => item_use_to_use_statements(context, handler, item_use)? .into_iter() - .map(AstNodeContent::UseStatement) + .map(|use_stmt| AstNodeContent::Statement(parsed::Statement::Use(use_stmt))) .collect(), ItemKind::Struct(item_struct) => { let struct_decl = Declaration::StructDeclaration(item_struct_to_struct_declaration( @@ -4647,8 +4650,8 @@ fn statement_let_to_ast_nodes_unfold( Ok(ast_nodes) } -fn submodule_to_include_statement(submodule: &Submodule) -> IncludeStatement { - IncludeStatement { +fn submodule_to_mod_statement(submodule: &Submodule) -> ModStatement { + ModStatement { span: submodule.span(), mod_name: submodule.name.clone(), visibility: pub_token_opt_to_visibility(submodule.visibility.clone()), diff --git a/sway-lsp/src/capabilities/code_actions/diagnostic/auto_import.rs b/sway-lsp/src/capabilities/code_actions/diagnostic/auto_import.rs index 593ed808bce..694260b97c2 100644 --- a/sway-lsp/src/capabilities/code_actions/diagnostic/auto_import.rs +++ b/sway-lsp/src/capabilities/code_actions/diagnostic/auto_import.rs @@ -17,9 +17,7 @@ use std::{ }; use sway_core::language::{ parsed::ImportType, - ty::{ - TyConstantDecl, TyDecl, TyFunctionDecl, TyIncludeStatement, TyTypeAliasDecl, TyUseStatement, - }, + ty::{TyConstantDecl, TyDecl, TyFunctionDecl, TyModStatement, TyTypeAliasDecl, TyUseStatement}, CallPath, }; use sway_types::{Ident, Spanned}; @@ -37,16 +35,14 @@ pub(crate) fn import_code_action( // Collect the tokens we need to determine where to insert the import statement. let mut use_statements = Vec::::new(); - let mut include_statements = Vec::::new(); + let mut mod_statements = Vec::::new(); let mut program_type_keyword = None; ctx.tokens.tokens_for_file(ctx.temp_uri).for_each(|item| { if let Some(TypedAstToken::TypedUseStatement(use_stmt)) = &item.value().as_typed() { use_statements.push(use_stmt.clone()); - } else if let Some(TypedAstToken::TypedIncludeStatement(include_stmt)) = - &item.value().as_typed() - { - include_statements.push(include_stmt.clone()); + } else if let Some(TypedAstToken::TypedModStatement(mod_stmt)) = &item.value().as_typed() { + mod_statements.push(mod_stmt.clone()); } else if item.value().kind == SymbolKind::ProgramTypeKeyword { if let Some(ParsedAstToken::Keyword(ident)) = &item.value().as_parsed() { program_type_keyword = Some(ident.clone()); @@ -60,7 +56,7 @@ pub(crate) fn import_code_action( let text_edit = get_text_edit( &call_path, &use_statements, - &include_statements, + &mod_statements, &program_type_keyword, ); let changes = HashMap::from([(ctx.uri.clone(), vec![text_edit])]); @@ -179,14 +175,14 @@ pub(crate) fn get_call_paths_for_name<'s>( fn get_text_edit( call_path: &CallPath, use_statements: &[TyUseStatement], - include_statements: &[TyIncludeStatement], + mod_statements: &[TyModStatement], program_type_keyword: &Option, ) -> TextEdit { get_text_edit_for_group(call_path, use_statements) .or_else(|| get_text_edit_in_use_block(call_path, use_statements)) .unwrap_or(get_text_edit_fallback( call_path, - include_statements, + mod_statements, program_type_keyword, )) } @@ -286,10 +282,10 @@ fn get_text_edit_in_use_block( /// type statement, or at the beginning of the file. fn get_text_edit_fallback( call_path: &CallPath, - include_statements: &[TyIncludeStatement], + mod_statements: &[TyModStatement], program_type_keyword: &Option, ) -> TextEdit { - let range_line = include_statements + let range_line = mod_statements .iter() .map(|stmt| stmt.span()) .reduce(|acc, span| { @@ -371,8 +367,8 @@ mod tests { } } - fn get_incl_stmt_from_src(src: &Source, mod_name: &str, text: &str) -> TyIncludeStatement { - TyIncludeStatement { + fn get_mod_stmt_from_src(src: &Source, mod_name: &str, text: &str) -> TyModStatement { + TyModStatement { span: get_span_from_src(src, text).unwrap(), mod_name: get_ident_from_src(src, mod_name).unwrap(), visibility: Visibility::Private, @@ -399,7 +395,7 @@ use b:c:*; get_use_stmt_from_src(&src, Vec::from(["b", "c"]), ImportType::Star, "use b:c:*;"), ]; - let include_statements = vec![]; + let mod_statements = vec![]; let program_type_keyword = get_ident_from_src(&src, "contract"); let expected_range = Range::new(Position::new(2, 0), Position::new(2, 10)); @@ -408,7 +404,7 @@ use b:c:*; let text_edit = get_text_edit( &new_call_path, &use_statements, - &include_statements, + &mod_statements, &program_type_keyword, ); assert_text_edit(text_edit, expected_range, expected_text); @@ -430,7 +426,7 @@ use b:c:*; "use b:c:*;", )]; - let include_statements = vec![]; + let mod_statements = vec![]; let program_type_keyword = get_ident_from_src(&src, "predicate"); let expected_range = Range::new(Position::new(2, 0), Position::new(2, 0)); @@ -439,7 +435,7 @@ use b:c:*; let text_edit = get_text_edit( &new_call_path, &use_statements, - &include_statements, + &mod_statements, &program_type_keyword, ); assert_text_edit(text_edit, expected_range, expected_text); @@ -469,7 +465,7 @@ use b:c:{D, F}; ), ]; - let include_statements = vec![]; + let mod_statements = vec![]; let program_type_keyword = get_ident_from_src(&src, "contract"); let expected_range = Range::new(Position::new(2, 0), Position::new(2, 15)); @@ -478,7 +474,7 @@ use b:c:{D, F}; let text_edit = get_text_edit( &new_call_path, &use_statements, - &include_statements, + &mod_statements, &program_type_keyword, ); assert_text_edit(text_edit, expected_range, expected_text); @@ -496,9 +492,9 @@ pub mod zz_module; let new_call_path = get_mock_call_path(vec!["b", "c"], "D"); let use_statements = vec![]; - let include_statements = vec![ - get_incl_stmt_from_src(&src, "my_module", "mod my_module;"), - get_incl_stmt_from_src(&src, "zz_module", "pub mod zz_module"), + let mod_statements = vec![ + get_mod_stmt_from_src(&src, "my_module", "mod my_module;"), + get_mod_stmt_from_src(&src, "zz_module", "pub mod zz_module"), ]; let program_type_keyword = get_ident_from_src(&src, "library"); @@ -508,7 +504,7 @@ pub mod zz_module; let text_edit = get_text_edit( &new_call_path, &use_statements, - &include_statements, + &mod_statements, &program_type_keyword, ); assert_text_edit(text_edit, expected_range, expected_text); @@ -525,7 +521,7 @@ const HI: u8 = 0; let new_call_path = get_mock_call_path(vec!["b", "c"], "D"); let use_statements = vec![]; - let include_statements = vec![]; + let mod_statements = vec![]; let program_type_keyword = get_ident_from_src(&src, "script"); let expected_range = Range::new(Position::new(1, 0), Position::new(1, 0)); @@ -534,7 +530,7 @@ const HI: u8 = 0; let text_edit = get_text_edit( &new_call_path, &use_statements, - &include_statements, + &mod_statements, &program_type_keyword, ); assert_text_edit(text_edit, expected_range, expected_text); diff --git a/sway-lsp/src/capabilities/document_symbol.rs b/sway-lsp/src/capabilities/document_symbol.rs index 40b8f5f55f1..c38292edf03 100644 --- a/sway-lsp/src/capabilities/document_symbol.rs +++ b/sway-lsp/src/capabilities/document_symbol.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use sway_core::{ language::ty::{ TyAbiDecl, TyAstNodeContent, TyConstantDecl, TyDecl, TyEnumDecl, TyFunctionDecl, - TyFunctionParameter, TyIncludeStatement, TyProgram, TySideEffectVariant, TyStorageDecl, - TyStructDecl, TyTraitInterfaceItem, TyTraitItem, TyTraitType, + TyFunctionParameter, TyModStatement, TyProgram, TyStatement, TyStorageDecl, TyStructDecl, + TyTraitInterfaceItem, TyTraitItem, TyTraitType, }, Engines, GenericArgument, }; @@ -51,15 +51,10 @@ pub fn to_document_symbols( .flatten() .filter_map(|node| { match &node.content { - TyAstNodeContent::SideEffect(side_effect) => { - if let TySideEffectVariant::IncludeStatement(include_statement) = - &side_effect.side_effect - { - Some(build_include_symbol(include_statement)) - } else { - None - } + TyAstNodeContent::Statement(TyStatement::Mod(mod_statement)) => { + Some(build_mod_symbol(mod_statement)) } + TyAstNodeContent::Statement(_) => None, TyAstNodeContent::Declaration(decl) => match decl { TyDecl::TypeAliasDecl(decl) => { let type_alias_decl = engines.de().get_type_alias(&decl.decl_id); @@ -228,8 +223,8 @@ pub fn to_document_symbols( nodes } -fn build_include_symbol(include_statement: &TyIncludeStatement) -> DocumentSymbol { - let span = include_statement.span(); +fn build_mod_symbol(mod_statement: &TyModStatement) -> DocumentSymbol { + let span = mod_statement.span(); let range = get_range_from_span(&span); DocumentSymbolBuilder::new() .name(span.str().to_string()) diff --git a/sway-lsp/src/core/token.rs b/sway-lsp/src/core/token.rs index ffb18aec9bb..517dc426e39 100644 --- a/sway-lsp/src/core/token.rs +++ b/sway-lsp/src/core/token.rs @@ -7,9 +7,9 @@ use sway_core::{ parsed::{ AbiCastExpression, AmbiguousPathExpression, Declaration, DelineatedPathExpression, EnumVariant, Expression, FunctionApplicationExpression, FunctionParameter, - IncludeStatement, MethodApplicationExpression, Scrutinee, StorageField, - StorageNamespace, StructExpression, StructExpressionField, StructField, - StructScrutineeField, Supertrait, TraitFn, UseStatement, + MethodApplicationExpression, ModStatement, Scrutinee, StorageField, StorageNamespace, + StructExpression, StructExpressionField, StructField, StructScrutineeField, Supertrait, + TraitFn, UseStatement, }, ty, }, @@ -37,7 +37,7 @@ pub enum ParsedAstToken { FunctionParameter(FunctionParameter), Ident(Ident), ModuleName, - IncludeStatement(IncludeStatement), + ModStatement(ModStatement), Intrinsic(Intrinsic), Keyword(Ident), LibrarySpan(Span), @@ -84,8 +84,9 @@ pub enum TypedAstToken { TypedParameter(TypeParameter), TypedTraitConstraint(TraitConstraint), TypedModuleName, - TypedIncludeStatement(ty::TyIncludeStatement), + TypedModStatement(ty::TyModStatement), TypedUseStatement(ty::TyUseStatement), + TypedStatement(ty::TyStatement), Ident(Ident), } diff --git a/sway-lsp/src/traverse/parsed_tree.rs b/sway-lsp/src/traverse/parsed_tree.rs index 04ceb89b841..b31bd3c0e36 100644 --- a/sway-lsp/src/traverse/parsed_tree.rs +++ b/sway-lsp/src/traverse/parsed_tree.rs @@ -24,15 +24,15 @@ use sway_core::{ ConstGenericDeclaration, ConstantDeclaration, Declaration, DelineatedPathExpression, EnumDeclaration, EnumVariant, Expression, ExpressionKind, ForLoopExpression, FunctionApplicationExpression, FunctionDeclaration, FunctionParameter, IfExpression, - ImplItem, ImplSelfOrTrait, ImportType, IncludeStatement, IntrinsicFunctionExpression, + ImplItem, ImplSelfOrTrait, ImportType, IntrinsicFunctionExpression, LazyOperatorExpression, MatchExpression, MethodApplicationExpression, MethodName, - ParseModule, ParseProgram, ParseSubmodule, QualifiedPathType, ReassignmentExpression, - ReassignmentTarget, RefExpression, Scrutinee, StorageAccessExpression, - StorageDeclaration, StorageEntry, StorageField, StorageNamespace, StructDeclaration, - StructExpression, StructExpressionField, StructField, StructScrutineeField, - SubfieldExpression, Supertrait, TraitDeclaration, TraitFn, TraitItem, - TraitTypeDeclaration, TupleIndexExpression, TypeAliasDeclaration, UseStatement, - VariableDeclaration, WhileLoopExpression, + ModStatement, ParseModule, ParseProgram, ParseSubmodule, QualifiedPathType, + ReassignmentExpression, ReassignmentTarget, RefExpression, Scrutinee, Statement, + StorageAccessExpression, StorageDeclaration, StorageEntry, StorageField, + StorageNamespace, StructDeclaration, StructExpression, StructExpressionField, + StructField, StructScrutineeField, SubfieldExpression, Supertrait, TraitDeclaration, + TraitFn, TraitItem, TraitTypeDeclaration, TupleIndexExpression, TypeAliasDeclaration, + UseStatement, VariableDeclaration, WhileLoopExpression, }, CallPathTree, HasSubmodules, Literal, }, @@ -111,13 +111,21 @@ impl Parse for AstNode { AstNodeContent::Expression(expression) => { expression.parse(ctx); } - AstNodeContent::UseStatement(use_statement) => use_statement.parse(ctx), - AstNodeContent::IncludeStatement(include_statement) => include_statement.parse(ctx), + AstNodeContent::Statement(statement) => statement.parse(ctx), AstNodeContent::Error(_, _) => {} } } } +impl Parse for Statement { + fn parse(&self, ctx: &ParseContext) { + match self { + Statement::Use(use_statement) => use_statement.parse(ctx), + Statement::Mod(mod_statement) => mod_statement.parse(ctx), + } + } +} + impl Parse for Declaration { fn parse(&self, ctx: &ParseContext) { match self { @@ -184,12 +192,12 @@ impl Parse for UseStatement { } } -impl Parse for IncludeStatement { +impl Parse for ModStatement { fn parse(&self, ctx: &ParseContext) { ctx.tokens.insert( ctx.ident(&self.mod_name), Token::from_parsed( - ParsedAstToken::IncludeStatement(self.clone()), + ParsedAstToken::ModStatement(self.clone()), SymbolKind::Unknown, ), ); diff --git a/sway-lsp/src/traverse/typed_tree.rs b/sway-lsp/src/traverse/typed_tree.rs index 5f28b93500a..9a606189b77 100644 --- a/sway-lsp/src/traverse/typed_tree.rs +++ b/sway-lsp/src/traverse/typed_tree.rs @@ -66,8 +66,8 @@ impl Parse for ty::TyAstNode { fn parse(&self, ctx: &ParseContext) { match &self.content { ty::TyAstNodeContent::Declaration(declaration) => declaration.parse(ctx), + ty::TyAstNodeContent::Statement(statement) => statement.parse(ctx), ty::TyAstNodeContent::Expression(expression) => expression.parse(ctx), - ty::TyAstNodeContent::SideEffect(side_effect) => side_effect.parse(ctx), ty::TyAstNodeContent::Error(_, _) => {} }; } @@ -96,126 +96,6 @@ impl Parse for ty::TyDecl { } } -impl Parse for ty::TySideEffect { - fn parse(&self, ctx: &ParseContext) { - use ty::TySideEffectVariant::{IncludeStatement, UseStatement}; - match &self.side_effect { - UseStatement( - use_statement @ ty::TyUseStatement { - call_path, - span: _, - import_type, - alias, - is_relative_to_package_root, - }, - ) => { - let full_path = - mod_path_to_full_path(call_path, *is_relative_to_package_root, ctx.namespace); - for (mod_path, ident) in iter_prefixes(&full_path).zip(&full_path) { - if let Some(mut token) = ctx.tokens.try_get_mut_with_retry(&ctx.ident(ident)) { - token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedUseStatement( - use_statement.clone(), - )); - - if let Some(span) = ctx - .namespace - .module_from_absolute_path(mod_path) - .and_then(|tgt_submod| tgt_submod.span().clone()) - { - token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); - } - } - } - match &import_type { - ImportType::Item(item) => { - if let Some(mut token) = ctx.tokens.try_get_mut_with_retry(&ctx.ident(item)) - { - token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedUseStatement( - use_statement.clone(), - )); - let mut symbol_kind = SymbolKind::Unknown; - let mut type_def = None; - if let Some(decl_ident) = ctx - .namespace - .module_from_absolute_path(&full_path) - .and_then(|module| { - module - .resolve_symbol(&Handler::default(), ctx.engines, item) - .ok() - }) - .and_then(|(decl, _)| { - decl.expect_typed_ref().get_decl_ident(ctx.engines) - }) - { - // Update the symbol kind to match the declarations symbol kind - if let Some(decl) = - ctx.tokens.try_get(&ctx.ident(&decl_ident)).try_unwrap() - { - symbol_kind = decl.value().kind.clone(); - } - type_def = Some(TypeDefinition::Ident(decl_ident)); - } - token.kind = symbol_kind.clone(); - token.type_def.clone_from(&type_def); - // the alias should take on the same symbol kind and type definition - if let Some(alias) = alias { - if let Some(mut token) = - ctx.tokens.try_get_mut_with_retry(&ctx.ident(alias)) - { - token.ast_node = TokenAstNode::Typed( - TypedAstToken::TypedUseStatement(use_statement.clone()), - ); - token.kind = symbol_kind; - token.type_def = type_def; - } - } - } - } - ImportType::SelfImport(span) => { - if let Some(mut token) = ctx - .tokens - .try_get_mut_with_retry(&ctx.ident(&Ident::new(span.clone()))) - { - token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedUseStatement( - use_statement.clone(), - )); - if let Some(span) = ctx - .namespace - .module_from_absolute_path(&full_path) - .and_then(|tgt_submod| tgt_submod.span().clone()) - { - token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); - } - } - } - ImportType::Star => {} - } - } - IncludeStatement( - include_statement @ ty::TyIncludeStatement { - span: _, - mod_name, - visibility: _, - }, - ) => { - if let Some(mut token) = ctx.tokens.try_get_mut_with_retry(&ctx.ident(mod_name)) { - token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedIncludeStatement( - include_statement.clone(), - )); - if let Some(span) = ctx - .namespace - .root_module() - .submodule(std::slice::from_ref(mod_name)) - .and_then(|tgt_submod| tgt_submod.span().clone()) - { - token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); - } - } - } - } - } -} - impl Parse for ty::TyExpression { fn parse(&self, ctx: &ParseContext) { match &self.expression { @@ -662,6 +542,131 @@ impl Parse for ty::TyVariableDecl { } } +impl Parse for ty::TyStatement { + fn parse(&self, ctx: &ParseContext) { + match self { + ty::TyStatement::Let(binding) => { + if let Some(mut token) = + ctx.tokens.try_get_mut_with_retry(&ctx.ident(&binding.name)) + { + token.ast_node = + TokenAstNode::Typed(TypedAstToken::TypedStatement(self.clone())); + token.type_def = Some(TypeDefinition::Ident(binding.name.clone())); + } + if let Some(call_path_tree) = &binding.type_ascription.call_path_tree() { + collect_call_path_tree(ctx, call_path_tree, &binding.type_ascription); + } + binding.value.parse(ctx); + } + ty::TyStatement::Use(use_statement) => { + let full_path = mod_path_to_full_path( + &use_statement.call_path, + use_statement.is_relative_to_package_root, + ctx.namespace, + ); + for (mod_path, ident) in iter_prefixes(&full_path).zip(&full_path) { + if let Some(mut token) = ctx.tokens.try_get_mut_with_retry(&ctx.ident(ident)) { + token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedUseStatement( + use_statement.clone(), + )); + + if let Some(span) = ctx + .namespace + .module_from_absolute_path(mod_path) + .and_then(|tgt_submod| tgt_submod.span().clone()) + { + token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); + } + } + } + match &use_statement.import_type { + ImportType::Item(item) => { + if let Some(mut token) = ctx.tokens.try_get_mut_with_retry(&ctx.ident(item)) + { + token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedUseStatement( + use_statement.clone(), + )); + let mut symbol_kind = SymbolKind::Unknown; + let mut type_def = None; + if let Some(decl_ident) = ctx + .namespace + .module_from_absolute_path(&full_path) + .and_then(|module| { + module + .resolve_symbol(&Handler::default(), ctx.engines, item) + .ok() + }) + .and_then(|(decl, _)| { + decl.expect_typed_ref().get_decl_ident(ctx.engines) + }) + { + if let Some(decl) = + ctx.tokens.try_get(&ctx.ident(&decl_ident)).try_unwrap() + { + symbol_kind = decl.value().kind.clone(); + } + type_def = Some(TypeDefinition::Ident(decl_ident)); + } + token.kind = symbol_kind.clone(); + token.type_def.clone_from(&type_def); + if let Some(alias) = &use_statement.alias { + if let Some(mut token) = + ctx.tokens.try_get_mut_with_retry(&ctx.ident(alias)) + { + token.ast_node = TokenAstNode::Typed( + TypedAstToken::TypedUseStatement(use_statement.clone()), + ); + token.kind = symbol_kind; + token.type_def = type_def; + } + } + } + } + ImportType::SelfImport(span) => { + if let Some(mut token) = ctx + .tokens + .try_get_mut_with_retry(&ctx.ident(&Ident::new(span.clone()))) + { + token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedUseStatement( + use_statement.clone(), + )); + if let Some(span) = ctx + .namespace + .module_from_absolute_path(&full_path) + .and_then(|tgt_submod| tgt_submod.span().clone()) + { + token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); + } + } + } + ImportType::Star => {} + } + } + ty::TyStatement::Mod( + mod_statement @ ty::TyModStatement { + span: _, + mod_name, + visibility: _, + }, + ) => { + if let Some(mut token) = ctx.tokens.try_get_mut_with_retry(&ctx.ident(mod_name)) { + token.ast_node = TokenAstNode::Typed(TypedAstToken::TypedModStatement( + mod_statement.clone(), + )); + if let Some(span) = ctx + .namespace + .root_module() + .submodule(std::slice::from_ref(mod_name)) + .and_then(|tgt_submod| tgt_submod.span().clone()) + { + token.type_def = Some(TypeDefinition::Ident(Ident::new(span))); + } + } + } + } + } +} + impl Parse for ty::ConstantDecl { fn parse(&self, ctx: &ParseContext) { let const_decl = ctx.engines.de().get_constant(&self.decl_id); diff --git a/sway-lsp/src/utils/debug.rs b/sway-lsp/src/utils/debug.rs index e98390d6694..9ab4a7e7dac 100644 --- a/sway-lsp/src/utils/debug.rs +++ b/sway-lsp/src/utils/debug.rs @@ -114,7 +114,7 @@ pub(crate) fn print_decl_engine_types( ty::TyAstNodeContent::Expression(expression) => { format!("{expression:#?}") } - ty::TyAstNodeContent::SideEffect(side_effect) => format!("{side_effect:#?}"), + ty::TyAstNodeContent::Statement(statement) => format!("{statement:#?}"), ty::TyAstNodeContent::Error(_, _) => "error".to_string(), }) .fold(String::new(), |output, s| format!("{output}{s}\n"))