diff --git a/sway-core/src/monomorphize/collect/code_block.rs b/sway-core/src/monomorphize/collect/code_block.rs new file mode 100644 index 00000000000..09903be796a --- /dev/null +++ b/sway-core/src/monomorphize/collect/code_block.rs @@ -0,0 +1,7 @@ +use crate::{language::ty, monomorphize::priv_prelude::*}; + +pub(crate) fn gather_from_code_block(ctx: GatherContext, body: &ty::TyCodeBlock) { + body.contents + .iter() + .for_each(|node| gather_from_node(ctx, &node.content)); +} diff --git a/sway-core/src/monomorphize/collect/collect_from.rs b/sway-core/src/monomorphize/collect/collect_from.rs new file mode 100644 index 00000000000..f0cf10b7659 --- /dev/null +++ b/sway-core/src/monomorphize/collect/collect_from.rs @@ -0,0 +1,217 @@ +use crate::{monomorphize::priv_prelude::*, language::ty::*}; + +pub(crate) trait CollectFrom { + fn collect_from(&self, ctx: CollectContext); +} + +impl CollectFrom for TyModule { + fn collect_from(&self, ctx: CollectContext) { + for (_, submod) in self.submodules_recursive() { + submod.module.collect_from(ctx); + } + for node in self.all_nodes.iter() { + node.content.collect_from(ctx); + } + } +} + +impl CollectFrom for TyAstNodeContent { + fn collect_from(&self, ctx: CollectContext) { + use TyAstNodeContent::*; + match self { + Declaration(decl) => { + decl.collect_from(ctx); + } + Expression(exp) => { + exp.collect_from(ctx); + } + ImplicitReturnExpression(exp) => { + exp.collect_from(ctx); + } + SideEffect(_) => {} + } + } +} + +impl CollectFrom for TyDecl { + fn collect_from(&self, ctx: CollectContext) { + use TyDecl::*; + match self { + VariableDecl(decl) => { + decl.body.collect_from(ctx); + } + ConstantDecl { .. } => todo!(), + FunctionDecl { + decl_id, + subst_list, + .. + } => { + gather_from_fn_decl(ctx, decl_id, subst_list.inner()); + } + TraitDecl { + name: _, + decl_id, + subst_list, + decl_span: _, + } => { + gather_from_trait_decl(ctx, decl_id, subst_list.inner()); + } + StructDecl { + name: _, + decl_id, + subst_list, + decl_span: _, + } => { + gather_from_struct_decl(ctx, decl_id, subst_list.inner()); + } + EnumDecl { + name: _, + decl_id, + subst_list, + decl_span: _, + } => { + gather_from_enum_decl(ctx, decl_id, subst_list.inner()); + } + EnumVariantDecl { .. } => todo!(), + ImplTrait { .. } => todo!(), + AbiDecl { .. } => todo!(), + GenericTypeForFunctionScope { .. } => todo!(), + StorageDecl { .. } => todo!(), + ErrorRecovery(_) => {} + TypeAliasDecl { .. } => todo!(), + } + } +} + +impl CollectFrom for TyFunctionDecl { + fn collect_from(&self, ctx: CollectContext) { + ctx.add_constraint(Constraint::mk_fn_decl(decl_id, subst_list)); + let fn_decl = ctx.decl_engine.get_function(decl_id); + for param in fn_decl.parameters { + gather_from_ty(ctx, param.type_argument.type_id); + } + gather_from_ty(ctx, fn_decl.return_type.type_id); + gather_from_code_block(ctx, &fn_decl.body); + } +} + +impl CollectFrom for TyStructDecl { + fn collect_from(&self, ctx: CollectContext) { + ctx.add_constraint(Constraint::mk_struct_decl(decl_id, subst_list)); + let struct_decl = ctx.decl_engine.get_struct(decl_id); + for field in struct_decl.fields { + gather_from_ty(ctx, field.type_argument.type_id); + } + } +} + +impl CollectFrom for TyEnumDecl { + fn collect_from(&self, ctx: CollectContext) { + ctx.add_constraint(Constraint::mk_enum_decl(decl_id, subst_list)); + let enum_decl = ctx.decl_engine.get_enum(decl_id); + for variant in enum_decl.variants { + gather_from_ty(ctx, variant.type_argument.type_id); + } + } +} + +impl CollectFrom for TyTraitDecl { + fn collect_from(&self, ctx: CollectContext) { + ctx.add_constraint(Constraint::mk_trait_decl(decl_id, subst_list)); + let trait_decl = ctx.decl_engine.get_trait(decl_id); + todo!(); + } +} + +impl CollectFrom for TyExpression { + fn collect_from(&self, ctx: CollectContext) { + gather_from_ty(ctx, return_type); + self.expression.collect_from(ctx); + } +} + +impl CollectFrom for TyExpressionVariant { + fn collect_from(&self, ctx: CollectContext) { + use TyExpressionVariant::*; + match exp { + FunctionApplication { + arguments, + contract_call_params, + call_path, + fn_ref, + .. + } => { + arguments + .iter() + .for_each(|(_, arg)| { + arg.collect_from(ctx); + }); + contract_call_params + .iter() + .for_each(|(_, arg)| { + arg.collect_from(ctx); + }); + ctx.add_constraint(Constraint::mk_fn_call(call_path, arguments, fn_ref)); + } + LazyOperator { lhs, rhs, .. } => { + lhs.collect_from(ctx); + rhs.collect_from(ctx); + } + VariableExpression { .. } => { + // NOTE: may need to do something here later + } + Tuple { fields } => { + fields.iter().for_each(|field| { + field.collect_from(ctx); + }); + } + Array { + contents: _, + elem_type: _, + } => { + todo!(); + // contents + // .iter() + // .for_each(|elem| gather_from_exp(ctx, elem)); + } + ArrayIndex { + prefix: _, + index: _, + } => { + todo!(); + // gather_from_exp(ctx, prefix); + // gather_from_exp(ctx, index); + } + StructExpression { .. } => todo!(), + CodeBlock(block) => { + gather_from_code_block(ctx, block); + } + IfExp { .. } => todo!(), + MatchExp { .. } => todo!(), + AsmExpression { .. } => todo!(), + StructFieldAccess { .. } => todo!(), + TupleElemAccess { prefix, .. } => { + prefix.collect_from(ctx); + } + EnumInstantiation { .. } => todo!(), + AbiCast { .. } => todo!(), + StorageAccess(_) => todo!(), + IntrinsicFunction(_) => todo!(), + AbiName(_) => todo!(), + EnumTag { exp } => { + exp.collect_from(ctx); + } + UnsafeDowncast { .. } => todo!(), + WhileLoop { .. } => todo!(), + Reassignment(_) => todo!(), + StorageReassignment(_) => todo!(), + Return(exp) => { + exp.collect_from(ctx); + } + Literal(_) => {} + Break => {} + Continue => {} + FunctionParameter => {} + } + } +} diff --git a/sway-core/src/monomorphize/collect/context.rs b/sway-core/src/monomorphize/collect/context.rs new file mode 100644 index 00000000000..485b3cc334b --- /dev/null +++ b/sway-core/src/monomorphize/collect/context.rs @@ -0,0 +1,54 @@ +use hashbrown::{hash_map::RawEntryMut, HashMap}; +use std::sync::RwLock; + +use crate::{decl_engine::*, engine_threading::*, monomorphize::priv_prelude::*, TypeEngine}; + +/// Contextual state tracked and accumulated throughout collecting information +/// for monomorphization. +#[derive(Clone, Copy)] +pub(crate) struct CollectContext<'a> { + /// The type engine storing types. + pub(crate) type_engine: &'a TypeEngine, + + /// The declaration engine holds declarations. + pub(crate) decl_engine: &'a DeclEngine, + + /// The list of constraints. + /// NOTE: This only needs to be a [HashSet][hashbrown::HashSet], but there + /// isn't the right method implement on that data type for what we need, so + /// instead we use a dummy [HashMap][hashbrown::HashMap]. + constraints: &'a RwLock>, +} + +impl<'a> CollectContext<'a> { + /// Initialize a context. + pub(crate) fn new( + engines: Engines<'a>, + constraints: &'a RwLock>, + ) -> CollectContext<'a> { + let (type_engine, decl_engine) = engines.unwrap(); + Self { + type_engine, + decl_engine, + constraints, + } + } + + pub(crate) fn add_constraint(&self, constraint: Constraint) { + let engines = Engines::new(self.type_engine, self.decl_engine); + let mut constraints = self.constraints.write().unwrap(); + let hash_builder = constraints.hasher().clone(); + let constraint_hash = make_hasher(&hash_builder, engines)(&constraint); + let raw_entry = constraints + .raw_entry_mut() + .from_hash(constraint_hash, |x| x.eq(&constraint, engines)); + if let RawEntryMut::Vacant(v) = raw_entry { + v.insert_with_hasher( + constraint_hash, + constraint, + 0, + make_hasher(&hash_builder, engines), + ); + } + } +} diff --git a/sway-core/src/monomorphize/collect/declaration.rs b/sway-core/src/monomorphize/collect/declaration.rs new file mode 100644 index 00000000000..f4a3f4d3f2f --- /dev/null +++ b/sway-core/src/monomorphize/collect/declaration.rs @@ -0,0 +1,93 @@ +use crate::{decl_engine::DeclId, language::ty::*, monomorphize::priv_prelude::*, type_system::*}; + +pub(crate) fn gather_from_decl(ctx: GatherContext, decl: &TyDecl) { + use TyDecl::*; + match decl { + VariableDecl(decl) => { + gather_from_exp(ctx, &decl.body); + } + ConstantDecl { .. } => todo!(), + FunctionDecl { + decl_id, + subst_list, + .. + } => { + gather_from_fn_decl(ctx, decl_id, subst_list.inner()); + } + TraitDecl { + name: _, + decl_id, + subst_list, + decl_span: _, + } => { + gather_from_trait_decl(ctx, decl_id, subst_list.inner()); + } + StructDecl { + name: _, + decl_id, + subst_list, + decl_span: _, + } => { + gather_from_struct_decl(ctx, decl_id, subst_list.inner()); + } + EnumDecl { + name: _, + decl_id, + subst_list, + decl_span: _, + } => { + gather_from_enum_decl(ctx, decl_id, subst_list.inner()); + } + EnumVariantDecl { .. } => todo!(), + ImplTrait { .. } => todo!(), + AbiDecl { .. } => todo!(), + GenericTypeForFunctionScope { .. } => todo!(), + StorageDecl { .. } => todo!(), + ErrorRecovery(_) => {} + TypeAliasDecl { .. } => todo!(), + } +} + +fn gather_from_fn_decl( + ctx: GatherContext, + decl_id: &DeclId, + subst_list: &SubstList, +) { + ctx.add_constraint(Constraint::mk_fn_decl(decl_id, subst_list)); + let fn_decl = ctx.decl_engine.get_function(decl_id); + for param in fn_decl.parameters { + gather_from_ty(ctx, param.type_argument.type_id); + } + gather_from_ty(ctx, fn_decl.return_type.type_id); + gather_from_code_block(ctx, &fn_decl.body); +} + +fn gather_from_trait_decl( + ctx: GatherContext, + decl_id: &DeclId, + subst_list: &SubstList, +) { + ctx.add_constraint(Constraint::mk_trait_decl(decl_id, subst_list)); + let trait_decl = ctx.decl_engine.get_trait(decl_id); + todo!(); +} + +fn gather_from_struct_decl( + ctx: GatherContext, + decl_id: &DeclId, + subst_list: &SubstList, +) { + ctx.add_constraint(Constraint::mk_struct_decl(decl_id, subst_list)); + let struct_decl = ctx.decl_engine.get_struct(decl_id); + for field in struct_decl.fields { + gather_from_ty(ctx, field.type_argument.type_id); + } +} + +fn gather_from_enum_decl(ctx: GatherContext, decl_id: &DeclId, subst_list: &SubstList) { + ctx.add_constraint(Constraint::mk_enum_decl(decl_id, subst_list)); + let enum_decl = ctx.decl_engine.get_enum(decl_id); + for variant in enum_decl.variants { + gather_from_ty(ctx, variant.type_argument.type_id); + } +} diff --git a/sway-core/src/monomorphize/collect/expression.rs b/sway-core/src/monomorphize/collect/expression.rs new file mode 100644 index 00000000000..28de4422f5b --- /dev/null +++ b/sway-core/src/monomorphize/collect/expression.rs @@ -0,0 +1,87 @@ +use crate::{language::ty, monomorphize::priv_prelude::*, type_system::*}; + +pub(crate) fn gather_from_exp(ctx: GatherContext, exp: &ty::TyExpression) { + gather_from_exp_inner(ctx, &exp.expression, exp.return_type) +} + +pub(crate) fn gather_from_exp_inner( + ctx: GatherContext, + exp: &ty::TyExpressionVariant, + return_type: TypeId, +) { + gather_from_ty(ctx, return_type); + match exp { + ty::TyExpressionVariant::FunctionApplication { + arguments, + contract_call_params, + call_path, + fn_ref, + .. + } => { + arguments + .iter() + .for_each(|(_, arg)| gather_from_exp(ctx, arg)); + contract_call_params + .iter() + .for_each(|(_, arg)| gather_from_exp(ctx, arg)); + ctx.add_constraint(Constraint::mk_fn_call(call_path, arguments, fn_ref)); + } + ty::TyExpressionVariant::LazyOperator { lhs, rhs, .. } => { + gather_from_exp(ctx, lhs); + gather_from_exp(ctx, rhs); + } + ty::TyExpressionVariant::VariableExpression { .. } => { + // NOTE: may need to do something here later + } + ty::TyExpressionVariant::Tuple { fields } => { + fields.iter().for_each(|field| gather_from_exp(ctx, field)); + } + ty::TyExpressionVariant::Array { + contents: _, + elem_type: _, + } => { + todo!(); + // contents + // .iter() + // .for_each(|elem| gather_from_exp(ctx, elem)); + } + ty::TyExpressionVariant::ArrayIndex { + prefix: _, + index: _, + } => { + todo!(); + // gather_from_exp(ctx, prefix); + // gather_from_exp(ctx, index); + } + ty::TyExpressionVariant::StructExpression { .. } => todo!(), + ty::TyExpressionVariant::CodeBlock(block) => { + gather_from_code_block(ctx, block); + } + ty::TyExpressionVariant::IfExp { .. } => todo!(), + ty::TyExpressionVariant::MatchExp { .. } => todo!(), + ty::TyExpressionVariant::AsmExpression { .. } => todo!(), + ty::TyExpressionVariant::StructFieldAccess { .. } => todo!(), + ty::TyExpressionVariant::TupleElemAccess { prefix, .. } => { + gather_from_exp(ctx, prefix); + } + ty::TyExpressionVariant::EnumInstantiation { .. } => todo!(), + ty::TyExpressionVariant::AbiCast { .. } => todo!(), + ty::TyExpressionVariant::StorageAccess(_) => todo!(), + ty::TyExpressionVariant::IntrinsicFunction(_) => todo!(), + ty::TyExpressionVariant::AbiName(_) => todo!(), + ty::TyExpressionVariant::EnumTag { exp } => { + gather_from_exp(ctx, exp); + } + ty::TyExpressionVariant::UnsafeDowncast { .. } => todo!(), + ty::TyExpressionVariant::WhileLoop { .. } => todo!(), + ty::TyExpressionVariant::Reassignment(_) => todo!(), + ty::TyExpressionVariant::StorageReassignment(_) => todo!(), + ty::TyExpressionVariant::Return(exp) => { + gather_from_exp(ctx, exp); + } + ty::TyExpressionVariant::Literal(_) => {} + ty::TyExpressionVariant::Break => {} + ty::TyExpressionVariant::Continue => {} + ty::TyExpressionVariant::FunctionParameter => {} + } +} diff --git a/sway-core/src/monomorphize/collect/mod.rs b/sway-core/src/monomorphize/collect/mod.rs new file mode 100644 index 00000000000..5b0a384b8fe --- /dev/null +++ b/sway-core/src/monomorphize/collect/mod.rs @@ -0,0 +1,29 @@ +//! This module gathers a list of [Constraint]s from a typed AST. + +pub(crate) mod code_block; +pub(crate) mod context; +pub(crate) mod declaration; +pub(crate) mod expression; +pub(crate) mod module; +pub(crate) mod node; +pub(crate) mod type_system; +pub(crate) mod collect_from; + +use std::sync::RwLock; + +use hashbrown::HashMap; + +use crate::{language::ty::*, monomorphize::priv_prelude::*, Engines}; + +/// Gathers [Constraint]s from a typed AST. +pub(super) fn gather_constraints( + engines: Engines<'_>, + module: &TyModule, +) -> impl IntoIterator { + let constraints = RwLock::new(HashMap::new()); + let ctx = GatherContext::new(engines, &constraints); + + gather_from_root(ctx, module); + + constraints.into_inner().unwrap().into_keys() +} diff --git a/sway-core/src/monomorphize/collect/module.rs b/sway-core/src/monomorphize/collect/module.rs new file mode 100644 index 00000000000..a6f683dce71 --- /dev/null +++ b/sway-core/src/monomorphize/collect/module.rs @@ -0,0 +1,19 @@ +use crate::{language::ty, monomorphize::priv_prelude::*}; + +pub(crate) fn gather_from_root(ctx: GatherContext, module: &ty::TyModule) { + for (_, submod) in module.submodules_recursive() { + gather_from_module(ctx, &submod.module); + } + for node in module.all_nodes.iter() { + gather_from_node(ctx, &node.content); + } +} + +pub(crate) fn gather_from_module(ctx: GatherContext, module: &ty::TyModule) { + for (_, submod) in module.submodules_recursive() { + gather_from_module(ctx, &submod.module); + } + for node in module.all_nodes.iter() { + gather_from_node(ctx, &node.content); + } +} diff --git a/sway-core/src/monomorphize/collect/node.rs b/sway-core/src/monomorphize/collect/node.rs new file mode 100644 index 00000000000..ed62adb9a33 --- /dev/null +++ b/sway-core/src/monomorphize/collect/node.rs @@ -0,0 +1,16 @@ +use crate::{language::ty, monomorphize::priv_prelude::*}; + +pub(crate) fn gather_from_node(ctx: GatherContext, node: &ty::TyAstNodeContent) { + match node { + ty::TyAstNodeContent::Declaration(decl) => { + gather_from_decl(ctx, decl); + } + ty::TyAstNodeContent::Expression(exp) => { + gather_from_exp(ctx, exp); + } + ty::TyAstNodeContent::ImplicitReturnExpression(exp) => { + gather_from_exp(ctx, exp); + } + ty::TyAstNodeContent::SideEffect(_) => {} + } +} diff --git a/sway-core/src/monomorphize/collect/type_system.rs b/sway-core/src/monomorphize/collect/type_system.rs new file mode 100644 index 00000000000..d619d7dbf7c --- /dev/null +++ b/sway-core/src/monomorphize/collect/type_system.rs @@ -0,0 +1,83 @@ +use crate::{monomorphize::priv_prelude::*, type_system::*}; + +pub(crate) fn gather_from_ty(ctx: GatherContext, type_id: TypeId) { + use TypeInfo::*; + let type_engine = ctx.type_engine; + match type_engine.get(type_id) { + UnknownGeneric { + name: _, + trait_constraints, + } => gather_from_trait_constraints(ctx, trait_constraints.0), + Enum(enum_ref) => { + ctx.add_constraint(Constraint::mk_enum_decl( + enum_ref.id(), + enum_ref.subst_list(), + )); + } + Struct(struct_ref) => { + ctx.add_constraint(Constraint::mk_struct_decl( + struct_ref.id(), + struct_ref.subst_list(), + )); + } + Tuple(elems) => { + for elem in elems { + gather_from_ty(ctx, elem.type_id); + } + } + ContractCaller { + abi_name: _, + address, + } => { + if let Some(address) = address { + gather_from_exp(ctx, &address); + } + } + Custom { + call_path: _, + type_arguments, + } => { + if let Some(type_args) = type_arguments { + for type_arg in type_args { + gather_from_ty(ctx, type_arg.type_id); + } + } + } + Array(ty, _) => { + gather_from_ty(ctx, ty.type_id); + } + Storage { fields } => { + for field in fields { + gather_from_ty(ctx, field.type_argument.type_id); + } + } + Alias { name: _, ty } => { + gather_from_ty(ctx, ty.type_id); + } + Unknown + | Placeholder(_) + | TypeParam { .. } + | Str(_) + | UnsignedInteger(_) + | Boolean + | SelfType + | B256 + | Numeric + | Contract + | ErrorRecovery + | RawUntypedPtr + | RawUntypedSlice => {} + } +} + +pub(crate) fn gather_from_trait_constraints(ctx: GatherContext, constraints: Vec) { + for c in constraints { + let TraitConstraint { + trait_name: _, + type_arguments, + } = c; + for type_arg in type_arguments { + gather_from_ty(ctx, type_arg.type_id); + } + } +} diff --git a/sway-core/src/monomorphize/mod.rs b/sway-core/src/monomorphize/mod.rs index 49bcf93c0ac..a81663509f1 100644 --- a/sway-core/src/monomorphize/mod.rs +++ b/sway-core/src/monomorphize/mod.rs @@ -8,6 +8,9 @@ mod instructions; mod priv_prelude; mod solve; mod state_graphs; +mod collect; +mod state_graph; +mod mono_item; use std::sync::RwLock; diff --git a/sway-core/src/monomorphize/mono_item.rs b/sway-core/src/monomorphize/mono_item.rs new file mode 100644 index 00000000000..85473212eac --- /dev/null +++ b/sway-core/src/monomorphize/mono_item.rs @@ -0,0 +1,14 @@ +use crate::{decl_engine::DeclId, language::ty::*, type_system::*}; + + +pub(crate) enum MonoItem { + MonoFn(DeclId, SubstList), + MonoStruct(DeclId, SubstList), + MonoEnum(DeclId, SubstList), + MonoTrait(DeclId, SubstList), + MonoImplTrait(DeclId, SubstList), + MonoStorage(DeclId), + MonoAbi(DeclId), + MonoConstant(DeclId), + MonoTypeAlias(DeclId), +} diff --git a/sway-core/src/monomorphize/priv_prelude.rs b/sway-core/src/monomorphize/priv_prelude.rs index 507741708ad..8ed89664cbb 100644 --- a/sway-core/src/monomorphize/priv_prelude.rs +++ b/sway-core/src/monomorphize/priv_prelude.rs @@ -33,4 +33,10 @@ pub(super) use super::{ ConstraintPQ, ConstraintTick, ConstraintWrapper, }, state_graphs::StateGraphs, + state_graph::StateGraph, + mono_item::MonoItem, + collect::{ + collect_from::CollectFrom, + context::CollectContext, + } }; diff --git a/sway-core/src/monomorphize/state_graph.rs b/sway-core/src/monomorphize/state_graph.rs new file mode 100644 index 00000000000..98035fb7196 --- /dev/null +++ b/sway-core/src/monomorphize/state_graph.rs @@ -0,0 +1,7 @@ +use petgraph::Graph; + +use crate::monomorphize::priv_prelude::*; + +pub(crate) struct StateGraph { + graph: Graph +}