finished revamping type system as setup for generics

This commit is contained in:
Andrew Segavac
2021-10-24 15:59:26 -06:00
parent fbb81f3d09
commit 742c271732
7 changed files with 529 additions and 352 deletions

View File

@@ -17,7 +17,7 @@ impl IdGenerator {
pub fn new_unit() -> TypeUsage { pub fn new_unit() -> TypeUsage {
TypeUsage::Named(NamedTypeUsage { TypeUsage::Named(NamedTypeUsage {
type_parameters: GenericUsage::Known(GenericInstantiation{parameters: vec!()}), type_parameters: GenericUsage::Known(GenericInstantiation { parameters: vec![] }),
name: Identifier { name: Identifier {
name: Spanned { name: Spanned {
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
@@ -29,7 +29,7 @@ pub fn new_unit() -> TypeUsage {
pub fn new_never() -> TypeUsage { pub fn new_never() -> TypeUsage {
TypeUsage::Named(NamedTypeUsage { TypeUsage::Named(NamedTypeUsage {
type_parameters: GenericUsage::Known(GenericInstantiation{parameters: vec!()}), type_parameters: GenericUsage::Known(GenericInstantiation { parameters: vec![] }),
name: Identifier { name: Identifier {
name: Spanned { name: Spanned {
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
@@ -81,12 +81,15 @@ impl TypeUsage {
} }
pub fn new_named(identifier: &Identifier, generic_usage: &GenericUsage) -> TypeUsage { pub fn new_named(identifier: &Identifier, generic_usage: &GenericUsage) -> TypeUsage {
return TypeUsage::Named(NamedTypeUsage { type_parameters: generic_usage.clone(), name: identifier.clone() }); return TypeUsage::Named(NamedTypeUsage {
type_parameters: generic_usage.clone(),
name: identifier.clone(),
});
} }
pub fn new_builtin(name: String) -> TypeUsage { pub fn new_builtin(name: String) -> TypeUsage {
TypeUsage::Named(NamedTypeUsage { TypeUsage::Named(NamedTypeUsage {
type_parameters: GenericUsage::Known(GenericInstantiation{parameters: vec!()}), type_parameters: GenericUsage::Known(GenericInstantiation { parameters: vec![] }),
name: Identifier { name: Identifier {
name: Spanned { name: Spanned {
span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these
@@ -128,16 +131,12 @@ pub enum GenericUsage {
impl GenericUsage { impl GenericUsage {
pub fn new(type_parameters: &[TypeUsage]) -> Self { pub fn new(type_parameters: &[TypeUsage]) -> Self {
GenericUsage::Known(GenericInstantiation{ GenericUsage::Known(GenericInstantiation {
parameters: type_parameters.iter().map(|tp| { parameters: type_parameters.iter().map(|tp| tp.clone()).collect(),
tp.clone()
}).collect(),
}) })
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Operator { pub enum Operator {
Mul, Mul,

View File

@@ -27,10 +27,7 @@ pub enum TypingError {
#[error("name is not a struct, cannot instaniate")] #[error("name is not a struct, cannot instaniate")]
NotAStructLiteral { identifier: ast::Identifier }, NotAStructLiteral { identifier: ast::Identifier },
#[error("struct literal fields mismatch")] #[error("struct literal fields mismatch")]
StructLiteralFieldsMismatch { StructLiteralFieldsMismatch { struct_name: ast::Identifier },
struct_name: ast::Identifier,
struct_definition_name: ast::Identifier,
},
#[error("missing trait function")] #[error("missing trait function")]
MissingTraitFunction { MissingTraitFunction {
struct_name: ast::Identifier, struct_name: ast::Identifier,
@@ -48,6 +45,8 @@ pub enum TypingError {
IfConditionMustBeBool { IfConditionMustBeBool {
// TODO: add position // TODO: add position
}, },
#[error("cannot use type as an expression")]
TypeIsNotAnExpression { type_name: ast::Identifier },
#[error("multiple errors")] #[error("multiple errors")]
MultipleErrors { errors: Vec<TypingError> }, MultipleErrors { errors: Vec<TypingError> },
} }

View File

@@ -95,12 +95,10 @@ impl Context {
ast::ModuleItem::Function(function) => { ast::ModuleItem::Function(function) => {
ctx.environment.insert( ctx.environment.insert(
function.declaration.name.name.value.to_string(), function.declaration.name.name.value.to_string(),
NamedEntity::Variable(Value::Function( NamedEntity::Variable(Value::Function(Function {
Function{ partial: vec![],
partial: vec!(),
ref_: FunctionRef::User(function.clone()), ref_: FunctionRef::User(function.clone()),
} })),
)),
); );
} }
ast::ModuleItem::Impl(impl_) => { ast::ModuleItem::Impl(impl_) => {
@@ -225,11 +223,9 @@ impl TreeWalkInterpreter {
let mut ctx = Context::from_module(module); let mut ctx = Context::from_module(module);
let main = match &ctx.environment["main"] { let main = match &ctx.environment["main"] {
NamedEntity::Variable(Value::Function(func)) => { NamedEntity::Variable(Value::Function(func)) => match &func.ref_ {
match &func.ref_ {
FunctionRef::User(ref_) => ref_.clone(), FunctionRef::User(ref_) => ref_.clone(),
_ => panic!("main should be a user defined function"), _ => panic!("main should be a user defined function"),
}
}, },
_ => panic!("main should be a user defined function"), _ => panic!("main should be a user defined function"),
}; };
@@ -378,26 +374,35 @@ impl TreeWalkInterpreter {
argument_values.push(argument_value); argument_values.push(argument_value);
} }
match &source { match &source {
Value::Function(function) => { Value::Function(function) => match &function.ref_ {
match &function.ref_ {
FunctionRef::User(user_function) => { FunctionRef::User(user_function) => {
let mut fn_ctx = ctx.new_env(); let mut fn_ctx = ctx.new_env();
let mut i = 0; let mut i = 0;
for partial_arg in &function.partial { for partial_arg in &function.partial {
fn_ctx.set_variable(user_function.declaration.arguments[i].name.name.value.to_string(), &partial_arg.clone()); fn_ctx.set_variable(
user_function.declaration.arguments[i].name.name.value.to_string(),
&partial_arg.clone(),
);
i = i + 1; i = i + 1;
} }
for argument_value in &argument_values { for argument_value in &argument_values {
fn_ctx.set_variable(user_function.declaration.arguments[i].name.name.value.to_string(), &argument_value.clone()); fn_ctx.set_variable(
user_function.declaration.arguments[i].name.name.value.to_string(),
&argument_value.clone(),
);
} }
return ExpressionResult::Value(self.with_function(&mut fn_ctx, user_function)); return ExpressionResult::Value(self.with_function(&mut fn_ctx, user_function));
} }
FunctionRef::Builtin(builtin_function) => { FunctionRef::Builtin(builtin_function) => {
let all_values = function.partial.iter().map(|val| {val.clone()}).chain(argument_values.into_iter()).collect(); let all_values = function
.partial
.iter()
.map(|val| val.clone())
.chain(argument_values.into_iter())
.collect();
return ExpressionResult::Value(builtin_function(all_values)); return ExpressionResult::Value(builtin_function(all_values));
} }
} },
}
_ => panic!("type error: function call source must be a function"), _ => panic!("type error: function call source must be a function"),
} }
} }
@@ -454,17 +459,17 @@ impl TreeWalkInterpreter {
match &method.declaration.arguments[0].type_ { match &method.declaration.arguments[0].type_ {
ast::TypeUsage::Named(arg_named) => { ast::TypeUsage::Named(arg_named) => {
if arg_named.name.name.value == s.source.name.name.value { if arg_named.name.name.value == s.source.name.name.value {
return ExpressionResult::Value(Value::Function(Function{ return ExpressionResult::Value(Value::Function(Function {
partial: vec!(source.clone()), partial: vec![source.clone()],
ref_: FunctionRef::User(method.clone()), ref_: FunctionRef::User(method.clone()),
})); }));
} }
} }
_ => {}, _ => {}
} }
} }
return ExpressionResult::Value(Value::Function(Function{ return ExpressionResult::Value(Value::Function(Function {
partial: vec!(), partial: vec![],
ref_: FunctionRef::User(method.clone()), ref_: FunctionRef::User(method.clone()),
})); }));
} }

View File

@@ -2,6 +2,7 @@
mod ast; mod ast;
mod errors; mod errors;
mod interpreter; mod interpreter;
mod trait_checking;
mod type_alias_resolution; mod type_alias_resolution;
mod type_checking; mod type_checking;
#[macro_use] #[macro_use]
@@ -42,6 +43,14 @@ fn main() {
let alias_resolver = type_alias_resolution::TypeAliasResolver {}; let alias_resolver = type_alias_resolution::TypeAliasResolver {};
let resolved_ast = alias_resolver.with_module(&module_ast); let resolved_ast = alias_resolver.with_module(&module_ast);
// println!("resolved ast: {:#?}", &resolved_ast); // println!("resolved ast: {:#?}", &resolved_ast);
let trait_checker = trait_checking::TraitChecker {};
match trait_checker.with_module(&resolved_ast) {
Ok(_) => {}
Err(err) => {
println!("type checking error: {:#?}", &err);
return;
}
}
let type_checker = type_checking::TypeChecker {}; let type_checker = type_checking::TypeChecker {};
let type_checking_result = type_checker.with_module(&resolved_ast); let type_checking_result = type_checker.with_module(&resolved_ast);
match &type_checking_result { match &type_checking_result {

171
src/trait_checking.rs Normal file
View File

@@ -0,0 +1,171 @@
use crate::ast;
use crate::errors;
use std::collections::HashMap;
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
#[derive(Debug, Clone, PartialEq, Eq)]
struct Context {
pub environment_traits: HashMap<String, ast::TraitTypeDeclaration>,
}
fn create_builtins() -> HashMap<String, ast::TraitTypeDeclaration> {
let mut result = HashMap::<String, ast::TraitTypeDeclaration>::new();
return result;
}
fn compare_struct_trait(
struct_: &ast::TypeUsage,
trait_: &ast::TypeUsage,
struct_name: &ast::Identifier,
trait_name: &ast::Identifier,
) -> Result<()> {
match struct_ {
ast::TypeUsage::Named(named) => match trait_ {
ast::TypeUsage::Named(trait_named) => {
if named.name.name.value == trait_named.name.name.value
|| (named.name.name.value == struct_name.name.value && trait_named.name.name.value == trait_name.name.value)
{
return Ok(());
}
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
ast::TypeUsage::Function(_) => {
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
_ => panic!("Unknown in function definition"),
},
ast::TypeUsage::Function(function) => match trait_ {
ast::TypeUsage::Named(_) => {
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
ast::TypeUsage::Function(trait_function) => {
if function.arguments.len() != trait_function.arguments.len() {
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
for (i, _) in function.arguments.iter().enumerate() {
compare_struct_trait(&function.arguments[i], &trait_function.arguments[i], struct_name, trait_name)?;
}
compare_struct_trait(&function.return_type, &trait_function.return_type, struct_name, trait_name)?;
return Ok(());
}
_ => panic!("Unknown in function definition"),
},
_ => panic!("Unknown in function definition"),
}
}
pub struct TraitChecker {}
impl TraitChecker {
pub fn with_module(self: &Self, module: &ast::Module) -> Result<()> {
let mut ctx = Context {
environment_traits: create_builtins(),
};
for item in module.items.iter() {
match item {
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Trait(trait_)) => {
ctx.environment_traits.insert(trait_.name.name.value.to_string(), trait_.clone());
}
_ => {}
}
}
for item in module.items.iter() {
match item {
ast::ModuleItem::Impl(impl_) => {
self.with_impl(&ctx, impl_)?;
}
_ => {}
}
}
return Ok(());
}
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> Result<()> {
// See if trait actually matches
match &impl_.trait_ {
Some(trait_) => {
// assert trait functions satisfied
if !ctx.environment_traits.contains_key(&trait_.name.value) {
return Err(errors::TypingError::TypeDoesNotExist {
identifier: trait_.clone(),
});
}
let trait_declaration = &ctx.environment_traits[&trait_.name.value];
for trait_item in trait_declaration.functions.iter() {
match trait_item {
ast::TraitItem::FunctionDeclaration(declaration) => {
let mut found = false;
for impl_function in impl_.functions.iter() {
if impl_function.declaration.name.name.value == declaration.name.name.value {
found = true;
compare_struct_trait(
&impl_function.declaration.to_type(),
&declaration.to_type(),
&impl_.struct_name,
&trait_,
)?;
}
}
if found == false {
return Err(errors::TypingError::MissingTraitFunction {
struct_name: impl_.struct_name.clone(),
function_name: declaration.name.clone(),
});
}
}
ast::TraitItem::Function(function) => {
// skip found check because it has a default
for impl_function in impl_.functions.iter() {
if impl_function.declaration.name.name.value == function.declaration.name.name.value {
compare_struct_trait(
&impl_function.declaration.to_type(),
&function.declaration.to_type(),
&impl_.struct_name,
&trait_,
)?;
}
}
}
}
}
// assert all functions are in trait
for impl_function in impl_.functions.iter() {
let mut found = false;
for trait_item in trait_declaration.functions.iter() {
let declaration = match trait_item {
ast::TraitItem::Function(function) => &function.declaration,
ast::TraitItem::FunctionDeclaration(declaration) => &declaration,
};
if impl_function.declaration.name.name.value == declaration.name.name.value {
found = true;
break;
}
}
if found == false {
return Err(errors::TypingError::FunctionNotInTrait {
function_name: impl_function.declaration.name.clone(),
});
}
}
}
None => {}
}
// TODO: check for duplicate functions
return Ok(());
}
}

View File

@@ -138,7 +138,7 @@ impl TypeAliasResolver {
}, },
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage { replaces: ast::TypeUsage::Named(ast::NamedTypeUsage {
type_parameters: ast::GenericUsage::Unknown, type_parameters: ast::GenericUsage::Unknown,
name: trait_.name.clone() name: trait_.name.clone(),
}), }),
}); });
return ast::TraitTypeDeclaration { return ast::TraitTypeDeclaration {
@@ -148,9 +148,7 @@ impl TypeAliasResolver {
.functions .functions
.iter() .iter()
.map(|f| match f { .map(|f| match f {
ast::TraitItem::Function(function) => { ast::TraitItem::Function(function) => ast::TraitItem::Function(self.with_function(&trait_ctx, function)),
ast::TraitItem::Function(self.with_function(&trait_ctx, function))
},
ast::TraitItem::FunctionDeclaration(function_declaration) => { ast::TraitItem::FunctionDeclaration(function_declaration) => {
ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration)) ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration))
} }

View File

@@ -6,16 +6,72 @@ pub type SubstitutionMap = HashMap<String, ast::TypeUsage>;
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>; pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnvImpl {
trait_: Option<String>,
functions: HashMap<String, ast::TypeUsage>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TypeType {
Scalar,
Trait,
Struct,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnvType {
is_a: TypeType,
fields: HashMap<String, ast::TypeUsage>,
impls: Vec<EnvImpl>,
}
impl EnvType {
fn from_struct(struct_: &ast::StructTypeDeclaration) -> EnvType {
return EnvType {
is_a: TypeType::Struct,
fields: struct_
.fields
.iter()
.map(|field| (field.name.name.value.to_string(), field.type_.clone()))
.collect(),
impls: vec![],
};
}
fn from_trait(trait_: &ast::TraitTypeDeclaration) -> EnvType {
let mut functions = HashMap::new();
for func in trait_.functions.iter() {
match func {
ast::TraitItem::FunctionDeclaration(fd) => {
functions.insert(fd.name.name.value.to_string(), fd.to_type());
}
ast::TraitItem::Function(f) => {
functions.insert(f.declaration.name.name.value.to_string(), f.declaration.to_type());
}
}
}
let impl_ = EnvImpl {
trait_: None,
functions: functions,
};
return EnvType {
is_a: TypeType::Trait,
fields: HashMap::new(),
impls: vec![impl_],
};
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NamedEntity { pub enum NamedEntity {
TypeDeclaration(ast::TypeDeclaration), NamedType(EnvType),
Variable(ast::TypeUsage), Variable(ast::TypeUsage),
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
struct Context { struct Context {
pub current_function_return: Option<ast::TypeUsage>, pub current_function_return: Option<ast::TypeUsage>,
pub impls: Vec<ast::Impl>,
pub environment: HashMap<String, NamedEntity>, pub environment: HashMap<String, NamedEntity>,
} }
@@ -23,99 +79,127 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
let mut result = HashMap::new(); let mut result = HashMap::new();
result.insert( result.insert(
"i8".to_string(), "i8".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "i8".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"i16".to_string(), "i16".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "i16".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"i32".to_string(), "i32".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "i32".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"i64".to_string(), "i64".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "i64".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"isize".to_string(), "isize".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "isize".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"u8".to_string(), "u8".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "u8".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"u16".to_string(), "u16".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "u16".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"u32".to_string(), "u32".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "u32".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"u64".to_string(), "u64".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "u64".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"usize".to_string(), "usize".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "usize".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"f32".to_string(), "f32".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "f32".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"f64".to_string(), "f64".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "f64".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"bool".to_string(), "bool".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "bool".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"!".to_string(), "!".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "!".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
result.insert( result.insert(
"unit".to_string(), "unit".to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration { NamedEntity::NamedType(EnvType {
name: "unit".to_string(), is_a: TypeType::Scalar,
})), fields: HashMap::new(),
impls: vec![],
}),
); );
return result; return result;
} }
@@ -124,73 +208,38 @@ enum StructAttr {
Method(ast::TypeUsage), Method(ast::TypeUsage),
} }
fn get_struct_attr(ctx: &Context, struct_declaration: &ast::StructTypeDeclaration, attribute: &ast::Identifier) -> Result<StructAttr> { fn apply_self(type_name: &str, type_: &ast::TypeUsage) -> ast::TypeUsage {
for field in struct_declaration.fields.iter() { match type_ {
if field.name.name.value == attribute.name.value { ast::TypeUsage::Function(func) => {
return Ok(StructAttr::Field(field.type_.clone())); if func.arguments.len() > 0 {
} match &func.arguments[0] {
}
let mut result = Vec::new();
for impl_ in ctx.impls.iter() {
if &struct_declaration.name.name.value != &impl_.struct_name.name.value {
continue;
}
for method in impl_.functions.iter() {
if method.declaration.name.name.value == attribute.name.value {
let mut function_type = method.declaration.to_type();
// if the name of the type of the first argument == the class, remove the first arg
if method.declaration.arguments.len() > 0 {
match &method.declaration.arguments[0].type_ {
ast::TypeUsage::Named(named) => { ast::TypeUsage::Named(named) => {
if named.name.name.value == struct_declaration.name.name.value { if type_name == named.name.name.value {
function_type = method.declaration.to_method_type(); return ast::TypeUsage::Function(ast::FunctionTypeUsage {
arguments: func.arguments[1..func.arguments.len()].iter().map(|arg| arg.clone()).collect(),
return_type: func.return_type.clone(),
});
} }
} }
_ => {} _ => {}
};
}
result.push(function_type);
} }
} }
} }
// TODO: default trait impls _ => {}
if result.len() == 0 {
return Err(errors::TypingError::UnknownFieldName {
identifier: attribute.clone(),
});
} }
if result.len() > 1 { return type_.clone();
return Err(errors::TypingError::MultipleFieldName {
identifier: attribute.clone(),
});
}
return Ok(StructAttr::Method(result[0].clone()));
} }
fn get_trait_attr(ctx: &Context, trait_declaration: &ast::TraitTypeDeclaration, attribute: &ast::Identifier) -> Result<StructAttr> { fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier) -> Result<StructAttr> {
match get_from {
NamedEntity::NamedType(env_type) => {
if env_type.fields.contains_key(&attribute.name.value) {
return Ok(StructAttr::Field(env_type.fields[&attribute.name.value].clone()));
}
let mut result = Vec::new(); let mut result = Vec::new();
for trait_item in trait_declaration.functions.iter() { for impl_ in env_type.impls.iter() {
let declaration = match trait_item { if impl_.functions.contains_key(&attribute.name.value) {
ast::TraitItem::Function(function) => &function.declaration, result.push(impl_.functions[&attribute.name.value].clone())
ast::TraitItem::FunctionDeclaration(declaration) => declaration,
};
if declaration.name.name.value == attribute.name.value {
let mut function_type = declaration.to_type();
println!("foo: {:?}", declaration);
// if the name of the type of the first argument == the class, remove the first arg
if declaration.arguments.len() > 0 {
match &declaration.arguments[0].type_ {
ast::TypeUsage::Named(named) => {
if named.name.name.value == trait_declaration.name.name.value {
function_type = declaration.to_method_type();
}
}
_ => {}
};
}
result.push(function_type);
} }
} }
if result.len() == 0 { if result.len() == 0 {
@@ -204,87 +253,22 @@ fn get_trait_attr(ctx: &Context, trait_declaration: &ast::TraitTypeDeclaration,
}); });
} }
return Ok(StructAttr::Method(result[0].clone())); return Ok(StructAttr::Method(result[0].clone()));
}
fn get_attr(ctx: &Context, source_type: &ast::TypeUsage, attribute: &ast::Identifier) -> Result<StructAttr> {
match source_type {
ast::TypeUsage::Named(named) => {
match &ctx.environment[&named.name.name.value] {
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(type_declaration)) => {
return get_struct_attr(ctx, type_declaration, attribute);
} }
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Trait(type_declaration)) => { NamedEntity::Variable(type_) => match type_ {
return get_trait_attr(ctx, type_declaration, attribute); ast::TypeUsage::Named(named) => {
let attr = get_attr(ctx, &ctx.environment[&named.name.name.value], attribute)?;
let method = match attr {
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
StructAttr::Method(method) => method,
};
return Ok(StructAttr::Method(apply_self(&named.name.name.value, &method)));
} }
_ => { _ => {
return Err(errors::TypingError::AttributeOfNonstruct { return Err(errors::TypingError::AttributeOfNonstruct {
identifier: attribute.clone(), identifier: attribute.clone(),
}); });
// TODO: support builtins - float, int, etc.
} }
}
}
ast::TypeUsage::Function(_) => {
return Err(errors::TypingError::NotAStructLiteral {
identifier: attribute.clone(),
});
}
_ => {
panic!("tried to get attr of unknown");
}
};
}
fn compare_struct_trait(
struct_: &ast::TypeUsage,
trait_: &ast::TypeUsage,
struct_name: &ast::Identifier,
trait_name: &ast::Identifier,
) -> Result<()> {
match struct_ {
ast::TypeUsage::Named(named) => match trait_ {
ast::TypeUsage::Named(trait_named) => {
if named.name.name.value == trait_named.name.name.value
|| (named.name.name.value == struct_name.name.value && trait_named.name.name.value == trait_name.name.value)
{
return Ok(());
}
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
ast::TypeUsage::Function(_) => {
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
_ => panic!("Unknown in function definition"),
}, },
ast::TypeUsage::Function(function) => match trait_ {
ast::TypeUsage::Named(_) => {
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
ast::TypeUsage::Function(trait_function) => {
if function.arguments.len() != trait_function.arguments.len() {
return Err(errors::TypingError::TypeMismatch {
type_one: struct_.clone(),
type_two: trait_.clone(),
});
}
for (i, _) in function.arguments.iter().enumerate() {
compare_struct_trait(&function.arguments[i], &trait_function.arguments[i], struct_name, trait_name)?;
}
compare_struct_trait(&function.return_type, &trait_function.return_type, struct_name, trait_name)?;
return Ok(());
}
_ => panic!("Unknown in function definition"),
},
_ => panic!("Unknown in function definition"),
} }
} }
@@ -300,6 +284,59 @@ impl Context {
ctx.current_function_return = Some(function.clone()); ctx.current_function_return = Some(function.clone());
return ctx; return 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() {
functions.insert(func.declaration.name.name.value.to_string(), func.declaration.to_type());
}
// fill out defaults
match &impl_.trait_ {
Some(trait_name) => {
if !traits.contains_key(&trait_name.name.value) {
return Err(errors::TypingError::TypeDoesNotExist {
identifier: trait_name.clone(),
});
}
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) {
functions.insert(
default_function.declaration.name.name.value.to_string(),
default_function.declaration.to_type(),
);
}
}
_ => {}
}
}
}
None => {}
}
let mut result = self.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()),
None => None,
},
functions: functions,
});
result
.environment
.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(),
});
}
}
return Ok(result);
}
} }
fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> { fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
@@ -311,7 +348,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
}); });
} }
match ctx.environment[&named.name.name.value] { match ctx.environment[&named.name.name.value] {
NamedEntity::TypeDeclaration(_) => { NamedEntity::NamedType(_) => {
// is a type // is a type
} }
_ => { _ => {
@@ -464,28 +501,24 @@ impl TypeChecker {
pub fn with_module(self: &Self, module: &ast::Module) -> Result<(ast::Module, SubstitutionMap)> { pub fn with_module(self: &Self, module: &ast::Module) -> Result<(ast::Module, SubstitutionMap)> {
let mut ctx = Context { let mut ctx = Context {
environment: create_builtins(), environment: create_builtins(),
impls: Vec::new(),
current_function_return: None, current_function_return: None,
}; };
let mut traits = HashMap::new();
for item in module.items.iter() { for item in module.items.iter() {
match item { match item {
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Struct(struct_)) => { ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Struct(struct_)) => {
ctx.environment.insert( ctx.environment.insert(
struct_.name.name.value.to_string(), struct_.name.name.value.to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(struct_.clone())), NamedEntity::NamedType(EnvType::from_struct(&struct_)),
);
}
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Alias(alias)) => {
ctx.environment.insert(
alias.name.name.value.to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Alias(alias.clone())),
); );
} }
ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Trait(trait_)) => { ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Trait(trait_)) => {
traits.insert(trait_.name.name.value.to_string(), trait_.clone());
ctx.environment.insert( ctx.environment.insert(
trait_.name.name.value.to_string(), trait_.name.name.value.to_string(),
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Trait(trait_.clone())), NamedEntity::NamedType(EnvType::from_trait(&trait_)),
); );
} }
ast::ModuleItem::Function(function) => { ast::ModuleItem::Function(function) => {
@@ -498,8 +531,19 @@ impl TypeChecker {
NamedEntity::Variable(ast::TypeUsage::Function(function_type)), NamedEntity::Variable(ast::TypeUsage::Function(function_type)),
); );
} }
_ => {}
}
}
for item in module.items.iter() {
match item {
ast::ModuleItem::Impl(impl_) => { ast::ModuleItem::Impl(impl_) => {
ctx.impls.push(impl_.clone()); if !ctx.environment.contains_key(&impl_.struct_name.name.value) {
return Err(errors::TypingError::IdentifierIsNotType {
identifier: impl_.struct_name.clone(),
});
}
ctx = ctx.add_impl(&impl_, &traits)?;
} }
_ => {} _ => {}
} }
@@ -530,11 +574,7 @@ impl TypeChecker {
return Ok((result, subst)); return Ok((result, subst));
} }
fn with_function_declaration( fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> Result<ast::FunctionDeclaration> {
self: &Self,
ctx: &Context,
declaration: &ast::FunctionDeclaration,
) -> Result<ast::FunctionDeclaration> {
for arg in declaration.arguments.iter() { for arg in declaration.arguments.iter() {
type_exists(ctx, &arg.type_)?; type_exists(ctx, &arg.type_)?;
} }
@@ -621,7 +661,7 @@ impl TypeChecker {
trait_: &ast::TraitTypeDeclaration, trait_: &ast::TraitTypeDeclaration,
) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> { ) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> {
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) => {
@@ -668,79 +708,16 @@ impl TypeChecker {
impl_: &ast::Impl, impl_: &ast::Impl,
) -> Result<(ast::Impl, SubstitutionMap)> { ) -> Result<(ast::Impl, SubstitutionMap)> {
let mut substitutions = incoming_substitutions.clone(); let mut substitutions = incoming_substitutions.clone();
type_exists(ctx, &ast::TypeUsage::new_named(&impl_.struct_name.clone(), &ast::GenericUsage::Unknown))?; type_exists(
ctx,
&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(&ctx, &substitutions, function)?;
substitutions = compose_substitutions(ctx, &substitutions, &function_subs)?; substitutions = compose_substitutions(ctx, &substitutions, &function_subs)?;
functions.push(result); functions.push(result);
} }
// See if trait actually matches
match &impl_.trait_ {
Some(trait_) => {
// assert trait functions satisfied
if !ctx.environment.contains_key(&trait_.name.value) {
return Err(errors::TypingError::TypeDoesNotExist {
identifier: trait_.clone(),
});
}
let trait_declaration = match &ctx.environment[&trait_.name.value] {
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Trait(declaration)) => declaration,
_ => {
return Err(errors::TypingError::ImplTraitMustBeTrait {
trait_name: trait_.clone(),
});
}
};
for trait_item in trait_declaration.functions.iter() {
match trait_item {
ast::TraitItem::FunctionDeclaration(declaration) => {
let mut found = false;
for impl_function in impl_.functions.iter() {
if impl_function.declaration.name.name.value == declaration.name.name.value {
found = true;
compare_struct_trait(&impl_function.declaration.to_type(), &declaration.to_type(), &impl_.struct_name, &trait_)?;
}
}
if found == false {
return Err(errors::TypingError::MissingTraitFunction {
struct_name: impl_.struct_name.clone(),
function_name: declaration.name.clone(),
});
}
}
ast::TraitItem::Function(function) => {
// skip found check because it has a default
for impl_function in impl_.functions.iter() {
if impl_function.declaration.name.name.value == function.declaration.name.name.value {
compare_struct_trait(&impl_function.declaration.to_type(), &function.declaration.to_type(), &impl_.struct_name, &trait_)?;
}
}
}
}
}
// assert all functions are in trait
for impl_function in impl_.functions.iter() {
let mut found = false;
for trait_item in trait_declaration.functions.iter() {
let declaration = match trait_item {
ast::TraitItem::Function(function) => &function.declaration,
ast::TraitItem::FunctionDeclaration(declaration) => declaration,
};
if impl_function.declaration.name.name.value == declaration.name.name.value {
found = true;
break;
}
}
if found == false {
return Err(errors::TypingError::FunctionNotInTrait {
function_name: impl_function.declaration.name.clone(),
});
}
}
}
None => {}
}
return Ok(( return Ok((
ast::Impl { ast::Impl {
generic: impl_.generic.clone(), generic: impl_.generic.clone(),
@@ -903,7 +880,7 @@ impl TypeChecker {
let (source, subst) = self.with_expression(ctx, &substitution, &struct_attr.source)?; let (source, subst) = self.with_expression(ctx, &substitution, &struct_attr.source)?;
let mut subst = subst.clone(); let mut subst = subst.clone();
let field_type = match get_attr(ctx, &source.type_, &struct_attr.attribute)? { let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_attr.attribute)? {
StructAttr::Field(type_) => type_, StructAttr::Field(type_) => type_,
StructAttr::Method(_) => { StructAttr::Method(_) => {
return Err(errors::TypingError::CannotAssignToMethod { return Err(errors::TypingError::CannotAssignToMethod {
@@ -1062,40 +1039,47 @@ impl TypeChecker {
literal_struct: &ast::LiteralStruct, literal_struct: &ast::LiteralStruct,
) -> Result<(ast::LiteralStruct, SubstitutionMap)> { ) -> Result<(ast::LiteralStruct, SubstitutionMap)> {
let mut substitution = substitution.clone(); let mut substitution = substitution.clone();
let type_declaration = match &ctx.environment[&literal_struct.name.name.value] { let struct_type = match &ctx.environment[&literal_struct.name.name.value] {
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(type_declaration)) => type_declaration, NamedEntity::NamedType(env_type) => match &env_type.is_a {
TypeType::Struct => env_type.clone(),
_ => {
return Err(errors::TypingError::NotAStructLiteral {
identifier: literal_struct.name.clone(),
});
}
},
_ => { _ => {
return Err(errors::TypingError::NotAStructLiteral { return Err(errors::TypingError::NotAStructLiteral {
identifier: literal_struct.name.clone(), identifier: literal_struct.name.clone(),
}); });
} }
}; };
if type_declaration.fields.len() != literal_struct.fields.len() { if struct_type.fields.len() != literal_struct.fields.len() {
return Err(errors::TypingError::StructLiteralFieldsMismatch { return Err(errors::TypingError::StructLiteralFieldsMismatch {
struct_name: literal_struct.name.clone(), struct_name: literal_struct.name.clone(),
struct_definition_name: type_declaration.name.clone(),
}); });
} }
let mut fields = vec![]; let mut fields = vec![];
for type_field in type_declaration.fields.iter() { for (type_field_name, type_field_type) in struct_type.fields.iter() {
let mut found = false; let mut found = false;
let mut field_expression: Option<ast::Expression> = None; let mut field_expression: Option<ast::Expression> = None;
let mut field_name: Option<ast::Identifier> = None;
for field in literal_struct.fields.iter() { for field in literal_struct.fields.iter() {
if type_field.name.name.value == field.0.name.value { if type_field_name == &field.0.name.value {
found = true; found = true;
let (result, subst) = self.with_expression(ctx, &substitution, &field.1)?; let (result, subst) = self.with_expression(ctx, &substitution, &field.1)?;
substitution = compose_substitutions(ctx, &substitution, &subst)?; substitution = compose_substitutions(ctx, &substitution, &subst)?;
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &type_field.type_, &result.type_)?)?; substitution = compose_substitutions(ctx, &substitution, &unify(ctx, type_field_type, &result.type_)?)?;
field_expression = Some(result); field_expression = Some(result);
field_name = Some(field.0.clone());
} }
} }
if !found { if !found {
return Err(errors::TypingError::StructLiteralFieldsMismatch { return Err(errors::TypingError::StructLiteralFieldsMismatch {
struct_name: literal_struct.name.clone(), struct_name: literal_struct.name.clone(),
struct_definition_name: type_field.name.clone(),
}); });
} }
fields.push((type_field.name.clone(), field_expression.unwrap())); fields.push((field_name.unwrap(), field_expression.unwrap()));
} }
Ok(( Ok((
ast::LiteralStruct { ast::LiteralStruct {
@@ -1164,8 +1148,10 @@ impl TypeChecker {
) -> Result<(ast::VariableUsage, SubstitutionMap)> { ) -> Result<(ast::VariableUsage, SubstitutionMap)> {
let mut substitution = substitution.clone(); let mut substitution = substitution.clone();
match &ctx.environment[&variable_usage.name.name.value] { match &ctx.environment[&variable_usage.name.name.value] {
NamedEntity::TypeDeclaration(_) => { NamedEntity::NamedType(_) => {
panic!("Using types not yet supported"); return Err(errors::TypingError::TypeIsNotAnExpression {
type_name: variable_usage.name.clone(),
});
} }
NamedEntity::Variable(variable) => { NamedEntity::Variable(variable) => {
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &variable)?)?; substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &variable)?)?;
@@ -1277,7 +1263,7 @@ impl TypeChecker {
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?; let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
substitution = compose_substitutions(ctx, &substitution, &subst)?; substitution = compose_substitutions(ctx, &substitution, &subst)?;
let field_type = match get_attr(ctx, &source.type_, &struct_getter.attribute)? { let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_getter.attribute)? {
StructAttr::Field(type_) => type_, StructAttr::Field(type_) => type_,
StructAttr::Method(type_) => type_, StructAttr::Method(type_) => type_,
}; };
@@ -1295,14 +1281,24 @@ impl TypeChecker {
)) ))
} }
fn with_block_expression(self: &Self, ctx: &Context, substitution: &SubstitutionMap, block: &ast::Block) -> Result<(ast::Block, SubstitutionMap)> { fn with_block_expression(
self: &Self,
ctx: &Context,
substitution: &SubstitutionMap,
block: &ast::Block,
) -> Result<(ast::Block, SubstitutionMap)> {
let mut substitution = substitution.clone(); let mut substitution = substitution.clone();
let (result, subst) = self.with_block(ctx, &substitution, &block)?; let (result, subst) = self.with_block(ctx, &substitution, &block)?;
substitution = compose_substitutions(ctx, &substitution, &subst)?; substitution = compose_substitutions(ctx, &substitution, &subst)?;
Ok((result, substitution)) Ok((result, substitution))
} }
fn with_op(self: &Self, ctx: &Context, substitution: &SubstitutionMap, op: &ast::Operation) -> Result<(ast::Operation, SubstitutionMap)> { fn with_op(
self: &Self,
ctx: &Context,
substitution: &SubstitutionMap,
op: &ast::Operation,
) -> Result<(ast::Operation, SubstitutionMap)> {
let mut substitution = substitution.clone(); let mut substitution = substitution.clone();
let (expr_left, subst_left) = self.with_expression(ctx, &substitution, &op.left)?; let (expr_left, subst_left) = self.with_expression(ctx, &substitution, &op.left)?;
let (expr_right, subst_right) = self.with_expression(ctx, &substitution, &op.right)?; let (expr_right, subst_right) = self.with_expression(ctx, &substitution, &op.right)?;