diff --git a/src/lower/datatype.rs b/src/lower/datatype.rs index 5be3ccf..035ebe0 100644 --- a/src/lower/datatype.rs +++ b/src/lower/datatype.rs @@ -61,8 +61,8 @@ pub fn lower_type( resolved_ast, )?))), resolved::TypeKind::Void => Ok(ir::Type::Void), - resolved::TypeKind::Structure(_, structure_ref) => { - todo!("lower structure"); + resolved::TypeKind::Structure(_, structure_ref, parameters) => { + todo!("instantiate structure"); // Ok(ir::Type::Structure(*structure_ref)) } resolved::TypeKind::AnonymousStruct() => { diff --git a/src/resolve/core_structure_info.rs b/src/resolve/core_structure_info.rs index 1e6a05b..fe0fd91 100644 --- a/src/resolve/core_structure_info.rs +++ b/src/resolve/core_structure_info.rs @@ -8,13 +8,15 @@ pub fn get_core_structure_info<'a, 'b>( resolved_ast: &'b resolved::Ast<'a>, resolved_type: &'a resolved::Type, source: Source, -) -> Result<(&'b HumanName, StructureRef), ResolveError> { +) -> Result<(&'b HumanName, StructureRef, &'b [resolved::Type]), ResolveError> { match &resolved_ast .unalias(resolved_type) .map_err(|e| ResolveErrorKind::from(e).at(source))? .kind { - resolved::TypeKind::Structure(name, structure_ref) => Ok((name, *structure_ref)), + resolved::TypeKind::Structure(name, structure_ref, parameters) => { + Ok((name, *structure_ref, parameters.as_slice())) + } _ => Err(ResolveErrorKind::CannotCreateStructLiteralForNonStructure { bad_type: resolved_type.to_string(), } diff --git a/src/resolve/expr/member_expr.rs b/src/resolve/expr/member_expr.rs index b4b765d..401c01d 100644 --- a/src/resolve/expr/member_expr.rs +++ b/src/resolve/expr/member_expr.rs @@ -20,7 +20,7 @@ pub fn resolve_member_expr( ) -> Result { let resolved_subject = resolve_expr(ctx, subject, None, Initialized::Require)?; - let (_, structure_ref) = + let (_, structure_ref, parameters) = get_core_structure_info(ctx.resolved_ast, &resolved_subject.resolved_type, source)?; let structure = ctx diff --git a/src/resolve/expr/struct_literal.rs b/src/resolve/expr/struct_literal.rs index 064d89d..c2c9f38 100644 --- a/src/resolve/expr/struct_literal.rs +++ b/src/resolve/expr/struct_literal.rs @@ -38,11 +38,12 @@ pub fn resolve_struct_literal_expr( source: Source, ) -> Result { let resolved_struct_type = ctx.type_ctx().resolve(ast_type)?; - let (struct_name, structure_ref) = + let (struct_name, structure_ref, parameters) = get_core_structure_info(ctx.resolved_ast, &resolved_struct_type, source)?; let structure_type = - resolved::TypeKind::Structure(struct_name.clone(), structure_ref).at(source); + resolved::TypeKind::Structure(struct_name.clone(), structure_ref, parameters.to_vec()) + .at(source); let mut next_index = 0; let mut resolved_fields = IndexMap::new(); @@ -118,7 +119,7 @@ pub fn resolve_struct_literal_expr( .insert(field_name.to_string(), (resolved_expr.expr, index)) .is_some() { - let (struct_name, _) = + let (struct_name, _, _) = get_core_structure_info(ctx.resolved_ast, &resolved_struct_type, source)?; return Err(ResolveErrorKind::FieldSpecifiedMoreThanOnce { diff --git a/src/resolve/function_haystack.rs b/src/resolve/function_haystack.rs index 0d24e65..4d2445c 100644 --- a/src/resolve/function_haystack.rs +++ b/src/resolve/function_haystack.rs @@ -245,7 +245,7 @@ impl FunctionHaystack { .and_then(|first_type| { if let Ok(first_type) = ctx.resolved_ast.unalias(first_type) { match &first_type.kind { - TypeKind::Structure(_, structure_ref) => Some( + TypeKind::Structure(_, structure_ref, _) => Some( ctx.resolved_ast .structures .get(*structure_ref) diff --git a/src/resolve/function_head.rs b/src/resolve/function_head.rs index b4efc45..5ed59ee 100644 --- a/src/resolve/function_head.rs +++ b/src/resolve/function_head.rs @@ -142,7 +142,11 @@ fn collect_constraints(map: &mut HashMap>, ty: &reso resolved::TypeKind::FixedArray(fixed_array) => collect_constraints(map, &fixed_array.inner), resolved::TypeKind::FunctionPointer(_) => todo!(), resolved::TypeKind::Enum(_, _) => (), - resolved::TypeKind::Structure(_, _) => (), + resolved::TypeKind::Structure(_, _, parameters) => { + for parameter in parameters { + collect_constraints(map, parameter); + } + } resolved::TypeKind::TypeAlias(_, _) => (), resolved::TypeKind::Polymorph(name, constraints) => { let set = map.entry(name.to_string()).or_default(); diff --git a/src/resolve/polymorph.rs b/src/resolve/polymorph.rs index b5ad467..79f28d8 100644 --- a/src/resolve/polymorph.rs +++ b/src/resolve/polymorph.rs @@ -97,7 +97,7 @@ impl PolyRecipe { } resolved::TypeKind::FunctionPointer(_) => todo!(), resolved::TypeKind::Enum(_, _) => ty.clone(), - resolved::TypeKind::Structure(_, _) => ty.clone(), + resolved::TypeKind::Structure(_, _, _) => ty.clone(), resolved::TypeKind::TypeAlias(_, _) => ty.clone(), resolved::TypeKind::Polymorph(name, _) => { let Some(value) = polymorphs.get(name) else { @@ -181,7 +181,6 @@ impl PolyCatalog { | resolved::TypeKind::Floating(_) | resolved::TypeKind::Void | resolved::TypeKind::Enum(_, _) - | resolved::TypeKind::Structure(_, _) | resolved::TypeKind::TypeAlias(_, _) => { if *pattern_type == *concrete_type { Ok(()) @@ -189,6 +188,30 @@ impl PolyCatalog { Err(None) } } + resolved::TypeKind::Structure(_, structure_ref, parameters) => { + match &concrete_type.kind { + resolved::TypeKind::Structure( + _, + concrete_structure_ref, + concrete_parameters, + ) => { + if *structure_ref != *concrete_structure_ref + || parameters.len() != concrete_parameters.len() + { + return Err(None); + } + + for (pattern_parameter, concrete_parameter) in + parameters.iter().zip(concrete_parameters.iter()) + { + self.match_type(ctx, pattern_parameter, concrete_parameter)?; + } + + Ok(()) + } + _ => Err(None), + } + } resolved::TypeKind::Pointer(pattern_inner) => match &concrete_type.kind { resolved::TypeKind::Pointer(concrete_inner) => { self.match_type(ctx, pattern_inner, concrete_inner) diff --git a/src/resolve/type_ctx/find.rs b/src/resolve/type_ctx/find.rs index 6db24c7..b72183a 100644 --- a/src/resolve/type_ctx/find.rs +++ b/src/resolve/type_ctx/find.rs @@ -22,25 +22,23 @@ impl<'a> ResolveTypeCtx<'a> { .expect("valid settings id") .0]; - if let Some(name) = name.as_plain_str() { - if let Some(types_in_module) = self.types_in_modules.get(&self.module_fs_node_id) { - if let Some(decl) = types_in_module.get(name) { - if let resolved::TypeKind::Structure(_, structure_ref) = decl.kind { - let parameters = &self - .resolved_ast - .structures - .get(structure_ref) - .unwrap() - .parameters; - - if parameters.len() > 0 { - todo!("Handle generics for generic type") - } - } + if !arguments.is_empty() { + eprintln!( + "warning: ResolveTypeCtx does not properly handle compile time arguments yet" + ); + } - return Ok(Cow::Borrowed(&decl.kind)); - } - } + if let Some(decl) = name + .as_plain_str() + .and_then(|name| { + self.types_in_modules + .get(&self.module_fs_node_id) + .and_then(|types_in_module| types_in_module.get(name)) + }) + // NOTE: This will need to be map instead at some point + .filter(|decl| decl.num_parameters(self.resolved_ast) == arguments.len()) + { + return Ok(Cow::Borrowed(&decl.kind)); } if !name.namespace.is_empty() { @@ -58,7 +56,9 @@ impl<'a> ResolveTypeCtx<'a> { .flat_map(|dep| settings.dependency_to_module.get(dep)) .flat_map(|fs_node_id| self.types_in_modules.get(fs_node_id)) .flat_map(|decls| decls.get(basename.as_ref())) - .filter(|decl| decl.privacy.is_public()); + .filter(|decl| decl.privacy.is_public()) + // NOTE: This will need to be flat_map instead at some point + .filter(|decl| decl.num_parameters(self.resolved_ast) == arguments.len()); if let Some(found) = matches.next() { if matches.next().is_some() { diff --git a/src/resolve/type_definition/prepare.rs b/src/resolve/type_definition/prepare.rs index 1f0a937..0d9a954 100644 --- a/src/resolve/type_definition/prepare.rs +++ b/src/resolve/type_definition/prepare.rs @@ -10,6 +10,7 @@ use crate::{ workspace::fs::FsNodeId, }; use indexmap::IndexMap; +use itertools::Itertools; pub fn prepare_type_jobs( ctx: &mut ResolveCtx, @@ -97,8 +98,18 @@ fn prepare_structure( source: structure.source, }); - let struct_type_kind = - resolved::TypeKind::Structure(HumanName(structure.name.to_string()), structure_ref); + // TODO: Improve the source tracking for these + let polymorphs = structure + .parameters + .keys() + .map(|name| resolved::TypeKind::Polymorph(name.into(), vec![]).at(structure.source)) + .collect_vec(); + + let struct_type_kind = resolved::TypeKind::Structure( + HumanName(structure.name.to_string()), + structure_ref, + polymorphs, + ); ctx.types_in_modules .entry(module_fs_node_id) diff --git a/src/resolved/datatype/kind/mod.rs b/src/resolved/datatype/kind/mod.rs index 347338a..9b80215 100644 --- a/src/resolved/datatype/kind/mod.rs +++ b/src/resolved/datatype/kind/mod.rs @@ -6,7 +6,7 @@ mod function_pointer; use super::Type; use crate::{ ast::{fmt_c_integer, CInteger, FloatSize, IntegerBits, IntegerSign}, - resolved::{human_name::HumanName, EnumRef, StructureRef, TypeAliasRef}, + resolved::{human_name::HumanName, Ast, EnumRef, StructureRef, TypeAliasRef}, source_files::Source, target::Target, }; @@ -36,7 +36,7 @@ pub enum TypeKind { FixedArray(Box), FunctionPointer(FunctionPointer), Enum(HumanName, EnumRef), - Structure(HumanName, StructureRef), + Structure(HumanName, StructureRef, Vec), TypeAlias(HumanName, TypeAliasRef), Polymorph(String, Vec), } @@ -65,7 +65,9 @@ impl TypeKind { TypeKind::FixedArray(fixed_array) => fixed_array.inner.kind.contains_polymorph(), TypeKind::FunctionPointer(_) => todo!(), TypeKind::Enum(_, _) => false, - TypeKind::Structure(_, _) => false, + TypeKind::Structure(_, _, parameters) => parameters + .iter() + .any(|parameter| parameter.kind.contains_polymorph()), TypeKind::TypeAlias(_, _) => false, TypeKind::Polymorph(_, _) => true, } @@ -88,7 +90,7 @@ impl TypeKind { TypeKind::Floating(_) | TypeKind::FloatLiteral(_) | TypeKind::Pointer(_) - | TypeKind::Structure(_, _) + | TypeKind::Structure(_, _, _) | TypeKind::Void | TypeKind::AnonymousStruct(..) | TypeKind::AnonymousUnion(..) @@ -99,6 +101,18 @@ impl TypeKind { | TypeKind::Polymorph(_, _) => None, } } + + pub fn num_target_parameters(&self, resolved_ast: &Ast) -> usize { + match self { + TypeKind::Structure(_, structure_ref, _) => resolved_ast + .structures + .get(*structure_ref) + .unwrap() + .parameters + .len(), + _ => 0, + } + } } impl Display for TypeKind { @@ -140,7 +154,23 @@ impl Display for TypeKind { write!(f, "ptr<{}>", **inner)?; } TypeKind::Void => f.write_str("void")?, - TypeKind::Structure(name, _) => write!(f, "{}", name)?, + TypeKind::Structure(name, _, parameters) => { + write!(f, "{}", name)?; + + if !parameters.is_empty() { + write!(f, "<")?; + + for (i, parameter) in parameters.iter().enumerate() { + write!(f, "{}", parameter)?; + + if i + 1 < parameters.len() { + write!(f, ", ")?; + } + } + + write!(f, ">")? + } + } TypeKind::AnonymousStruct() => f.write_str("anonymous-struct")?, TypeKind::AnonymousUnion() => f.write_str("anonymous-union")?, TypeKind::AnonymousEnum(..) => f.write_str("anonymous-enum")?, diff --git a/src/resolved/datatype/mod.rs b/src/resolved/datatype/mod.rs index 6a39d10..a8ce080 100644 --- a/src/resolved/datatype/mod.rs +++ b/src/resolved/datatype/mod.rs @@ -46,7 +46,11 @@ impl Type { TypeKind::FixedArray(fixed_array) => fixed_array.inner.strip_constraints(), TypeKind::FunctionPointer(_) => todo!(), TypeKind::Enum(_, _) => (), - TypeKind::Structure(_, _) => (), + TypeKind::Structure(_, _, parameters) => { + for parameter in parameters { + parameter.strip_constraints(); + } + } TypeKind::TypeAlias(_, _) => (), TypeKind::Polymorph(_, constraints) => { constraints.drain(..); diff --git a/src/resolved/type_decl.rs b/src/resolved/type_decl.rs index d25ec68..726a5a9 100644 --- a/src/resolved/type_decl.rs +++ b/src/resolved/type_decl.rs @@ -1,4 +1,4 @@ -use super::{Constraint, TypeKind}; +use super::{Ast, Constraint, TypeKind}; use crate::{ast::Privacy, source_files::Source}; use std::collections::HashMap; @@ -9,6 +9,12 @@ pub struct TypeDecl { pub privacy: Privacy, } +impl TypeDecl { + pub fn num_parameters(&self, resolved_ast: &Ast) -> usize { + self.kind.num_target_parameters(resolved_ast) + } +} + #[derive(Clone, Debug, Default)] pub struct TypeParameters { pub parameters: HashMap,