working on adding generics

This commit is contained in:
Andrew Segavac
2022-03-12 04:35:48 -07:00
parent 51c698ba5d
commit 4c1c13149d
10 changed files with 443 additions and 278 deletions

114
Cargo.lock generated
View File

@@ -72,19 +72,12 @@ name = "boring-lang"
version = "0.0.1"
dependencies = [
"clap",
"inkwell",
"lalrpop",
"lalrpop-util",
"regex",
"thiserror",
]
[[package]]
name = "cc"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -196,39 +189,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "inkwell"
version = "0.1.0"
source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#ef1f5e491fd599d84ba67f82b87e55cb7be4b0b8"
dependencies = [
"either",
"inkwell_internals",
"libc",
"llvm-sys",
"once_cell",
"parking_lot",
"regex",
]
[[package]]
name = "inkwell_internals"
version = "0.2.0"
source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#ef1f5e491fd599d84ba67f82b87e55cb7be4b0b8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "instant"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
"cfg-if",
]
[[package]]
name = "itertools"
version = "0.10.1"
@@ -282,28 +242,6 @@ version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
[[package]]
name = "llvm-sys"
version = "70.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673300127ec17878e6f7fee4e851ba6fd36b08c26b2d6258732d699d1b3e3fcd"
dependencies = [
"cc",
"lazy_static",
"libc",
"regex",
"semver",
]
[[package]]
name = "lock_api"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.14"
@@ -331,31 +269,6 @@ version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "parking_lot"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "petgraph"
version = "0.5.1"
@@ -448,39 +361,12 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "siphasher"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "729a25c17d72b06c68cb47955d44fda88ad2d3e7d77e025663fdd69b93dd71a1"
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "string_cache"
version = "0.8.1"

View File

@@ -13,6 +13,6 @@ features = ["lexer"]
[dependencies]
lalrpop-util = "0.19.6"
regex = "1"
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" }
# inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" }
clap = "2.33.0"
thiserror = "1"

27
examples/generics.bl Normal file
View File

@@ -0,0 +1,27 @@
type MyTrait trait {}
type Pair[K, V: MyTrait] struct {
k: K,
v: V,
}
type Value struct {
value: i64,
}
impl MyTrait for Value {}
impl [K, V: MyTrait] Pair[K, V] {
fn get_value[T](self: Self, a: T): V {
return self.v;
}
}
fn main(): i64 {
let a = Pair{
k: 4,
v: Value{value: 6},
};
return a.get_value(999);
}

View File

