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

feat: Add trait definition representation in DefCollector and HIR #2338

Merged
merged 3 commits into from
Aug 17, 2023
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
1 change: 1 addition & 0 deletions crates/noirc_frontend/src/hir/def_map/item_scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ impl ItemScope {
ModuleDefId::FunctionId(_) => add_item(&mut self.values),
ModuleDefId::TypeId(_) => add_item(&mut self.types),
ModuleDefId::TypeAliasId(_) => add_item(&mut self.types),
ModuleDefId::TraitId(_) => add_item(&mut self.types),
ModuleDefId::GlobalId(_) => add_item(&mut self.values),
}
}
Expand Down
6 changes: 5 additions & 1 deletion crates/noirc_frontend/src/hir/def_map/module_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use noirc_errors::Location;

use crate::{
node_interner::{FuncId, StmtId, StructId, TypeAliasId},
node_interner::{FuncId, StmtId, StructId, TraitId, TypeAliasId},
Ident,
};

Expand Down Expand Up @@ -69,6 +69,10 @@ impl ModuleData {
self.declare(name, id.into())
}

pub fn declare_trait(&mut self, name: Ident, id: TraitId) -> Result<(), (Ident, Ident)> {
self.declare(name, ModuleDefId::TraitId(id))
}

pub fn declare_child_module(
&mut self,
name: Ident,
Expand Down
27 changes: 25 additions & 2 deletions crates/noirc_frontend/src/hir/def_map/module_def.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use crate::node_interner::{FuncId, StmtId, StructId, TypeAliasId};
use crate::node_interner::{FuncId, StmtId, StructId, TraitId, TypeAliasId};

use super::ModuleId;

/// A generic ID that references either a module, function, type, or global
/// A generic ID that references either a module, function, type, interface or global
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ModuleDefId {
ModuleId(ModuleId),
FunctionId(FuncId),
TypeId(StructId),
TypeAliasId(TypeAliasId),
TraitId(TraitId),
GlobalId(StmtId),
}

Expand All @@ -34,6 +35,13 @@ impl ModuleDefId {
}
}

pub fn as_trait(&self) -> Option<TraitId> {
match self {
ModuleDefId::TraitId(trait_id) => Some(*trait_id),
_ => None,
}
}

