From 985a8d7cb12e6e2fd7ff732d69d3834780993eab Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Wed, 31 Dec 2025 08:58:35 -0300 Subject: [PATCH] refactor: rename TypeKind to TypeShape for clarity --- crates/plotnik-lib/src/query/emit.rs | 32 ++++++------ .../src/query/type_check/context.rs | 50 +++++++++---------- .../plotnik-lib/src/query/type_check/infer.rs | 16 +++--- .../plotnik-lib/src/query/type_check/mod.rs | 2 +- .../plotnik-lib/src/query/type_check/types.rs | 10 ++-- 5 files changed, 57 insertions(+), 53 deletions(-) diff --git a/crates/plotnik-lib/src/query/emit.rs b/crates/plotnik-lib/src/query/emit.rs index 0daf25c8..ab2f1665 100644 --- a/crates/plotnik-lib/src/query/emit.rs +++ b/crates/plotnik-lib/src/query/emit.rs @@ -14,7 +14,7 @@ use crate::type_system::TypeKind; use super::query::LinkedQuery; use super::type_check::{ - FieldInfo, TYPE_NODE, TYPE_STRING, TYPE_VOID, TypeContext, TypeId, TypeKind as InferredTypeKind, + FieldInfo, TYPE_NODE, TYPE_STRING, TYPE_VOID, TypeContext, TypeId, TypeShape, }; /// Error during bytecode emission. @@ -236,18 +236,18 @@ impl TypeTableBuilder { &mut self, slot_index: usize, _type_id: TypeId, - type_kind: &InferredTypeKind, + type_kind: &TypeShape, type_ctx: &TypeContext, interner: &Interner, strings: &mut StringTableBuilder, ) -> Result<(), EmitError> { match type_kind { - InferredTypeKind::Void | InferredTypeKind::Node | InferredTypeKind::String => { + TypeShape::Void | TypeShape::Node | TypeShape::String => { // Builtins - should not reach here unreachable!("builtins should be handled separately") } - InferredTypeKind::Custom(sym) => { + TypeShape::Custom(sym) => { // Custom type annotation: @x :: Identifier → type Identifier = Node let bc_type_id = QTypeId::from_custom_index(slot_index); @@ -266,7 +266,7 @@ impl TypeTableBuilder { Ok(()) } - InferredTypeKind::Optional(inner) => { + TypeShape::Optional(inner) => { let inner_bc = self.resolve_type(*inner, type_ctx)?; self.type_defs[slot_index] = TypeDef { @@ -277,7 +277,7 @@ impl TypeTableBuilder { Ok(()) } - InferredTypeKind::Array { element, non_empty } => { + TypeShape::Array { element, non_empty } => { let element_bc = self.resolve_type(*element, type_ctx)?; let kind = if *non_empty { @@ -293,7 +293,7 @@ impl TypeTableBuilder { Ok(()) } - InferredTypeKind::Struct(fields) => { + TypeShape::Struct(fields) => { // Resolve field types (this may create Optional wrappers at later indices) let mut resolved_fields = Vec::with_capacity(fields.len()); for (field_sym, field_info) in fields { @@ -320,7 +320,7 @@ impl TypeTableBuilder { Ok(()) } - InferredTypeKind::Enum(variants) => { + TypeShape::Enum(variants) => { // Resolve variant types (this may create types at later indices) let mut resolved_variants = Vec::with_capacity(variants.len()); for (variant_sym, variant_type_id) in variants { @@ -347,7 +347,7 @@ impl TypeTableBuilder { Ok(()) } - InferredTypeKind::Ref(_def_id) => { + TypeShape::Ref(_def_id) => { // Ref types are not emitted - they resolve to their target unreachable!("Ref types should not be collected for emission") } @@ -363,7 +363,7 @@ impl TypeTableBuilder { // Handle Ref types by following the reference if let Some(type_kind) = type_ctx.get_type(type_id) - && let InferredTypeKind::Ref(def_id) = type_kind + && let TypeShape::Ref(def_id) = type_kind && let Some(def_type_id) = type_ctx.get_def_type(*def_id) { return self.resolve_type(def_type_id, type_ctx); @@ -491,7 +491,7 @@ fn collect_types_dfs( }; // Resolve Ref types to their target - if let InferredTypeKind::Ref(def_id) = type_kind { + if let TypeShape::Ref(def_id) = type_kind { if let Some(target_id) = type_ctx.get_def_type(*def_id) { collect_types_dfs(target_id, type_ctx, out, seen); } @@ -502,29 +502,29 @@ fn collect_types_dfs( // Collect children first (depth-first), then add self match type_kind { - InferredTypeKind::Struct(fields) => { + TypeShape::Struct(fields) => { for field_info in fields.values() { collect_types_dfs(field_info.type_id, type_ctx, out, seen); } out.push(type_id); } - InferredTypeKind::Enum(variants) => { + TypeShape::Enum(variants) => { for &variant_type_id in variants.values() { collect_types_dfs(variant_type_id, type_ctx, out, seen); } out.push(type_id); } - InferredTypeKind::Array { element, .. } => { + TypeShape::Array { element, .. } => { // Collect element type first, then add the Array itself collect_types_dfs(*element, type_ctx, out, seen); out.push(type_id); } - InferredTypeKind::Optional(inner) => { + TypeShape::Optional(inner) => { // Collect inner type first, then add the Optional itself collect_types_dfs(*inner, type_ctx, out, seen); out.push(type_id); } - InferredTypeKind::Custom(_) => { + TypeShape::Custom(_) => { // Custom types alias Node, no children to collect out.push(type_id); } diff --git a/crates/plotnik-lib/src/query/type_check/context.rs b/crates/plotnik-lib/src/query/type_check/context.rs index bc795c6e..92533ce0 100644 --- a/crates/plotnik-lib/src/query/type_check/context.rs +++ b/crates/plotnik-lib/src/query/type_check/context.rs @@ -10,14 +10,14 @@ use crate::parser::ast::Expr; use super::symbol::{DefId, Interner, Symbol}; use super::types::{ - Arity, FieldInfo, TYPE_NODE, TYPE_STRING, TYPE_VOID, TermInfo, TypeId, TypeKind, + Arity, FieldInfo, TYPE_NODE, TYPE_STRING, TYPE_VOID, TermInfo, TypeId, TypeShape, }; /// Central registry for types, symbols, and expression metadata. #[derive(Clone, Debug)] pub struct TypeContext { - types: Vec, - type_map: HashMap, + types: Vec, + type_map: HashMap, def_names: Vec, def_ids: HashMap, @@ -48,13 +48,13 @@ impl TypeContext { }; // Pre-register builtin types at their expected IDs - let void_id = ctx.intern_type(TypeKind::Void); + let void_id = ctx.intern_type(TypeShape::Void); debug_assert_eq!(void_id, TYPE_VOID); - let node_id = ctx.intern_type(TypeKind::Node); + let node_id = ctx.intern_type(TypeShape::Node); debug_assert_eq!(node_id, TYPE_NODE); - let string_id = ctx.intern_type(TypeKind::String); + let string_id = ctx.intern_type(TypeShape::String); debug_assert_eq!(string_id, TYPE_STRING); ctx @@ -68,42 +68,42 @@ impl TypeContext { } /// Intern a type, returning its ID. Deduplicates identical types. - pub fn intern_type(&mut self, kind: TypeKind) -> TypeId { - if let Some(&id) = self.type_map.get(&kind) { + pub fn intern_type(&mut self, shape: TypeShape) -> TypeId { + if let Some(&id) = self.type_map.get(&shape) { return id; } let id = TypeId(self.types.len() as u32); - self.types.push(kind.clone()); - self.type_map.insert(kind, id); + self.types.push(shape.clone()); + self.type_map.insert(shape, id); id } - /// Get the TypeKind for a TypeId. - pub fn get_type(&self, id: TypeId) -> Option<&TypeKind> { + /// Get the TypeShape for a TypeId. + pub fn get_type(&self, id: TypeId) -> Option<&TypeShape> { self.types.get(id.0 as usize) } /// Get or create a type, returning both the ID and a reference. - pub fn get_or_intern(&mut self, kind: TypeKind) -> (TypeId, &TypeKind) { - let id = self.intern_type(kind); + pub fn get_or_intern(&mut self, shape: TypeShape) -> (TypeId, &TypeShape) { + let id = self.intern_type(shape); (id, &self.types[id.0 as usize]) } /// Intern a struct type from fields. pub fn intern_struct(&mut self, fields: BTreeMap) -> TypeId { - self.intern_type(TypeKind::Struct(fields)) + self.intern_type(TypeShape::Struct(fields)) } /// Intern a struct type with a single field. pub fn intern_single_field(&mut self, name: Symbol, info: FieldInfo) -> TypeId { - self.intern_type(TypeKind::Struct(BTreeMap::from([(name, info)]))) + self.intern_type(TypeShape::Struct(BTreeMap::from([(name, info)]))) } /// Get struct fields from a TypeId, if it points to a Struct. pub fn get_struct_fields(&self, id: TypeId) -> Option<&BTreeMap> { match self.get_type(id)? { - TypeKind::Struct(fields) => Some(fields), + TypeShape::Struct(fields) => Some(fields), _ => None, } } @@ -199,7 +199,7 @@ impl TypeContext { } /// Iterate over all interned types. - pub fn iter_types(&self) -> impl Iterator { + pub fn iter_types(&self) -> impl Iterator { self.types .iter() .enumerate() @@ -239,17 +239,17 @@ mod tests { fn builtin_types_have_correct_ids() { let ctx = TypeContext::new(); - assert_eq!(ctx.get_type(TYPE_VOID), Some(&TypeKind::Void)); - assert_eq!(ctx.get_type(TYPE_NODE), Some(&TypeKind::Node)); - assert_eq!(ctx.get_type(TYPE_STRING), Some(&TypeKind::String)); + assert_eq!(ctx.get_type(TYPE_VOID), Some(&TypeShape::Void)); + assert_eq!(ctx.get_type(TYPE_NODE), Some(&TypeShape::Node)); + assert_eq!(ctx.get_type(TYPE_STRING), Some(&TypeShape::String)); } #[test] fn type_interning_deduplicates() { let mut ctx = TypeContext::new(); - let id1 = ctx.intern_type(TypeKind::Node); - let id2 = ctx.intern_type(TypeKind::Node); + let id1 = ctx.intern_type(TypeShape::Node); + let id2 = ctx.intern_type(TypeShape::Node); assert_eq!(id1, id2); assert_eq!(id1, TYPE_NODE); @@ -264,8 +264,8 @@ mod tests { let mut fields = BTreeMap::new(); fields.insert(x_sym, FieldInfo::required(TYPE_NODE)); - let id1 = ctx.intern_type(TypeKind::Struct(fields.clone())); - let id2 = ctx.intern_type(TypeKind::Struct(fields)); + let id1 = ctx.intern_type(TypeShape::Struct(fields.clone())); + let id2 = ctx.intern_type(TypeShape::Struct(fields)); assert_eq!(id1, id2); } diff --git a/crates/plotnik-lib/src/query/type_check/infer.rs b/crates/plotnik-lib/src/query/type_check/infer.rs index 9b0bb4c2..ab8954a0 100644 --- a/crates/plotnik-lib/src/query/type_check/infer.rs +++ b/crates/plotnik-lib/src/query/type_check/infer.rs @@ -12,7 +12,7 @@ use rowan::TextRange; use super::context::TypeContext; use super::symbol::Symbol; use super::types::{ - Arity, FieldInfo, QuantifierKind, TYPE_NODE, TYPE_STRING, TermInfo, TypeFlow, TypeId, TypeKind, + Arity, FieldInfo, QuantifierKind, TYPE_NODE, TYPE_STRING, TermInfo, TypeFlow, TypeId, TypeShape, }; use super::unify::{UnifyError, unify_flows}; @@ -224,7 +224,7 @@ impl<'a, 'd> InferenceVisitor<'a, 'd> { variants.insert(label_sym, self.flow_to_type(&body_info.flow)); } - let enum_type = self.ctx.intern_type(TypeKind::Enum(variants)); + let enum_type = self.ctx.intern_type(TypeShape::Enum(variants)); TermInfo::new(combined_arity, TypeFlow::Scalar(enum_type)) } @@ -373,7 +373,7 @@ impl<'a, 'd> InferenceVisitor<'a, 'd> { TYPE_STRING } else { let sym = self.interner.intern(text); - self.ctx.intern_type(TypeKind::Custom(sym)) + self.ctx.intern_type(TypeShape::Custom(sym)) } }) }) @@ -426,7 +426,7 @@ impl<'a, 'd> InferenceVisitor<'a, 'd> { let sym = self.interner.intern(name); let def_id = self.ctx.get_def_id_sym(sym)?; if self.ctx.is_recursive(def_id) { - Some(self.ctx.intern_type(TypeKind::Ref(def_id))) + Some(self.ctx.intern_type(TypeShape::Ref(def_id))) } else { None } @@ -474,7 +474,7 @@ impl<'a, 'd> InferenceVisitor<'a, 'd> { fn make_flow_optional(&mut self, flow: TypeFlow) -> TypeFlow { match flow { TypeFlow::Void => TypeFlow::Void, - TypeFlow::Scalar(t) => TypeFlow::Scalar(self.ctx.intern_type(TypeKind::Optional(t))), + TypeFlow::Scalar(t) => TypeFlow::Scalar(self.ctx.intern_type(TypeShape::Optional(t))), TypeFlow::Bubble(type_id) => { let fields = self .ctx @@ -495,11 +495,11 @@ impl<'a, 'd> InferenceVisitor<'a, 'd> { TypeFlow::Void => { // Scalar list: void inner -> array of Node (or Ref) let element = self.get_recursive_ref_type(inner).unwrap_or(TYPE_NODE); - let array_type = self.ctx.intern_type(TypeKind::Array { element, non_empty }); + let array_type = self.ctx.intern_type(TypeShape::Array { element, non_empty }); TypeFlow::Scalar(array_type) } TypeFlow::Scalar(t) => { - let array_type = self.ctx.intern_type(TypeKind::Array { + let array_type = self.ctx.intern_type(TypeShape::Array { element: t, non_empty, }); @@ -508,7 +508,7 @@ impl<'a, 'd> InferenceVisitor<'a, 'd> { TypeFlow::Bubble(struct_type) => { // Note: Bubble with * or + is strictly invalid unless it's a row capture, // but we construct a valid type as fallback. - let array_type = self.ctx.intern_type(TypeKind::Array { + let array_type = self.ctx.intern_type(TypeShape::Array { element: struct_type, non_empty, }); diff --git a/crates/plotnik-lib/src/query/type_check/mod.rs b/crates/plotnik-lib/src/query/type_check/mod.rs index 7cd56d0e..2010af76 100644 --- a/crates/plotnik-lib/src/query/type_check/mod.rs +++ b/crates/plotnik-lib/src/query/type_check/mod.rs @@ -16,7 +16,7 @@ pub use context::TypeContext; pub use symbol::{DefId, Interner, Symbol}; pub use types::{ Arity, FieldInfo, QuantifierKind, TYPE_NODE, TYPE_STRING, TYPE_VOID, TermInfo, TypeFlow, - TypeId, TypeKind, + TypeId, TypeShape, }; pub use unify::{UnifyError, unify_flow, unify_flows}; diff --git a/crates/plotnik-lib/src/query/type_check/types.rs b/crates/plotnik-lib/src/query/type_check/types.rs index ce4c8429..45938248 100644 --- a/crates/plotnik-lib/src/query/type_check/types.rs +++ b/crates/plotnik-lib/src/query/type_check/types.rs @@ -29,9 +29,13 @@ impl TypeId { } } -/// The kind of a type, determining its structure. +/// The shape of an inferred type, determining its structure. +/// +/// This represents the inference-time type representation which carries +/// actual data (fields, variants, inner types). Distinct from +/// `type_system::TypeKind` which is the bytecode format discriminant. #[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum TypeKind { +pub enum TypeShape { /// Produces nothing, transparent to parent scope. Void, /// A tree-sitter node. @@ -52,7 +56,7 @@ pub enum TypeKind { Ref(DefId), } -impl TypeKind { +impl TypeShape { pub fn is_void(&self) -> bool { matches!(self, Self::Void) }