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,
}
type Generic[T] struct {
value: T,
}
impl User {
fn new(id: i64): Self {
return Self{

View File

@@ -358,10 +358,8 @@ pub enum TypeDeclaration {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Impl {
pub generic: Generic,
pub trait_type_parameters: Option<GenericUsage>,
pub trait_: Option<Identifier>,
pub struct_name: Identifier,
pub struct_type_parameters: GenericUsage,
pub struct_: NamedTypeUsage,
pub trait_: Option<NamedTypeUsage>,
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 {
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 = {
<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>> ")" ":" <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 = {
"impl" <g:Generic?> <i:SpannedIdentifier> <sgu:GenericUsage?> "{" <f:Function*> "}" => {
"impl" <g:Generic?> <s:NamedTypeUsage> "{" <f:Function*> "}" => {
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" <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 {
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}
}
};

View File

@@ -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

View File

@@ -10,7 +10,7 @@ struct Context {
}
fn create_builtins() -> HashMap<String, ast::TraitTypeDeclaration> {
let mut result = HashMap::<String, ast::TraitTypeDeclaration>::new();
let result = HashMap::<String, ast::TraitTypeDeclaration>::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,
)?;
}
}

View File

@@ -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(),
};
}

View File

@@ -285,6 +285,32 @@ impl Context {
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> {
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<ast::StructTypeDeclaration> {
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,