Skip to content

Commit

Permalink
Introduce the symbol collection context and a symbol collection step. (
Browse files Browse the repository at this point in the history
…#5661)

## Description

This PR introduces a new symbol collection step to the compiler
pipeline, that is done after parsing but before type checking.

It collects identifiers for the top level entities in the AST and allows
referencing through a parsed declaration id.

These will be used in a subsequent PR that introduces a new AST order
resolving pass that runs before type checking, thus allowing us to get
rid of the deferred monormophization "hack", simplifying some things and
eliminating some bugs.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
  • Loading branch information
tritao authored Mar 11, 2024
1 parent 0583480 commit dc20ac2
Show file tree
Hide file tree
Showing 11 changed files with 306 additions and 25 deletions.
14 changes: 14 additions & 0 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,19 @@ pub fn parsed_to_ast(
let experimental = build_config.map(|x| x.experimental).unwrap_or_default();
let lsp_config = build_config.map(|x| x.lsp_mode.clone()).unwrap_or_default();

// Build the dependency graph for the submodules.
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 All @@ -490,6 +503,7 @@ pub fn parsed_to_ast(
initial_namespace,
package_name,
build_config,
module_eval_order,
);

check_should_abort(handler, retrigger_compilation.clone())?;
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::{Ident, Named, Spanned};
use sway_types::{BaseIdent, Ident, Named, Spanned};

use crate::{
decl_engine::{
Expand All @@ -12,14 +12,79 @@ use crate::{
},
namespace::{IsExtendingExistingImpl, IsImplSelf},
semantic_analysis::{
type_check_context::EnforceTypeArguments, ConstShadowingMode, GenericShadowingMode,
TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext, TypeCheckFinalization,
TypeCheckFinalizationContext,
collection_context::SymbolCollectionContext, type_check_context::EnforceTypeArguments,
ConstShadowingMode, GenericShadowingMode, 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)
}
}
71 changes: 66 additions & 5 deletions sway-core/src/semantic_analysis/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ use crate::{
Engines, TypeInfo,
};

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

#[derive(Clone, Debug)]
pub struct ModuleDepGraphEdge();
Expand Down Expand Up @@ -188,7 +191,7 @@ impl ModuleDepGraph {

impl ty::TyModule {
/// Analyzes the given parsed module to produce a dependency graph.
pub fn analyze(
pub fn build_dep_graph(
handler: &Handler,
parsed: &ParseModule,
) -> Result<ModuleDepGraph, ErrorEmitted> {
Expand All @@ -208,12 +211,51 @@ impl ty::TyModule {

// Analyze submodules first in order of declaration.
submodules.iter().for_each(|(name, submodule)| {
let _ = ty::TySubmodule::analyze(handler, &mut dep_graph, name.clone(), submodule);
let _ =
ty::TySubmodule::build_dep_graph(handler, &mut dep_graph, name.clone(), submodule);
});

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 @@ -418,7 +460,7 @@ impl ty::TyModule {
}

impl ty::TySubmodule {
pub fn analyze(
pub fn build_dep_graph(
_handler: &Handler,
module_dep_graph: &mut ModuleDepGraph,
mod_name: ModName,
Expand Down Expand Up @@ -454,6 +496,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 All @@ -467,7 +528,7 @@ impl ty::TySubmodule {
mod_name_span,
visibility,
} = submodule;
let modules_dep_graph = ty::TyModule::analyze(handler, module)?;
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| {
let module_res = ty::TyModule::type_check(
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 `Vec<Ident>` path is absolute.
pub(super) type UseSynonyms = im::HashMap<Ident, (Vec<Ident>, GlobImport, ty::TyDecl)>;
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;
Loading

0 comments on commit dc20ac2

Please sign in to comment.