Skip to content

Commit

Permalink
Add a collection context and symbol collection step.
Browse files Browse the repository at this point in the history
  • Loading branch information
tritao committed Mar 3, 2024
1 parent 5329efb commit abb5522
Show file tree
Hide file tree
Showing 11 changed files with 294 additions and 15 deletions.
9 changes: 9 additions & 0 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,15 @@ pub fn parsed_to_ast(
let modules_dep_graph = ty::TyModule::build_dep_graph(handler, &parse_program.root)?;
let module_eval_order = modules_dep_graph.compute_order(handler)?;

// Collect the program symbols.
let _collection_ctx = ty::TyProgram::collect(
handler,
engines,
parse_program,
initial_namespace.clone(),
&module_eval_order,
)?;

// Type check the program.
let typed_program_opt = ty::TyProgram::type_check(
handler,
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/semantic_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pub mod ast_node;
pub(crate) mod cei_pattern_analysis;
pub(crate) mod coins_analysis;
pub mod collection_context;
mod module;
pub mod namespace;
mod node_dependencies;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::{Named, Spanned};
use sway_types::{BaseIdent, Named, Spanned};

use crate::{
decl_engine::{DeclEngineInsert, DeclRef, ReplaceFunctionImplementingType},
Expand All @@ -10,13 +10,79 @@ use crate::{
},
namespace::{IsExtendingExistingImpl, IsImplSelf},
semantic_analysis::{
type_check_context::EnforceTypeArguments, TypeCheckAnalysis, TypeCheckAnalysisContext,
TypeCheckContext, TypeCheckFinalization, TypeCheckFinalizationContext,
collection_context::SymbolCollectionContext, type_check_context::EnforceTypeArguments,
TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization,
TypeCheckFinalizationContext,
},
type_system::*,
Engines,
};

impl TyDecl {
pub(crate) fn collect(
handler: &Handler,
engines: &Engines,
ctx: &mut SymbolCollectionContext,
decl: parsed::Declaration,
) -> Result<(), ErrorEmitted> {
match &decl {
parsed::Declaration::VariableDeclaration(decl_id) => {
let var_decl = engines.pe().get_variable(decl_id);
ctx.insert_parsed_symbol(handler, var_decl.name.clone(), decl)?;
}
parsed::Declaration::ConstantDeclaration(decl_id) => {
let const_decl = engines.pe().get_constant(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, const_decl.name.clone(), decl)?;
}
parsed::Declaration::TraitTypeDeclaration(decl_id) => {
let trait_type_decl = engines.pe().get_trait_type(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, trait_type_decl.name.clone(), decl)?;
}
parsed::Declaration::EnumDeclaration(decl_id) => {
let enum_decl = engines.pe().get_enum(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, enum_decl.name.clone(), decl)?;
}
parsed::Declaration::FunctionDeclaration(decl_id) => {
let fn_decl = engines.pe().get_function(decl_id);
let _ = ctx.insert_parsed_symbol(handler, fn_decl.name.clone(), decl);
}
parsed::Declaration::TraitDeclaration(decl_id) => {
let trait_decl = engines.pe().get_trait(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, trait_decl.name.clone(), decl)?;
}
parsed::Declaration::ImplTrait(decl_id) => {
let impl_trait = engines.pe().get_impl_trait(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, impl_trait.trait_name.suffix.clone(), decl)?;
}
parsed::Declaration::ImplSelf(decl_id) => {
let impl_self = engines.pe().get_impl_self(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(
handler,
BaseIdent::new(impl_self.implementing_for.span),
decl,
)?;
}
parsed::Declaration::StructDeclaration(decl_id) => {
let struct_decl = engines.pe().get_struct(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, struct_decl.name.clone(), decl)?;
}
parsed::Declaration::AbiDeclaration(decl_id) => {
let abi_decl = engines.pe().get_abi(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, abi_decl.name.clone(), decl)?;
}
parsed::Declaration::StorageDeclaration(decl_id) => {
let _storage_decl = engines.pe().get_storage(decl_id).as_ref().clone();
//ctx.insert_parsed_symbol(handler, storage_decl.name.clone(), decl)?;
}
parsed::Declaration::TypeAliasDeclaration(decl_id) => {
let type_alias_decl = engines.pe().get_type_alias(decl_id).as_ref().clone();
ctx.insert_parsed_symbol(handler, type_alias_decl.name, decl.clone())?;
}
};

Ok(())
}

pub(crate) fn type_check(
handler: &Handler,
mut ctx: TypeCheckContext,
Expand Down
21 changes: 20 additions & 1 deletion sway-core/src/semantic_analysis/ast_node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
language::{parsed::*, ty},
semantic_analysis::*,
type_system::*,
Ident,
Engines, Ident,
};

use sway_error::{
Expand All @@ -19,7 +19,26 @@ use sway_error::{
};
use sway_types::{span::Span, Spanned};

use super::collection_context::SymbolCollectionContext;

impl ty::TyAstNode {
pub(crate) fn collect(
handler: &Handler,
engines: &Engines,
ctx: &mut SymbolCollectionContext,
node: &AstNode,
) -> Result<(), ErrorEmitted> {
match node.content.clone() {
AstNodeContent::UseStatement(_a) => {}
AstNodeContent::IncludeStatement(_i) => (),
AstNodeContent::Declaration(decl) => ty::TyDecl::collect(handler, engines, ctx, decl)?,
AstNodeContent::Expression(_expr) => (),
AstNodeContent::Error(_spans, _err) => (),
};

Ok(())
}

pub(crate) fn type_check(
handler: &Handler,
mut ctx: TypeCheckContext,
Expand Down
64 changes: 64 additions & 0 deletions sway-core/src/semantic_analysis/collection_context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::{
language::{parsed::Declaration, Visibility},
semantic_analysis::Namespace,
};
use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::{span::Span, Ident};

#[derive(Clone)]
/// Contextual state tracked and accumulated throughout symbol collecting.
pub struct SymbolCollectionContext {
/// The namespace context accumulated throughout symbol collecting.
pub(crate) namespace: Namespace,
}

impl SymbolCollectionContext {
/// Initialize a context at the top-level of a module with its namespace.
pub fn new(namespace: Namespace) -> Self {
Self { namespace }
}

/// Scope the `CollectionContext` with a new lexical scope.
pub fn scoped<T>(
mut self,
with_scoped_ctx: impl FnOnce(SymbolCollectionContext) -> Result<T, ErrorEmitted>,
) -> Result<T, ErrorEmitted> {
self.namespace.module_mut().push_new_lexical_scope();
let ret = with_scoped_ctx(self.clone());
self.namespace.module_mut().pop_lexical_scope();
ret
}

/// Enter the submodule with the given name and produce a collection context ready for
/// collecting its content.
///
/// Returns the result of the given `with_submod_ctx` function.
pub fn enter_submodule<T>(
&mut self,
mod_name: Ident,
visibility: Visibility,
module_span: Span,
with_submod_ctx: impl FnOnce(&mut SymbolCollectionContext) -> T,
) -> T {
self.namespace
.push_new_submodule(mod_name, visibility, module_span);
//let Self { namespace, .. } = self;
//let mut submod_ns = namespace.enter_submodule(mod_name, visibility, module_span);
let ret = with_submod_ctx(self);
self.namespace.pop_submodule();
ret
}

/// Short-hand for calling [Items::insert_parsed_symbol].
pub(crate) fn insert_parsed_symbol(
&mut self,
_handler: &Handler,
name: Ident,
item: Declaration,
) -> Result<(), ErrorEmitted> {
self.namespace
.module_mut()
.current_items_mut()
.insert_parsed_symbol(name, item)
}
}
61 changes: 60 additions & 1 deletion sway-core/src/semantic_analysis/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ use crate::{
Engines, TypeInfo,
};

use super::declaration::auto_impl::AutoImplAbiEncodeContext;
use super::{
collection_context::SymbolCollectionContext, declaration::auto_impl::AutoImplAbiEncodeContext,
};

#[derive(Clone, Debug)]
pub struct ModuleDepGraphEdge();
Expand Down Expand Up @@ -215,6 +217,44 @@ impl ty::TyModule {
Ok(dep_graph)
}

/// Collects the given parsed module to produce a module symbol map.
///
/// Recursively collects submodules first.
pub fn collect(
handler: &Handler,
engines: &Engines,
ctx: &mut SymbolCollectionContext,
parsed: &ParseModule,
module_eval_order: &ModuleEvaluationOrder,
) -> Result<(), ErrorEmitted> {
let ParseModule {
submodules,
tree,
attributes: _,
span: _,
hash: _,
..
} = parsed;

// Analyze submodules first in order of evaluation previously computed by the dependency graph.
module_eval_order.iter().for_each(|eval_mod_name| {
let (name, submodule) = submodules
.iter()
.find(|(submod_name, _submodule)| eval_mod_name == submod_name)
.unwrap();
let _ = ty::TySubmodule::collect(handler, engines, ctx, name.clone(), submodule);
});

let _ = tree
.root_nodes
.iter()
.map(|node| ty::TyAstNode::collect(handler, engines, ctx, node))
.filter_map(|res| res.ok())
.collect::<Vec<_>>();

Ok(())
}

/// Type-check the given parsed module to produce a typed module.
///
/// Recursively type-checks submodules first.
Expand Down Expand Up @@ -394,6 +434,25 @@ impl ty::TySubmodule {
Ok(())
}

pub fn collect(
handler: &Handler,
engines: &Engines,
parent_ctx: &mut SymbolCollectionContext,
mod_name: ModName,
submodule: &ParseSubmodule,
) -> Result<(), ErrorEmitted> {
let ParseSubmodule {
module,
mod_name_span: _,
visibility,
} = submodule;
let modules_dep_graph = ty::TyModule::build_dep_graph(handler, module)?;
let module_eval_order = modules_dep_graph.compute_order(handler)?;
parent_ctx.enter_submodule(mod_name, *visibility, module.span.clone(), |submod_ctx| {
ty::TyModule::collect(handler, engines, submod_ctx, module, &module_eval_order)
})
}

pub fn type_check(
handler: &Handler,
parent_ctx: TypeCheckContext,
Expand Down
14 changes: 14 additions & 0 deletions sway-core/src/semantic_analysis/namespace/lexical_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
decl_engine::*,
engine_threading::Engines,
language::{
parsed::Declaration,
ty::{self, StructAccessInfo, TyDecl, TyStorageDecl},
CallPath,
},
Expand All @@ -27,6 +28,7 @@ pub(crate) enum GlobImport {
No,
}

pub(super) type ParsedSymbolMap = im::OrdMap<Ident, Declaration>;
pub(super) type SymbolMap = im::OrdMap<Ident, ty::TyDecl>;
// The final `bool` field of `UseSynonyms` is true if the `Vec<Ident>` path is absolute.
pub(super) type UseSynonyms = im::HashMap<Ident, (Vec<Ident>, GlobImport, ty::TyDecl, bool)>;
Expand Down Expand Up @@ -55,6 +57,8 @@ pub struct LexicalScope {
/// The set of items that exist within some lexical scope via declaration or importing.
#[derive(Clone, Debug, Default)]
pub struct Items {
/// An ordered map from `Ident`s to their associated parsed declarations.
pub(crate) parsed_symbols: ParsedSymbolMap,
/// An ordered map from `Ident`s to their associated typed declarations.
pub(crate) symbols: SymbolMap,
pub(crate) implemented_traits: TraitMap,
Expand Down Expand Up @@ -123,6 +127,16 @@ impl Items {
self.symbols().keys()
}

pub(crate) fn insert_parsed_symbol(
&mut self,
name: Ident,
item: Declaration,
) -> Result<(), ErrorEmitted> {
self.parsed_symbols.insert(name, item);

Ok(())
}

pub(crate) fn insert_symbol(
&mut self,
handler: &Handler,
Expand Down
5 changes: 3 additions & 2 deletions sway-core/src/semantic_analysis/namespace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ pub(super) use trait_map::TraitMap;

use sway_types::Ident;

type ModuleName = String;

pub type Path = [Ident];
pub type PathBuf = Vec<Ident>;

type ModuleName = String;
pub type ModulePath = PathBuf;
8 changes: 4 additions & 4 deletions sway-core/src/semantic_analysis/namespace/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
lexical_scope::{GlobImport, Items, LexicalScope, SymbolMap},
root::Root,
trait_map::TraitMap,
LexicalScopeId, ModuleName, Path, PathBuf,
LexicalScopeId, ModuleName, ModulePath, Path,
};

use sway_ast::ItemConst;
Expand Down Expand Up @@ -61,7 +61,7 @@ pub struct Module {
///
/// When this is the root module, this is equal to `[]`. When this is a
/// submodule of the root called "foo", this would be equal to `[foo]`.
pub mod_path: PathBuf,
pub mod_path: ModulePath,
}

impl Default for Module {
Expand Down Expand Up @@ -245,12 +245,12 @@ impl Module {
.unwrap()
}

/// The collection of items declared by this module's root lexical scope.
/// The collection of items declared by this module's current lexical scope.
pub fn current_items(&self) -> &Items {
&self.current_lexical_scope().items
}

/// The mutable collection of items declared by this module's root lexical scope.
/// The mutable collection of items declared by this module's curent lexical scope.
pub fn current_items_mut(&mut self) -> &mut Items {
&mut self.current_lexical_scope_mut().items
}
Expand Down
Loading

0 comments on commit abb5522

Please sign in to comment.