Skip to content

Commit

Permalink
Add an AST order analysis step to the compiler.
Browse files Browse the repository at this point in the history
  • Loading branch information
tritao committed Mar 22, 2024
1 parent fe77e1a commit a218645
Show file tree
Hide file tree
Showing 10 changed files with 778 additions and 49 deletions.
12 changes: 11 additions & 1 deletion sway-core/src/language/parsed/declaration/variable.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use crate::{language::parsed::Expression, Ident, TypeArgument};
use std::fmt;

use crate::{
engine_threading::DebugWithEngines, language::parsed::Expression, Engines, Ident, TypeArgument,
};

#[derive(Debug, Clone)]
pub struct VariableDeclaration {
Expand All @@ -7,3 +11,9 @@ pub struct VariableDeclaration {
pub body: Expression, // will be codeblock variant
pub is_mutable: bool,
}

impl DebugWithEngines for VariableDeclaration {
fn fmt(&self, f: &mut fmt::Formatter<'_>, _engines: &Engines) -> fmt::Result {
write!(f, "{}", self.name)
}
}
7 changes: 6 additions & 1 deletion sway-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub use debug_generation::write_dwarf;
use indexmap::IndexMap;
use metadata::MetadataManager;
use query_engine::{ModuleCacheKey, ModulePath, ProgramsCacheEntry};
use semantic_analysis::node_analysis::{NodeAnalysis, NodeAnalysisContext};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -489,18 +490,22 @@ pub fn parsed_to_ast(
let module_eval_order = modules_dep_graph.compute_order(handler)?;

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

let mut node_analysis_ctx = NodeAnalysisContext::new(engines, &symbol_collection_ctx);
let _ = parse_program.analyze(handler, &mut node_analysis_ctx);

// Type check the program.
let typed_program_opt = ty::TyProgram::type_check(
handler,
engines,
&symbol_collection_ctx,
parse_program,
initial_namespace,
package_name,
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 @@ -5,6 +5,7 @@ pub(crate) mod coins_analysis;
pub mod collection_context;
mod module;
pub mod namespace;
pub mod node_analysis;
mod node_dependencies;
mod program;
mod type_check_analysis;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ impl TyDecl {
let impl_self = engines.pe().get_impl_self(&decl_id).as_ref().clone();
let span = impl_self.block_span.clone();
let impl_trait_decl =
match ty::TyImplTrait::type_check_impl_self(handler, ctx.by_ref(), impl_self) {
match ty::TyImplTrait::type_check_impl_self(handler, ctx.by_ref(), decl_id) {
Ok(val) => val,
Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)),
};
Expand Down
73 changes: 35 additions & 38 deletions sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use sway_error::{
use sway_types::{Ident, Span, Spanned};

use crate::{
decl_engine::*,
decl_engine::{parsed_id::ParsedDeclId, *},
engine_threading::*,
language::{
parsed::*,
Expand All @@ -19,8 +19,9 @@ use crate::{
},
namespace::{IsExtendingExistingImpl, IsImplSelf, TryInsertingTraitImplOnFailure},
semantic_analysis::{
type_check_context::EnforceTypeArguments, AbiMode, ConstShadowingMode,
TyNodeDepGraphNodeId, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext,
node_analysis::{NodeAnalysis, NodeAnalysisContext, ParsedNodeDepGraphNodeId},
type_check_context::EnforceTypeArguments,
AbiMode, ConstShadowingMode, TypeCheckAnalysis, TypeCheckAnalysisContext, TypeCheckContext,
TypeCheckFinalization, TypeCheckFinalizationContext,
},
type_system::*,
Expand Down Expand Up @@ -277,19 +278,20 @@ impl TyImplTrait {
pub(crate) fn type_check_impl_self(
handler: &Handler,
ctx: TypeCheckContext,
impl_self: ImplSelf,
decl_id: ParsedDeclId<ImplSelf>,
) -> Result<ty::TyDecl, ErrorEmitted> {
let type_engine = ctx.engines.te();
let decl_engine = ctx.engines.de();
let engines = ctx.engines();

let impl_self = engines.pe().get_impl_self(&decl_id).as_ref().clone();
let ImplSelf {
impl_type_parameters,
mut implementing_for,
items,
block_span,
} = impl_self;

let type_engine = ctx.engines.te();
let decl_engine = ctx.engines.de();
let engines = ctx.engines();

// create the namespace for the impl
ctx.with_const_shadowing_mode(ConstShadowingMode::ItemStyle)
.allow_functions()
Expand Down Expand Up @@ -455,12 +457,29 @@ impl TyImplTrait {
IsExtendingExistingImpl::No,
)?;

let new_items = &impl_trait.items;

// First lets perform a node analysis pass.
// This returns a vector with ordered indexes to the items in the order that they
// should be processed.
let ordered_node_indices_opt = ty::TyImplTrait::node_analyze_impl_self_items(
handler,
ctx.by_ref(),
&decl_id,
)?;

// In case there was any issue processing the dependency graph, then lets just
// process them in the original order.
let ordered_node_indices: Vec<_> = match ordered_node_indices_opt {
Some(value) => value.iter().map(|n| n.index()).collect(),
None => (0..new_items.len()).collect(),
};

// Now lets do a partial type check of the body of the functions (while deferring full
// monomorphization of function applications). We will use this tree to perform type check
// analysis (mainly dependency analysis), and re-type check the items ordered by dependency.
let mut defer_ctx = ctx.by_ref().with_defer_monomorphization();

let new_items = &impl_trait.items;
for (item, new_item) in items.clone().into_iter().zip(new_items) {
match (item, new_item) {
(ImplItem::Fn(fn_decl_id), TyTraitItem::Fn(decl_ref)) => {
Expand Down Expand Up @@ -488,29 +507,6 @@ impl TyImplTrait {
}
}

let impl_trait_decl = decl_engine.insert(impl_trait.clone()).into();

// First lets perform an analysis pass.
// This returns a vector with ordered indexes to the items in the order that they
// should be processed.
let ordered_node_indices_opt =
if let TyDecl::ImplTrait(impl_trait) = &impl_trait_decl {
ty::TyImplTrait::type_check_analyze_impl_self_items(
handler,
ctx.by_ref(),
impl_trait,
)?
} else {
unreachable!();
};

// In case there was any issue processing the dependency graph, then lets just
// process them in the original order.
let ordered_node_indices: Vec<_> = match ordered_node_indices_opt {
Some(value) => value.iter().map(|n| n.index()).collect(),
None => (0..new_items.len()).collect(),
};

// Now lets type check the body of the functions (for real this time).
for idx in ordered_node_indices {
match (&items[idx], &new_items[idx]) {
Expand Down Expand Up @@ -575,18 +571,19 @@ impl TyImplTrait {
})
}

pub(crate) fn type_check_analyze_impl_self_items(
pub(crate) fn node_analyze_impl_self_items(
handler: &Handler,
ctx: TypeCheckContext,
impl_self: &ty::ImplTrait,
) -> Result<Option<Vec<TyNodeDepGraphNodeId>>, ErrorEmitted> {
impl_self: &ParsedDeclId<ImplSelf>,
) -> Result<Option<Vec<ParsedNodeDepGraphNodeId>>, ErrorEmitted> {
let engines = ctx.engines;
let symbol_collection_ctx = ctx.symbol_collection_ctx;
handler.scope(|handler| {
let mut analysis_ctx = TypeCheckAnalysisContext::new(engines);
let _ = impl_self.type_check_analyze(handler, &mut analysis_ctx);
let mut analysis_ctx = NodeAnalysisContext::new(engines, symbol_collection_ctx);
let _ = impl_self.analyze(handler, &mut analysis_ctx);

// Build a sub graph that just contains the items for this impl trait.
let impl_trait_node_index = analysis_ctx.nodes.get(&impl_self.decl_id.unique_id());
let impl_trait_node_index = analysis_ctx.nodes.get(&impl_self.unique_id());
let sub_graph = analysis_ctx.get_sub_graph(
*impl_trait_node_index.expect("expected a valid impl trait node id"),
);
Expand Down
1 change: 0 additions & 1 deletion sway-core/src/semantic_analysis/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@ impl ty::TyModule {
})
.collect::<Result<Vec<_>, _>>();

// TODO: Ordering should be solved across all modules prior to the beginning of type-check.
let ordered_nodes = node_dependencies::order_ast_nodes_by_dependency(
handler,
ctx.engines(),
Expand Down
10 changes: 8 additions & 2 deletions sway-core/src/semantic_analysis/namespace/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
ty::{self, TyTraitItem},
CallPath, Visibility,
},
semantic_analysis::*,
semantic_analysis::{collection_context::SymbolCollectionContext, *},
transform::to_parsed_lang,
Ident, Namespace, TypeId, TypeInfo,
};
Expand Down Expand Up @@ -166,7 +166,13 @@ impl Module {
ns.root.module.name = ns_name;
ns.root.module.is_external = true;
ns.root.module.visibility = Visibility::Public;
let type_check_ctx = TypeCheckContext::from_namespace(&mut ns, engines, experimental);
let symbol_collection_ctx = SymbolCollectionContext::new(ns.clone());
let type_check_ctx = TypeCheckContext::from_namespace(
&mut ns,
engines,
&symbol_collection_ctx,
experimental,
);
let typed_node = ty::TyAstNode::type_check(handler, type_check_ctx, ast_node).unwrap();
// get the decl out of the typed node:
// we know as an invariant this must be a const decl, as we hardcoded a const decl in
Expand Down

0 comments on commit a218645

Please sign in to comment.