diff --git a/crates/noirc_frontend/src/hir/def_map/item_scope.rs b/crates/noirc_frontend/src/hir/def_map/item_scope.rs index 760088a3b7e..7dcc5051a0c 100644 --- a/crates/noirc_frontend/src/hir/def_map/item_scope.rs +++ b/crates/noirc_frontend/src/hir/def_map/item_scope.rs @@ -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), } } diff --git a/crates/noirc_frontend/src/hir/def_map/module_data.rs b/crates/noirc_frontend/src/hir/def_map/module_data.rs index 5382ca6ad15..1a5b1692208 100644 --- a/crates/noirc_frontend/src/hir/def_map/module_data.rs +++ b/crates/noirc_frontend/src/hir/def_map/module_data.rs @@ -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, }; @@ -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, diff --git a/crates/noirc_frontend/src/hir/def_map/module_def.rs b/crates/noirc_frontend/src/hir/def_map/module_def.rs index b64ced78772..ade0fcaf7aa 100644 --- a/crates/noirc_frontend/src/hir/def_map/module_def.rs +++ b/crates/noirc_frontend/src/hir/def_map/module_def.rs @@ -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), } @@ -34,6 +35,13 @@ impl ModuleDefId { } } + pub fn as_trait(&self) -> Option { + match self { + ModuleDefId::TraitId(trait_id) => Some(*trait_id), + _ => None, + } + } + pub fn as_global(&self) -> Option { match self { ModuleDefId::GlobalId(stmt_id) => Some(*stmt_id), @@ -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", } @@ -126,6 +135,20 @@ impl TryFromModuleDefId for TypeAliasId { } } +impl TryFromModuleDefId for TraitId { + fn try_from(id: ModuleDefId) -> Option { + 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 { id.as_global() diff --git a/crates/noirc_frontend/src/hir/resolution/import.rs b/crates/noirc_frontend/src/hir/resolution/import.rs index 9a6ef9b1b8b..68796cf26bd 100644 --- a/crates/noirc_frontend/src/hir/resolution/import.rs +++ b/crates/noirc_frontend/src/hir/resolution/import.rs @@ -153,6 +153,7 @@ 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"), }; @@ -160,15 +161,14 @@ fn resolve_name_in_module( // 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; } diff --git a/crates/noirc_frontend/src/hir/resolution/resolver.rs b/crates/noirc_frontend/src/hir/resolution/resolver.rs index 945d11aae51..26c99d436cc 100644 --- a/crates/noirc_frontend/src/hir/resolution/resolver.rs +++ b/crates/noirc_frontend/src/hir/resolution/resolver.rs @@ -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}, @@ -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; @@ -1297,6 +1297,10 @@ impl<'a> Resolver<'a> { self.interner.get_struct(type_id) } + pub fn get_trait(&self, type_id: TraitId) -> Shared { + self.interner.get_trait(type_id) + } + fn lookup(&mut self, path: Path) -> Result { let span = path.span(); let id = self.resolve_path(path)?; diff --git a/crates/noirc_frontend/src/hir_def/types.rs b/crates/noirc_frontend/src/hir_def/types.rs index b29b01e1ed2..bb566880fb3 100644 --- a/crates/noirc_frontend/src/hir_def/types.rs +++ b/crates/noirc_frontend/src/hir_def/types.rs @@ -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}; @@ -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, + 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, + + pub name: Ident, + pub generics: Generics, + pub span: Span, +} + /// Corresponds to generic lists such as `` in the source /// program. The `TypeVariableId` portion is used to match two /// type variables to check for equality, while the `TypeVariable` is @@ -142,6 +175,36 @@ impl PartialEq for StructType { } } +impl std::hash::Hash for Trait { + fn hash(&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, + 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, diff --git a/crates/noirc_frontend/src/node_interner.rs b/crates/noirc_frontend/src/node_interner.rs index ad1638c3f0b..5a45cfee42b 100644 --- a/crates/noirc_frontend/src/node_interner.rs +++ b/crates/noirc_frontend/src/node_interner.rs @@ -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}, @@ -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, + // 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. + traits: HashMap>, /// 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. @@ -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 { @@ -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, @@ -547,6 +569,10 @@ impl NodeInterner { self.structs[&id].clone() } + pub fn get_trait(&self, id: TraitId) -> Shared { + self.traits[&id].clone() + } + pub fn get_type_alias(&self, id: TypeAliasId) -> &TypeAliasType { &self.type_aliases[id.0] }