pub fn as_global(&self) -> Option<StmtId> {
match self {
ModuleDefId::GlobalId(stmt_id) => Some(*stmt_id),
Expand All @@ -48,6 +56,7 @@ impl ModuleDefId {
ModuleDefId::FunctionId(_) => "function",
ModuleDefId::TypeId(_) => "type",
ModuleDefId::TypeAliasId(_) => "type alias",
ModuleDefId::TraitId(_) => "trait",
ModuleDefId::ModuleId(_) => "module",
ModuleDefId::GlobalId(_) => "global",
}
Expand Down Expand Up @@ -126,6 +135,20 @@ impl TryFromModuleDefId for TypeAliasId {
}
}

impl TryFromModuleDefId for TraitId {
fn try_from(id: ModuleDefId) -> Option<Self> {
id.as_trait()
}

fn dummy_id() -> Self {
TraitId::dummy_id()
}

fn description() -> String {
"trait".to_string()
}
}

impl TryFromModuleDefId for StmtId {
fn try_from(id: ModuleDefId) -> Option<Self> {
id.as_global()
Expand Down
4 changes: 2 additions & 2 deletions crates/noirc_frontend/src/hir/resolution/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,22 +153,22 @@ fn resolve_name_in_module(
// TODO: If impls are ever implemented, types can be used in a path
ModuleDefId::TypeId(id) => id.0,
ModuleDefId::TypeAliasId(_) => panic!("type aliases cannot be used in type namespace"),
ModuleDefId::TraitId(id) => id.0,
ModuleDefId::GlobalId(_) => panic!("globals cannot be in the type namespace"),
};

current_mod = &def_maps[&new_module_id.krate].modules[new_module_id.local_id.0];

// Check if namespace
let found_ns = current_mod.find_name(segment);

if found_ns.is_none() {
return Err(PathResolutionError::Unresolved(segment.clone()));
}

// Check if it is a contract and we're calling from a non-contract context
if current_mod.is_contract && !allow_contracts {
return Err(PathResolutionError::ExternalContractUsed(segment.clone()));
}

current_ns = found_ns;
}

Expand Down
8 changes: 6 additions & 2 deletions crates/noirc_frontend/src/hir/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::graph::CrateId;
use crate::hir::def_map::{ModuleDefId, ModuleId, TryFromModuleDefId, MAIN_FUNCTION};
use crate::hir_def::stmt::{HirAssignStatement, HirLValue, HirPattern};
use crate::node_interner::{
DefinitionId, DefinitionKind, ExprId, FuncId, NodeInterner, StmtId, StructId,
DefinitionId, DefinitionKind, ExprId, FuncId, NodeInterner, StmtId, StructId, TraitId,
};
use crate::{
hir::{def_map::CrateDefMap, resolution::path_resolver::PathResolver},
Expand All @@ -35,7 +35,7 @@ use crate::{
};
use crate::{
ArrayLiteral, ContractFunctionType, Generics, LValue, NoirStruct, NoirTypeAlias, Path, Pattern,
Shared, StructType, Type, TypeAliasType, TypeBinding, TypeVariable, UnaryOp,
Shared, StructType, Trait, Type, TypeAliasType, TypeBinding, TypeVariable, UnaryOp,
UnresolvedGenerics, UnresolvedType, UnresolvedTypeExpression, ERROR_IDENT,
};
use fm::FileId;
Expand Down Expand Up @@ -1297,6 +1297,10 @@ impl<'a> Resolver<'a> {
self.interner.get_struct(type_id)
}

pub fn get_trait(&self, type_id: TraitId) -> Shared<Trait> {
self.interner.get_trait(type_id)
}

fn lookup<T: TryFromModuleDefId>(&mut self, path: Path) -> Result<T, ResolverError> {
let span = path.span();
let id = self.resolve_path(path)?;
Expand Down
65 changes: 64 additions & 1 deletion crates/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use iter_extended::vecmap;
use noirc_abi::AbiType;
use noirc_errors::Span;

use crate::{node_interner::StructId, Ident, Signedness};
use crate::{node_interner::StructId, node_interner::TraitId, Ident, Signedness};

use super::expr::{HirCallExpression, HirExpression, HirIdent};

Expand Down Expand Up @@ -124,6 +124,39 @@ pub struct StructType {
pub span: Span,
}

#[derive(Debug, PartialEq, Eq)]
pub enum TraitItemType {
/// A function declaration in a trait.
Function {
name: Ident,
generics: Generics,
arguments: Vec<Type>,
return_type: Type,
span: Span,
},

/// A constant declaration in a trait.
Constant { name: Ident, ty: Type, span: Span },

/// A type declaration in a trait.
Type { name: Ident, ty: Type, span: Span },
}
/// Represents a trait type in the type system. Each instance of this
/// rust struct will be shared across all Type::Trait variants that represent
/// the same trait type.
#[derive(Debug, Eq)]
pub struct Trait {
/// A unique id representing this trait type. Used to check if two
/// struct traits are equal.
pub id: TraitId,

pub items: Vec<TraitItemType>,

pub name: Ident,
pub generics: Generics,
pub span: Span,
}

/// Corresponds to generic lists such as `<T, U>` in the source
/// program. The `TypeVariableId` portion is used to match two
/// type variables to check for equality, while the `TypeVariable` is
Expand All @@ -142,6 +175,36 @@ impl PartialEq for StructType {
}
}

impl std::hash::Hash for Trait {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}

impl PartialEq for Trait {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}

impl Trait {
pub fn new(
id: TraitId,
name: Ident,
span: Span,
items: Vec<TraitItemType>,
generics: Generics,
) -> Trait {
Trait { id, name, span, items, generics }
}
}

impl std::fmt::Display for Trait {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
}

impl StructType {
pub fn new(
id: StructId,
Expand Down
28 changes: 27 additions & 1 deletion crates/noirc_frontend/src/node_interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTypeAlias}
use crate::hir::def_map::{LocalModuleId, ModuleId};
use crate::hir::StorageSlot;
use crate::hir_def::stmt::HirLetStatement;
use crate::hir_def::types::{StructType, Type};
use crate::hir_def::types::{StructType, Trait, Type};
use crate::hir_def::{
expr::HirExpression,
function::{FuncMeta, HirFunction},
Expand Down Expand Up @@ -61,6 +61,15 @@ pub struct NodeInterner {
// When resolving types, check against this map to see if a type alias is defined.
type_aliases: Vec<TypeAliasType>,

// Trait map.
//
// Each trait definition is possibly shared across multiple type nodes.
// It is also mutated through the RefCell during name resolution to append
// methods from impls to the type.
//
// TODO: We may be able to remove the Shared wrapper once traits are no longer types.
// We'd just lookup their methods as needed through the NodeInterner.
jfecher marked this conversation as resolved.
Show resolved Hide resolved
traits: HashMap<TraitId, Shared<Trait>>,
/// Map from ExprId (referring to a Function/Method call) to its corresponding TypeBindings,
/// filled out during type checking from instantiated variables. Used during monomorphization
/// to map call site types back onto function parameter types, and undo this binding as needed.
Expand Down Expand Up @@ -150,6 +159,18 @@ impl TypeAliasId {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TraitId(pub ModuleId);

impl TraitId {
// dummy id for error reporting
// This can be anything, as the program will ultimately fail
// after resolution
pub fn dummy_id() -> TraitId {
TraitId(ModuleId { krate: CrateId::dummy_id(), local_id: LocalModuleId::dummy_id() })
}
}

macro_rules! into_index {
($id_type:ty) => {
impl From<$id_type> for Index {
Expand Down Expand Up @@ -262,6 +283,7 @@ impl Default for NodeInterner {
id_to_type: HashMap::new(),
structs: HashMap::new(),
type_aliases: Vec::new(),
traits: HashMap::new(),
instantiation_bindings: HashMap::new(),
field_indices: HashMap::new(),
next_type_variable_id: 0,
Expand Down Expand Up @@ -547,6 +569,10 @@ impl NodeInterner {
self.structs[&id].clone()
}

pub fn get_trait(&self, id: TraitId) -> Shared<Trait> {
self.traits[&id].clone()
}

pub fn get_type_alias(&self, id: TypeAliasId) -> &TypeAliasType {
&self.type_aliases[id.0]
}
Expand Down