added generics without type instantiation

This commit is contained in:
Andrew Segavac
2021-10-30 22:03:12 -06:00
parent 742c271732
commit 51c698ba5d
7 changed files with 81 additions and 63 deletions

View File

@@ -48,6 +48,10 @@ type User struct {
id: i64, id: i64,
} }
type Generic[T] struct {
value: T,
}
impl User { impl User {
fn new(id: i64): Self { fn new(id: i64): Self {
return Self{ return Self{

View File

@@ -358,10 +358,8 @@ pub enum TypeDeclaration {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Impl { pub struct Impl {
pub generic: Generic, pub generic: Generic,
pub trait_type_parameters: Option<GenericUsage>, pub struct_: NamedTypeUsage,
pub trait_: Option<Identifier>, pub trait_: Option<NamedTypeUsage>,
pub struct_name: Identifier,
pub struct_type_parameters: GenericUsage,
pub functions: Vec<Function>, pub functions: Vec<Function>,
} }

View File

@@ -207,11 +207,15 @@ pub Block: ast::Block = {
} }
}; };
pub TypeUsage: ast::TypeUsage = { pub NamedTypeUsage: ast::NamedTypeUsage = {
<n:SpannedIdentifier> <gu:GenericUsage?> => match gu { <n:SpannedIdentifier> <gu:GenericUsage?> => match gu {
Some(tp) => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: tp, name: n}), Some(tp) => ast::NamedTypeUsage{type_parameters: tp, name: n},
None => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n}), None => ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n},
}, },
};
pub TypeUsage: ast::TypeUsage = {
<n:NamedTypeUsage> => ast::TypeUsage::Named(n),
"fn" "(" <args:Comma<TypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}), "fn" "(" <args:Comma<TypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}),
"fn" "(" <args:Comma<TypeUsage>> ")" ":" <rt:TypeUsage> => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}), "fn" "(" <args:Comma<TypeUsage>> ")" ":" <rt:TypeUsage> => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}),
}; };
@@ -272,31 +276,19 @@ pub TypeDeclaration: ast::TypeDeclaration = {
}; };
pub Impl: ast::Impl = { pub Impl: ast::Impl = {
"impl" <g:Generic?> <i:SpannedIdentifier> <sgu:GenericUsage?> "{" <f:Function*> "}" => { "impl" <g:Generic?> <s:NamedTypeUsage> "{" <f:Function*> "}" => {
let generic = match g { let generic = match g {
Some(g) => g, Some(g) => g,
None => ast::Generic{parameters: vec!()}, None => ast::Generic{parameters: vec!()},
}; };
let struct_type_params = match sgu { ast::Impl{generic: generic, trait_: None, struct_: s, functions: f}
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}
}, },
"impl" <g:Generic?> <t:SpannedIdentifier> <tgu:GenericUsage?> "for" <i:SpannedIdentifier> <sgu:GenericUsage?> "{" <f:Function*> "}" => { "impl" <g:Generic?> <t:NamedTypeUsage> "for" <s:NamedTypeUsage> "{" <f:Function*> "}" => {
let generic = match g { let generic = match g {
Some(g) => g, Some(g) => g,
None => ast::Generic{parameters: vec!()}, None => ast::Generic{parameters: vec!()},
}; };
let struct_type_params = match sgu { ast::Impl{generic: generic, trait_: Some(t), struct_: s, functions: f}
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}
} }
}; };

View File

