From 5453479f72c0d5d7c6b3984dd355fa1467b58860 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 17 Jan 2025 15:18:40 -0600 Subject: [PATCH 1/2] More setup for enums --- compiler/noirc_driver/src/abi_gen.rs | 2 +- compiler/noirc_driver/src/lib.rs | 2 +- compiler/noirc_frontend/src/ast/expression.rs | 4 +- .../noirc_frontend/src/elaborator/comptime.rs | 4 +- .../src/elaborator/expressions.rs | 12 +- compiler/noirc_frontend/src/elaborator/mod.rs | 24 +- .../src/elaborator/path_resolution.rs | 14 +- .../noirc_frontend/src/elaborator/patterns.rs | 14 +- .../noirc_frontend/src/elaborator/scope.rs | 12 +- .../src/elaborator/statements.rs | 6 +- .../src/elaborator/trait_impls.rs | 2 +- .../noirc_frontend/src/elaborator/types.rs | 6 +- .../src/hir/comptime/display.rs | 4 +- .../src/hir/comptime/hir_to_display_ast.rs | 4 +- .../src/hir/comptime/interpreter/builtin.rs | 24 +- .../interpreter/builtin/builtin_helpers.rs | 15 +- .../noirc_frontend/src/hir/comptime/value.rs | 8 +- .../src/hir/def_collector/dc_crate.rs | 8 +- .../src/hir/def_collector/dc_mod.rs | 156 ++++++++++-- .../src/hir/def_collector/errors.rs | 33 +-- .../noirc_frontend/src/hir/def_map/mod.rs | 4 +- .../src/hir/def_map/module_data.rs | 4 +- .../src/hir/def_map/module_def.rs | 6 +- compiler/noirc_frontend/src/hir/mod.rs | 4 +- .../src/hir/resolution/visibility.rs | 4 +- .../src/hir/type_check/generics.rs | 4 +- compiler/noirc_frontend/src/hir_def/expr.rs | 4 +- .../noirc_frontend/src/hir_def/function.rs | 4 +- compiler/noirc_frontend/src/hir_def/types.rs | 238 ++++++++++-------- compiler/noirc_frontend/src/locations.rs | 41 ++- .../src/monomorphization/mod.rs | 6 +- compiler/noirc_frontend/src/node_interner.rs | 86 +++---- .../noirc_frontend/src/resolve_locations.rs | 6 +- compiler/noirc_frontend/src/usage_tracker.rs | 6 +- .../code_action/fill_struct_fields.rs | 2 +- tooling/lsp/src/requests/completion.rs | 22 +- .../requests/completion/completion_items.rs | 6 +- tooling/lsp/src/requests/hover.rs | 90 ++++++- tooling/lsp/src/requests/inlay_hint.rs | 12 +- .../src/trait_impl_method_stub_generator.rs | 2 +- 40 files changed, 566 insertions(+), 339 deletions(-) diff --git a/compiler/noirc_driver/src/abi_gen.rs b/compiler/noirc_driver/src/abi_gen.rs index 625a35c8d15..59b3faf1a4e 100644 --- a/compiler/noirc_driver/src/abi_gen.rs +++ b/compiler/noirc_driver/src/abi_gen.rs @@ -110,7 +110,7 @@ pub(super) fn abi_type_from_hir_type(context: &Context, typ: &Type) -> AbiType { AbiType::String { length: size } } - Type::Struct(def, args) => { + Type::DataType(def, args) => { let struct_type = def.borrow(); let fields = struct_type.get_fields(args); let fields = diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index a7e7e2d4e2f..be5cde1e0ea 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -549,7 +549,7 @@ fn compile_contract_inner( let structs = structs .into_iter() .map(|struct_id| { - let typ = context.def_interner.get_struct(struct_id); + let typ = context.def_interner.get_type(struct_id); let typ = typ.borrow(); let fields = vecmap(typ.get_fields(&[]), |(name, typ)| { (name, abi_type_from_hir_type(context, &typ)) diff --git a/compiler/noirc_frontend/src/ast/expression.rs b/compiler/noirc_frontend/src/ast/expression.rs index 9d521545e7a..1f7a37428b2 100644 --- a/compiler/noirc_frontend/src/ast/expression.rs +++ b/compiler/noirc_frontend/src/ast/expression.rs @@ -8,7 +8,7 @@ use crate::ast::{ UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, Visibility, }; use crate::node_interner::{ - ExprId, InternedExpressionKind, InternedStatementKind, QuotedTypeId, StructId, + ExprId, InternedExpressionKind, InternedStatementKind, QuotedTypeId, TypeId, }; use crate::token::{Attributes, FmtStrFragment, FunctionAttribute, Token, Tokens}; use crate::{Kind, Type}; @@ -559,7 +559,7 @@ pub struct ConstructorExpression { /// This may be filled out during macro expansion /// so that we can skip re-resolving the type name since it /// would be lost at that point. - pub struct_type: Option, + pub struct_type: Option, } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 9f5eef6e785..c13c74f44cb 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -19,7 +19,7 @@ use crate::{ resolution::errors::ResolverError, }, hir_def::expr::{HirExpression, HirIdent}, - node_interner::{DefinitionKind, DependencyId, FuncId, NodeInterner, StructId, TraitId}, + node_interner::{DefinitionKind, DependencyId, FuncId, NodeInterner, TraitId, TypeId}, parser::{Item, ItemKind}, token::{MetaAttribute, SecondaryAttribute}, Type, TypeBindings, UnificationError, @@ -512,7 +512,7 @@ impl<'context> Elaborator<'context> { pub(super) fn run_attributes( &mut self, traits: &BTreeMap, - types: &BTreeMap, + types: &BTreeMap, functions: &[UnresolvedFunctions], module_attributes: &[ModuleAttribute], ) { diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index ef2ae9c4df0..0cee880e781 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -29,7 +29,7 @@ use crate::{ }, node_interner::{DefinitionKind, ExprId, FuncId, InternedStatementKind, TraitMethodId}, token::{FmtStrFragment, Tokens}, - Kind, QuotedType, Shared, StructType, Type, + DataType, Kind, QuotedType, Shared, Type, }; use super::{Elaborator, LambdaContext, UnsafeBlockStatus}; @@ -614,12 +614,12 @@ impl<'context> Elaborator<'context> { let is_self_type = last_segment.ident.is_self_type_name(); let (r#type, struct_generics) = if let Some(struct_id) = constructor.struct_type { - let typ = self.interner.get_struct(struct_id); + let typ = self.interner.get_type(struct_id); let generics = typ.borrow().instantiate(self.interner); (typ, generics) } else { match self.lookup_type_or_error(path) { - Some(Type::Struct(r#type, struct_generics)) => (r#type, struct_generics), + Some(Type::DataType(r#type, struct_generics)) => (r#type, struct_generics), Some(typ) => { self.push_err(ResolverError::NonStructUsedInConstructor { typ: typ.to_string(), @@ -659,10 +659,10 @@ impl<'context> Elaborator<'context> { let reference_location = Location::new(last_segment.ident.span(), self.file); self.interner.add_struct_reference(struct_id, reference_location, is_self_type); - (expr, Type::Struct(struct_type, generics)) + (expr, Type::DataType(struct_type, generics)) } - pub(super) fn mark_struct_as_constructed(&mut self, struct_type: Shared) { + pub(super) fn mark_struct_as_constructed(&mut self, struct_type: Shared) { let struct_type = struct_type.borrow(); let parent_module_id = struct_type.id.parent_module_id(self.def_maps); self.usage_tracker.mark_as_used(parent_module_id, &struct_type.name); @@ -673,7 +673,7 @@ impl<'context> Elaborator<'context> { /// are part of the struct. fn resolve_constructor_expr_fields( &mut self, - struct_type: Shared, + struct_type: Shared, field_types: Vec<(String, ItemVisibility, Type)>, fields: Vec<(Ident, Expression)>, span: Span, diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index 79f6be444ce..9cbb6884433 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -32,7 +32,7 @@ use crate::{ }, node_interner::{ DefinitionKind, DependencyId, ExprId, FuncId, FunctionModifiers, GlobalId, NodeInterner, - ReferenceId, StructId, TraitId, TraitImplId, TypeAliasId, + ReferenceId, TraitId, TraitImplId, TypeAliasId, TypeId, }, token::SecondaryAttribute, Shared, Type, TypeVariable, @@ -43,7 +43,7 @@ use crate::{ hir_def::traits::ResolvedTraitBound, node_interner::GlobalValue, usage_tracker::UsageTracker, - StructField, StructType, TypeBindings, + DataType, StructField, TypeBindings, }; mod comptime; @@ -146,7 +146,7 @@ pub struct Elaborator<'context> { /// struct Wrapped { /// } /// ``` - resolving_ids: BTreeSet, + resolving_ids: BTreeSet, /// Each constraint in the `where` clause of the function currently being resolved. trait_bounds: Vec, @@ -976,7 +976,7 @@ impl<'context> Elaborator<'context> { let statements = std::mem::take(&mut func.def.body.statements); let body = BlockExpression { statements }; - let struct_id = if let Some(Type::Struct(struct_type, _)) = &self.self_type { + let struct_id = if let Some(Type::DataType(struct_type, _)) = &self.self_type { Some(struct_type.borrow().id) } else { None @@ -1024,7 +1024,7 @@ impl<'context> Elaborator<'context> { self.mark_type_as_used(typ); } } - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { self.mark_struct_as_constructed(struct_type.clone()); for generic in generics { self.mark_type_as_used(generic); @@ -1501,7 +1501,7 @@ impl<'context> Elaborator<'context> { let function_ids = functions.function_ids(); - if let Type::Struct(struct_type, _) = &self_type { + if let Type::DataType(struct_type, _) = &self_type { let struct_ref = struct_type.borrow(); // `impl`s are only allowed on types defined within the current crate @@ -1596,7 +1596,7 @@ impl<'context> Elaborator<'context> { } /// Find the struct in the parent module so we can know its visibility - fn find_struct_visibility(&self, struct_type: &StructType) -> Option { + fn find_struct_visibility(&self, struct_type: &DataType) -> Option { let parent_module_id = struct_type.id.parent_module_id(self.def_maps); let parent_module_data = self.get_module(parent_module_id); let per_ns = parent_module_data.find_name(&struct_type.name); @@ -1638,7 +1638,7 @@ impl<'context> Elaborator<'context> { span: Span, ) { match typ { - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { let struct_type = struct_type.borrow(); let struct_module_id = struct_type.id.module_id(); @@ -1708,7 +1708,7 @@ impl<'context> Elaborator<'context> { } } - fn collect_struct_definitions(&mut self, structs: &BTreeMap) { + fn collect_struct_definitions(&mut self, structs: &BTreeMap) { // This is necessary to avoid cloning the entire struct map // when adding checks after each struct field is resolved. let struct_ids = structs.keys().copied().collect::>(); @@ -1760,7 +1760,7 @@ impl<'context> Elaborator<'context> { // We need to check after all structs are resolved to // make sure every struct's fields is accurately set. for id in struct_ids { - let struct_type = self.interner.get_struct(id); + let struct_type = self.interner.get_type(id); // Only handle structs without generics as any generics args will be checked // after monomorphization when performing SSA codegen @@ -1780,14 +1780,14 @@ impl<'context> Elaborator<'context> { pub fn resolve_struct_fields( &mut self, unresolved: &NoirStruct, - struct_id: StructId, + struct_id: TypeId, ) -> Vec { self.recover_generics(|this| { this.current_item = Some(DependencyId::Struct(struct_id)); this.resolving_ids.insert(struct_id); - let struct_def = this.interner.get_struct(struct_id); + let struct_def = this.interner.get_type(struct_id); this.add_existing_generics(&unresolved.generics, &struct_def.borrow().generics); let fields = vecmap(&unresolved.fields, |field| { diff --git a/compiler/noirc_frontend/src/elaborator/path_resolution.rs b/compiler/noirc_frontend/src/elaborator/path_resolution.rs index 0d0b153b6b6..4bfb13f5f1f 100644 --- a/compiler/noirc_frontend/src/elaborator/path_resolution.rs +++ b/compiler/noirc_frontend/src/elaborator/path_resolution.rs @@ -9,7 +9,7 @@ use crate::hir::resolution::errors::ResolverError; use crate::hir::resolution::visibility::item_in_module_is_visible; use crate::locations::ReferencesTracker; -use crate::node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{FuncId, GlobalId, TraitId, TypeAliasId, TypeId}; use crate::{Shared, Type, TypeAlias}; use super::types::SELF_TYPE_NAME; @@ -27,12 +27,12 @@ pub(crate) struct PathResolution { #[derive(Debug, Clone)] pub enum PathResolutionItem { Module(ModuleId), - Struct(StructId), + Struct(TypeId), TypeAlias(TypeAliasId), Trait(TraitId), Global(GlobalId), ModuleFunction(FuncId), - StructFunction(StructId, Option, FuncId), + StructFunction(TypeId, Option, FuncId), TypeAliasFunction(TypeAliasId, Option, FuncId), TraitFunction(TraitId, Option, FuncId), } @@ -80,7 +80,7 @@ pub struct Turbofish { #[derive(Debug)] enum IntermediatePathResolutionItem { Module, - Struct(StructId, Option), + Struct(TypeId, Option), TypeAlias(TypeAliasId, Option), Trait(TraitId, Option), } @@ -124,7 +124,7 @@ impl<'context> Elaborator<'context> { let mut module_id = self.module_id(); if path.kind == PathKind::Plain && path.first_name() == Some(SELF_TYPE_NAME) { - if let Some(Type::Struct(struct_type, _)) = &self.self_type { + if let Some(Type::DataType(struct_type, _)) = &self.self_type { let struct_type = struct_type.borrow(); if path.segments.len() == 1 { return Ok(PathResolution { @@ -373,7 +373,7 @@ impl<'context> Elaborator<'context> { } fn self_type_module_id(&self) -> Option { - if let Some(Type::Struct(struct_type, _)) = &self.self_type { + if let Some(Type::DataType(struct_type, _)) = &self.self_type { Some(struct_type.borrow().id.module_id()) } else { None @@ -478,7 +478,7 @@ fn get_type_alias_module_def_id(type_alias: &Shared) -> Option Some(struct_id.borrow().id.module_id()), + Type::DataType(struct_id, _generics) => Some(struct_id.borrow().id.module_id()), Type::Alias(type_alias, _generics) => get_type_alias_module_def_id(type_alias), Type::Error => None, _ => { diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index 6a672866d7e..cb81d5f3f00 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -17,7 +17,7 @@ use crate::{ stmt::HirPattern, }, node_interner::{DefinitionId, DefinitionKind, ExprId, FuncId, GlobalId, TraitImplKind}, - Kind, Shared, StructType, Type, TypeAlias, TypeBindings, + DataType, Kind, Shared, Type, TypeAlias, TypeBindings, }; use super::{path_resolution::PathResolutionItem, Elaborator, ResolverMeta}; @@ -192,7 +192,7 @@ impl<'context> Elaborator<'context> { }; let (struct_type, generics) = match self.lookup_type_or_error(name) { - Some(Type::Struct(struct_type, struct_generics)) => (struct_type, struct_generics), + Some(Type::DataType(struct_type, struct_generics)) => (struct_type, struct_generics), None => return error_identifier(self), Some(typ) => { let typ = typ.to_string(); @@ -210,7 +210,7 @@ impl<'context> Elaborator<'context> { turbofish_span, ); - let actual_type = Type::Struct(struct_type.clone(), generics); + let actual_type = Type::DataType(struct_type.clone(), generics); let location = Location::new(span, self.file); self.unify(&actual_type, &expected_type, || TypeCheckError::TypeMismatchWithSource { @@ -250,7 +250,7 @@ impl<'context> Elaborator<'context> { #[allow(clippy::too_many_arguments)] fn resolve_constructor_pattern_fields( &mut self, - struct_type: Shared, + struct_type: Shared, fields: Vec<(Ident, Pattern)>, span: Span, expected_type: Type, @@ -434,7 +434,7 @@ impl<'context> Elaborator<'context> { pub(super) fn resolve_struct_turbofish_generics( &mut self, - struct_type: &StructType, + struct_type: &DataType, generics: Vec, unresolved_turbofish: Option>, span: Span, @@ -575,7 +575,7 @@ impl<'context> Elaborator<'context> { fn resolve_item_turbofish(&mut self, item: PathResolutionItem) -> Vec { match item { PathResolutionItem::StructFunction(struct_id, Some(generics), _func_id) => { - let struct_type = self.interner.get_struct(struct_id); + let struct_type = self.interner.get_type(struct_id); let struct_type = struct_type.borrow(); let struct_generics = struct_type.instantiate(self.interner); self.resolve_struct_turbofish_generics( @@ -886,7 +886,7 @@ impl<'context> Elaborator<'context> { fn get_type_alias_generics(type_alias: &TypeAlias, generics: &[Type]) -> Vec { let typ = type_alias.get_type(generics); match typ { - Type::Struct(_, generics) => generics, + Type::DataType(_, generics) => generics, Type::Alias(type_alias, generics) => { get_type_alias_generics(&type_alias.borrow(), &generics) } diff --git a/compiler/noirc_frontend/src/elaborator/scope.rs b/compiler/noirc_frontend/src/elaborator/scope.rs index fe01e3cb7f3..60e3ee030e9 100644 --- a/compiler/noirc_frontend/src/elaborator/scope.rs +++ b/compiler/noirc_frontend/src/elaborator/scope.rs @@ -10,8 +10,8 @@ use crate::{ expr::{HirCapturedVar, HirIdent}, traits::Trait, }, - node_interner::{DefinitionId, StructId, TraitId}, - Shared, StructType, + node_interner::{DefinitionId, TraitId, TypeId}, + DataType, Shared, }; use crate::{Type, TypeAlias}; @@ -37,8 +37,8 @@ impl<'context> Elaborator<'context> { current_module } - pub(super) fn get_struct(&self, type_id: StructId) -> Shared { - self.interner.get_struct(type_id) + pub(super) fn get_struct(&self, type_id: TypeId) -> Shared { + self.interner.get_type(type_id) } pub(super) fn get_trait_mut(&mut self, trait_id: TraitId) -> &mut Trait { @@ -160,7 +160,7 @@ impl<'context> Elaborator<'context> { } /// Lookup a given struct type by name. - pub fn lookup_struct_or_error(&mut self, path: Path) -> Option> { + pub fn lookup_struct_or_error(&mut self, path: Path) -> Option> { let span = path.span(); match self.resolve_path_or_error(path) { Ok(item) => { @@ -197,7 +197,7 @@ impl<'context> Elaborator<'context> { Ok(PathResolutionItem::Struct(struct_id)) => { let struct_type = self.get_struct(struct_id); let generics = struct_type.borrow().instantiate(self.interner); - Some(Type::Struct(struct_type, generics)) + Some(Type::DataType(struct_type, generics)) } Ok(PathResolutionItem::TypeAlias(alias_id)) => { let alias = self.interner.get_type_alias(alias_id); diff --git a/compiler/noirc_frontend/src/elaborator/statements.rs b/compiler/noirc_frontend/src/elaborator/statements.rs index a01b24c2f0f..403f04842b9 100644 --- a/compiler/noirc_frontend/src/elaborator/statements.rs +++ b/compiler/noirc_frontend/src/elaborator/statements.rs @@ -21,7 +21,7 @@ use crate::{ }, }, node_interner::{DefinitionId, DefinitionKind, GlobalId, StmtId}, - StructType, Type, + DataType, Type, }; use super::{lints, Elaborator}; @@ -478,7 +478,7 @@ impl<'context> Elaborator<'context> { let lhs_type = lhs_type.follow_bindings(); match &lhs_type { - Type::Struct(s, args) => { + Type::DataType(s, args) => { let s = s.borrow(); if let Some((field, visibility, index)) = s.get_field(field_name, args) { let reference_location = Location::new(span, self.file); @@ -542,7 +542,7 @@ impl<'context> Elaborator<'context> { pub(super) fn check_struct_field_visibility( &mut self, - struct_type: &StructType, + struct_type: &DataType, field_name: &str, visibility: ItemVisibility, span: Span, diff --git a/compiler/noirc_frontend/src/elaborator/trait_impls.rs b/compiler/noirc_frontend/src/elaborator/trait_impls.rs index 20f048bed05..aa27ac29fa6 100644 --- a/compiler/noirc_frontend/src/elaborator/trait_impls.rs +++ b/compiler/noirc_frontend/src/elaborator/trait_impls.rs @@ -217,7 +217,7 @@ impl<'context> Elaborator<'context> { self.file = trait_impl.file_id; let object_crate = match &trait_impl.resolved_object_type { - Some(Type::Struct(struct_type, _)) => struct_type.borrow().id.krate(), + Some(Type::DataType(struct_type, _)) => struct_type.borrow().id.krate(), _ => CrateId::Dummy, }; diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index a1b63910a3e..15726df6562 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -154,7 +154,7 @@ impl<'context> Elaborator<'context> { let location = Location::new(named_path_span.unwrap_or(typ.span), self.file); match resolved_type { - Type::Struct(ref struct_type, _) => { + Type::DataType(ref struct_type, _) => { // Record the location of the type reference self.interner.push_type_ref_location(resolved_type.clone(), location); if !is_synthetic { @@ -288,7 +288,7 @@ impl<'context> Elaborator<'context> { self.interner.add_type_dependency(current_item, dependency_id); } - Type::Struct(struct_type, args) + Type::DataType(struct_type, args) } None => Type::Error, } @@ -1420,7 +1420,7 @@ impl<'context> Elaborator<'context> { return self.return_trait_method_in_scope(&generic_methods, method_name, span); } - if let Type::Struct(struct_type, _) = object_type { + if let Type::DataType(struct_type, _) = object_type { let has_field_with_function_type = struct_type .borrow() .get_fields_as_written() diff --git a/compiler/noirc_frontend/src/hir/comptime/display.rs b/compiler/noirc_frontend/src/hir/comptime/display.rs index ccdfdf00e72..168812125f8 100644 --- a/compiler/noirc_frontend/src/hir/comptime/display.rs +++ b/compiler/noirc_frontend/src/hir/comptime/display.rs @@ -357,7 +357,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { } Value::Struct(fields, typ) => { let typename = match typ.follow_bindings() { - Type::Struct(def, _) => def.borrow().name.to_string(), + Type::DataType(def, _) => def.borrow().name.to_string(), other => other.to_string(), }; let fields = vecmap(fields, |(name, value)| { @@ -376,7 +376,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { } Value::Quoted(tokens) => display_quoted(tokens, 0, self.interner, f), Value::StructDefinition(id) => { - let def = self.interner.get_struct(*id); + let def = self.interner.get_type(*id); let def = def.borrow(); write!(f, "{}", def.name) } diff --git a/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs b/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs index 71a462c9066..354762a2e75 100644 --- a/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs +++ b/compiler/noirc_frontend/src/hir/comptime/hir_to_display_ast.rs @@ -246,7 +246,7 @@ impl HirPattern { (name.clone(), pattern.to_display_ast(interner)) }); let name = match typ.follow_bindings() { - Type::Struct(struct_def, _) => { + Type::DataType(struct_def, _) => { let struct_def = struct_def.borrow(); struct_def.name.0.contents.clone() } @@ -301,7 +301,7 @@ impl Type { let fields = vecmap(fields, |field| field.to_display_ast()); UnresolvedTypeData::Tuple(fields) } - Type::Struct(def, generics) => { + Type::DataType(def, generics) => { let struct_def = def.borrow(); let ordered_args = vecmap(generics, |generic| generic.to_display_ast()); let generics = diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 3506b63919c..3f6b10a0176 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -403,7 +403,7 @@ fn struct_def_add_generic( }; let struct_id = get_struct(self_argument)?; - let the_struct = interner.get_struct(struct_id); + let the_struct = interner.get_type(struct_id); let mut the_struct = the_struct.borrow_mut(); let name = Rc::new(generic_name); @@ -436,7 +436,7 @@ fn struct_def_as_type( ) -> IResult { let argument = check_one_argument(arguments, location)?; let struct_id = get_struct(argument)?; - let struct_def_rc = interner.get_struct(struct_id); + let struct_def_rc = interner.get_type(struct_id); let struct_def = struct_def_rc.borrow(); let generics = vecmap(&struct_def.generics, |generic| { @@ -444,7 +444,7 @@ fn struct_def_as_type( }); drop(struct_def); - Ok(Value::Type(Type::Struct(struct_def_rc, generics))) + Ok(Value::Type(Type::DataType(struct_def_rc, generics))) } /// fn generics(self) -> [(Type, Option)] @@ -456,7 +456,7 @@ fn struct_def_generics( ) -> IResult { let argument = check_one_argument(arguments, location)?; let struct_id = get_struct(argument)?; - let struct_def = interner.get_struct(struct_id); + let struct_def = interner.get_type(struct_id); let struct_def = struct_def.borrow(); let expected = Type::Slice(Box::new(Type::Tuple(vec![ @@ -526,7 +526,7 @@ fn struct_def_fields( ) -> IResult { let (typ, generic_args) = check_two_arguments(arguments, location)?; let struct_id = get_struct(typ)?; - let struct_def = interner.get_struct(struct_id); + let struct_def = interner.get_type(struct_id); let struct_def = struct_def.borrow(); let args_location = generic_args.1; @@ -569,7 +569,7 @@ fn struct_def_fields_as_written( ) -> IResult { let argument = check_one_argument(arguments, location)?; let struct_id = get_struct(argument)?; - let struct_def = interner.get_struct(struct_id); + let struct_def = interner.get_type(struct_id); let struct_def = struct_def.borrow(); let mut fields = im::Vector::new(); @@ -607,7 +607,7 @@ fn struct_def_name( ) -> IResult { let self_argument = check_one_argument(arguments, location)?; let struct_id = get_struct(self_argument)?; - let the_struct = interner.get_struct(struct_id); + let the_struct = interner.get_type(struct_id); let name = Token::Ident(the_struct.borrow().name.to_string()); Ok(Value::Quoted(Rc::new(vec![name]))) @@ -623,7 +623,7 @@ fn struct_def_set_fields( let (the_struct, fields) = check_two_arguments(arguments, location)?; let struct_id = get_struct(the_struct)?; - let struct_def = interner.get_struct(struct_id); + let struct_def = interner.get_type(struct_id); let mut struct_def = struct_def.borrow_mut(); let field_location = fields.1; @@ -1057,7 +1057,7 @@ fn type_as_struct( location: Location, ) -> IResult { type_as(arguments, return_type, location, |typ| { - if let Type::Struct(struct_type, generics) = typ { + if let Type::DataType(struct_type, generics) = typ { Some(Value::Tuple(vec![ Value::StructDefinition(struct_type.borrow().id), Value::Slice( @@ -1432,7 +1432,7 @@ fn zeroed(return_type: Type, span: Span) -> IResult { } Type::Unit => Ok(Value::Unit), Type::Tuple(fields) => Ok(Value::Tuple(try_vecmap(fields, |field| zeroed(field, span))?)), - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { let fields = struct_type.borrow().get_fields(&generics); let mut values = HashMap::default(); @@ -1441,7 +1441,7 @@ fn zeroed(return_type: Type, span: Span) -> IResult { values.insert(Rc::new(field_name), field_value); } - let typ = Type::Struct(struct_type, generics); + let typ = Type::DataType(struct_type, generics); Ok(Value::Struct(values, typ)) } Type::Alias(alias, generics) => zeroed(alias.borrow().get_type(&generics), span), @@ -2890,7 +2890,7 @@ pub(crate) fn option(option_type: Type, value: Option, span: Span) -> IRe /// Given a type, assert that it's an Option and return the Type for T pub(crate) fn extract_option_generic_type(typ: Type) -> Type { - let Type::Struct(struct_type, mut generics) = typ else { + let Type::DataType(struct_type, mut generics) = typ else { panic!("Expected type to be a struct"); }; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs index a3f84a00bfb..342f494023d 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin/builtin_helpers.rs @@ -28,11 +28,11 @@ use crate::{ function::{FuncMeta, FunctionBody}, stmt::HirPattern, }, - node_interner::{FuncId, NodeInterner, StructId, TraitId, TraitImplId}, + node_interner::{FuncId, NodeInterner, TraitId, TraitImplId, TypeId}, token::{SecondaryAttribute, Token, Tokens}, QuotedType, Type, }; -use crate::{Kind, Shared, StructType}; +use crate::{DataType, Kind, Shared}; use rustc_hash::FxHashMap as HashMap; pub(crate) fn check_argument_count( @@ -108,14 +108,13 @@ pub(crate) fn get_struct_fields( match value { Value::Struct(fields, typ) => Ok((fields, typ)), _ => { - let expected = StructType::new( - StructId::dummy_id(), + let expected = DataType::new( + TypeId::dummy_id(), Ident::new(name.to_string(), location.span), location, Vec::new(), - Vec::new(), ); - let expected = Type::Struct(Shared::new(expected), Vec::new()); + let expected = Type::DataType(Shared::new(expected), Vec::new()); type_mismatch(value, expected, location) } } @@ -327,7 +326,7 @@ pub(crate) fn get_module((value, location): (Value, Location)) -> IResult IResult { +pub(crate) fn get_struct((value, location): (Value, Location)) -> IResult { match value { Value::StructDefinition(id) => Ok(id), _ => type_mismatch(value, Type::Quoted(QuotedType::StructDefinition), location), @@ -434,7 +433,7 @@ fn gather_hir_pattern_tokens( tokens.push(Token::RightParen); } HirPattern::Struct(typ, fields, _) => { - let Type::Struct(struct_type, _) = typ.follow_bindings() else { + let Type::DataType(struct_type, _) = typ.follow_bindings() else { panic!("Expected type to be a struct"); }; diff --git a/compiler/noirc_frontend/src/hir/comptime/value.rs b/compiler/noirc_frontend/src/hir/comptime/value.rs index 77933ba9361..c5ec7d861cd 100644 --- a/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -18,7 +18,7 @@ use crate::{ HirArrayLiteral, HirConstructorExpression, HirExpression, HirIdent, HirLambda, HirLiteral, ImplKind, }, - node_interner::{ExprId, FuncId, NodeInterner, StmtId, StructId, TraitId, TraitImplId}, + node_interner::{ExprId, FuncId, NodeInterner, StmtId, TraitId, TraitImplId, TypeId}, parser::{Item, Parser}, token::{SpannedToken, Token, Tokens}, Kind, QuotedType, Shared, Type, TypeBindings, @@ -62,7 +62,7 @@ pub enum Value { /// tokens can cause larger spans to be before lesser spans, causing an assert. They may also /// be inserted into separate files entirely. Quoted(Rc>), - StructDefinition(StructId), + StructDefinition(TypeId), TraitConstraint(TraitId, TraitGenerics), TraitDefinition(TraitId), TraitImpl(TraitImplId), @@ -234,7 +234,7 @@ impl Value { })?; let struct_type = match typ.follow_bindings() { - Type::Struct(def, _) => Some(def.borrow().id), + Type::DataType(def, _) => Some(def.borrow().id), _ => return Err(InterpreterError::NonStructInConstructor { typ, location }), }; @@ -388,7 +388,7 @@ impl Value { })?; let (r#type, struct_generics) = match typ.follow_bindings() { - Type::Struct(def, generics) => (def, generics), + Type::DataType(def, generics) => (def, generics), _ => return Err(InterpreterError::NonStructInConstructor { typ, location }), }; diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 10866f4b309..9aad806bb3c 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -16,8 +16,8 @@ use crate::hir::Context; use crate::ast::{Expression, NoirEnumeration}; use crate::node_interner::{ - FuncId, GlobalId, ModuleAttributes, NodeInterner, ReferenceId, StructId, TraitId, TraitImplId, - TypeAliasId, + FuncId, GlobalId, ModuleAttributes, NodeInterner, ReferenceId, TraitId, TraitImplId, + TypeAliasId, TypeId, }; use crate::ast::{ @@ -147,8 +147,8 @@ pub struct DefCollector { #[derive(Default)] pub struct CollectedItems { pub functions: Vec, - pub(crate) structs: BTreeMap, - pub(crate) enums: BTreeMap, + pub(crate) structs: BTreeMap, + pub(crate) enums: BTreeMap, pub(crate) type_aliases: BTreeMap, pub(crate) traits: BTreeMap, pub globals: Vec, diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 41234980942..31c4566ce10 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -17,7 +17,7 @@ use crate::ast::{ UnresolvedTypeData, }; use crate::hir::resolution::errors::ResolverError; -use crate::node_interner::{ModuleAttributes, NodeInterner, ReferenceId, StructId}; +use crate::node_interner::{ModuleAttributes, NodeInterner, ReferenceId, TypeId}; use crate::token::SecondaryAttribute; use crate::usage_tracker::{UnusedItem, UsageTracker}; use crate::{ @@ -819,7 +819,7 @@ impl<'a> ModCollector<'a> { inner_attributes: Vec, add_to_parent_scope: bool, is_contract: bool, - is_struct: bool, + is_type: bool, ) -> Result { push_child_module( &mut context.def_interner, @@ -832,7 +832,7 @@ impl<'a> ModCollector<'a> { inner_attributes, add_to_parent_scope, is_contract, - is_struct, + is_type, ) } @@ -868,7 +868,7 @@ fn push_child_module( inner_attributes: Vec, add_to_parent_scope: bool, is_contract: bool, - is_struct: bool, + is_type: bool, ) -> Result { // Note: the difference between `location` and `mod_location` is: // - `mod_location` will point to either the token "foo" in `mod foo { ... }` @@ -884,7 +884,7 @@ fn push_child_module( outer_attributes, inner_attributes, is_contract, - is_struct, + is_type, ); let module_id = def_map.modules.insert(new_module); @@ -998,7 +998,7 @@ pub fn collect_struct( module_id: LocalModuleId, krate: CrateId, definition_errors: &mut Vec<(CompilationError, FileId)>, -) -> Option<(StructId, UnresolvedStruct)> { +) -> Option<(TypeId, UnresolvedStruct)> { let doc_comments = struct_definition.doc_comments; let struct_definition = struct_definition.item; @@ -1031,7 +1031,11 @@ pub fn collect_struct( true, // is struct ) { Ok(module_id) => { - interner.new_struct(&unresolved, resolved_generics, krate, module_id.local_id, file_id) + let name = unresolved.struct_def.name.clone(); + let span = unresolved.struct_def.span; + let attributes = unresolved.struct_def.attributes.clone(); + let local_id = module_id.local_id; + interner.new_type(name, span, attributes, resolved_generics, krate, local_id, file_id) } Err(error) => { definition_errors.push((error.into(), file_id)); @@ -1081,16 +1085,97 @@ pub fn collect_struct( #[allow(clippy::too_many_arguments)] pub fn collect_enum( - _interner: &mut NodeInterner, - _def_map: &mut CrateDefMap, - _usage_tracker: &mut UsageTracker, - _enum_definition: Documented, - _file_id: FileId, - _module_id: LocalModuleId, - _krate: CrateId, - _definition_errors: &mut [(CompilationError, FileId)], -) -> Option<(StructId, UnresolvedEnum)> { - todo!("Implement collect_enum") + interner: &mut NodeInterner, + def_map: &mut CrateDefMap, + usage_tracker: &mut UsageTracker, + enum_def: Documented, + file_id: FileId, + module_id: LocalModuleId, + krate: CrateId, + definition_errors: &mut Vec<(CompilationError, FileId)>, +) -> Option<(TypeId, UnresolvedEnum)> { + let doc_comments = enum_def.doc_comments; + let enum_def = enum_def.item; + + check_duplicate_variant_names(&enum_def, file_id, definition_errors); + + let name = enum_def.name.clone(); + + let unresolved = UnresolvedEnum { file_id, module_id, enum_def }; + + let resolved_generics = Context::resolve_generics( + interner, + &unresolved.enum_def.generics, + definition_errors, + file_id, + ); + + // Create the corresponding module for the struct namespace + let location = Location::new(name.span(), file_id); + let id = match push_child_module( + interner, + def_map, + module_id, + &name, + ItemVisibility::Public, + location, + Vec::new(), + Vec::new(), + false, // add to parent scope + false, // is contract + true, // is type + ) { + Ok(module_id) => { + let name = unresolved.enum_def.name.clone(); + let span = unresolved.enum_def.span; + let attributes = unresolved.enum_def.attributes.clone(); + let local_id = module_id.local_id; + interner.new_type(name, span, attributes, resolved_generics, krate, local_id, file_id) + } + Err(error) => { + definition_errors.push((error.into(), file_id)); + return None; + } + }; + + interner.set_doc_comments(ReferenceId::Struct(id), doc_comments); + + for (index, variant) in unresolved.enum_def.variants.iter().enumerate() { + if !variant.doc_comments.is_empty() { + let id = ReferenceId::EnumVariant(id, index); + interner.set_doc_comments(id, variant.doc_comments.clone()); + } + } + + // Add the enum to scope so its path can be looked up later + let visibility = unresolved.enum_def.visibility; + let result = def_map.modules[module_id.0].declare_struct(name.clone(), visibility, id); + + let parent_module_id = ModuleId { krate, local_id: module_id }; + + if !unresolved.enum_def.is_abi() { + usage_tracker.add_unused_item( + parent_module_id, + name.clone(), + UnusedItem::Enum(id), + visibility, + ); + } + + if let Err((first_def, second_def)) = result { + let error = DefCollectorErrorKind::Duplicate { + typ: DuplicateType::TypeDefinition, + first_def, + second_def, + }; + definition_errors.push((error.into(), file_id)); + } + + if interner.is_in_lsp_mode() { + interner.register_enum(id, name.to_string(), visibility, parent_module_id); + } + + Some((id, unresolved)) } pub fn collect_impl( @@ -1333,14 +1418,35 @@ fn check_duplicate_field_names( } let previous_field_name = *seen_field_names.get(field_name).unwrap(); - definition_errors.push(( - DefCollectorErrorKind::DuplicateField { - first_def: previous_field_name.clone(), - second_def: field_name.clone(), - } - .into(), - file, - )); + let error = DefCollectorErrorKind::Duplicate { + typ: DuplicateType::StructField, + first_def: previous_field_name.clone(), + second_def: field_name.clone(), + }; + definition_errors.push((error.into(), file)); + } +} + +fn check_duplicate_variant_names( + enum_def: &NoirEnumeration, + file: FileId, + definition_errors: &mut Vec<(CompilationError, FileId)>, +) { + let mut seen_variant_names = std::collections::HashSet::new(); + for variant in &enum_def.variants { + let variant_name = &variant.item.name; + + if seen_variant_names.insert(variant_name) { + continue; + } + + let previous_variant_name = *seen_variant_names.get(variant_name).unwrap(); + let error = DefCollectorErrorKind::Duplicate { + typ: DuplicateType::EnumVariant, + first_def: previous_variant_name.clone(), + second_def: variant_name.clone(), + }; + definition_errors.push((error.into(), file)); } } diff --git a/compiler/noirc_frontend/src/hir/def_collector/errors.rs b/compiler/noirc_frontend/src/hir/def_collector/errors.rs index 1582e297144..1ca62acd29b 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/errors.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/errors.rs @@ -21,21 +21,21 @@ pub enum DuplicateType { TraitAssociatedType, TraitAssociatedConst, TraitAssociatedFunction, + StructField, + EnumVariant, } #[derive(Error, Debug, Clone)] pub enum DefCollectorErrorKind { - #[error("duplicate {typ} found in namespace")] + #[error("Duplicate {typ}")] Duplicate { typ: DuplicateType, first_def: Ident, second_def: Ident }, - #[error("duplicate struct field {first_def}")] - DuplicateField { first_def: Ident, second_def: Ident }, - #[error("unresolved import")] + #[error("Unresolved import")] UnresolvedModuleDecl { mod_name: Ident, expected_path: String, alternative_path: String }, - #[error("overlapping imports")] + #[error("Overlapping imports")] OverlappingModuleDecls { mod_name: Ident, expected_path: String, alternative_path: String }, - #[error("path resolution error")] + #[error("Path resolution error")] PathResolutionError(PathResolutionError), - #[error("cannot re-export {item_name} because it has less visibility than this use statement")] + #[error("Cannot re-export {item_name} because it has less visibility than this use statement")] CannotReexportItemWithLessVisibility { item_name: Ident, desired_visibility: ItemVisibility }, #[error("Non-struct type used in impl")] NonStructTypeInImpl { span: Span }, @@ -120,6 +120,8 @@ impl fmt::Display for DuplicateType { DuplicateType::TraitAssociatedType => write!(f, "trait associated type"), DuplicateType::TraitAssociatedConst => write!(f, "trait associated constant"), DuplicateType::TraitAssociatedFunction => write!(f, "trait associated function"), + DuplicateType::StructField => write!(f, "struct field"), + DuplicateType::EnumVariant => write!(f, "enum variant"), } } } @@ -144,23 +146,6 @@ impl<'a> From<&'a DefCollectorErrorKind> for Diagnostic { diag } } - DefCollectorErrorKind::DuplicateField { first_def, second_def } => { - let primary_message = format!( - "Duplicate definitions of struct field with name {} found", - &first_def.0.contents - ); - { - let first_span = first_def.0.span(); - let second_span = second_def.0.span(); - let mut diag = Diagnostic::simple_error( - primary_message, - "First definition found here".to_string(), - first_span, - ); - diag.add_secondary("Second definition found here".to_string(), second_span); - diag - } - } DefCollectorErrorKind::UnresolvedModuleDecl { mod_name, expected_path, alternative_path } => { let span = mod_name.0.span(); let mod_name = &mod_name.0.contents; diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index f7fc6ca08ea..3d4049a1738 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -1,7 +1,7 @@ use crate::graph::{CrateGraph, CrateId}; use crate::hir::def_collector::dc_crate::{CompilationError, DefCollector}; use crate::hir::Context; -use crate::node_interner::{FuncId, GlobalId, NodeInterner, StructId}; +use crate::node_interner::{FuncId, GlobalId, NodeInterner, TypeId}; use crate::parse_program; use crate::parser::{ParsedModule, ParserError}; use crate::token::{FunctionAttribute, SecondaryAttribute, TestScope}; @@ -356,7 +356,7 @@ pub struct ContractFunctionMeta { } pub struct ContractOutputs { - pub structs: HashMap>, + pub structs: HashMap>, pub globals: HashMap>, } diff --git a/compiler/noirc_frontend/src/hir/def_map/module_data.rs b/compiler/noirc_frontend/src/hir/def_map/module_data.rs index 06188f3920b..a9cdadf78d1 100644 --- a/compiler/noirc_frontend/src/hir/def_map/module_data.rs +++ b/compiler/noirc_frontend/src/hir/def_map/module_data.rs @@ -4,7 +4,7 @@ use noirc_errors::Location; use super::{ItemScope, LocalModuleId, ModuleDefId, ModuleId, PerNs}; use crate::ast::{Ident, ItemVisibility}; -use crate::node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{FuncId, GlobalId, TraitId, TypeAliasId, TypeId}; use crate::token::SecondaryAttribute; /// Contains the actual contents of a module: its parent (if one exists), @@ -124,7 +124,7 @@ impl ModuleData { &mut self, name: Ident, visibility: ItemVisibility, - id: StructId, + id: TypeId, ) -> Result<(), (Ident, Ident)> { self.declare(name, visibility, ModuleDefId::TypeId(id), None) } diff --git a/compiler/noirc_frontend/src/hir/def_map/module_def.rs b/compiler/noirc_frontend/src/hir/def_map/module_def.rs index a751eacd2dd..40d57ae2e23 100644 --- a/compiler/noirc_frontend/src/hir/def_map/module_def.rs +++ b/compiler/noirc_frontend/src/hir/def_map/module_def.rs @@ -1,4 +1,4 @@ -use crate::node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}; +use crate::node_interner::{FuncId, GlobalId, TraitId, TypeAliasId, TypeId}; use super::ModuleId; @@ -7,7 +7,7 @@ use super::ModuleId; pub enum ModuleDefId { ModuleId(ModuleId), FunctionId(FuncId), - TypeId(StructId), + TypeId(TypeId), TypeAliasId(TypeAliasId), TraitId(TraitId), GlobalId(GlobalId), @@ -21,7 +21,7 @@ impl ModuleDefId { } } - pub fn as_type(&self) -> Option { + pub fn as_type(&self) -> Option { match self { ModuleDefId::TypeId(type_id) => Some(*type_id), _ => None, diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index b231f8c9698..fea52be88bc 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -9,7 +9,7 @@ use crate::ast::UnresolvedGenerics; use crate::debug::DebugInstrumenter; use crate::graph::{CrateGraph, CrateId}; use crate::hir_def::function::FuncMeta; -use crate::node_interner::{FuncId, NodeInterner, StructId}; +use crate::node_interner::{FuncId, NodeInterner, TypeId}; use crate::parser::ParserError; use crate::usage_tracker::UsageTracker; use crate::{Generics, Kind, ParsedModule, ResolvedGeneric, TypeVariable}; @@ -151,7 +151,7 @@ impl Context<'_, '_> { /// /// For example, if you project contains a `main.nr` and `foo.nr` and you provide the `main_crate_id` and the /// `bar_struct_id` where the `Bar` struct is inside `foo.nr`, this function would return `foo::Bar` as a [String]. - pub fn fully_qualified_struct_path(&self, crate_id: &CrateId, id: StructId) -> String { + pub fn fully_qualified_struct_path(&self, crate_id: &CrateId, id: TypeId) -> String { fully_qualified_module_path(&self.def_maps, &self.crate_graph, crate_id, id.module_id()) } diff --git a/compiler/noirc_frontend/src/hir/resolution/visibility.rs b/compiler/noirc_frontend/src/hir/resolution/visibility.rs index 557f799df89..25806ed299d 100644 --- a/compiler/noirc_frontend/src/hir/resolution/visibility.rs +++ b/compiler/noirc_frontend/src/hir/resolution/visibility.rs @@ -1,5 +1,5 @@ use crate::graph::CrateId; -use crate::node_interner::{FuncId, NodeInterner, StructId, TraitId}; +use crate::node_interner::{FuncId, NodeInterner, TraitId, TypeId}; use crate::Type; use std::collections::BTreeMap; @@ -75,7 +75,7 @@ fn module_is_parent_of_struct_module( } pub fn struct_member_is_visible( - struct_id: StructId, + struct_id: TypeId, visibility: ItemVisibility, current_module_id: ModuleId, def_maps: &BTreeMap, diff --git a/compiler/noirc_frontend/src/hir/type_check/generics.rs b/compiler/noirc_frontend/src/hir/type_check/generics.rs index 370223f1f11..f823b495040 100644 --- a/compiler/noirc_frontend/src/hir/type_check/generics.rs +++ b/compiler/noirc_frontend/src/hir/type_check/generics.rs @@ -5,7 +5,7 @@ use iter_extended::vecmap; use crate::{ hir_def::traits::NamedType, node_interner::{FuncId, NodeInterner, TraitId, TypeAliasId}, - ResolvedGeneric, StructType, Type, + DataType, ResolvedGeneric, Type, }; /// Represents something that can be generic over type variables @@ -74,7 +74,7 @@ impl Generic for TypeAliasId { } } -impl Generic for Ref<'_, StructType> { +impl Generic for Ref<'_, DataType> { fn item_kind(&self) -> &'static str { "struct" } diff --git a/compiler/noirc_frontend/src/hir_def/expr.rs b/compiler/noirc_frontend/src/hir_def/expr.rs index 5ac228a56d6..14a3c6fc5e9 100644 --- a/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/compiler/noirc_frontend/src/hir_def/expr.rs @@ -12,7 +12,7 @@ use crate::Shared; use super::stmt::HirPattern; use super::traits::{ResolvedTraitBound, TraitConstraint}; -use super::types::{StructType, Type}; +use super::types::{DataType, Type}; /// A HirExpression is the result of an Expression in the AST undergoing /// name resolution. It is almost identical to the Expression AST node, but @@ -273,7 +273,7 @@ impl HirMethodCallExpression { #[derive(Debug, Clone)] pub struct HirConstructorExpression { - pub r#type: Shared, + pub r#type: Shared, pub struct_generics: Vec, // NOTE: It is tempting to make this a BTreeSet to force ordering of field diff --git a/compiler/noirc_frontend/src/hir_def/function.rs b/compiler/noirc_frontend/src/hir_def/function.rs index aa04738733f..33515d4888e 100644 --- a/compiler/noirc_frontend/src/hir_def/function.rs +++ b/compiler/noirc_frontend/src/hir_def/function.rs @@ -8,7 +8,7 @@ use super::traits::TraitConstraint; use crate::ast::{BlockExpression, FunctionKind, FunctionReturnType, Visibility}; use crate::graph::CrateId; use crate::hir::def_map::LocalModuleId; -use crate::node_interner::{ExprId, NodeInterner, StructId, TraitId, TraitImplId}; +use crate::node_interner::{ExprId, NodeInterner, TraitId, TraitImplId, TypeId}; use crate::{ResolvedGeneric, Type}; @@ -133,7 +133,7 @@ pub struct FuncMeta { pub trait_constraints: Vec, /// The struct this function belongs to, if any - pub struct_id: Option, + pub struct_id: Option, // The trait this function belongs to, if any pub trait_id: Option, diff --git a/compiler/noirc_frontend/src/hir_def/types.rs b/compiler/noirc_frontend/src/hir_def/types.rs index 4eeec314917..e9c561965f2 100644 --- a/compiler/noirc_frontend/src/hir_def/types.rs +++ b/compiler/noirc_frontend/src/hir_def/types.rs @@ -21,7 +21,7 @@ use noirc_printable_type::PrintableType; use crate::{ ast::{Ident, Signedness}, - node_interner::StructId, + node_interner::TypeId, }; use super::{ @@ -67,7 +67,7 @@ pub enum Type { /// A user-defined struct type. The `Shared` field here refers to /// the shared definition for each instance of this struct type. The `Vec` /// represents the generic arguments (if any) to this struct type. - Struct(Shared, Vec), + DataType(Shared, Vec), /// A user-defined alias to another type. Similar to a Struct, this carries a shared /// reference to the definition of the alias along with any generics that may have @@ -330,31 +330,46 @@ pub enum QuotedType { /// the binding to later be undone if needed. pub type TypeBindings = HashMap; -/// Represents a struct type in the type system. Each instance of this -/// rust struct will be shared across all Type::Struct variants that represent -/// the same struct type. -pub struct StructType { - /// A unique id representing this struct type. Used to check if two - /// struct types are equal. - pub id: StructId, +/// Represents a struct or enum type in the type system. Each instance of this +/// rust struct will be shared across all Type::DataType variants that represent +/// the same struct or enum type. +pub struct DataType { + /// A unique id representing this type. Used to check if two types are equal. + pub id: TypeId, pub name: Ident, - /// Fields are ordered and private, they should only - /// be accessed through get_field(), get_fields(), or instantiate() + /// A type's body is private to force struct fields or enum variants to only be + /// accessed through get_field(), get_fields(), instantiate(), or similar functions /// since these will handle applying generic arguments to fields as well. - fields: Vec, + body: TypeBody, pub generics: Generics, pub location: Location, } +enum TypeBody { + /// A type with no body is still in the process of being created + None, + Struct(Vec), + + #[allow(unused)] + Enum(Vec), +} + +#[derive(Clone)] pub struct StructField { pub visibility: ItemVisibility, pub name: Ident, pub typ: Type, } +#[derive(Clone)] +pub struct EnumVariant { + pub name: Ident, + pub params: Vec, +} + /// Corresponds to generic lists such as `` in the source program. /// Used mainly for resolved types which no longer need information such /// as names or kinds @@ -388,42 +403,35 @@ enum FunctionCoercionResult { UnconstrainedMismatch(Type), } -impl std::hash::Hash for StructType { +impl std::hash::Hash for DataType { fn hash(&self, state: &mut H) { self.id.hash(state); } } -impl Eq for StructType {} +impl Eq for DataType {} -impl PartialEq for StructType { +impl PartialEq for DataType { fn eq(&self, other: &Self) -> bool { self.id == other.id } } -impl PartialOrd for StructType { +impl PartialOrd for DataType { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for StructType { +impl Ord for DataType { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.id.cmp(&other.id) } } -impl StructType { - pub fn new( - id: StructId, - name: Ident, - - location: Location, - fields: Vec, - generics: Generics, - ) -> StructType { - StructType { id, fields, name, location, generics } +impl DataType { + pub fn new(id: TypeId, name: Ident, location: Location, generics: Generics) -> DataType { + DataType { id, name, location, generics, body: TypeBody::None } } /// To account for cyclic references between structs, a struct's @@ -431,14 +439,38 @@ impl StructType { /// created. Therefore, this method is used to set the fields once they /// become known. pub fn set_fields(&mut self, fields: Vec) { - self.fields = fields; + self.body = TypeBody::Struct(fields); } + /// Returns the number of fields this struct has. Returns 0 if this type + /// is not a struct. pub fn num_fields(&self) -> usize { - self.fields.len() + match &self.body { + TypeBody::Struct(fields) => fields.len(), + _ => 0, + } + } + + /// Retrieve the fields of this type with no modifications. + /// Panics if this is not a struct type. + fn fields_raw(&self) -> &[StructField] { + match &self.body { + TypeBody::Struct(fields) => fields, + _ => panic!("Called DataType::fields_raw on a non-struct type: {}", self.name), + } + } + + /// Retrieve the variants of this type with no modifications. + /// Panics if this is not an enum type. + fn variants_raw(&self) -> &[EnumVariant] { + match &self.body { + TypeBody::Enum(variants) => variants, + _ => panic!("Called DataType::variants_raw on a non-enum type: {}", self.name), + } } /// Returns the field matching the given field name, as well as its visibility and field index. + /// Panics if this is not a struct type. pub fn get_field( &self, field_name: &str, @@ -446,42 +478,38 @@ impl StructType { ) -> Option<(Type, ItemVisibility, usize)> { assert_eq!(self.generics.len(), generic_args.len()); - self.fields.iter().enumerate().find(|(_, field)| field.name.0.contents == field_name).map( - |(i, field)| { - let substitutions = self - .generics - .iter() - .zip(generic_args) - .map(|(old, new)| { - ( - old.type_var.id(), - (old.type_var.clone(), old.type_var.kind(), new.clone()), - ) - }) - .collect(); + let mut fields = self.fields_raw().iter().enumerate(); + fields.find(|(_, field)| field.name.0.contents == field_name).map(|(i, field)| { + let generics = self.generics.iter().zip(generic_args); + let substitutions = generics + .map(|(old, new)| { + (old.type_var.id(), (old.type_var.clone(), old.type_var.kind(), new.clone())) + }) + .collect(); - (field.typ.substitute(&substitutions), field.visibility, i) - }, - ) + (field.typ.substitute(&substitutions), field.visibility, i) + }) } /// Returns all the fields of this type, after being applied to the given generic arguments. + /// Panics if this is not a struct type. pub fn get_fields_with_visibility( &self, generic_args: &[Type], ) -> Vec<(String, ItemVisibility, Type)> { let substitutions = self.get_fields_substitutions(generic_args); - vecmap(&self.fields, |field| { + vecmap(self.fields_raw(), |field| { let name = field.name.0.contents.clone(); (name, field.visibility, field.typ.substitute(&substitutions)) }) } + /// Retrieve the fields of this type. Panics if this is not a struct type pub fn get_fields(&self, generic_args: &[Type]) -> Vec<(String, Type)> { let substitutions = self.get_fields_substitutions(generic_args); - vecmap(&self.fields, |field| { + vecmap(self.fields_raw(), |field| { let name = field.name.0.contents.clone(); (name, field.typ.substitute(&substitutions)) }) @@ -508,21 +536,35 @@ impl StructType { /// /// This method is almost never what is wanted for type checking or monomorphization, /// prefer to use `get_fields` whenever possible. + /// + /// Panics if this is not a struct type. pub fn get_fields_as_written(&self) -> Vec { - vecmap(&self.fields, |field| StructField { - visibility: field.visibility, - name: field.name.clone(), - typ: field.typ.clone(), - }) + self.fields_raw().to_vec() } - /// Returns the field at the given index. Panics if no field exists at the given index. + /// Returns the name and raw parameters of each variant of this type. + /// This will not substitute any generic arguments so a generic variant like `X` + /// in `enum Foo { X(T) }` will return a `("X", Vec)` pair. + /// + /// Panics if this is not an enum type. + pub fn get_variants_as_written(&self) -> Vec { + self.variants_raw().to_vec() + } + + /// Returns the field at the given index. Panics if no field exists at the given index or this + /// is not a struct type. pub fn field_at(&self, index: usize) -> &StructField { - &self.fields[index] + &self.fields_raw()[index] + } + + /// Returns the enum variant at the given index. Panics if no field exists at the given index + /// or this is not an enum type. + pub fn variant_at(&self, index: usize) -> &EnumVariant { + &self.variants_raw()[index] } pub fn field_names(&self) -> BTreeSet { - self.fields.iter().map(|field| field.name.clone()).collect() + self.fields_raw().iter().map(|field| field.name.clone()).collect() } /// Instantiate this struct type, returning a Vec of the new generic args (in @@ -530,9 +572,27 @@ impl StructType { pub fn instantiate(&self, interner: &mut NodeInterner) -> Vec { vecmap(&self.generics, |generic| interner.next_type_variable_with_kind(generic.kind())) } + + /// Returns the function type of the variant at the given index of this enum. + /// Requires the `Shared` handle of self to create the given function type. + /// Panics if this is not an enum. + /// + /// The function type uses the variant "as written" ie. no generic substitutions. + /// Although the returned function is technically generic, Type::Function is returned + /// instead of Type::Forall. + pub fn variant_function_type(&self, variant_index: usize, this: Shared) -> Type { + let variant = self.variant_at(variant_index); + let args = variant.params.clone(); + assert_eq!(this.borrow().id, self.id); + let generics = vecmap(&self.generics, |generic| { + Type::NamedGeneric(generic.type_var.clone(), generic.name.clone()) + }); + let ret = Box::new(Type::DataType(this, generics)); + Type::Function(args, ret, Box::new(Type::Unit), false) + } } -impl std::fmt::Display for StructType { +impl std::fmt::Display for DataType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name) } @@ -850,7 +910,7 @@ impl std::fmt::Display for Type { } } } - Type::Struct(s, args) => { + Type::DataType(s, args) => { let args = vecmap(args, |arg| arg.to_string()); if args.is_empty() { write!(f, "{}", s.borrow()) @@ -1084,7 +1144,7 @@ impl Type { alias_type.borrow().get_type(&generics).is_primitive() } Type::MutableReference(typ) => typ.is_primitive(), - Type::Struct(..) + Type::DataType(..) | Type::TypeVariable(..) | Type::TraitAsType(..) | Type::NamedGeneric(..) @@ -1145,7 +1205,7 @@ impl Type { } Type::String(length) => length.is_valid_for_program_input(), Type::Tuple(elements) => elements.iter().all(|elem| elem.is_valid_for_program_input()), - Type::Struct(definition, generics) => definition + Type::DataType(definition, generics) => definition .borrow() .get_fields(generics) .into_iter() @@ -1200,7 +1260,7 @@ impl Type { } Type::String(length) => length.is_valid_non_inlined_function_input(), Type::Tuple(elements) => elements.iter().all(|elem| elem.is_valid_non_inlined_function_input()), - Type::Struct(definition, generics) => definition + Type::DataType(definition, generics) => definition .borrow() .get_fields(generics) .into_iter() @@ -1252,7 +1312,7 @@ impl Type { Type::Tuple(elements) => { elements.iter().all(|elem| elem.is_valid_for_unconstrained_boundary()) } - Type::Struct(definition, generics) => definition + Type::DataType(definition, generics) => definition .borrow() .get_fields(generics) .into_iter() @@ -1324,7 +1384,7 @@ impl Type { | Type::FmtString(..) | Type::Unit | Type::Tuple(..) - | Type::Struct(..) + | Type::DataType(..) | Type::TraitAsType(..) | Type::Function(..) | Type::MutableReference(..) @@ -1398,7 +1458,7 @@ impl Type { let typ = typ.as_ref(); length * typ.field_count(location) } - Type::Struct(def, args) => { + Type::DataType(def, args) => { let struct_type = def.borrow(); let fields = struct_type.get_fields(args); fields.iter().fold(0, |acc, (_, field_type)| acc + field_type.field_count(location)) @@ -1439,7 +1499,7 @@ impl Type { pub(crate) fn contains_slice(&self) -> bool { match self { Type::Slice(_) => true, - Type::Struct(struct_typ, generics) => { + Type::DataType(struct_typ, generics) => { let fields = struct_typ.borrow().get_fields(generics); for field in fields.iter() { if field.1.contains_slice() { @@ -1687,7 +1747,7 @@ impl Type { // No recursive try_unify call for struct fields. Don't want // to mutate shared type variables within struct definitions. // This isn't possible currently but will be once noir gets generic types - (Struct(id_a, args_a), Struct(id_b, args_b)) => { + (DataType(id_a, args_a), DataType(id_b, args_b)) => { if id_a == id_b && args_a.len() == args_b.len() { for (a, b) in args_a.iter().zip(args_b) { a.try_unify(b, bindings)?; @@ -2037,28 +2097,6 @@ impl Type { } } - /// Iterate over the fields of this type. - /// Panics if the type is not a struct or tuple. - pub fn iter_fields(&self) -> impl Iterator { - let fields: Vec<_> = match self { - // Unfortunately the .borrow() here forces us to collect into a Vec - // only to have to call .into_iter again afterward. Trying to elide - // collecting to a Vec leads to us dropping the temporary Ref before - // the iterator is returned - Type::Struct(def, args) => vecmap(&def.borrow().fields, |field| { - let name = &field.name.0.contents; - let typ = def.borrow().get_field(name, args).unwrap().0; - (name.clone(), typ) - }), - Type::Tuple(fields) => { - let fields = fields.iter().enumerate(); - vecmap(fields, |(i, field)| (i.to_string(), field.clone())) - } - other => panic!("Tried to iterate over the fields of '{other}', which has none"), - }; - fields.into_iter() - } - /// Retrieves the type of the given field name /// Panics if the type is not a struct or tuple. pub fn get_field_type_and_visibility( @@ -2066,7 +2104,7 @@ impl Type { field_name: &str, ) -> Option<(Type, ItemVisibility)> { match self.follow_bindings() { - Type::Struct(def, args) => def + Type::DataType(def, args) => def .borrow() .get_field(field_name, &args) .map(|(typ, visibility, _)| (typ, visibility)), @@ -2266,11 +2304,11 @@ impl Type { // Do not substitute_helper fields, it can lead to infinite recursion // and we should not match fields when type checking anyway. - Type::Struct(fields, args) => { + Type::DataType(fields, args) => { let args = vecmap(args, |arg| { arg.substitute_helper(type_bindings, substitute_bound_typevars) }); - Type::Struct(fields.clone(), args) + Type::DataType(fields.clone(), args) } Type::Alias(alias, args) => { let args = vecmap(args, |arg| { @@ -2342,7 +2380,7 @@ impl Type { let field_occurs = fields.occurs(target_id); len_occurs || field_occurs } - Type::Struct(_, generic_args) | Type::Alias(_, generic_args) => { + Type::DataType(_, generic_args) | Type::Alias(_, generic_args) => { generic_args.iter().any(|arg| arg.occurs(target_id)) } Type::TraitAsType(_, _, args) => { @@ -2399,9 +2437,9 @@ impl Type { let args = Box::new(args.follow_bindings()); FmtString(size, args) } - Struct(def, args) => { + DataType(def, args) => { let args = vecmap(args, |arg| arg.follow_bindings()); - Struct(def.clone(), args) + DataType(def.clone(), args) } Alias(def, args) => { // We don't need to vecmap(args, follow_bindings) since we're recursively @@ -2499,7 +2537,7 @@ impl Type { field.replace_named_generics_with_type_variables(); } } - Type::Struct(_, generics) => { + Type::DataType(_, generics) => { for generic in generics { generic.replace_named_generics_with_type_variables(); } @@ -2601,7 +2639,7 @@ impl Type { | Type::FmtString(..) | Type::Unit | Type::Tuple(..) - | Type::Struct(..) + | Type::DataType(..) | Type::TraitAsType(..) | Type::Function(..) | Type::Forall(..) @@ -2759,7 +2797,7 @@ impl From<&Type> for PrintableType { Type::Error => unreachable!(), Type::Unit => PrintableType::Unit, Type::Constant(_, _) => unreachable!(), - Type::Struct(def, ref args) => { + Type::DataType(def, ref args) => { let struct_type = def.borrow(); let fields = struct_type.get_fields(args); let fields = vecmap(fields, |(name, typ)| (name, typ.into())); @@ -2815,7 +2853,7 @@ impl std::fmt::Debug for Type { write!(f, "{}", binding.borrow()) } } - Type::Struct(s, args) => { + Type::DataType(s, args) => { let args = vecmap(args, |arg| format!("{:?}", arg)); if args.is_empty() { write!(f, "{}", s.borrow()) @@ -2897,7 +2935,7 @@ impl std::fmt::Debug for TypeVariable { } } -impl std::fmt::Debug for StructType { +impl std::fmt::Debug for DataType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name) } @@ -2934,7 +2972,7 @@ impl std::hash::Hash for Type { env.hash(state); } Type::Tuple(elems) => elems.hash(state), - Type::Struct(def, args) => { + Type::DataType(def, args) => { def.hash(state); args.hash(state); } @@ -3005,7 +3043,7 @@ impl PartialEq for Type { lhs_len == rhs_len && lhs_env == rhs_env } (Tuple(lhs_types), Tuple(rhs_types)) => lhs_types == rhs_types, - (Struct(lhs_struct, lhs_generics), Struct(rhs_struct, rhs_generics)) => { + (DataType(lhs_struct, lhs_generics), DataType(rhs_struct, rhs_generics)) => { lhs_struct == rhs_struct && lhs_generics == rhs_generics } (Alias(lhs_alias, lhs_generics), Alias(rhs_alias, rhs_generics)) => { diff --git a/compiler/noirc_frontend/src/locations.rs b/compiler/noirc_frontend/src/locations.rs index ecae5b19a95..33c37172b50 100644 --- a/compiler/noirc_frontend/src/locations.rs +++ b/compiler/noirc_frontend/src/locations.rs @@ -7,7 +7,7 @@ use crate::{ ast::{FunctionDefinition, ItemVisibility}, hir::def_map::{ModuleDefId, ModuleId}, node_interner::{ - DefinitionId, FuncId, GlobalId, NodeInterner, ReferenceId, StructId, TraitId, TypeAliasId, + DefinitionId, FuncId, GlobalId, NodeInterner, ReferenceId, TraitId, TypeAliasId, TypeId, }, }; use petgraph::prelude::NodeIndex as PetGraphIndex; @@ -60,18 +60,22 @@ impl NodeInterner { match reference { ReferenceId::Module(id) => self.module_attributes(&id).location, ReferenceId::Function(id) => self.function_modifiers(&id).name_location, - ReferenceId::Struct(id) => { - let struct_type = self.get_struct(id); - let struct_type = struct_type.borrow(); - Location::new(struct_type.name.span(), struct_type.location.file) + ReferenceId::Struct(id) | ReferenceId::Enum(id) => { + let typ = self.get_type(id); + let typ = typ.borrow(); + Location::new(typ.name.span(), typ.location.file) } ReferenceId::StructMember(id, field_index) => { - let struct_type = self.get_struct(id); + let struct_type = self.get_type(id); let struct_type = struct_type.borrow(); - Location::new( - struct_type.field_at(field_index).name.span(), - struct_type.location.file, - ) + let file = struct_type.location.file; + Location::new(struct_type.field_at(field_index).name.span(), file) + } + ReferenceId::EnumVariant(id, variant_index) => { + let typ = self.get_type(id); + let typ = typ.borrow(); + let file = typ.location.file; + Location::new(typ.variant_at(variant_index).name.span(), file) } ReferenceId::Trait(id) => { let trait_type = self.get_trait(id); @@ -126,7 +130,7 @@ impl NodeInterner { pub(crate) fn add_struct_reference( &mut self, - id: StructId, + id: TypeId, location: Location, is_self_type: bool, ) { @@ -135,7 +139,7 @@ impl NodeInterner { pub(crate) fn add_struct_member_reference( &mut self, - id: StructId, + id: TypeId, member_index: usize, location: Location, ) { @@ -324,7 +328,7 @@ impl NodeInterner { pub(crate) fn register_struct( &mut self, - id: StructId, + id: TypeId, name: String, visibility: ItemVisibility, parent_module_id: ModuleId, @@ -333,6 +337,17 @@ impl NodeInterner { self.register_name_for_auto_import(name, ModuleDefId::TypeId(id), visibility, None); } + pub(crate) fn register_enum( + &mut self, + id: TypeId, + name: String, + visibility: ItemVisibility, + parent_module_id: ModuleId, + ) { + self.add_definition_location(ReferenceId::Enum(id), Some(parent_module_id)); + self.register_name_for_auto_import(name, ModuleDefId::TypeId(id), visibility, None); + } + pub(crate) fn register_trait( &mut self, id: TraitId, diff --git a/compiler/noirc_frontend/src/monomorphization/mod.rs b/compiler/noirc_frontend/src/monomorphization/mod.rs index 191c3937e4b..3e4b478c23a 100644 --- a/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -1159,7 +1159,7 @@ impl<'interner> Monomorphizer<'interner> { monomorphized_default } - HirType::Struct(def, args) => { + HirType::DataType(def, args) => { // Not all generic arguments may be used in a struct's fields so we have to check // the arguments as well as the fields in case any need to be defaulted or are unbound. for arg in args { @@ -1279,7 +1279,7 @@ impl<'interner> Monomorphizer<'interner> { Self::check_type(&default, location) } - HirType::Struct(_def, args) => { + HirType::DataType(_def, args) => { for arg in args { Self::check_type(arg, location)?; } @@ -2133,7 +2133,7 @@ fn unwrap_struct_type( location: Location, ) -> Result, MonomorphizationError> { match typ.follow_bindings() { - HirType::Struct(def, args) => { + HirType::DataType(def, args) => { // Some of args might not be mentioned in fields, so we need to check that they aren't unbound. for arg in &args { Monomorphizer::check_type(arg, location)?; diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index ae2cf224cbd..3efb1afd798 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -18,7 +18,7 @@ use crate::ast::{ use crate::graph::CrateId; use crate::hir::comptime; use crate::hir::def_collector::dc_crate::CompilationError; -use crate::hir::def_collector::dc_crate::{UnresolvedStruct, UnresolvedTrait, UnresolvedTypeAlias}; +use crate::hir::def_collector::dc_crate::{UnresolvedTrait, UnresolvedTypeAlias}; use crate::hir::def_map::DefMaps; use crate::hir::def_map::{LocalModuleId, ModuleDefId, ModuleId}; use crate::hir::type_check::generics::TraitGenerics; @@ -32,7 +32,7 @@ use crate::hir_def::expr::HirIdent; use crate::hir_def::stmt::HirLetStatement; use crate::hir_def::traits::TraitImpl; use crate::hir_def::traits::{Trait, TraitConstraint}; -use crate::hir_def::types::{Kind, StructType, Type}; +use crate::hir_def::types::{DataType, Kind, Type}; use crate::hir_def::{ expr::HirExpression, function::{FuncMeta, HirFunction}, @@ -106,14 +106,14 @@ pub struct NodeInterner { // Similar to `id_to_type` but maps definitions to their type definition_to_type: HashMap, - // Struct map. + // Struct and Enum map. // - // Each struct definition is possibly shared across multiple type nodes. + // Each type 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. - structs: HashMap>, + data_types: HashMap>, - struct_attributes: HashMap, + type_attributes: HashMap, // Maps TypeAliasId -> Shared // @@ -286,7 +286,7 @@ pub struct NodeInterner { /// ``` #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum DependencyId { - Struct(StructId), + Struct(TypeId), Global(GlobalId), Function(FuncId), Alias(TypeAliasId), @@ -299,8 +299,10 @@ pub enum DependencyId { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum ReferenceId { Module(ModuleId), - Struct(StructId), - StructMember(StructId, usize), + Struct(TypeId), + StructMember(TypeId, usize), + Enum(TypeId), + EnumVariant(TypeId, usize), Trait(TraitId), Global(GlobalId), Function(FuncId), @@ -465,14 +467,14 @@ impl fmt::Display for FuncId { } #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, PartialOrd, Ord)] -pub struct StructId(ModuleId); +pub struct TypeId(ModuleId); -impl StructId { +impl TypeId { //dummy id for error reporting // This can be anything, as the program will ultimately fail // after resolution - pub fn dummy_id() -> StructId { - StructId(ModuleId { krate: CrateId::dummy_id(), local_id: LocalModuleId::dummy_id() }) + pub fn dummy_id() -> TypeId { + TypeId(ModuleId { krate: CrateId::dummy_id(), local_id: LocalModuleId::dummy_id() }) } pub fn module_id(self) -> ModuleId { @@ -652,8 +654,8 @@ impl Default for NodeInterner { definitions: vec![], id_to_type: HashMap::default(), definition_to_type: HashMap::default(), - structs: HashMap::default(), - struct_attributes: HashMap::default(), + data_types: HashMap::default(), + type_attributes: HashMap::default(), type_aliases: Vec::new(), traits: HashMap::default(), trait_implementations: HashMap::default(), @@ -747,25 +749,25 @@ impl NodeInterner { self.traits.insert(type_id, new_trait); } - pub fn new_struct( + /// Creates a new struct or enum type with no fields or variants. + #[allow(clippy::too_many_arguments)] + pub fn new_type( &mut self, - typ: &UnresolvedStruct, + name: Ident, + span: Span, + attributes: Vec, generics: Generics, krate: CrateId, local_id: LocalModuleId, file_id: FileId, - ) -> StructId { - let struct_id = StructId(ModuleId { krate, local_id }); - let name = typ.struct_def.name.clone(); + ) -> TypeId { + let type_id = TypeId(ModuleId { krate, local_id }); - // Fields will be filled in later - let no_fields = Vec::new(); - - let location = Location::new(typ.struct_def.span, file_id); - let new_struct = StructType::new(struct_id, name, location, no_fields, generics); - self.structs.insert(struct_id, Shared::new(new_struct)); - self.struct_attributes.insert(struct_id, typ.struct_def.attributes.clone()); - struct_id + let location = Location::new(span, file_id); + let new_type = DataType::new(type_id, name, location, generics); + self.data_types.insert(type_id, Shared::new(new_type)); + self.type_attributes.insert(type_id, attributes); + type_id } pub fn push_type_alias( @@ -791,8 +793,8 @@ impl NodeInterner { pub fn add_type_alias_ref(&mut self, type_id: TypeAliasId, location: Location) { self.type_alias_ref.push((type_id, location)); } - pub fn update_struct(&mut self, type_id: StructId, f: impl FnOnce(&mut StructType)) { - let mut value = self.structs.get_mut(&type_id).unwrap().borrow_mut(); + pub fn update_struct(&mut self, type_id: TypeId, f: impl FnOnce(&mut DataType)) { + let mut value = self.data_types.get_mut(&type_id).unwrap().borrow_mut(); f(&mut value); } @@ -803,10 +805,10 @@ impl NodeInterner { pub fn update_struct_attributes( &mut self, - type_id: StructId, + type_id: TypeId, f: impl FnOnce(&mut StructAttributes), ) { - let value = self.struct_attributes.get_mut(&type_id).unwrap(); + let value = self.type_attributes.get_mut(&type_id).unwrap(); f(value); } @@ -1096,8 +1098,8 @@ impl NodeInterner { &self.function_modifiers[func_id].attributes } - pub fn struct_attributes(&self, struct_id: &StructId) -> &StructAttributes { - &self.struct_attributes[struct_id] + pub fn struct_attributes(&self, struct_id: &TypeId) -> &StructAttributes { + &self.type_attributes[struct_id] } pub fn add_module_attributes(&mut self, module_id: ModuleId, attributes: ModuleAttributes) { @@ -1213,8 +1215,8 @@ impl NodeInterner { self.id_to_location.insert(id.into(), Location::new(span, file)); } - pub fn get_struct(&self, id: StructId) -> Shared { - self.structs[&id].clone() + pub fn get_type(&self, id: TypeId) -> Shared { + self.data_types[&id].clone() } pub fn get_type_methods(&self, typ: &Type) -> Option<&HashMap> { @@ -1387,7 +1389,7 @@ impl NodeInterner { unreachable!("Cannot add a method to the unsupported type '{}'", self_type) }); - if trait_id.is_none() && matches!(self_type, Type::Struct(..)) { + if trait_id.is_none() && matches!(self_type, Type::DataType(..)) { if let Some(existing) = self.lookup_direct_method(self_type, &method_name, true) { return Some(existing); @@ -1970,7 +1972,7 @@ impl NodeInterner { /// Register that `dependent` depends on `dependency`. /// This is usually because `dependent` refers to `dependency` in one of its struct fields. - pub fn add_type_dependency(&mut self, dependent: DependencyId, dependency: StructId) { + pub fn add_type_dependency(&mut self, dependent: DependencyId, dependency: TypeId) { self.add_dependency(dependent, DependencyId::Struct(dependency)); } @@ -2023,7 +2025,7 @@ impl NodeInterner { for (i, index) in scc.iter().enumerate() { match self.dependency_graph[*index] { DependencyId::Struct(struct_id) => { - let struct_type = self.get_struct(struct_id); + let struct_type = self.get_type(struct_id); let struct_type = struct_type.borrow(); push_error(struct_type.name.to_string(), &scc, i, struct_type.location); break; @@ -2070,7 +2072,7 @@ impl NodeInterner { /// element at the given start index. fn get_cycle_error_string(&self, scc: &[PetGraphIndex], start_index: usize) -> String { let index_to_string = |index: PetGraphIndex| match self.dependency_graph[index] { - DependencyId::Struct(id) => Cow::Owned(self.get_struct(id).borrow().name.to_string()), + DependencyId::Struct(id) => Cow::Owned(self.get_type(id).borrow().name.to_string()), DependencyId::Function(id) => Cow::Borrowed(self.function_name(&id)), DependencyId::Alias(id) => { Cow::Owned(self.get_type_alias(id).borrow().name.to_string()) @@ -2412,7 +2414,7 @@ enum TypeMethodKey { Function, Generic, Quoted(QuotedType), - Struct(StructId), + Struct(TypeId), } fn get_type_method_key(typ: &Type) -> Option { @@ -2440,7 +2442,7 @@ fn get_type_method_key(typ: &Type) -> Option { Type::Quoted(quoted) => Some(Quoted(*quoted)), Type::MutableReference(element) => get_type_method_key(element), Type::Alias(alias, _) => get_type_method_key(&alias.borrow().typ), - Type::Struct(struct_type, _) => Some(Struct(struct_type.borrow().id)), + Type::DataType(struct_type, _) => Some(Struct(struct_type.borrow().id)), // We do not support adding methods to these types Type::Forall(_, _) diff --git a/compiler/noirc_frontend/src/resolve_locations.rs b/compiler/noirc_frontend/src/resolve_locations.rs index b9e86bf0ef7..1b904f653bd 100644 --- a/compiler/noirc_frontend/src/resolve_locations.rs +++ b/compiler/noirc_frontend/src/resolve_locations.rs @@ -93,7 +93,7 @@ impl NodeInterner { fn get_type_location_from_index(&self, index: impl Into) -> Option { match self.id_type(index.into()) { - Type::Struct(struct_type, _) => Some(struct_type.borrow().location), + Type::DataType(struct_type, _) => Some(struct_type.borrow().location), _ => None, } } @@ -150,7 +150,7 @@ impl NodeInterner { let expr_rhs = &expr_member_access.rhs; let lhs_self_struct = match self.id_type(expr_lhs) { - Type::Struct(struct_type, _) => struct_type, + Type::DataType(struct_type, _) => struct_type, _ => return None, }; @@ -217,7 +217,7 @@ impl NodeInterner { .iter() .find(|(_typ, type_ref_location)| type_ref_location.contains(&location)) .and_then(|(typ, _)| match typ { - Type::Struct(struct_typ, _) => Some(struct_typ.borrow().location), + Type::DataType(struct_typ, _) => Some(struct_typ.borrow().location), _ => None, }) } diff --git a/compiler/noirc_frontend/src/usage_tracker.rs b/compiler/noirc_frontend/src/usage_tracker.rs index 6987358ddb7..ea4919096c0 100644 --- a/compiler/noirc_frontend/src/usage_tracker.rs +++ b/compiler/noirc_frontend/src/usage_tracker.rs @@ -3,14 +3,15 @@ use std::collections::HashMap; use crate::{ ast::{Ident, ItemVisibility}, hir::def_map::ModuleId, - node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}, + node_interner::{FuncId, GlobalId, TraitId, TypeAliasId, TypeId}, }; #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum UnusedItem { Import, Function(FuncId), - Struct(StructId), + Struct(TypeId), + Enum(TypeId), Trait(TraitId), TypeAlias(TypeAliasId), Global(GlobalId), @@ -22,6 +23,7 @@ impl UnusedItem { UnusedItem::Import => "import", UnusedItem::Function(_) => "function", UnusedItem::Struct(_) => "struct", + UnusedItem::Enum(_) => "enum", UnusedItem::Trait(_) => "trait", UnusedItem::TypeAlias(_) => "type alias", UnusedItem::Global(_) => "global", diff --git a/tooling/lsp/src/requests/code_action/fill_struct_fields.rs b/tooling/lsp/src/requests/code_action/fill_struct_fields.rs index 739f0bf4a21..7a4d562e402 100644 --- a/tooling/lsp/src/requests/code_action/fill_struct_fields.rs +++ b/tooling/lsp/src/requests/code_action/fill_struct_fields.rs @@ -24,7 +24,7 @@ impl<'a> CodeActionFinder<'a> { return; }; - let struct_type = self.interner.get_struct(struct_id); + let struct_type = self.interner.get_type(struct_id); let struct_type = struct_type.borrow(); // First get all of the struct's fields diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index a845fd4496f..597b778260a 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -31,10 +31,10 @@ use noirc_frontend::{ }, }, hir_def::traits::Trait, - node_interner::{FuncId, NodeInterner, ReferenceId, StructId}, + node_interner::{FuncId, NodeInterner, ReferenceId, TypeId}, parser::{Item, ItemKind, ParsedSubModule}, token::{MetaAttribute, Token, Tokens}, - Kind, ParsedModule, StructType, Type, TypeBinding, + DataType, Kind, ParsedModule, Type, TypeBinding, }; use sort_text::underscore_sort_text; @@ -203,7 +203,7 @@ impl<'a> NodeFinder<'a> { return; }; - let struct_type = self.interner.get_struct(struct_id); + let struct_type = self.interner.get_type(struct_id); let struct_type = struct_type.borrow(); // First get all of the struct's fields @@ -318,9 +318,9 @@ impl<'a> NodeFinder<'a> { match module_def_id { ModuleDefId::ModuleId(id) => module_id = id, ModuleDefId::TypeId(struct_id) => { - let struct_type = self.interner.get_struct(struct_id); + let struct_type = self.interner.get_type(struct_id); self.complete_type_methods( - &Type::Struct(struct_type, vec![]), + &Type::DataType(struct_type, vec![]), &prefix, FunctionKind::Any, function_completion_kind, @@ -568,7 +568,7 @@ impl<'a> NodeFinder<'a> { ) { let typ = &typ; match typ { - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { self.complete_struct_fields(&struct_type.borrow(), generics, prefix, self_prefix); } Type::MutableReference(typ) => { @@ -800,7 +800,7 @@ impl<'a> NodeFinder<'a> { fn complete_struct_fields( &mut self, - struct_type: &StructType, + struct_type: &DataType, generics: &[Type], prefix: &str, self_prefix: bool, @@ -1799,7 +1799,7 @@ impl<'a> Visitor for NodeFinder<'a> { fn get_field_type(typ: &Type, name: &str) -> Option { match typ { - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { Some(struct_type.borrow().get_field(name, generics)?.0) } Type::Tuple(types) => { @@ -1839,9 +1839,9 @@ fn get_array_element_type(typ: Type) -> Option { } } -fn get_type_struct_id(typ: &Type) -> Option { +fn get_type_struct_id(typ: &Type) -> Option { match typ { - Type::Struct(struct_type, _) => Some(struct_type.borrow().id), + Type::DataType(struct_type, _) => Some(struct_type.borrow().id), Type::Alias(type_alias, generics) => { let type_alias = type_alias.borrow(); let typ = type_alias.get_type(generics); @@ -1898,10 +1898,12 @@ fn module_def_id_from_reference_id(reference_id: ReferenceId) -> Option Some(ModuleDefId::ModuleId(module_id)), ReferenceId::Struct(struct_id) => Some(ModuleDefId::TypeId(struct_id)), + ReferenceId::Enum(enum_id) => Some(ModuleDefId::TypeId(enum_id)), ReferenceId::Trait(trait_id) => Some(ModuleDefId::TraitId(trait_id)), ReferenceId::Function(func_id) => Some(ModuleDefId::FunctionId(func_id)), ReferenceId::Alias(type_alias_id) => Some(ModuleDefId::TypeAliasId(type_alias_id)), ReferenceId::StructMember(_, _) + | ReferenceId::EnumVariant(_, _) | ReferenceId::Global(_) | ReferenceId::Local(_) | ReferenceId::Reference(_, _) => None, diff --git a/tooling/lsp/src/requests/completion/completion_items.rs b/tooling/lsp/src/requests/completion/completion_items.rs index db31683d51a..c8ae16bf1f4 100644 --- a/tooling/lsp/src/requests/completion/completion_items.rs +++ b/tooling/lsp/src/requests/completion/completion_items.rs @@ -6,7 +6,7 @@ use noirc_frontend::{ ast::AttributeTarget, hir::def_map::{ModuleDefId, ModuleId}, hir_def::{function::FuncMeta, stmt::HirPattern}, - node_interner::{FuncId, GlobalId, ReferenceId, StructId, TraitId, TypeAliasId}, + node_interner::{FuncId, GlobalId, ReferenceId, TraitId, TypeAliasId, TypeId}, QuotedType, Type, }; @@ -110,7 +110,7 @@ impl<'a> NodeFinder<'a> { self.completion_item_with_doc_comments(ReferenceId::Module(id), completion_item) } - fn struct_completion_item(&self, name: String, struct_id: StructId) -> CompletionItem { + fn struct_completion_item(&self, name: String, struct_id: TypeId) -> CompletionItem { let completion_item = simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)); self.completion_item_with_doc_comments(ReferenceId::Struct(struct_id), completion_item) @@ -120,7 +120,7 @@ impl<'a> NodeFinder<'a> { &self, field: &str, typ: &Type, - struct_id: StructId, + struct_id: TypeId, field_index: usize, self_type: bool, ) -> CompletionItem { diff --git a/tooling/lsp/src/requests/hover.rs b/tooling/lsp/src/requests/hover.rs index 5d8c50fa47b..bfe2a2a2448 100644 --- a/tooling/lsp/src/requests/hover.rs +++ b/tooling/lsp/src/requests/hover.rs @@ -13,10 +13,10 @@ use noirc_frontend::{ traits::Trait, }, node_interner::{ - DefinitionId, DefinitionKind, ExprId, FuncId, GlobalId, NodeInterner, ReferenceId, - StructId, TraitId, TraitImplKind, TypeAliasId, + DefinitionId, DefinitionKind, ExprId, FuncId, GlobalId, NodeInterner, ReferenceId, TraitId, + TraitImplKind, TypeAliasId, TypeId, }, - Generics, Shared, StructType, Type, TypeAlias, TypeBinding, TypeVariable, + DataType, Generics, Shared, Type, TypeAlias, TypeBinding, TypeVariable, }; use crate::{ @@ -77,6 +77,10 @@ fn format_reference(reference: ReferenceId, args: &ProcessRequestCallbackArgs) - ReferenceId::StructMember(id, field_index) => { Some(format_struct_member(id, field_index, args)) } + ReferenceId::Enum(id) => Some(format_enum(id, args)), + ReferenceId::EnumVariant(id, variant_index) => { + Some(format_enum_variant(id, variant_index, args)) + } ReferenceId::Trait(id) => Some(format_trait(id, args)), ReferenceId::Global(id) => Some(format_global(id, args)), ReferenceId::Function(id) => Some(format_function(id, args)), @@ -122,8 +126,8 @@ fn format_module(id: ModuleId, args: &ProcessRequestCallbackArgs) -> Option String { - let struct_type = args.interner.get_struct(id); +fn format_struct(id: TypeId, args: &ProcessRequestCallbackArgs) -> String { + let struct_type = args.interner.get_type(id); let struct_type = struct_type.borrow(); let mut string = String::new(); @@ -149,12 +153,45 @@ fn format_struct(id: StructId, args: &ProcessRequestCallbackArgs) -> String { string } +fn format_enum(id: TypeId, args: &ProcessRequestCallbackArgs) -> String { + let typ = args.interner.get_type(id); + let typ = typ.borrow(); + + let mut string = String::new(); + if format_parent_module(ReferenceId::Enum(id), args, &mut string) { + string.push('\n'); + } + string.push_str(" "); + string.push_str("enum "); + string.push_str(&typ.name.0.contents); + format_generics(&typ.generics, &mut string); + string.push_str(" {\n"); + for field in typ.get_variants_as_written() { + string.push_str(" "); + string.push_str(&field.name.0.contents); + + if !field.params.is_empty() { + let types = field.params.iter().map(ToString::to_string).collect::>(); + string.push('('); + string.push_str(&types.join(", ")); + string.push(')'); + } + + string.push_str(",\n"); + } + string.push_str(" }"); + + append_doc_comments(args.interner, ReferenceId::Enum(id), &mut string); + + string +} + fn format_struct_member( - id: StructId, + id: TypeId, field_index: usize, args: &ProcessRequestCallbackArgs, ) -> String { - let struct_type = args.interner.get_struct(id); + let struct_type = args.interner.get_type(id); let struct_type = struct_type.borrow(); let field = struct_type.field_at(field_index); @@ -175,6 +212,39 @@ fn format_struct_member( string } +fn format_enum_variant( + id: TypeId, + field_index: usize, + args: &ProcessRequestCallbackArgs, +) -> String { + let enum_type = args.interner.get_type(id); + let enum_type = enum_type.borrow(); + let variant = enum_type.variant_at(field_index); + + let mut string = String::new(); + if format_parent_module(ReferenceId::Enum(id), args, &mut string) { + string.push_str("::"); + } + string.push_str(&enum_type.name.0.contents); + string.push('\n'); + string.push_str(" "); + string.push_str(&variant.name.0.contents); + if !variant.params.is_empty() { + let types = variant.params.iter().map(ToString::to_string).collect::>(); + string.push('('); + string.push_str(&types.join(", ")); + string.push(')'); + } + + for typ in variant.params.iter() { + string.push_str(&go_to_type_links(typ, args.interner, args.files)); + } + + append_doc_comments(args.interner, ReferenceId::EnumVariant(id, field_index), &mut string); + + string +} + fn format_trait(id: TraitId, args: &ProcessRequestCallbackArgs) -> String { let a_trait = args.interner.get_trait(id); @@ -368,7 +438,7 @@ fn format_function(id: FuncId, args: &ProcessRequestCallbackArgs) -> String { true } else if let Some(struct_id) = func_meta.struct_id { - let struct_type = args.interner.get_struct(struct_id); + let struct_type = args.interner.get_type(struct_id); let struct_type = struct_type.borrow(); if formatted_parent_module { string.push_str("::"); @@ -685,7 +755,7 @@ impl<'a> TypeLinksGatherer<'a> { self.gather_type_links(typ); } } - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { self.gather_struct_type_links(struct_type); for generic in generics { self.gather_type_links(generic); @@ -739,7 +809,7 @@ impl<'a> TypeLinksGatherer<'a> { } } - fn gather_struct_type_links(&mut self, struct_type: &Shared) { + fn gather_struct_type_links(&mut self, struct_type: &Shared) { let struct_type = struct_type.borrow(); if let Some(lsp_location) = to_lsp_location(self.files, struct_type.location.file, struct_type.name.span()) diff --git a/tooling/lsp/src/requests/inlay_hint.rs b/tooling/lsp/src/requests/inlay_hint.rs index c6415acb545..6629f3d0336 100644 --- a/tooling/lsp/src/requests/inlay_hint.rs +++ b/tooling/lsp/src/requests/inlay_hint.rs @@ -95,13 +95,21 @@ impl<'a> InlayHintCollector<'a> { self.push_type_hint(lsp_location, &typ, editable); } ReferenceId::StructMember(struct_id, field_index) => { - let struct_type = self.interner.get_struct(struct_id); + let struct_type = self.interner.get_type(struct_id); let struct_type = struct_type.borrow(); let field = struct_type.field_at(field_index); self.push_type_hint(lsp_location, &field.typ, false); } + ReferenceId::EnumVariant(type_id, variant_index) => { + let typ = self.interner.get_type(type_id); + let shared_type = typ.clone(); + let typ = typ.borrow(); + let variant_type = typ.variant_function_type(variant_index, shared_type); + self.push_type_hint(lsp_location, &variant_type, false); + } ReferenceId::Module(_) | ReferenceId::Struct(_) + | ReferenceId::Enum(_) | ReferenceId::Trait(_) | ReferenceId::Function(_) | ReferenceId::Alias(_) @@ -410,7 +418,7 @@ fn push_type_parts(typ: &Type, parts: &mut Vec, files: &File } parts.push(string_part(")")); } - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { let struct_type = struct_type.borrow(); let location = Location::new(struct_type.name.span(), struct_type.location.file); parts.push(text_part_with_location(struct_type.name.to_string(), location, files)); diff --git a/tooling/lsp/src/trait_impl_method_stub_generator.rs b/tooling/lsp/src/trait_impl_method_stub_generator.rs index eb1709e34d0..4e505eb5e12 100644 --- a/tooling/lsp/src/trait_impl_method_stub_generator.rs +++ b/tooling/lsp/src/trait_impl_method_stub_generator.rs @@ -181,7 +181,7 @@ impl<'a> TraitImplMethodStubGenerator<'a> { } self.string.push(')'); } - Type::Struct(struct_type, generics) => { + Type::DataType(struct_type, generics) => { let struct_type = struct_type.borrow(); let current_module_data = From 13b865c481193f22fd79612bf3028debe16a73f1 Mon Sep 17 00:00:00 2001 From: Jake Fecher Date: Fri, 17 Jan 2025 15:25:25 -0600 Subject: [PATCH 2/2] Fix frontend test --- compiler/noirc_frontend/src/tests.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 29ba7b0fab1..8b205ac5b63 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -2818,12 +2818,13 @@ fn duplicate_struct_field() { let errors = get_program_errors(src); assert_eq!(errors.len(), 1); - let CompilationError::DefinitionError(DefCollectorErrorKind::DuplicateField { + let CompilationError::DefinitionError(DefCollectorErrorKind::Duplicate { + typ: _, first_def, second_def, }) = &errors[0].0 else { - panic!("Expected a duplicate field error, got {:?}", errors[0].0); + panic!("Expected a 'duplicate' error, got {:?}", errors[0].0); }; assert_eq!(first_def.to_string(), "x");