@@ -1,17 +1,19 @@
use std::cell::RefCell;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IdGenerator {
id_key: String,
counter: RefCell<i64>,
}
impl IdGenerator {
pub fn new() -> Self {
IdGenerator { counter: RefCell::new(0) }
pub fn new(key: &str) -> Self {
IdGenerator { id_key: key.to_string(), counter: RefCell::new(0) }
}
pub fn next(&self) -> String {
*self.counter.borrow_mut() += 1;
("S".to_owned() + &self.counter.borrow().to_string()).to_string()
(self.id_key.to_owned() + &self.counter.borrow().to_string()).to_string()
}
}
@@ -68,11 +70,18 @@ pub struct UnknownTypeUsage {
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum NamespaceTypeUsage {
Type(NamedTypeUsage)
// Module
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TypeUsage {
Function(FunctionTypeUsage),
Named(NamedTypeUsage),
Unknown(UnknownTypeUsage),
Namespace(NamespaceTypeUsage)
}
impl TypeUsage {
@@ -200,8 +209,8 @@ pub struct Operation {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VariableUsage {
pub type_parameters: GenericUsage,
pub name: Identifier,
pub type_parameters: GenericUsage,
pub type_: TypeUsage,
}

1
src/builtins.rs Normal file
View File

@@ -0,0 +1 @@
use std::collections::HashMap;

View File

@@ -47,6 +47,14 @@ pub enum TypingError {
},
#[error("cannot use type as an expression")]
TypeIsNotAnExpression { type_name: ast::Identifier },
#[error("wrong number of type parameters")]
WrongNumberOfTypeParameters {
// TODO: add position
},
#[error("invalid use of alias")]
InvalidUseofAlias,
#[error("type cannot be used for generic")]
InvalidTypeForGeneric,
#[error("multiple errors")]
MultipleErrors { errors: Vec<TypingError> },
}

View File

@@ -117,8 +117,8 @@ pub StructGetter: ast::StructGetter = {
pub VariableUsage: ast::VariableUsage = {
<identifier:SpannedIdentifier> <gu:GenericUsage?> => match gu {
Some(tp) => ast::VariableUsage{type_parameters: tp, name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)},
None => ast::VariableUsage{type_parameters: ast::GenericUsage::Unknown, name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)},
Some(tp) => ast::VariableUsage{name: identifier, type_parameters: tp.clone(), type_: ast::TypeUsage::new_unknown(&id_generator)},
None => ast::VariableUsage{name: identifier, type_parameters: ast::GenericUsage::Unknown, type_: ast::TypeUsage::new_unknown(&id_generator)},
}
};

View File

@@ -37,11 +37,18 @@ fn main() {
let _output = matches.value_of("OUTPUT").unwrap_or(default_output);
let contents = fs::read_to_string(input).expect("input file not found");
let unknown_id_gen = ast::IdGenerator::new();
let unknown_id_gen = ast::IdGenerator::new("S");
let module_ast = grammar::ModuleParser::new().parse(&unknown_id_gen, &contents).unwrap(); //TODO: convert to error
// println!("ast: {:#?}", &module_ast);
let alias_resolver = type_alias_resolution::TypeAliasResolver {};
let resolved_ast = alias_resolver.with_module(&module_ast);
let resolved_ast = match alias_resolver.with_module(&module_ast) {
Ok(r) => r,
Err(err) => {
println!("type checking error: {:#?}", &err);
panic!("bad alias");
}
};
// println!("resolved ast: {:#?}", &resolved_ast);
let trait_checker = trait_checking::TraitChecker {};
match trait_checker.with_module(&resolved_ast) {
@@ -76,7 +83,7 @@ fn main() {
#[test]
fn grammar() {
let id_gen = ast::IdGenerator::new();
let id_gen = ast::IdGenerator::new("S");
assert!(grammar::LiteralIntParser::new().parse(&id_gen, "22").is_ok());
assert!(grammar::IdentifierParser::new().parse(&id_gen, "foo").is_ok());
assert!(grammar::LiteralIntParser::new().parse(&id_gen, "2a").is_err());

View File

@@ -1,4 +1,7 @@
use crate::ast;
use crate::errors;
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Context {
@@ -26,19 +29,38 @@ fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage {
return result;
}
fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> ast::TypeUsage {
fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> Result<ast::TypeUsage> {
match type_ {
ast::TypeUsage::Named(named) => {
return resolve_type(ctx, named);
return Ok(resolve_type(ctx, named));
}
ast::TypeUsage::Function(function) => {
return ast::TypeUsage::Function(ast::FunctionTypeUsage {
arguments: function.arguments.iter().map(|a| process_type(ctx, &a.clone())).collect(),
return_type: Box::new(process_type(ctx, &function.return_type.clone())),
});
let mut arguments = vec!();
for a in function.arguments.iter() {
arguments.push(process_type(ctx, &a.clone())?);
}
return Ok(ast::TypeUsage::Function(ast::FunctionTypeUsage {
arguments: arguments,
return_type: Box::new(process_type(ctx, &function.return_type.clone())?),
}));
}
ast::TypeUsage::Unknown(unknown) => {
return ast::TypeUsage::Unknown(unknown.clone());
return Ok(ast::TypeUsage::Unknown(unknown.clone()));
},
ast::TypeUsage::Namespace(namespace) => {
match namespace {
ast::NamespaceTypeUsage::Type(named_type)=> {
let result = resolve_type(ctx, named_type);
match result {
ast::TypeUsage::Named(named) => {
return Ok(ast::TypeUsage::Namespace(ast::NamespaceTypeUsage::Type(named)));
},
_ => {
return Err(errors::TypingError::InvalidUseofAlias);
}
}
}
}
}
}
}
@@ -46,7 +68,7 @@ fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> ast::TypeUsage {
pub struct TypeAliasResolver {}
impl TypeAliasResolver {
pub fn with_module(self: &Self, module: &ast::Module) -> ast::Module {
pub fn with_module(self: &Self, module: &ast::Module) -> Result<ast::Module> {
let mut ctx = Context { type_aliases: vec![] };
for item in module.items.iter() {
match item {
@@ -57,77 +79,78 @@ impl TypeAliasResolver {
}
}
return ast::Module {
items: module
.items
.iter()
.map(|item| match item {
ast::ModuleItem::Function(function) => ast::ModuleItem::Function(self.with_function(&ctx, function)),
let mut items = vec!();
for item in module.items.iter() {
items.push(match item {
ast::ModuleItem::Function(function) => ast::ModuleItem::Function(self.with_function(&ctx, function)?),
ast::ModuleItem::TypeDeclaration(type_declaration) => {
ast::ModuleItem::TypeDeclaration(self.with_type_declaration(&ctx, type_declaration))
ast::ModuleItem::TypeDeclaration(self.with_type_declaration(&ctx, type_declaration)?)
}
ast::ModuleItem::Impl(impl_) => ast::ModuleItem::Impl(self.with_impl(&ctx, impl_)),
})
.collect(),
};
ast::ModuleItem::Impl(impl_) => ast::ModuleItem::Impl(self.with_impl(&ctx, impl_)?),
});
}
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> ast::Function {
return ast::Function {
declaration: self.with_function_declaration(ctx, &function.declaration),
block: self.with_block(ctx, &function.block),
};
return Ok(ast::Module {
items: items,
});
}
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> ast::FunctionDeclaration {
return ast::FunctionDeclaration {
fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> Result<ast::Function> {
return Ok(ast::Function {
declaration: self.with_function_declaration(ctx, &function.declaration)?,
block: self.with_block(ctx, &function.block)?,
});
}
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> Result<ast::FunctionDeclaration> {
let mut arguments = vec!();
for arg in declaration.arguments.iter() {
arguments.push(ast::VariableDeclaration {
name: arg.name.clone(),
type_: process_type(ctx, &arg.type_)?,
});
}
return Ok(ast::FunctionDeclaration {
name: declaration.name.clone(),
generic: declaration.generic.clone(),
arguments: declaration
.arguments
.iter()
.map(|arg| ast::VariableDeclaration {
name: arg.name.clone(),
type_: process_type(ctx, &arg.type_),
})
.collect(),
return_type: process_type(ctx, &declaration.return_type),
};
arguments: arguments,
return_type: process_type(ctx, &declaration.return_type)?,
});
}
fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> ast::TypeDeclaration {
fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> Result<ast::TypeDeclaration> {
match type_declaration {
ast::TypeDeclaration::Struct(struct_) => {
return ast::TypeDeclaration::Struct(self.with_struct_declaration(ctx, struct_));
return Ok(ast::TypeDeclaration::Struct(self.with_struct_declaration(ctx, struct_)?));
}
ast::TypeDeclaration::Primitive(primitive) => {
return ast::TypeDeclaration::Primitive(primitive.clone());
return Ok(ast::TypeDeclaration::Primitive(primitive.clone()));
}
ast::TypeDeclaration::Alias(alias) => {
return ast::TypeDeclaration::Alias(alias.clone());
return Ok(ast::TypeDeclaration::Alias(alias.clone()));
}
ast::TypeDeclaration::Trait(trait_) => {
return ast::TypeDeclaration::Trait(self.with_trait(ctx, trait_));
return Ok(ast::TypeDeclaration::Trait(self.with_trait(ctx, trait_)?));
}
}
}
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> ast::StructTypeDeclaration {
return ast::StructTypeDeclaration {
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> Result<ast::StructTypeDeclaration> {
let mut fields = vec!();
for field in struct_.fields.iter() {
fields.push(ast::StructField {
name: field.name.clone(),
type_: process_type(ctx, &field.type_)?,
});
}
return Ok(ast::StructTypeDeclaration {
generic: struct_.generic.clone(),
name: struct_.name.clone(),
fields: struct_
.fields
.iter()
.map(|field| ast::StructField {
name: field.name.clone(),
type_: process_type(ctx, &field.type_),
})
.collect(),
};
fields: fields,
});
}
fn with_trait(self: &Self, ctx: &Context, trait_: &ast::TraitTypeDeclaration) -> ast::TraitTypeDeclaration {
fn with_trait(self: &Self, ctx: &Context, trait_: &ast::TraitTypeDeclaration) -> Result<ast::TraitTypeDeclaration> {
let mut trait_ctx = ctx.clone();
trait_ctx.type_aliases.push(ast::AliasTypeDeclaration {
name: ast::Identifier {
@@ -141,23 +164,23 @@ impl TypeAliasResolver {
name: trait_.name.clone(),
}),
});
return ast::TraitTypeDeclaration {
let mut functions = vec!();
for f in trait_.functions.iter() {
functions.push(match f {
ast::TraitItem::Function(function) => ast::TraitItem::Function(self.with_function(&trait_ctx, function)?),
ast::TraitItem::FunctionDeclaration(function_declaration) => {
ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration)?)
}
});
}
return Ok(ast::TraitTypeDeclaration {
generic: trait_.generic.clone(),
name: trait_.name.clone(),
functions: trait_
.functions
.iter()
.map(|f| match f {
ast::TraitItem::Function(function) => ast::TraitItem::Function(self.with_function(&trait_ctx, function)),
ast::TraitItem::FunctionDeclaration(function_declaration) => {
ast::TraitItem::FunctionDeclaration(self.with_function_declaration(&trait_ctx, function_declaration))
}
})
.collect(),
};
functions: functions,
});
}
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> ast::Impl {
fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> Result<ast::Impl> {
let mut impl_ctx = ctx.clone();
impl_ctx.type_aliases.push(ast::AliasTypeDeclaration {
name: ast::Identifier {
@@ -168,85 +191,93 @@ impl TypeAliasResolver {
},
replaces: ast::TypeUsage::Named(impl_.struct_.clone()),
});
return ast::Impl {
let mut functions = vec!();
for f in impl_.functions.iter() {
functions.push(self.with_function(&impl_ctx, f)?);
}
return Ok(ast::Impl {
generic: impl_.generic.clone(),
trait_: impl_.trait_.clone(),
struct_: impl_.struct_.clone(),
functions: impl_.functions.iter().map(|f| self.with_function(&impl_ctx, f)).collect(),
};
functions: functions,
});
}
fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> ast::Block {
return ast::Block {
statements: block.statements.iter().map(|s| self.with_statement(ctx, s)).collect(),
type_: process_type(ctx, &block.type_),
};
fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> Result<ast::Block> {
let mut statements = vec!();
for s in block.statements.iter() {
statements.push(self.with_statement(ctx, s)?);
}
return Ok(ast::Block {
statements: statements,
type_: process_type(ctx, &block.type_)?,
});
}
fn with_statement(self: &Self, ctx: &Context, statement: &ast::Statement) -> ast::Statement {
fn with_statement(self: &Self, ctx: &Context, statement: &ast::Statement) -> Result<ast::Statement> {
match statement {
ast::Statement::Return(return_statement) => {
return ast::Statement::Return(self.with_return_statement(ctx, return_statement));
return Ok(ast::Statement::Return(self.with_return_statement(ctx, return_statement)?));
}
ast::Statement::Let(let_statement) => {
return ast::Statement::Let(self.with_let_statement(ctx, let_statement));
return Ok(ast::Statement::Let(self.with_let_statement(ctx, let_statement)?));
}
ast::Statement::Assignment(assignment_statement) => {
return ast::Statement::Assignment(self.with_assignment_statement(ctx, assignment_statement));
return Ok(ast::Statement::Assignment(self.with_assignment_statement(ctx, assignment_statement)?));
}
ast::Statement::Expression(expression) => {
return ast::Statement::Expression(self.with_expression(ctx, expression));
return Ok(ast::Statement::Expression(self.with_expression(ctx, expression)?));
}
}
}
fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> ast::ReturnStatement {
return ast::ReturnStatement {
source: self.with_expression(ctx, &statement.source),
};
fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> Result<ast::ReturnStatement> {
return Ok(ast::ReturnStatement {
source: self.with_expression(ctx, &statement.source)?,
});
}
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> ast::LetStatement {
return ast::LetStatement {
fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> Result<ast::LetStatement> {
return Ok(ast::LetStatement {
variable_name: statement.variable_name.clone(),
expression: self.with_expression(ctx, &statement.expression),
type_: process_type(ctx, &statement.type_),
};
expression: self.with_expression(ctx, &statement.expression)?,
type_: process_type(ctx, &statement.type_)?,
});
}
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> ast::AssignmentStatement {
return ast::AssignmentStatement {
fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> Result<ast::AssignmentStatement> {
return Ok(ast::AssignmentStatement {
source: match &statement.source {
ast::AssignmentTarget::Variable(variable) => ast::AssignmentTarget::Variable(ast::VariableUsage {
type_parameters: variable.type_parameters.clone(),
name: variable.name.clone(),
type_: process_type(ctx, &variable.type_),
type_: process_type(ctx, &variable.type_)?,
}),
ast::AssignmentTarget::StructAttr(struct_attr) => ast::AssignmentTarget::StructAttr(ast::StructGetter {
type_parameters: struct_attr.type_parameters.clone(),
source: self.with_expression(ctx, &struct_attr.source),
source: self.with_expression(ctx, &struct_attr.source)?,
attribute: struct_attr.attribute.clone(),
type_: process_type(ctx, &struct_attr.type_),
type_: process_type(ctx, &struct_attr.type_)?,
}),
},
expression: self.with_expression(ctx, &statement.expression),
};
expression: self.with_expression(ctx, &statement.expression)?,
});
}
fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> ast::Expression {
return ast::Expression {
fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> Result<ast::Expression> {
return Ok(ast::Expression {
subexpression: Box::new(match &*expression.subexpression {
ast::Subexpression::LiteralInt(literal_int) => ast::Subexpression::LiteralInt(ast::LiteralInt {
value: literal_int.value.clone(),
type_: process_type(ctx, &literal_int.type_),
type_: process_type(ctx, &literal_int.type_)?,
}),
ast::Subexpression::LiteralFloat(literal_float) => ast::Subexpression::LiteralFloat(ast::LiteralFloat {
value: literal_float.value.clone(),
type_: process_type(ctx, &literal_float.type_),
type_: process_type(ctx, &literal_float.type_)?,
}),
ast::Subexpression::LiteralBool(literal_bool) => ast::Subexpression::LiteralBool(ast::LiteralBool {
value: literal_bool.value.clone(),
type_: process_type(ctx, &literal_bool.type_),
type_: process_type(ctx, &literal_bool.type_)?,
}),
ast::Subexpression::LiteralStruct(literal_struct) => {
let result = resolve_type(
@@ -260,50 +291,56 @@ impl TypeAliasResolver {
ast::TypeUsage::Named(named) => named.name.clone(),
_ => panic!("LiteralStruct resolved to non-named-type"),
};
let mut fields = vec!();
for field in literal_struct.fields.iter() {
fields.push((field.0.clone(), self.with_expression(ctx, &field.1)?));
}
ast::Subexpression::LiteralStruct(ast::LiteralStruct {
type_parameters: literal_struct.type_parameters.clone(),
name: new_name.clone(),
fields: literal_struct
.fields
.iter()
.map(|field| (field.0.clone(), self.with_expression(ctx, &field.1)))
.collect(),
type_: process_type(ctx, &literal_struct.type_),
fields: fields,
type_: process_type(ctx, &literal_struct.type_)?,
})
}
ast::Subexpression::FunctionCall(function_call) => ast::Subexpression::FunctionCall(ast::FunctionCall {
source: self.with_expression(ctx, &function_call.source),
arguments: function_call.arguments.iter().map(|arg| self.with_expression(ctx, arg)).collect(),
type_: process_type(ctx, &function_call.type_),
}),
ast::Subexpression::FunctionCall(function_call) => {
let mut arguments = vec!();
for arg in function_call.arguments.iter() {
arguments.push(self.with_expression(ctx, arg)?);
}
ast::Subexpression::FunctionCall(ast::FunctionCall {
source: self.with_expression(ctx, &function_call.source)?,
arguments: arguments,
type_: process_type(ctx, &function_call.type_)?,
})
},
ast::Subexpression::VariableUsage(variable_usage) => ast::Subexpression::VariableUsage(ast::VariableUsage {
type_parameters: variable_usage.type_parameters.clone(),
name: variable_usage.name.clone(),
type_: process_type(ctx, &variable_usage.type_),
type_parameters: variable_usage.type_parameters.clone(),
type_: process_type(ctx, &variable_usage.type_)?,
}),
ast::Subexpression::If(if_expression) => ast::Subexpression::If(ast::IfExpression {
condition: self.with_expression(ctx, &if_expression.condition),
block: self.with_block(ctx, &if_expression.block),
condition: self.with_expression(ctx, &if_expression.condition)?,
block: self.with_block(ctx, &if_expression.block)?,
else_: match &if_expression.else_ {
Some(else_) => Some(self.with_block(ctx, else_)),
Some(else_) => Some(self.with_block(ctx, else_)?),
None => None,
},
type_: process_type(ctx, &if_expression.type_),
type_: process_type(ctx, &if_expression.type_)?,
}),
ast::Subexpression::StructGetter(struct_getter) => ast::Subexpression::StructGetter(ast::StructGetter {
type_parameters: struct_getter.type_parameters.clone(),
source: self.with_expression(ctx, &struct_getter.source),
source: self.with_expression(ctx, &struct_getter.source)?,
attribute: struct_getter.attribute.clone(),
type_: process_type(ctx, &struct_getter.type_),
type_: process_type(ctx, &struct_getter.type_)?,
}),
ast::Subexpression::Block(block) => ast::Subexpression::Block(self.with_block(ctx, &block)),
ast::Subexpression::Block(block) => ast::Subexpression::Block(self.with_block(ctx, &block)?),
ast::Subexpression::Op(op) => ast::Subexpression::Op(ast::Operation {
left: self.with_expression(ctx, &op.left),
left: self.with_expression(ctx, &op.left)?,
op: op.op.clone(),
right: self.with_expression(ctx, &op.right),
right: self.with_expression(ctx, &op.right)?,
}),
}),
type_: process_type(ctx, &expression.type_),
};
type_: process_type(ctx, &expression.type_)?,
});
}
}

View File

@@ -1,15 +1,121 @@
use crate::ast;
use crate::errors;
use std::collections::HashMap;
use std::rc::Rc;
pub type SubstitutionMap = HashMap<String, ast::TypeUsage>;
pub type Result<T, E = errors::TypingError> = std::result::Result<T, E>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TypeConstructor {
generic: ast::Generic,
type_usage: ast::TypeUsage,
}
fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<ast::Identifier>) -> bool {
for bound in bounds.iter() {
let named = match type_ {
ast::TypeUsage::Named(named) => named,
ast::TypeUsage::Function(_) => {
return false;
},
ast::TypeUsage::Unknown(_) => {
return true; // unknown this pass, skip, test once known
},
ast::TypeUsage::Namespace(_) => {
panic!("impossible");
}
};
match &ctx.environment[&named.name.name.value] {
NamedEntity::NamedType(named_type) => {
println!("env value: {:?}", &ctx.environment[&named.name.name.value]);
let mut found = false;
for impl_ in named_type.impls.iter() {
println!("for: {:?}", &named.name.name.value);
println!("bounds: {:?}", &bound.name.value);
println!("trait: {:?}", &impl_.trait_);
if impl_.trait_ == Some(bound.name.value.to_string()) {
found = true;
break;
}
}
if found == false {
return false;
}
},
_ => {
panic!("type is a variable, this should not happen");
}
}
}
return true;
}
fn replace_generic_with_concrete(replace: &ast::Identifier, with_type: &ast::TypeUsage, in_type: &ast::TypeUsage) -> ast::TypeUsage {
match in_type {
ast::TypeUsage::Named(named) => {
if named.name.name.value == replace.name.value {
return with_type.clone();
}
return in_type.clone();
},
ast::TypeUsage::Function(func) => {
return ast::TypeUsage::Function(ast::FunctionTypeUsage{
arguments: func.arguments.iter().map(|arg| {
replace_generic_with_concrete(replace, with_type, arg)
}).collect(),
return_type: Box::new(replace_generic_with_concrete(replace, with_type, &func.return_type)),
});
},
_ => panic!("unknown in a generic, this should not happen")
};
}
impl TypeConstructor {
fn from_declaration(declaration: &ast::FunctionDeclaration) -> TypeConstructor {
return TypeConstructor{
generic: declaration.generic.clone(),
type_usage: declaration.to_type(),
}
}
fn construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<ast::TypeUsage> {
match usage {
ast::GenericUsage::Known(known_usage) => {
let mut result = self.type_usage.clone();
if known_usage.parameters.len() != self.generic.parameters.len() {
return Err(errors::TypingError::WrongNumberOfTypeParameters{});
}
// 1. for arg in args, assert arg matches self.generic traits via impl name
// 2. replace type usage names with arg types
for i in 0..known_usage.parameters.len() {
println!("test: {:?}\n{:?}", &known_usage.parameters[i], &self.generic.parameters[i].bounds);
if !type_meets_trait_bounds(ctx, &known_usage.parameters[i], &self.generic.parameters[i].bounds) {
panic!("InvalidTypeForGeneric");
return Err(errors::TypingError::InvalidTypeForGeneric);
}
result = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &self.type_usage);
}
return Ok(result);
},
ast::GenericUsage::Unknown => {
// generate new Unknown Types for matching
let mut result = self.type_usage.clone();
for param in self.generic.parameters.iter() {
let id = ctx.id_generator.next();
let unknown = ast::TypeUsage::Unknown(ast::UnknownTypeUsage{name: id});
result = replace_generic_with_concrete(&param.name, &unknown, &self.type_usage);
}
return Ok(result);
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnvImpl {
trait_: Option<String>,
functions: HashMap<String, ast::TypeUsage>,
functions: HashMap<String, TypeConstructor>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -21,6 +127,7 @@ pub enum TypeType {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnvType {
generic: ast::Generic,
is_a: TypeType,
fields: HashMap<String, ast::TypeUsage>,
impls: Vec<EnvImpl>,
@@ -29,6 +136,7 @@ pub struct EnvType {
impl EnvType {
fn from_struct(struct_: &ast::StructTypeDeclaration) -> EnvType {
return EnvType {
generic: struct_.generic.clone(),
is_a: TypeType::Struct,
fields: struct_
.fields
@@ -44,42 +152,65 @@ impl EnvType {
for func in trait_.functions.iter() {
match func {
ast::TraitItem::FunctionDeclaration(fd) => {
functions.insert(fd.name.name.value.to_string(), fd.to_type());
functions.insert(fd.name.name.value.to_string(), TypeConstructor::from_declaration(&fd));
}
ast::TraitItem::Function(f) => {
functions.insert(f.declaration.name.name.value.to_string(), f.declaration.to_type());
functions.insert(f.declaration.name.name.value.to_string(), TypeConstructor::from_declaration(&f.declaration));
}
}
}
let impl_ = EnvImpl {
trait_: None,
trait_: Some(trait_.name.name.value.to_string()),
functions: functions,
};
return EnvType {
generic: trait_.generic.clone(),
is_a: TypeType::Trait,
fields: HashMap::new(),
impls: vec![impl_],
};
}
fn type_construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<EnvType> {
let mut fields = HashMap::new();
for (k, v) in self.fields.iter() {
let type_usage = TypeConstructor{generic: self.generic.clone(), type_usage: v.clone()}.construct(ctx, usage)?;
fields.insert(k.clone(), type_usage);
}
let mut impls = vec!();
for impl_ in self.impls.iter() {
let mut functions = HashMap::new();
for (name, func) in impl_.functions.iter() {
let type_usage = TypeConstructor{generic: self.generic.clone(), type_usage: func.type_usage.clone()}.construct(ctx, usage)?;
functions.insert(name.clone(), TypeConstructor{generic: func.generic.clone(), type_usage: type_usage});
}
impls.push(EnvImpl{
trait_: impl_.trait_.clone(),
functions: functions,
});
}
return Ok(EnvType{
generic: ast::Generic{parameters: vec!()},
is_a: self.is_a.clone(),
fields: fields,
impls: impls,
});
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NamedEntity {
NamedType(EnvType),
Function(TypeConstructor),
Variable(ast::TypeUsage),
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Context {
pub current_function_return: Option<ast::TypeUsage>,
pub environment: HashMap<String, NamedEntity>,
}
fn create_builtins() -> HashMap<String, NamedEntity> {
let mut result = HashMap::new();
result.insert(
"i8".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -88,6 +219,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"i16".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -96,6 +228,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"i32".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -104,6 +237,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"i64".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -112,6 +246,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"isize".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -121,6 +256,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"u8".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -129,6 +265,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"u16".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -137,6 +274,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"u32".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -145,6 +283,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"u64".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -153,6 +292,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"usize".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -162,6 +302,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"f32".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -170,6 +311,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"f64".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -179,6 +321,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"bool".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -187,6 +330,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"!".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -195,6 +339,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
result.insert(
"unit".to_string(),
NamedEntity::NamedType(EnvType {
generic: ast::Generic{parameters: vec!()},
is_a: TypeType::Scalar,
fields: HashMap::new(),
impls: vec![],
@@ -205,20 +350,24 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
enum StructAttr {
Field(ast::TypeUsage),
Method(ast::TypeUsage),
Method(TypeConstructor),
}
fn apply_self(type_name: &str, type_: &ast::TypeUsage) -> ast::TypeUsage {
match type_ {
fn apply_self(type_name: &str, constructor: &TypeConstructor) -> TypeConstructor {
match &constructor.type_usage {
ast::TypeUsage::Function(func) => {
if func.arguments.len() > 0 {
match &func.arguments[0] {
ast::TypeUsage::Named(named) => {
if type_name == named.name.name.value {
return ast::TypeUsage::Function(ast::FunctionTypeUsage {
let result = ast::TypeUsage::Function(ast::FunctionTypeUsage {
arguments: func.arguments[1..func.arguments.len()].iter().map(|arg| arg.clone()).collect(),
return_type: func.return_type.clone(),
});
return TypeConstructor{
generic: constructor.generic.clone(),
type_usage: result,
}
}
}
_ => {}
@@ -227,7 +376,7 @@ fn apply_self(type_name: &str, type_: &ast::TypeUsage) -> ast::TypeUsage {
}
_ => {}
}
return type_.clone();
return constructor.clone();
}
fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier) -> Result<StructAttr> {
@@ -256,7 +405,12 @@ fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier)
}
NamedEntity::Variable(type_) => match type_ {
ast::TypeUsage::Named(named) => {
let attr = get_attr(ctx, &ctx.environment[&named.name.name.value], attribute)?;
let env_type = match &ctx.environment[&named.name.name.value] {
NamedEntity::NamedType(env_type) => env_type,
_ => panic!("variable has non-type as type"),
};
let type_ = env_type.type_construct(ctx, &named.type_parameters)?;
let attr = get_attr(ctx, &NamedEntity::NamedType(type_), attribute)?;
let method = match attr {
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
StructAttr::Method(method) => method,
@@ -269,7 +423,19 @@ fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier)
});
}
},
NamedEntity::Function(_) => {
return Err(errors::TypingError::AttributeOfNonstruct {
identifier: attribute.clone(),
});
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Context {
pub current_function_return: Option<ast::TypeUsage>,
pub environment: HashMap<String, NamedEntity>,
pub id_generator: Rc<ast::IdGenerator>,
}
impl Context {
@@ -289,11 +455,16 @@ impl Context {
let mut ctx = self.clone();
for parameter in generic.parameters.iter() {
let mut env_type = EnvType{
generic: ast::Generic{
parameters: vec!(),
},
is_a: TypeType::Trait,
fields: HashMap::new(),
impls: vec!(),
};
for bound in parameter.bounds.iter() {
println!("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
println!("found bound: {:?}", bound);
if !self.environment.contains_key(&bound.name.value) {
return Err(errors::TypingError::TypeDoesNotExist {
identifier: bound.clone(),
@@ -314,7 +485,7 @@ impl Context {
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());
functions.insert(func.declaration.name.name.value.to_string(), TypeConstructor::from_declaration(&func.declaration));
}
// fill out defaults
match &impl_.trait_ {
@@ -330,7 +501,7 @@ impl Context {
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(),
TypeConstructor::from_declaration(&default_function.declaration),
);
}
}
@@ -356,7 +527,12 @@ impl Context {
.insert(impl_.struct_.name.name.value.to_string(), NamedEntity::NamedType(env_type.clone()));
}
NamedEntity::Variable(_) => {
return Err(errors::TypingError::TypeDoesNotExist {
return Err(errors::TypingError::IdentifierIsNotType {
identifier: impl_.struct_.name.clone(),
});
}
NamedEntity::Function(_) => {
return Err(errors::TypingError::IdentifierIsNotType {
identifier: impl_.struct_.name.clone(),
});
}
@@ -369,6 +545,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
let result = match type_ {
ast::TypeUsage::Named(named) => {
if !ctx.environment.contains_key(&named.name.name.value) {
panic!("foo");
return Err(errors::TypingError::TypeDoesNotExist {
identifier: named.name.clone(),
});
@@ -385,6 +562,7 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
}
}
ast::TypeUsage::Unknown(_) => {} // do nothing
ast::TypeUsage::Namespace(_) => {}
ast::TypeUsage::Function(function) => {
let mut errs = vec![];
for arg in function.arguments.iter() {
@@ -415,6 +593,9 @@ fn apply_substitution(ctx: &Context, substitution: &SubstitutionMap, type_: &ast
ast::TypeUsage::Unknown(unknown.clone())
}
}
ast::TypeUsage::Namespace(namespace) => {
ast::TypeUsage::Namespace(namespace.clone())
}
ast::TypeUsage::Function(function) => {
let mut arguments = vec![];
for arg in function.arguments.iter() {
@@ -507,6 +688,7 @@ fn contains(t: &ast::TypeUsage, name: &str) -> bool {
match t {
ast::TypeUsage::Named(_) => return false,
ast::TypeUsage::Unknown(unknown) => unknown.name == name,
ast::TypeUsage::Namespace(_) => return false,
ast::TypeUsage::Function(f) => {
if contains(&*f.return_type, name) {
return true;
@@ -528,6 +710,7 @@ impl TypeChecker {
let mut ctx = Context {
environment: create_builtins(),
current_function_return: None,
id_generator: Rc::new(ast::IdGenerator::new("T")),
};
let mut traits = HashMap::new();
@@ -554,7 +737,10 @@ impl TypeChecker {
};
ctx.environment.insert(
function.declaration.name.name.value.to_string(),
NamedEntity::Variable(ast::TypeUsage::Function(function_type)),
NamedEntity::Function(TypeConstructor{
generic: function.declaration.generic.clone(),
type_usage: ast::TypeUsage::Function(function_type),
}),
);
}
_ => {}
@@ -743,6 +929,7 @@ impl TypeChecker {
&impl_ctx,
&ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown),
)?;
println!("env {:?}", impl_ctx);
let mut functions = vec![];
for function in impl_.functions.iter() {
let (result, function_subs) = self.with_function(&impl_ctx, &substitutions, function)?;
@@ -900,8 +1087,8 @@ impl TypeChecker {
ast::AssignmentTarget::Variable(variable) => {
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable.type_, &expr.type_)?)?;
ast::AssignmentTarget::Variable(ast::VariableUsage {
type_parameters: variable.type_parameters.clone(),
name: variable.name.clone(),
type_parameters: variable.type_parameters.clone(),
type_: apply_substitution(ctx, &substitution, &variable.type_)?,
})
}
@@ -1070,7 +1257,7 @@ impl TypeChecker {
let mut substitution = substitution.clone();
let struct_type = match &ctx.environment[&literal_struct.name.name.value] {
NamedEntity::NamedType(env_type) => match &env_type.is_a {
TypeType::Struct => env_type.clone(),
TypeType::Struct => env_type.type_construct(ctx, &literal_struct.type_parameters)?,
_ => {
return Err(errors::TypingError::NotAStructLiteral {
identifier: literal_struct.name.clone(),
@@ -1177,19 +1364,21 @@ impl TypeChecker {
) -> Result<(ast::VariableUsage, SubstitutionMap)> {
let mut substitution = substitution.clone();
match &ctx.environment[&variable_usage.name.name.value] {
NamedEntity::NamedType(_) => {
return Err(errors::TypingError::TypeIsNotAnExpression {
type_name: variable_usage.name.clone(),
});
NamedEntity::NamedType(named_type) => {
let type_ = ast::TypeUsage::Namespace(ast::NamespaceTypeUsage::Type(ast::NamedTypeUsage{name: variable_usage.name.clone(), type_parameters: variable_usage.type_parameters.clone()}));
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &type_)?)?;
}
NamedEntity::Variable(variable) => {
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &variable)?)?;
}
NamedEntity::Function(function) => {
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &function.construct(ctx, &variable_usage.type_parameters)?)?)?;
}
}
Ok((
ast::VariableUsage {
type_parameters: variable_usage.type_parameters.clone(),
name: variable_usage.name.clone(),
type_parameters: variable_usage.type_parameters.clone(), // Redundant to type
type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?,
},
substitution,
@@ -1290,11 +1479,12 @@ impl TypeChecker {
) -> Result<(ast::StructGetter, SubstitutionMap)> {
let mut substitution = substitution.clone();
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
println!("source: {:?}", &source);
substitution = compose_substitutions(ctx, &substitution, &subst)?;
let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_getter.attribute)? {
StructAttr::Field(type_) => type_,
StructAttr::Method(type_) => type_,
StructAttr::Method(constructor) => constructor.construct(ctx, &struct_getter.type_parameters)?,
};
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &struct_getter.type_, &field_type)?)?;