@@ -102,7 +102,7 @@ impl Context {
); );
} }
ast::ModuleItem::Impl(impl_) => { 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 { for module_item in &ctx.current_module.items {
match module_item { match module_item {
ast::ModuleItem::Impl(impl_) => { 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 { for method in &impl_.functions {
if method.declaration.name.name.value == struct_getter.attribute.name.value { if method.declaration.name.name.value == struct_getter.attribute.name.value {
// if first type matches, partial apply self // if first type matches, partial apply self

View File

@@ -10,7 +10,7 @@ struct Context {
} }
fn create_builtins() -> HashMap<String, ast::TraitTypeDeclaration> { fn create_builtins() -> HashMap<String, ast::TraitTypeDeclaration> {
let mut result = HashMap::<String, ast::TraitTypeDeclaration>::new(); let result = HashMap::<String, ast::TraitTypeDeclaration>::new();
return result; return result;
} }
@@ -100,12 +100,12 @@ impl TraitChecker {
match &impl_.trait_ { match &impl_.trait_ {
Some(trait_) => { Some(trait_) => {
// assert trait functions satisfied // 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 { 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() { for trait_item in trait_declaration.functions.iter() {
match trait_item { match trait_item {
ast::TraitItem::FunctionDeclaration(declaration) => { ast::TraitItem::FunctionDeclaration(declaration) => {
@@ -116,14 +116,14 @@ impl TraitChecker {
compare_struct_trait( compare_struct_trait(
&impl_function.declaration.to_type(), &impl_function.declaration.to_type(),
&declaration.to_type(), &declaration.to_type(),
&impl_.struct_name, &impl_.struct_.name,
&trait_, &trait_.name,
)?; )?;
} }
} }
if found == false { if found == false {
return Err(errors::TypingError::MissingTraitFunction { return Err(errors::TypingError::MissingTraitFunction {
struct_name: impl_.struct_name.clone(), struct_name: impl_.struct_.name.clone(),
function_name: declaration.name.clone(), function_name: declaration.name.clone(),
}); });
} }
@@ -135,8 +135,8 @@ impl TraitChecker {
compare_struct_trait( compare_struct_trait(
&impl_function.declaration.to_type(), &impl_function.declaration.to_type(),
&function.declaration.to_type(), &function.declaration.to_type(),
&impl_.struct_name, &impl_.struct_.name,
&trait_, &trait_.name,
)?; )?;
} }
} }

View File

@@ -166,17 +166,12 @@ impl TypeAliasResolver {
value: "Self".to_string(), value: "Self".to_string(),
}, },
}, },
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage { replaces: ast::TypeUsage::Named(impl_.struct_.clone()),
type_parameters: ast::GenericUsage::Unknown,
name: impl_.struct_name.clone(),
}),
}); });
return ast::Impl { return ast::Impl {
generic: impl_.generic.clone(), generic: impl_.generic.clone(),
trait_type_parameters: impl_.trait_type_parameters.clone(),
trait_: impl_.trait_.clone(), trait_: impl_.trait_.clone(),
struct_name: impl_.struct_name.clone(), struct_: impl_.struct_.clone(),
struct_type_parameters: impl_.struct_type_parameters.clone(),
functions: impl_.functions.iter().map(|f| self.with_function(&impl_ctx, f)).collect(), functions: impl_.functions.iter().map(|f| self.with_function(&impl_ctx, f)).collect(),
}; };
} }

View File

@@ -285,6 +285,32 @@ impl Context {
return ctx; return ctx;
} }
fn add_generic(&self, generic: &ast::Generic) -> Result<Context> {
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<String, ast::TraitTypeDeclaration>) -> Result<Context> { fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
let mut functions = HashMap::new(); let mut functions = HashMap::new();
for func in impl_.functions.iter() { for func in impl_.functions.iter() {
@@ -292,13 +318,13 @@ impl Context {
} }
// fill out defaults // fill out defaults
match &impl_.trait_ { match &impl_.trait_ {
Some(trait_name) => { Some(trait_) => {
if !traits.contains_key(&trait_name.name.value) { if !traits.contains_key(&trait_.name.name.value) {
return Err(errors::TypingError::TypeDoesNotExist { 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 { match func {
ast::TraitItem::Function(default_function) => { ast::TraitItem::Function(default_function) => {
if !functions.contains_key(&default_function.declaration.name.name.value) { if !functions.contains_key(&default_function.declaration.name.name.value) {
@@ -315,23 +341,23 @@ impl Context {
None => {} None => {}
} }
let mut result = self.clone(); 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 { match &mut env_named {
NamedEntity::NamedType(env_type) => { NamedEntity::NamedType(env_type) => {
env_type.impls.push(EnvImpl { env_type.impls.push(EnvImpl {
trait_: match &impl_.trait_ { trait_: match &impl_.trait_ {
Some(trait_) => Some(trait_.name.value.to_string()), Some(trait_) => Some(trait_.name.name.value.to_string()),
None => None, None => None,
}, },
functions: functions, functions: functions,
}); });
result result
.environment .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(_) => { NamedEntity::Variable(_) => {
return Err(errors::TypingError::TypeDoesNotExist { 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() { for item in module.items.iter() {
match item { match item {
ast::ModuleItem::Impl(impl_) => { 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 { return Err(errors::TypingError::IdentifierIsNotType {
identifier: impl_.struct_name.clone(), identifier: impl_.struct_.name.clone(),
}); });
} }
ctx = ctx.add_impl(&impl_, &traits)?; ctx = ctx.add_impl(&impl_, &traits)?;
@@ -588,9 +614,10 @@ impl TypeChecker {
incoming_substitutions: &SubstitutionMap, incoming_substitutions: &SubstitutionMap,
function: &ast::Function, function: &ast::Function,
) -> Result<(ast::Function, SubstitutionMap)> { ) -> 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 // 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() { for arg in declaration.arguments.iter() {
function_ctx = function_ctx.add_variable(arg.name.name.value.to_string(), &arg.type_.clone()); function_ctx = function_ctx.add_variable(arg.name.name.value.to_string(), &arg.type_.clone());
} }
@@ -660,16 +687,17 @@ impl TypeChecker {
incoming_substitutions: &SubstitutionMap, incoming_substitutions: &SubstitutionMap,
trait_: &ast::TraitTypeDeclaration, trait_: &ast::TraitTypeDeclaration,
) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> { ) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> {
let gen_ctx = ctx.add_generic(&trait_.generic)?;
let mut substitutions = incoming_substitutions.clone(); let mut substitutions = incoming_substitutions.clone();
let mut result_functions = vec![]; let mut result_functions = vec![];
for item in &trait_.functions { for item in &trait_.functions {
match item { match item {
ast::TraitItem::FunctionDeclaration(declaration) => { 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)); result_functions.push(ast::TraitItem::FunctionDeclaration(result_declaration));
} }
ast::TraitItem::Function(function) => { 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)?; substitutions = compose_substitutions(ctx, &substitutions, &susbt)?;
result_functions.push(ast::TraitItem::Function(function_result)); 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<ast::StructTypeDeclaration> { fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> Result<ast::StructTypeDeclaration> {
let struct_ctx = ctx.add_generic(&struct_.generic)?;
let mut fields = vec![]; let mut fields = vec![];
for field in struct_.fields.iter() { for field in struct_.fields.iter() {
type_exists(ctx, &field.type_)?; type_exists(&struct_ctx, &field.type_)?;
fields.push(ast::StructField { fields.push(ast::StructField {
name: field.name.clone(), name: field.name.clone(),
type_: field.type_.clone(), type_: field.type_.clone(),
@@ -707,24 +736,24 @@ impl TypeChecker {
incoming_substitutions: &SubstitutionMap, incoming_substitutions: &SubstitutionMap,
impl_: &ast::Impl, impl_: &ast::Impl,
) -> Result<(ast::Impl, SubstitutionMap)> { ) -> Result<(ast::Impl, SubstitutionMap)> {
let impl_ctx = ctx.add_generic(&impl_.generic)?;
let mut substitutions = incoming_substitutions.clone(); let mut substitutions = incoming_substitutions.clone();
type_exists( type_exists(
ctx, &impl_ctx,
&ast::TypeUsage::new_named(&impl_.struct_name.clone(), &ast::GenericUsage::Unknown), &ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown),
)?; )?;
let mut functions = vec![]; let mut functions = vec![];
for function in impl_.functions.iter() { for function in impl_.functions.iter() {
let (result, function_subs) = self.with_function(&ctx, &substitutions, function)?; let (result, function_subs) = self.with_function(&impl_ctx, &substitutions, function)?;
substitutions = compose_substitutions(ctx, &substitutions, &function_subs)?; substitutions = compose_substitutions(&impl_ctx, &substitutions, &function_subs)?;
functions.push(result); functions.push(result);
} }
return Ok(( return Ok((
ast::Impl { ast::Impl {
generic: impl_.generic.clone(), generic: impl_.generic.clone(),
trait_type_parameters: impl_.trait_type_parameters.clone(),
trait_: impl_.trait_.clone(), trait_: impl_.trait_.clone(),
struct_name: impl_.struct_name.clone(), struct_: impl_.struct_.clone(),
struct_type_parameters: impl_.struct_type_parameters.clone(),
functions: functions, functions: functions,
}, },
substitutions, substitutions,