Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(experimental): Add Elaborator pass #4992

Merged
merged 8 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ impl ForRange {
identifier: Ident,
block: Expression,
for_loop_span: Span,
) -> StatementKind {
) -> Statement {
/// Counter used to generate unique names when desugaring
/// code in the parser requires the creation of fresh variables.
/// The parser is stateless so this is a static global instead.
Expand Down Expand Up @@ -662,7 +662,8 @@ impl ForRange {
let block = ExpressionKind::Block(BlockExpression {
statements: vec![let_array, for_loop],
});
StatementKind::Expression(Expression::new(block, for_loop_span))
let kind = StatementKind::Expression(Expression::new(block, for_loop_span));
Statement { kind, span: for_loop_span }
}
}
}
Expand Down
604 changes: 604 additions & 0 deletions compiler/noirc_frontend/src/elaborator/expressions.rs

Large diffs are not rendered by default.

159 changes: 159 additions & 0 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#![allow(unused)]
use std::{
collections::{BTreeMap, BTreeSet},
rc::Rc,
};

use crate::graph::CrateId;
use crate::hir::def_map::CrateDefMap;
use crate::{
ast::{
ArrayLiteral, ConstructorExpression, FunctionKind, IfExpression, InfixExpression, Lambda,
UnresolvedTraitConstraint, UnresolvedTypeExpression,
},
hir::{
def_collector::dc_crate::CompilationError,
resolution::{errors::ResolverError, path_resolver::PathResolver, resolver::LambdaContext},
scope::ScopeForest as GenericScopeForest,
type_check::TypeCheckError,
},
hir_def::{
expr::{
HirArrayLiteral, HirBinaryOp, HirBlockExpression, HirCallExpression, HirCastExpression,
HirConstructorExpression, HirIdent, HirIfExpression, HirIndexExpression,
HirInfixExpression, HirLambda, HirMemberAccess, HirMethodCallExpression,
HirMethodReference, HirPrefixExpression,
},
traits::TraitConstraint,
},
macros_api::{
BlockExpression, CallExpression, CastExpression, Expression, ExpressionKind, HirExpression,
HirLiteral, HirStatement, Ident, IndexExpression, Literal, MemberAccessExpression,
MethodCallExpression, NodeInterner, NoirFunction, PrefixExpression, Statement,
StatementKind, StructId,
},
node_interner::{DefinitionKind, DependencyId, ExprId, FuncId, StmtId, TraitId},
Shared, StructType, Type, TypeVariable,
};

mod expressions;
mod patterns;
mod scope;
mod statements;
mod types;

use fm::FileId;
use iter_extended::vecmap;
use noirc_errors::{Location, Span};
use regex::Regex;
use rustc_hash::FxHashSet as HashSet;

/// ResolverMetas are tagged onto each definition to track how many times they are used
#[derive(Debug, PartialEq, Eq)]
struct ResolverMeta {
num_times_used: usize,
ident: HirIdent,
warn_if_unused: bool,
}

type ScopeForest = GenericScopeForest<String, ResolverMeta>;

struct Elaborator {
scopes: ScopeForest,

errors: Vec<CompilationError>,

interner: NodeInterner,
file: FileId,

in_unconstrained_fn: bool,
nested_loops: usize,

/// True if the current module is a contract.
/// This is usually determined by self.path_resolver.module_id(), but it can
/// be overridden for impls. Impls are an odd case since the methods within resolve
/// as if they're in the parent module, but should be placed in a child module.
/// Since they should be within a child module, in_contract is manually set to false
/// for these so we can still resolve them in the parent module without them being in a contract.
in_contract: bool,
michaeljklein marked this conversation as resolved.
Show resolved Hide resolved

/// Contains a mapping of the current struct or functions's generics to
/// unique type variables if we're resolving a struct. Empty otherwise.
/// This is a Vec rather than a map to preserve the order a functions generics
/// were declared in.
generics: Vec<(Rc<String>, TypeVariable, Span)>,

/// When resolving lambda expressions, we need to keep track of the variables
/// that are captured. We do this in order to create the hidden environment
/// parameter for the lambda function.
lambda_stack: Vec<LambdaContext>,

/// Set to the current type if we're resolving an impl
self_type: Option<Type>,

/// The current dependency item we're resolving.
/// Used to link items to their dependencies in the dependency graph
current_item: Option<DependencyId>,

trait_id: Option<TraitId>,

path_resolver: Rc<dyn PathResolver>,
def_maps: BTreeMap<CrateId, CrateDefMap>,

/// In-resolution names
///
/// This needs to be a set because we can have multiple in-resolution
/// names when resolving structs that are declared in reverse order of their
/// dependencies, such as in the following case:
///
/// ```
/// struct Wrapper {
/// value: Wrapped
/// }
/// struct Wrapped {
/// }
/// ```
resolving_ids: BTreeSet<StructId>,

trait_bounds: Vec<UnresolvedTraitConstraint>,

current_function: Option<FuncId>,

/// All type variables created in the current function.
/// This map is used to default any integer type variables at the end of
/// a function (before checking trait constraints) if a type wasn't already chosen.
type_variables: Vec<Type>,

/// Trait constraints are collected during type checking until they are
/// verified at the end of a function. This is because constraints arise
/// on each variable, but it is only until function calls when the types
/// needed for the trait constraint may become known.
trait_constraints: Vec<(TraitConstraint, ExprId)>,
}

impl Elaborator {
fn elaborate_function(&mut self, function: NoirFunction, _id: FuncId) {
// This is a stub until the elaborator is connected to dc_crate
match function.kind {
FunctionKind::LowLevel => todo!(),
FunctionKind::Builtin => todo!(),
FunctionKind::Oracle => todo!(),
FunctionKind::Recursive => todo!(),
FunctionKind::Normal => {
let _body = self.elaborate_block(function.def.body);
}
}
}

fn push_scope(&mut self) {
// stub
}

fn pop_scope(&mut self) {
// stub
}

fn push_err(&mut self, error: impl Into<CompilationError>) {
self.errors.push(error.into());
}
}
Loading
Loading