got generics working
This commit is contained in:
16
README.md
16
README.md
@@ -36,22 +36,24 @@ This language is under active development, progress will be marked here as the l
|
|||||||
- [x] Basic
|
- [x] Basic
|
||||||
- [ ] Default Functions
|
- [ ] Default Functions
|
||||||
- [ ] Generics
|
- [ ] Generics
|
||||||
- [ ] Basic
|
- [x] Basic
|
||||||
|
- [ ] Inferred
|
||||||
- [ ] Higher kinded types
|
- [ ] Higher kinded types
|
||||||
- [ ] Variadic generic types
|
- [ ] Variadic generic types
|
||||||
- [ ] Control Flow
|
- [ ] Control Flow
|
||||||
- [x] If
|
- [x] If
|
||||||
- [ ] While
|
- [ ] While
|
||||||
- [ ] For
|
- [ ] For
|
||||||
|
- [ ] Async-Await / Futures
|
||||||
- [ ] Enums
|
- [ ] Enums
|
||||||
- [ ] Lambdas
|
- [ ] Lambdas
|
||||||
- [ ] Async-Await
|
|
||||||
- [ ] Imports
|
- [ ] Imports
|
||||||
- [ ] Visibility
|
- [ ] Visibility
|
||||||
- [ ] Const / Mut
|
- [ ] Const / Mut
|
||||||
- [ ] Macros
|
- [ ] Macros
|
||||||
|
- [ ] Standard Library
|
||||||
|
|
||||||
This project is actively looking for contributors, so if you're interested in programming language design or have experience working with LLVM, don't hesitate to contact.
|
This project is actively looking for contributors, so if you're interested in programming language design or have experience working with LLVM, don't hesitate to contact. The current plan is to have this language transpile to a C-like subset of Rust, which can then be compiled into executable code.
|
||||||
|
|
||||||
## Philosophy
|
## Philosophy
|
||||||
|
|
||||||
@@ -116,7 +118,7 @@ async fn handle(req: http.Request, resp: mut http.Response): {
|
|||||||
await resp.write(json.encode[ExampleResponse](response_data));
|
await resp.write(json.encode[ExampleResponse](response_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn main(args: Vec[Str], os: OS): i32 {
|
async fn main(args: Vec[String], os: OS): i32 {
|
||||||
let log = logging.new_logger(os.console.stdout());
|
let log = logging.new_logger(os.console.stdout());
|
||||||
let router = http.Router("").add_route("/myroute", handle);
|
let router = http.Router("").add_route("/myroute", handle);
|
||||||
let http_server = http.Server(os.net(), "localhost", 8080, router);
|
let http_server = http.Server(os.net(), "localhost", 8080, router);
|
||||||
@@ -131,7 +133,7 @@ async fn main(args: Vec[Str], os: OS): i32 {
|
|||||||
All variables are immutable by default, to make them mutable use the `mut` keyword. Once a variable becomes immutable it cannot become mutable again. If you need it to become mutable, either implement the `clone` trait, or simply create a new one with the same data.
|
All variables are immutable by default, to make them mutable use the `mut` keyword. Once a variable becomes immutable it cannot become mutable again. If you need it to become mutable, either implement the `clone` trait, or simply create a new one with the same data.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let mut foo = Dict[String, Int32].new(); // constructor returns a mutable reference
|
let mut foo = Dict[String, i32].new(); // constructor returns a mutable reference
|
||||||
foo.insert("eggs", 12);
|
foo.insert("eggs", 12);
|
||||||
foo.insert("bananas", 2);
|
foo.insert("bananas", 2);
|
||||||
foo.insert("grapes", 2);
|
foo.insert("grapes", 2);
|
||||||
@@ -168,7 +170,7 @@ Context is an exceptionally useful feature in golang, but a common complaint is
|
|||||||
The boring standard library solves this by using parametric polymorphism. Context is by default an empty object passed through the chain, and each function/set of context parameters is an additional trait condition applied at compile time.
|
The boring standard library solves this by using parametric polymorphism. Context is by default an empty object passed through the chain, and each function/set of context parameters is an additional trait condition applied at compile time.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
type HTTPRequest[Ctx: Context] = async fn(Ctx, http.Request, mut http.Response);
|
type HTTPRequest = async fn[Ctx: Context](Ctx, http.Request, mut http.Response);
|
||||||
|
|
||||||
pub fn tracing_middleware[Ctx: Tracing](handler: HTTPRequest[Ctx]): HTTPRequest {
|
pub fn tracing_middleware[Ctx: Tracing](handler: HTTPRequest[Ctx]): HTTPRequest {
|
||||||
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
return async fn(ctx: Ctx, req: http.Request, resp: mut http.Response) {
|
||||||
@@ -209,7 +211,7 @@ Similar to python, folders/files represent the `.` seperated import path, but re
|
|||||||
import package.path as local_name;
|
import package.path as local_name;
|
||||||
|
|
||||||
pub type MyStruct struct {
|
pub type MyStruct struct {
|
||||||
pub id: I32,
|
pub id: i32,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ impl [K, V: MyTrait] Pair[K, V] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main(): i64 {
|
fn main(): i64 {
|
||||||
let a = Pair{
|
let a = Pair[i64, Value]{
|
||||||
k: 4,
|
k: 4,
|
||||||
v: Value{value: 6},
|
v: Value{value: 6},
|
||||||
};
|
};
|
||||||
return a.get_value(999);
|
return a.get_value[i64](999).value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ pub enum TypingError {
|
|||||||
},
|
},
|
||||||
#[error("invalid use of alias")]
|
#[error("invalid use of alias")]
|
||||||
InvalidUseofAlias,
|
InvalidUseofAlias,
|
||||||
|
#[error("alias cannot have type parameters")]
|
||||||
|
InvalidTypeParameterOnAlias {
|
||||||
|
alias: ast::Identifier,
|
||||||
|
},
|
||||||
#[error("type cannot be used for generic")]
|
#[error("type cannot be used for generic")]
|
||||||
InvalidTypeForGeneric,
|
InvalidTypeForGeneric,
|
||||||
#[error("multiple errors")]
|
#[error("multiple errors")]
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ pub LiteralStruct: ast::LiteralStruct = {
|
|||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
ast::LiteralStruct{
|
ast::LiteralStruct{
|
||||||
type_parameters: ast::GenericUsage::Unknown,
|
type_parameters: ast::GenericUsage::new(&[]),
|
||||||
name: i.clone(),
|
name: i.clone(),
|
||||||
fields: field_list,
|
fields: field_list,
|
||||||
type_: ast::TypeUsage::new_named(&i, &ast::GenericUsage::Unknown),
|
type_: ast::TypeUsage::new_named(&i, &ast::GenericUsage::new(&[])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,13 +207,26 @@ pub Block: ast::Block = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub NamedTypeUsage: ast::NamedTypeUsage = {
|
pub PartialNamedTypeUsage: ast::NamedTypeUsage = {
|
||||||
<n:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
<n:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
||||||
Some(tp) => ast::NamedTypeUsage{type_parameters: tp, name: n},
|
Some(tp) => ast::NamedTypeUsage{type_parameters: tp, name: n},
|
||||||
None => ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n},
|
None => ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub NamedTypeUsage: ast::NamedTypeUsage = {
|
||||||
|
<n:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
||||||
|
Some(tp) => ast::NamedTypeUsage{type_parameters: tp, name: n},
|
||||||
|
None => ast::NamedTypeUsage{type_parameters: ast::GenericUsage::new(&[]), name: n},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub PartialTypeUsage: ast::TypeUsage = {
|
||||||
|
<n:PartialNamedTypeUsage> => ast::TypeUsage::Named(n),
|
||||||
|
"fn" "(" <args:Comma<PartialTypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}),
|
||||||
|
"fn" "(" <args:Comma<PartialTypeUsage>> ")" ":" <rt:PartialTypeUsage> => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}),
|
||||||
|
};
|
||||||
|
|
||||||
pub TypeUsage: ast::TypeUsage = {
|
pub TypeUsage: ast::TypeUsage = {
|
||||||
<n:NamedTypeUsage> => ast::TypeUsage::Named(n),
|
<n:NamedTypeUsage> => ast::TypeUsage::Named(n),
|
||||||
"fn" "(" <args:Comma<TypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}),
|
"fn" "(" <args:Comma<TypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ struct Context {
|
|||||||
pub type_aliases: Vec<ast::AliasTypeDeclaration>,
|
pub type_aliases: Vec<ast::AliasTypeDeclaration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage {
|
fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> Result<ast::TypeUsage> {
|
||||||
let mut changed = true;
|
let mut changed = true;
|
||||||
let mut result = ast::TypeUsage::Named(type_.clone());
|
let mut result = ast::TypeUsage::Named(type_.clone());
|
||||||
while changed {
|
while changed {
|
||||||
@@ -17,7 +17,7 @@ fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage {
|
|||||||
match current {
|
match current {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
for alias in ctx.type_aliases.iter() {
|
for alias in ctx.type_aliases.iter() {
|
||||||
if named.name.name.value == alias.name.name.value {
|
if named.name.name.value == alias.name.name.value { // is alias, replace
|
||||||
changed = true;
|
changed = true;
|
||||||
result = alias.replaces.clone();
|
result = alias.replaces.clone();
|
||||||
}
|
}
|
||||||
@@ -26,13 +26,42 @@ fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage {
|
|||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
match &result {
|
||||||
|
ast::TypeUsage::Named(named) => {
|
||||||
|
match &named.type_parameters {
|
||||||
|
ast::GenericUsage::Known(known) => {
|
||||||
|
let mut result_params = vec!();
|
||||||
|
for param in known.parameters.iter() {
|
||||||
|
result_params.push(process_type(ctx, param)?);
|
||||||
|
}
|
||||||
|
let mut new_named = named.clone();
|
||||||
|
new_named.type_parameters = ast::GenericUsage::new(&result_params);
|
||||||
|
result = ast::TypeUsage::Named(new_named);
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::TypeUsage::Function(func) => {
|
||||||
|
match &type_.type_parameters {
|
||||||
|
ast::GenericUsage::Known(known) => {
|
||||||
|
if known.parameters.len() > 0 {
|
||||||
|
return Err(errors::TypingError::InvalidTypeParameterOnAlias{alias: type_.name.clone()});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {} //skip
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
panic!("alias of a non-type, not possible");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> Result<ast::TypeUsage> {
|
fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> Result<ast::TypeUsage> {
|
||||||
match type_ {
|
match type_ {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
return Ok(resolve_type(ctx, named));
|
return Ok(resolve_type(ctx, named)?);
|
||||||
}
|
}
|
||||||
ast::TypeUsage::Function(function) => {
|
ast::TypeUsage::Function(function) => {
|
||||||
let mut arguments = vec!();
|
let mut arguments = vec!();
|
||||||
@@ -50,7 +79,7 @@ fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> Result<ast::TypeUsage>
|
|||||||
ast::TypeUsage::Namespace(namespace) => {
|
ast::TypeUsage::Namespace(namespace) => {
|
||||||
match namespace {
|
match namespace {
|
||||||
ast::NamespaceTypeUsage::Type(named_type)=> {
|
ast::NamespaceTypeUsage::Type(named_type)=> {
|
||||||
let result = resolve_type(ctx, named_type);
|
let result = resolve_type(ctx, named_type)?;
|
||||||
match result {
|
match result {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
return Ok(ast::TypeUsage::Namespace(ast::NamespaceTypeUsage::Type(named)));
|
return Ok(ast::TypeUsage::Namespace(ast::NamespaceTypeUsage::Type(named)));
|
||||||
@@ -286,7 +315,7 @@ impl TypeAliasResolver {
|
|||||||
type_parameters: literal_struct.type_parameters.clone(),
|
type_parameters: literal_struct.type_parameters.clone(),
|
||||||
name: literal_struct.name.clone(),
|
name: literal_struct.name.clone(),
|
||||||
},
|
},
|
||||||
);
|
)?;
|
||||||
let new_name = match &result {
|
let new_name = match &result {
|
||||||
ast::TypeUsage::Named(named) => named.name.clone(),
|
ast::TypeUsage::Named(named) => named.name.clone(),
|
||||||
_ => panic!("LiteralStruct resolved to non-named-type"),
|
_ => panic!("LiteralStruct resolved to non-named-type"),
|
||||||
|
|||||||
@@ -29,12 +29,8 @@ fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<a
|
|||||||
};
|
};
|
||||||
match &ctx.environment[&named.name.name.value] {
|
match &ctx.environment[&named.name.name.value] {
|
||||||
NamedEntity::NamedType(named_type) => {
|
NamedEntity::NamedType(named_type) => {
|
||||||
println!("env value: {:?}", &ctx.environment[&named.name.name.value]);
|
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
for impl_ in named_type.impls.iter() {
|
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()) {
|
if impl_.trait_ == Some(bound.name.value.to_string()) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@@ -55,20 +51,37 @@ fn type_meets_trait_bounds(ctx: &Context, type_: &ast::TypeUsage, bounds: &Vec<a
|
|||||||
fn replace_generic_with_concrete(replace: &ast::Identifier, with_type: &ast::TypeUsage, in_type: &ast::TypeUsage) -> ast::TypeUsage {
|
fn replace_generic_with_concrete(replace: &ast::Identifier, with_type: &ast::TypeUsage, in_type: &ast::TypeUsage) -> ast::TypeUsage {
|
||||||
match in_type {
|
match in_type {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
|
let mut result = named.clone();
|
||||||
if named.name.name.value == replace.name.value {
|
if named.name.name.value == replace.name.value {
|
||||||
return with_type.clone();
|
return with_type.clone();
|
||||||
}
|
}
|
||||||
return in_type.clone();
|
result.type_parameters = match &named.type_parameters {
|
||||||
|
ast::GenericUsage::Known(known) => {
|
||||||
|
let mut param_result = vec!();
|
||||||
|
for param in known.parameters.iter() {
|
||||||
|
param_result.push(replace_generic_with_concrete(replace, with_type, param));
|
||||||
|
}
|
||||||
|
ast::GenericUsage::new(¶m_result)
|
||||||
|
},
|
||||||
|
ast::GenericUsage::Unknown => {
|
||||||
|
ast::GenericUsage::Unknown
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return ast::TypeUsage::Named(result);
|
||||||
},
|
},
|
||||||
ast::TypeUsage::Function(func) => {
|
ast::TypeUsage::Function(func) => {
|
||||||
return ast::TypeUsage::Function(ast::FunctionTypeUsage{
|
let result = ast::TypeUsage::Function(ast::FunctionTypeUsage{
|
||||||
arguments: func.arguments.iter().map(|arg| {
|
arguments: func.arguments.iter().map(|arg| {
|
||||||
replace_generic_with_concrete(replace, with_type, arg)
|
replace_generic_with_concrete(replace, with_type, arg)
|
||||||
}).collect(),
|
}).collect(),
|
||||||
return_type: Box::new(replace_generic_with_concrete(replace, with_type, &func.return_type)),
|
return_type: Box::new(replace_generic_with_concrete(replace, with_type, &func.return_type)),
|
||||||
});
|
});
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// in_type is unknown, skip
|
||||||
|
return in_type.clone();
|
||||||
},
|
},
|
||||||
_ => panic!("unknown in a generic, this should not happen")
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,9 +102,7 @@ impl TypeConstructor {
|
|||||||
// 1. for arg in args, assert arg matches self.generic traits via impl name
|
// 1. for arg in args, assert arg matches self.generic traits via impl name
|
||||||
// 2. replace type usage names with arg types
|
// 2. replace type usage names with arg types
|
||||||
for i in 0..known_usage.parameters.len() {
|
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) {
|
if !type_meets_trait_bounds(ctx, &known_usage.parameters[i], &self.generic.parameters[i].bounds) {
|
||||||
panic!("InvalidTypeForGeneric");
|
|
||||||
return Err(errors::TypingError::InvalidTypeForGeneric);
|
return Err(errors::TypingError::InvalidTypeForGeneric);
|
||||||
}
|
}
|
||||||
result = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &self.type_usage);
|
result = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &self.type_usage);
|
||||||
@@ -172,16 +183,44 @@ impl EnvType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn type_construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<EnvType> {
|
fn type_construct(&self, ctx: &Context, usage: &ast::GenericUsage) -> Result<EnvType> {
|
||||||
|
// steps
|
||||||
|
// 1. Check if matches bounds, create unknowns if necessary.
|
||||||
|
// 2. Replace all (Named+generics or function args/return) recursively.
|
||||||
|
// 3. Return updated, plus known generic usage to replace any unknown usage.
|
||||||
|
let known_usage = match usage {
|
||||||
|
ast::GenericUsage::Known(known) => known.clone(),
|
||||||
|
ast::GenericUsage::Unknown => {
|
||||||
|
let mut new_unknowns = vec!();
|
||||||
|
for _ in 0..self.generic.parameters.len() {
|
||||||
|
new_unknowns.push(ast::TypeUsage::new_unknown(&ctx.id_generator));
|
||||||
|
}
|
||||||
|
ast::GenericInstantiation {
|
||||||
|
parameters: new_unknowns.iter().map(|tp| tp.clone()).collect(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if known_usage.parameters.len() != self.generic.parameters.len() {
|
||||||
|
return Err(errors::TypingError::WrongNumberOfTypeParameters{});
|
||||||
|
}
|
||||||
|
for i in 0..known_usage.parameters.len() {
|
||||||
|
if !type_meets_trait_bounds(ctx, &known_usage.parameters[i], &self.generic.parameters[i].bounds) {
|
||||||
|
return Err(errors::TypingError::InvalidTypeForGeneric);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generic type matches, time to replace
|
||||||
|
let mut result = self.clone();
|
||||||
|
for i in 0..known_usage.parameters.len() {
|
||||||
let mut fields = HashMap::new();
|
let mut fields = HashMap::new();
|
||||||
for (k, v) in self.fields.iter() {
|
for (k, v) in result.fields.iter() {
|
||||||
let type_usage = TypeConstructor{generic: self.generic.clone(), type_usage: v.clone()}.construct(ctx, usage)?;
|
let type_usage = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &v);
|
||||||
fields.insert(k.clone(), type_usage);
|
fields.insert(k.clone(), type_usage);
|
||||||
}
|
}
|
||||||
let mut impls = vec!();
|
let mut impls = vec!();
|
||||||
for impl_ in self.impls.iter() {
|
for impl_ in result.impls.iter() {
|
||||||
let mut functions = HashMap::new();
|
let mut functions = HashMap::new();
|
||||||
for (name, func) in impl_.functions.iter() {
|
for (name, func) in impl_.functions.iter() {
|
||||||
let type_usage = TypeConstructor{generic: self.generic.clone(), type_usage: func.type_usage.clone()}.construct(ctx, usage)?;
|
let type_usage = replace_generic_with_concrete(&self.generic.parameters[i].name, &known_usage.parameters[i], &func.type_usage);
|
||||||
|
|
||||||
functions.insert(name.clone(), TypeConstructor{generic: func.generic.clone(), type_usage: type_usage});
|
functions.insert(name.clone(), TypeConstructor{generic: func.generic.clone(), type_usage: type_usage});
|
||||||
}
|
}
|
||||||
impls.push(EnvImpl{
|
impls.push(EnvImpl{
|
||||||
@@ -189,12 +228,14 @@ impl EnvType {
|
|||||||
functions: functions,
|
functions: functions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Ok(EnvType{
|
result = EnvType{
|
||||||
generic: ast::Generic{parameters: vec!()},
|
generic: ast::Generic{parameters: vec!()},
|
||||||
is_a: self.is_a.clone(),
|
is_a: self.is_a.clone(),
|
||||||
fields: fields,
|
fields: fields,
|
||||||
impls: impls,
|
impls: impls,
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
return Ok(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,6 +451,7 @@ fn get_attr(ctx: &Context, get_from: &NamedEntity, attribute: &ast::Identifier)
|
|||||||
_ => panic!("variable has non-type as type"),
|
_ => panic!("variable has non-type as type"),
|
||||||
};
|
};
|
||||||
let type_ = env_type.type_construct(ctx, &named.type_parameters)?;
|
let type_ = env_type.type_construct(ctx, &named.type_parameters)?;
|
||||||
|
|
||||||
let attr = get_attr(ctx, &NamedEntity::NamedType(type_), attribute)?;
|
let attr = get_attr(ctx, &NamedEntity::NamedType(type_), attribute)?;
|
||||||
let method = match attr {
|
let method = match attr {
|
||||||
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
|
StructAttr::Field(field) => return Ok(StructAttr::Field(field)),
|
||||||
@@ -463,8 +505,6 @@ impl Context {
|
|||||||
impls: vec!(),
|
impls: vec!(),
|
||||||
};
|
};
|
||||||
for bound in parameter.bounds.iter() {
|
for bound in parameter.bounds.iter() {
|
||||||
println!("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
|
|
||||||
println!("found bound: {:?}", bound);
|
|
||||||
if !self.environment.contains_key(&bound.name.value) {
|
if !self.environment.contains_key(&bound.name.value) {
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
identifier: bound.clone(),
|
identifier: bound.clone(),
|
||||||
@@ -545,7 +585,6 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) -> Result<()> {
|
|||||||
let result = match type_ {
|
let result = match type_ {
|
||||||
ast::TypeUsage::Named(named) => {
|
ast::TypeUsage::Named(named) => {
|
||||||
if !ctx.environment.contains_key(&named.name.name.value) {
|
if !ctx.environment.contains_key(&named.name.name.value) {
|
||||||
panic!("foo");
|
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
identifier: named.name.clone(),
|
identifier: named.name.clone(),
|
||||||
});
|
});
|
||||||
@@ -623,7 +662,32 @@ fn unify(ctx: &Context, t1: &ast::TypeUsage, t2: &ast::TypeUsage) -> Result<Subs
|
|||||||
match (t1, t2) {
|
match (t1, t2) {
|
||||||
(ast::TypeUsage::Named(named1), ast::TypeUsage::Named(named2)) => {
|
(ast::TypeUsage::Named(named1), ast::TypeUsage::Named(named2)) => {
|
||||||
if named1.name.name.value == named2.name.name.value {
|
if named1.name.name.value == named2.name.name.value {
|
||||||
return Ok(SubstitutionMap::new());
|
let mut result = SubstitutionMap::new();
|
||||||
|
match (&named1.type_parameters, &named2.type_parameters) {
|
||||||
|
(ast::GenericUsage::Known(known1), ast::GenericUsage::Known(known2)) => {
|
||||||
|
if known1.parameters.len() != known2.parameters.len() {
|
||||||
|
return Err(errors::TypingError::TypeMismatch {
|
||||||
|
type_one: t1.clone(),
|
||||||
|
type_two: t2.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (i, _) in known1.parameters.iter().enumerate() {
|
||||||
|
result = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&result,
|
||||||
|
&unify(
|
||||||
|
ctx,
|
||||||
|
&apply_substitution(ctx, &result, &known1.parameters[i])?,
|
||||||
|
&apply_substitution(ctx, &result, &known2.parameters[i])?,
|
||||||
|
)?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
panic!("should never be unknown")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return Ok(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -777,7 +841,8 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
ast::ModuleItem::Impl(impl_) => {
|
ast::ModuleItem::Impl(impl_) => {
|
||||||
let (impl_result, impl_subst) = self.with_impl(&ctx, &subst, impl_)?;
|
let (impl_result, impl_subst) = self.with_impl(&ctx, &subst, impl_)?;
|
||||||
subst = compose_substitutions(&ctx, &subst, &impl_subst)?;
|
// TODO: errors on generics not exist at global scope
|
||||||
|
// subst = compose_substitutions(&ctx, &subst, &impl_subst)?;
|
||||||
ast::ModuleItem::Impl(impl_result)
|
ast::ModuleItem::Impl(impl_result)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -929,7 +994,6 @@ impl TypeChecker {
|
|||||||
&impl_ctx,
|
&impl_ctx,
|
||||||
&ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown),
|
&ast::TypeUsage::new_named(&impl_.struct_.name.clone(), &ast::GenericUsage::Unknown),
|
||||||
)?;
|
)?;
|
||||||
println!("env {:?}", impl_ctx);
|
|
||||||
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(&impl_ctx, &substitutions, function)?;
|
let (result, function_subs) = self.with_function(&impl_ctx, &substitutions, function)?;
|
||||||
@@ -1270,6 +1334,7 @@ impl TypeChecker {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if struct_type.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(),
|
||||||
@@ -1321,7 +1386,6 @@ impl TypeChecker {
|
|||||||
ast::TypeUsage::Function(fn_type) => {
|
ast::TypeUsage::Function(fn_type) => {
|
||||||
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &function_call.type_, &*fn_type.return_type)?)?;
|
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &function_call.type_, &*fn_type.return_type)?)?;
|
||||||
if function_call.arguments.len() != fn_type.arguments.len() {
|
if function_call.arguments.len() != fn_type.arguments.len() {
|
||||||
println!("{:?}\n{:?}", &function_call, &fn_type);
|
|
||||||
return Err(errors::TypingError::ArgumentLengthMismatch {});
|
return Err(errors::TypingError::ArgumentLengthMismatch {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1479,7 +1543,6 @@ impl TypeChecker {
|
|||||||
) -> Result<(ast::StructGetter, SubstitutionMap)> {
|
) -> Result<(ast::StructGetter, SubstitutionMap)> {
|
||||||
let mut substitution = substitution.clone();
|
let mut substitution = substitution.clone();
|
||||||
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
||||||
println!("source: {:?}", &source);
|
|
||||||
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
|
|
||||||
let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_getter.attribute)? {
|
let field_type = match get_attr(ctx, &NamedEntity::Variable(source.type_.clone()), &struct_getter.attribute)? {
|
||||||
|
|||||||
Reference in New Issue
Block a user