From 51c698ba5df889541772019b11dd17fffb9bfdf9 Mon Sep 17 00:00:00 2001 From: Andrew Segavac Date: Sat, 30 Oct 2021 22:03:12 -0600 Subject: [PATCH] added generics without type instantiation --- examples/main.bl | 4 ++ src/ast.rs | 6 +-- src/grammar.lalrpop | 30 ++++++--------- src/interpreter.rs | 4 +- src/trait_checking.rs | 18 ++++----- src/type_alias_resolution.rs | 9 +---- src/type_checking.rs | 73 +++++++++++++++++++++++++----------- 7 files changed, 81 insertions(+), 63 deletions(-) diff --git a/examples/main.bl b/examples/main.bl index ec2c4bb..e901eae 100644 --- a/examples/main.bl +++ b/examples/main.bl @@ -48,6 +48,10 @@ type User struct { id: i64, } +type Generic[T] struct { + value: T, +} + impl User { fn new(id: i64): Self { return Self{ diff --git a/src/ast.rs b/src/ast.rs index 1f25b8f..358c69f 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -358,10 +358,8 @@ pub enum TypeDeclaration { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Impl { pub generic: Generic, - pub trait_type_parameters: Option, - pub trait_: Option, - pub struct_name: Identifier, - pub struct_type_parameters: GenericUsage, + pub struct_: NamedTypeUsage, + pub trait_: Option, pub functions: Vec, } diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index 06c3677..ef2566a 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -207,11 +207,15 @@ pub Block: ast::Block = { } }; -pub TypeUsage: ast::TypeUsage = { +pub NamedTypeUsage: ast::NamedTypeUsage = { => match gu { - Some(tp) => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: tp, name: n}), - None => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n}), + Some(tp) => ast::NamedTypeUsage{type_parameters: tp, name: n}, + None => ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n}, }, +}; + +pub TypeUsage: ast::TypeUsage = { + => ast::TypeUsage::Named(n), "fn" "(" > ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}), "fn" "(" > ")" ":" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}), }; @@ -272,31 +276,19 @@ pub TypeDeclaration: ast::TypeDeclaration = { }; pub Impl: ast::Impl = { - "impl" "{" "}" => { + "impl" "{" "}" => { let generic = match g { Some(g) => g, None => ast::Generic{parameters: vec!()}, }; - let struct_type_params = match sgu { - Some(stp) => stp, - None => ast::GenericUsage::new(&vec!()), - }; - ast::Impl{generic: generic, trait_: None, trait_type_parameters: None, struct_name: i, struct_type_parameters: struct_type_params, functions: f} + ast::Impl{generic: generic, trait_: None, struct_: s, functions: f} }, - "impl" "for" "{" "}" => { + "impl" "for" "{" "}" => { let generic = match g { Some(g) => g, None => ast::Generic{parameters: vec!()}, }; - let struct_type_params = match sgu { - Some(stp) => stp, - None => ast::GenericUsage::new(&vec!()), - }; - let trait_type_params = match tgu { - Some(ttp) => ttp, - None => ast::GenericUsage::new(&vec!()), - }; - ast::Impl{generic: generic, trait_: Some(t), trait_type_parameters: Some(trait_type_params), struct_name: i, struct_type_parameters: struct_type_params, functions: f} + ast::Impl{generic: generic, trait_: Some(t), struct_: s, functions: f} } }; diff --git a/src/interpreter.rs b/src/interpreter.rs index 5c03620..3179010 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -102,7 +102,7 @@ impl Context { ); } ast::ModuleItem::Impl(impl_) => { - ctx.impls.insert(impl_.struct_name.name.value.to_string(), impl_.clone()); + ctx.impls.insert(impl_.struct_.name.name.value.to_string(), impl_.clone()); } _ => {} } @@ -451,7 +451,7 @@ impl TreeWalkInterpreter { for module_item in &ctx.current_module.items { match module_item { ast::ModuleItem::Impl(impl_) => { - if impl_.struct_name.name.value == s.source.name.name.value { + if impl_.struct_.name.name.value == s.source.name.name.value { for method in &impl_.functions { if method.declaration.name.name.value == struct_getter.attribute.name.value { // if first type matches, partial apply self diff --git a/src/trait_checking.rs b/src/trait_checking.rs index 0c1fa06..77a9a7d 100644 --- a/src/trait_checking.rs +++ b/src/trait_checking.rs @@ -10,7 +10,7 @@ struct Context { } fn create_builtins() -> HashMap { - let mut result = HashMap::::new(); + let result = HashMap::::new(); return result; } @@ -100,12 +100,12 @@ impl TraitChecker { match &impl_.trait_ { Some(trait_) => { // assert trait functions satisfied - if !ctx.environment_traits.contains_key(&trait_.name.value) { + if !ctx.environment_traits.contains_key(&trait_.name.name.value) { return Err(errors::TypingError::TypeDoesNotExist { - identifier: trait_.clone(), + identifier: trait_.name.clone(), }); } - let trait_declaration = &ctx.environment_traits[&trait_.name.value]; + let trait_declaration = &ctx.environment_traits[&trait_.name.name.value]; for trait_item in trait_declaration.functions.iter() { match trait_item { ast::TraitItem::FunctionDeclaration(declaration) => { @@ -116,14 +116,14 @@ impl TraitChecker { compare_struct_trait( &impl_function.declaration.to_type(), &declaration.to_type(), - &impl_.struct_name, - &trait_, + &impl_.struct_.name, + &trait_.name, )?; } } if found == false { return Err(errors::TypingError::MissingTraitFunction { - struct_name: impl_.struct_name.clone(), + struct_name: impl_.struct_.name.clone(), function_name: declaration.name.clone(), }); } @@ -135,8 +135,8 @@ impl TraitChecker { compare_struct_trait( &impl_function.declaration.to_type(), &function.declaration.to_type(), - &impl_.struct_name, - &trait_, + &impl_.struct_.name, + &trait_.name, )?; } } diff --git a/src/type_alias_resolution.rs b/src/type_alias_resolution.rs index cd8187c..7c29d59 100644 --- a/src/type_alias_resolution.rs +++ b/src/type_alias_resolution.rs @@ -166,17 +166,12 @@ impl TypeAliasResolver { value: "Self".to_string(), }, }, - replaces: ast::TypeUsage::Named(ast::NamedTypeUsage { - type_parameters: ast::GenericUsage::Unknown, - name: impl_.struct_name.clone(), - }), + replaces: ast::TypeUsage::Named(impl_.struct_.clone()), }); return ast::Impl { generic: impl_.generic.clone(), - trait_type_parameters: impl_.trait_type_parameters.clone(), trait_: impl_.trait_.clone(), - struct_name: impl_.struct_name.clone(), - struct_type_parameters: impl_.struct_type_parameters.clone(), + struct_: impl_.struct_.clone(), functions: impl_.functions.iter().map(|f| self.with_function(&impl_ctx, f)).collect(), }; } diff --git a/src/type_checking.rs b/src/type_checking.rs index 14ce7b3..1a72625 100644 --- a/src/type_checking.rs +++ b/src/type_checking.rs @@ -285,6 +285,32 @@ impl Context { return ctx; } + fn add_generic(&self, generic: &ast::Generic) -> Result { + let mut ctx = self.clone(); + for parameter in generic.parameters.iter() { + let mut env_type = EnvType{ + is_a: TypeType::Trait, + fields: HashMap::new(), + impls: vec!(), + }; + for bound in parameter.bounds.iter() { + if !self.environment.contains_key(&bound.name.value) { + return Err(errors::TypingError::TypeDoesNotExist { + identifier: bound.clone(), + }); + } + match &self.environment[&bound.name.value] { + NamedEntity::NamedType(named_type) => { + env_type.impls.push(named_type.impls[0].clone()); + }, + _ => {} + } + }; + ctx.environment.insert(parameter.name.name.value.clone(), NamedEntity::NamedType(env_type)); + } + return Ok(ctx); + } + fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap) -> Result { let mut functions = HashMap::new(); for func in impl_.functions.iter() { @@ -292,13 +318,13 @@ impl Context { } // fill out defaults match &impl_.trait_ { - Some(trait_name) => { - if !traits.contains_key(&trait_name.name.value) { + Some(trait_) => { + if !traits.contains_key(&trait_.name.name.value) { return Err(errors::TypingError::TypeDoesNotExist { - identifier: trait_name.clone(), + identifier: trait_.name.clone(), }); } - for func in traits[&trait_name.name.value].functions.iter() { + for func in traits[&trait_.name.name.value].functions.iter() { match func { ast::TraitItem::Function(default_function) => { if !functions.contains_key(&default_function.declaration.name.name.value) { @@ -315,23 +341,23 @@ impl Context { None => {} } let mut result = self.clone(); - let mut env_named = result.environment[&impl_.struct_name.name.value].clone(); + let mut env_named = result.environment[&impl_.struct_.name.name.value].clone(); match &mut env_named { NamedEntity::NamedType(env_type) => { env_type.impls.push(EnvImpl { trait_: match &impl_.trait_ { - Some(trait_) => Some(trait_.name.value.to_string()), + Some(trait_) => Some(trait_.name.name.value.to_string()), None => None, }, functions: functions, }); result .environment - .insert(impl_.struct_name.name.value.to_string(), NamedEntity::NamedType(env_type.clone())); + .insert(impl_.struct_.name.name.value.to_string(), NamedEntity::NamedType(env_type.clone())); } NamedEntity::Variable(_) => { return Err(errors::TypingError::TypeDoesNotExist { - identifier: impl_.struct_name.clone(), + identifier: impl_.struct_.name.clone(), }); } } @@ -538,9 +564,9 @@ impl TypeChecker { for item in module.items.iter() { match item { ast::ModuleItem::Impl(impl_) => { - if !ctx.environment.contains_key(&impl_.struct_name.name.value) { + if !ctx.environment.contains_key(&impl_.struct_.name.name.value) { return Err(errors::TypingError::IdentifierIsNotType { - identifier: impl_.struct_name.clone(), + identifier: impl_.struct_.name.clone(), }); } ctx = ctx.add_impl(&impl_, &traits)?; @@ -588,9 +614,10 @@ impl TypeChecker { incoming_substitutions: &SubstitutionMap, function: &ast::Function, ) -> Result<(ast::Function, SubstitutionMap)> { - let declaration = self.with_function_declaration(ctx, &function.declaration)?; + let gen_ctx = ctx.add_generic(&function.declaration.generic)?; + let declaration = self.with_function_declaration(&gen_ctx, &function.declaration)?; // add args to env - let mut function_ctx = ctx.set_current_function_return(&declaration.return_type.clone()); + let mut function_ctx = gen_ctx.set_current_function_return(&declaration.return_type.clone()); for arg in declaration.arguments.iter() { function_ctx = function_ctx.add_variable(arg.name.name.value.to_string(), &arg.type_.clone()); } @@ -660,16 +687,17 @@ impl TypeChecker { incoming_substitutions: &SubstitutionMap, trait_: &ast::TraitTypeDeclaration, ) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> { + let gen_ctx = ctx.add_generic(&trait_.generic)?; let mut substitutions = incoming_substitutions.clone(); let mut result_functions = vec![]; for item in &trait_.functions { match item { ast::TraitItem::FunctionDeclaration(declaration) => { - let result_declaration = self.with_function_declaration(ctx, declaration)?; + let result_declaration = self.with_function_declaration(&gen_ctx, declaration)?; result_functions.push(ast::TraitItem::FunctionDeclaration(result_declaration)); } ast::TraitItem::Function(function) => { - let (function_result, susbt) = self.with_function(ctx, incoming_substitutions, function)?; + let (function_result, susbt) = self.with_function(&gen_ctx, incoming_substitutions, function)?; substitutions = compose_substitutions(ctx, &substitutions, &susbt)?; result_functions.push(ast::TraitItem::Function(function_result)); } @@ -686,9 +714,10 @@ impl TypeChecker { } fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> Result { + let struct_ctx = ctx.add_generic(&struct_.generic)?; let mut fields = vec![]; for field in struct_.fields.iter() { - type_exists(ctx, &field.type_)?; + type_exists(&struct_ctx, &field.type_)?; fields.push(ast::StructField { name: field.name.clone(), type_: field.type_.clone(), @@ -707,24 +736,24 @@ impl TypeChecker { incoming_substitutions: &SubstitutionMap, impl_: &ast::Impl, ) -> Result<(ast::Impl, SubstitutionMap)> { + let impl_ctx = ctx.add_generic(&impl_.generic)?; + let mut substitutions = incoming_substitutions.clone(); type_exists( - ctx, - &ast::TypeUsage::new_named(&impl_.struct_name.clone(), &ast::GenericUsage::Unknown), + &impl_ctx, + &ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown), )?; let mut functions = vec![]; for function in impl_.functions.iter() { - let (result, function_subs) = self.with_function(&ctx, &substitutions, function)?; - substitutions = compose_substitutions(ctx, &substitutions, &function_subs)?; + let (result, function_subs) = self.with_function(&impl_ctx, &substitutions, function)?; + substitutions = compose_substitutions(&impl_ctx, &substitutions, &function_subs)?; functions.push(result); } return Ok(( ast::Impl { generic: impl_.generic.clone(), - trait_type_parameters: impl_.trait_type_parameters.clone(), trait_: impl_.trait_.clone(), - struct_name: impl_.struct_name.clone(), - struct_type_parameters: impl_.struct_type_parameters.clone(), + struct_: impl_.struct_.clone(), functions: functions, }, substitutions,