added ast for generics

This commit is contained in:
Andrew Segavac
2021-10-08 19:17:07 -06:00
parent 2c37bced66
commit fbb81f3d09
5 changed files with 215 additions and 24 deletions

View File

@@ -53,6 +53,45 @@ This language is under active development, progress will be marked here as the l
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.
## Philosophy
Boring-lang is meant to be an industrial usage programming language optimized for quickly writing maintainable code above all else. To accomplish this, boring-lang has a simple rule:
1. Referential transparency is preferred, but anywhere it is broken must me encoded into the type system.
2. You cannot fundamentally change the behavior of a function (effects) without changing the type signature.
We accomplish this in a few ways:
### Sandboxing
Unlike many other programming languages, boringlang's `main` function takes in two arguments: a vector of command line arguments, and a reference to the OS which is the program's only link to the outside world. To open a file in boringlang, you cannot just call `open` anywhere, you *must* call `os.fs().open("path")`. All `os.whatever()` methods return an interface for interacting with that part of the OS, such as `fs`, `net`, `datetime`, and `syscall`. Because this is the only way to interact with the world outside of the program, this means that any IO the program does can be trivially mocked for testing, and that all operations the program can perform are sandboxed. If a function doesn't require a reference to the `FS` trait, you can be sure it doesn't interact with the file system.
### "Effects" System
Boring-lang doesn't have a formal effects system, but rather the "effects" are simply traits that get tacked onto a functions type. For an example, let's use a GUI program where clicking on a button can have an effect, in this case writing to a file.
```rust
type ClickHandler trait {
async fn on_click(self): ClickError;
}
type MyButton[T: FS] struct { // T is a generic type implementing fs
fs: T,
}
impl MyButton[T] {
fn new(fs: T): MyButton {
return MyButton{fs: fs};
}
}
impl ClickHandler for MyButton[T] {
async fn on_click(self): ClickError {
let file = await self.fs.open("my_file")?;
await file.write("foo")?;
}
}
```
## Http Server Example ## Http Server Example
@@ -62,7 +101,7 @@ import logging as logging;
import json as json; import json as json;
type ExampleResponse struct { type ExampleResponse struct {
id: I32, id: i32,
name: Str, name: Str,
email: Str, email: Str,
} }
@@ -77,7 +116,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[Str], 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);
@@ -162,10 +201,6 @@ pub fn cancel_middleware[Ctx: Cancel](handler: HTTPRequest[Ctx]): HTTPRequest {
for the above examples, you would pass a context type that implements all three traits. for the above examples, you would pass a context type that implements all three traits.
## Sandboxing
Unlike many other programming languages, boringlang's `main` function takes in two arguments: a vector of command line arguments, and a reference to the OS which is the program's only link to the outside world. To open a file in boringlang, you cannot just call `open` anywhere, you *must* call `os.fs().open("path")`. All `os.whatever()` methods return an interface for interacting with that part of the OS, such as `fs`, `net`, `datetime`, and `syscall`. Because this is the only way to interact with the world outside of the program, this means that any IO the program does can be trivially mocked for testing, and that all operations the program can perform are sandboxed. If a function doesn't require a reference to the `FS` trait, you can be sure it doesn't interact with the file system.
## Import System ## Import System
Similar to python, folders/files represent the `.` seperated import path, but relative imports are *not* supported. Exported values must be marked with `pub`. All imports take the form: Similar to python, folders/files represent the `.` seperated import path, but relative imports are *not* supported. Exported values must be marked with `pub`. All imports take the form:

View File

@@ -17,6 +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!()}),
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
@@ -28,6 +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!()}),
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
@@ -57,6 +59,7 @@ pub struct FunctionTypeUsage {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NamedTypeUsage { pub struct NamedTypeUsage {
pub type_parameters: GenericUsage,
pub name: Identifier, pub name: Identifier,
} }
@@ -77,12 +80,13 @@ impl TypeUsage {
return TypeUsage::Unknown(UnknownTypeUsage { name: id_gen.next() }); return TypeUsage::Unknown(UnknownTypeUsage { name: id_gen.next() });
} }
pub fn new_named(identifier: Identifier) -> TypeUsage { pub fn new_named(identifier: &Identifier, generic_usage: &GenericUsage) -> TypeUsage {
return TypeUsage::Named(NamedTypeUsage { 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!()}),
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
@@ -100,6 +104,40 @@ impl TypeUsage {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericParameter {
pub name: Identifier,
pub bounds: Vec<Identifier>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Generic {
pub parameters: Vec<GenericParameter>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericInstantiation {
pub parameters: Vec<TypeUsage>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericUsage {
Known(GenericInstantiation),
Unknown,
}
impl GenericUsage {
pub fn new(type_parameters: &[TypeUsage]) -> Self {
GenericUsage::Known(GenericInstantiation{
parameters: type_parameters.iter().map(|tp| {
tp.clone()
}).collect(),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Operator { pub enum Operator {
Mul, Mul,
@@ -128,6 +166,7 @@ pub struct LiteralBool {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LiteralStruct { pub struct LiteralStruct {
pub type_parameters: GenericUsage,
pub name: Identifier, pub name: Identifier,
pub fields: Vec<(Identifier, Expression)>, pub fields: Vec<(Identifier, Expression)>,
pub type_: TypeUsage, pub type_: TypeUsage,
@@ -147,6 +186,7 @@ pub struct FunctionCall {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StructGetter { pub struct StructGetter {
pub type_parameters: GenericUsage,
pub source: Expression, pub source: Expression,
pub attribute: Identifier, pub attribute: Identifier,
pub type_: TypeUsage, pub type_: TypeUsage,
@@ -161,6 +201,7 @@ pub struct Operation {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VariableUsage { pub struct VariableUsage {
pub type_parameters: GenericUsage,
pub name: Identifier, pub name: Identifier,
pub type_: TypeUsage, pub type_: TypeUsage,
} }
@@ -239,6 +280,7 @@ pub struct VariableDeclaration {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FunctionDeclaration { pub struct FunctionDeclaration {
pub generic: Generic,
pub name: Identifier, pub name: Identifier,
pub arguments: Vec<VariableDeclaration>, pub arguments: Vec<VariableDeclaration>,
pub return_type: TypeUsage, pub return_type: TypeUsage,
@@ -282,6 +324,7 @@ pub struct StructField {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StructTypeDeclaration { pub struct StructTypeDeclaration {
pub generic: Generic,
pub name: Identifier, pub name: Identifier,
pub fields: Vec<StructField>, pub fields: Vec<StructField>,
} }
@@ -294,6 +337,7 @@ pub enum TraitItem {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitTypeDeclaration { pub struct TraitTypeDeclaration {
pub generic: Generic,
pub name: Identifier, pub name: Identifier,
pub functions: Vec<TraitItem>, pub functions: Vec<TraitItem>,
} }
@@ -314,8 +358,11 @@ pub enum TypeDeclaration {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Impl { pub struct Impl {
pub generic: Generic,
pub trait_type_parameters: Option<GenericUsage>,
pub trait_: Option<Identifier>, pub trait_: Option<Identifier>,
pub struct_name: Identifier, pub struct_name: Identifier,
pub struct_type_parameters: GenericUsage,
pub functions: Vec<Function>, pub functions: Vec<Function>,
} }

View File

@@ -12,6 +12,9 @@ match {
"}", "}",
"(", "(",
")", ")",
"[",
"]",
"",
".", ".",
"+", "+",
"-", "-",
@@ -66,15 +69,34 @@ pub Identifier: String = {
<i:r"[A-Za-z_][A-Za-z0-9_]*"> => i.to_string() <i:r"[A-Za-z_][A-Za-z0-9_]*"> => i.to_string()
}; };
pub GenericUsage: ast::GenericUsage = {
"[" <tp:Comma<TypeUsage>> "]" => ast::GenericUsage::new(&tp),
};
pub LiteralStructField: (ast::Identifier, ast::Expression) = { pub LiteralStructField: (ast::Identifier, ast::Expression) = {
<field:SpannedIdentifier> ":" <expr:Expression> => (field, expr) <field:SpannedIdentifier> ":" <expr:Expression> => (field, expr)
}; };
pub LiteralStruct: ast::LiteralStruct = { pub LiteralStruct: ast::LiteralStruct = {
<i:SpannedIdentifier> "{" <field_list:Comma<LiteralStructField>> "}" => ast::LiteralStruct{ <i:SpannedIdentifier> <gu:GenericUsage?> "{" <field_list:Comma<LiteralStructField>> "}" => {
name: i.clone(), match gu {
fields: field_list, Some(tp) => {
type_: ast::TypeUsage::new_named(i.clone()), ast::LiteralStruct{
type_parameters: tp.clone(),
name: i.clone(),
fields: field_list,
type_: ast::TypeUsage::new_named(&i, &tp),
}
},
None => {
ast::LiteralStruct{
type_parameters: ast::GenericUsage::Unknown,
name: i.clone(),
fields: field_list,
type_: ast::TypeUsage::new_named(&i, &ast::GenericUsage::Unknown),
}
}
}
} }
}; };
@@ -87,11 +109,17 @@ pub FunctionCall: ast::FunctionCall = {
}; };
pub StructGetter: ast::StructGetter = { pub StructGetter: ast::StructGetter = {
<source:Term> "." <field:SpannedIdentifier> => ast::StructGetter{source: source, attribute: field, type_: ast::TypeUsage::new_unknown(&id_generator)} <source:Term> "." <field:SpannedIdentifier> <gu:GenericUsage?> => match gu {
Some(tp) => ast::StructGetter{type_parameters: tp, source: source, attribute: field, type_: ast::TypeUsage::new_unknown(&id_generator)},
None => ast::StructGetter{type_parameters: ast::GenericUsage::Unknown, source: source, attribute: field, type_: ast::TypeUsage::new_unknown(&id_generator)},
}
}; };
pub VariableUsage: ast::VariableUsage = { pub VariableUsage: ast::VariableUsage = {
<identifier:SpannedIdentifier> => ast::VariableUsage{name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)} <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)},
}
}; };
pub IfExpression: ast::IfExpression = { pub IfExpression: ast::IfExpression = {
@@ -180,7 +208,10 @@ pub Block: ast::Block = {
}; };
pub TypeUsage: ast::TypeUsage = { pub TypeUsage: ast::TypeUsage = {
<n:SpannedIdentifier> => ast::TypeUsage::Named(ast::NamedTypeUsage{name: n}), <n:SpannedIdentifier> <gu:GenericUsage?> => match gu {
Some(tp) => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: tp, name: n}),
None => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n}),
},
"fn" "(" <args:Comma<TypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}), "fn" "(" <args:Comma<TypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}),
"fn" "(" <args:Comma<TypeUsage>> ")" ":" <rt:TypeUsage> => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}), "fn" "(" <args:Comma<TypeUsage>> ")" ":" <rt:TypeUsage> => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(rt)}),
}; };
@@ -189,9 +220,20 @@ pub VariableDeclaration: ast::VariableDeclaration = {
<i:SpannedIdentifier> ":" <t:TypeUsage> => ast::VariableDeclaration{name: i, type_: t}, <i:SpannedIdentifier> ":" <t:TypeUsage> => ast::VariableDeclaration{name: i, type_: t},
}; };
pub GenericParameter: ast::GenericParameter = {
<i:SpannedIdentifier> => ast::GenericParameter{name: i, bounds: vec!()},
<i:SpannedIdentifier> ":" <bounds:PlusSeparated<SpannedIdentifier>> => ast::GenericParameter{name: i, bounds: bounds},
};
pub Generic: ast::Generic = {
"[" <p:Comma<GenericParameter>> "]" => ast::Generic{parameters: p},
};
pub FunctionDeclaration: ast::FunctionDeclaration = { pub FunctionDeclaration: ast::FunctionDeclaration = {
"fn" <n:SpannedIdentifier> "(" <args:Comma<VariableDeclaration>> ")" => ast::FunctionDeclaration{name: n, arguments: args, return_type: ast::new_unit()}, "fn" <n:SpannedIdentifier> <g:Generic> "(" <args:Comma<VariableDeclaration>> ")" => ast::FunctionDeclaration{name: n, generic: g, arguments: args, return_type: ast::new_unit()},
"fn" <n:SpannedIdentifier> "(" <args:Comma<VariableDeclaration>> ")" ":" <rt:TypeUsage> => ast::FunctionDeclaration{name: n, arguments: args, return_type: rt}, "fn" <n:SpannedIdentifier> <g:Generic> "(" <args:Comma<VariableDeclaration>> ")" ":" <rt:TypeUsage> => ast::FunctionDeclaration{name: n, generic: g, arguments: args, return_type: rt},
"fn" <n:SpannedIdentifier> "(" <args:Comma<VariableDeclaration>> ")" => ast::FunctionDeclaration{name: n, generic: ast::Generic{parameters: vec!()}, arguments: args, return_type: ast::new_unit()},
"fn" <n:SpannedIdentifier> "(" <args:Comma<VariableDeclaration>> ")" ":" <rt:TypeUsage> => ast::FunctionDeclaration{name: n, generic: ast::Generic{parameters: vec!()}, arguments: args, return_type: rt},
}; };
pub Function: ast::Function = { pub Function: ast::Function = {
@@ -203,7 +245,10 @@ pub StructField: ast::StructField = {
}; };
pub StructTypeDeclaration: ast::StructTypeDeclaration = { pub StructTypeDeclaration: ast::StructTypeDeclaration = {
"type" <i:SpannedIdentifier> "struct" "{" <f:Comma<StructField>> "}" => ast::StructTypeDeclaration{name: i, fields: f} "type" <i:SpannedIdentifier> <g:Generic?> "struct" "{" <f:Comma<StructField>> "}" => match g {
Some(generic) => ast::StructTypeDeclaration{name: i, generic: generic, fields: f},
None => ast::StructTypeDeclaration{name: i, generic: ast::Generic{parameters: vec!()}, fields: f},
}
}; };
pub AliasTypeDeclaration: ast::AliasTypeDeclaration = { pub AliasTypeDeclaration: ast::AliasTypeDeclaration = {
@@ -216,7 +261,8 @@ pub TraitItem: ast::TraitItem = {
}; };
pub TraitTypeDeclaration: ast::TraitTypeDeclaration = { pub TraitTypeDeclaration: ast::TraitTypeDeclaration = {
"type" <i:SpannedIdentifier> "trait" "{" <ti:TraitItem*> "}" => ast::TraitTypeDeclaration{name: i, functions: ti}, "type" <i:SpannedIdentifier> <g:Generic> "trait" "{" <ti:TraitItem*> "}" => ast::TraitTypeDeclaration{name: i, generic: g, functions: ti},
"type" <i:SpannedIdentifier> "trait" "{" <ti:TraitItem*> "}" => ast::TraitTypeDeclaration{name: i, generic: ast::Generic{parameters: vec!()}, functions: ti},
}; };
pub TypeDeclaration: ast::TypeDeclaration = { pub TypeDeclaration: ast::TypeDeclaration = {
@@ -226,8 +272,32 @@ pub TypeDeclaration: ast::TypeDeclaration = {
}; };
pub Impl: ast::Impl = { pub Impl: ast::Impl = {
"impl" <i:SpannedIdentifier> "{" <f:Function*> "}" => ast::Impl{trait_: None, struct_name: i, functions: f}, "impl" <g:Generic?> <i:SpannedIdentifier> <sgu:GenericUsage?> "{" <f:Function*> "}" => {
"impl" <t:SpannedIdentifier> "for" <i:SpannedIdentifier> "{" <f:Function*> "}" => ast::Impl{trait_: Some(t), struct_name: i, functions: f}, let generic = match g {
Some(g) => g,
None => ast::Generic{parameters: vec!()},
};
let struct_type_params = match sgu {
Some(stp) => stp,
None => ast::GenericUsage::new(&vec!()),
};
ast::Impl{generic: generic, trait_: None, trait_type_parameters: None, struct_name: i, struct_type_parameters: struct_type_params, functions: f}
},
"impl" <g:Generic?> <t:SpannedIdentifier> <tgu:GenericUsage?> "for" <i:SpannedIdentifier> <sgu:GenericUsage?> "{" <f:Function*> "}" => {
let generic = match g {
Some(g) => g,
None => ast::Generic{parameters: vec!()},
};
let struct_type_params = match sgu {
Some(stp) => stp,
None => ast::GenericUsage::new(&vec!()),
};
let trait_type_params = match tgu {
Some(ttp) => ttp,
None => ast::GenericUsage::new(&vec!()),
};
ast::Impl{generic: generic, trait_: Some(t), trait_type_parameters: Some(trait_type_params), struct_name: i, struct_type_parameters: struct_type_params, functions: f}
}
}; };
pub ModuleItem: ast::ModuleItem = { pub ModuleItem: ast::ModuleItem = {
@@ -241,7 +311,7 @@ pub Module: ast::Module = {
}; };
// From https://lalrpop.github.io/lalrpop/tutorial/006_macros.html // From https://lalrpop.github.io/lalrpop/tutorial/006_macros.html
// Comma seperated list of T with optional trailing comma // Comma separated list of T with optional trailing comma
Comma<T>: Vec<T> = { Comma<T>: Vec<T> = {
<v:(<T> ",")*> <e:T?> => match e { <v:(<T> ",")*> <e:T?> => match e {
None => v, None => v,
@@ -253,6 +323,18 @@ Comma<T>: Vec<T> = {
} }
}; };
// PlusSeparated separated list of T with optional trailing comma
PlusSeparated<T>: Vec<T> = {
<v:(<T> "+")*> <e:T?> => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
};
Spanned<Rule>: ast::Spanned<Rule> = { Spanned<Rule>: ast::Spanned<Rule> = {
<l: @L> <rule: Rule> <r: @R> => ast::Spanned{span: ast::Span{left: l, right: r}, value: rule} <l: @L> <rule: Rule> <r: @R> => ast::Spanned{span: ast::Span{left: l, right: r}, value: rule}
}; };

View File

@@ -82,6 +82,7 @@ impl TypeAliasResolver {
fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> ast::FunctionDeclaration { fn with_function_declaration(self: &Self, ctx: &Context, declaration: &ast::FunctionDeclaration) -> ast::FunctionDeclaration {
return ast::FunctionDeclaration { return ast::FunctionDeclaration {
name: declaration.name.clone(), name: declaration.name.clone(),
generic: declaration.generic.clone(),
arguments: declaration arguments: declaration
.arguments .arguments
.iter() .iter()
@@ -113,6 +114,7 @@ impl TypeAliasResolver {
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> ast::StructTypeDeclaration { fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> ast::StructTypeDeclaration {
return ast::StructTypeDeclaration { return ast::StructTypeDeclaration {
generic: struct_.generic.clone(),
name: struct_.name.clone(), name: struct_.name.clone(),
fields: struct_ fields: struct_
.fields .fields
@@ -134,9 +136,13 @@ impl TypeAliasResolver {
value: "Self".to_string(), value: "Self".to_string(),
}, },
}, },
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage { name: trait_.name.clone() }), replaces: ast::TypeUsage::Named(ast::NamedTypeUsage {
type_parameters: ast::GenericUsage::Unknown,
name: trait_.name.clone()
}),
}); });
return ast::TraitTypeDeclaration { return ast::TraitTypeDeclaration {
generic: trait_.generic.clone(),
name: trait_.name.clone(), name: trait_.name.clone(),
functions: trait_ functions: trait_
.functions .functions
@@ -163,12 +169,16 @@ impl TypeAliasResolver {
}, },
}, },
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage { replaces: ast::TypeUsage::Named(ast::NamedTypeUsage {
type_parameters: ast::GenericUsage::Unknown,
name: impl_.struct_name.clone(), name: impl_.struct_name.clone(),
}), }),
}); });
return ast::Impl { return ast::Impl {
generic: impl_.generic.clone(),
trait_type_parameters: impl_.trait_type_parameters.clone(),
trait_: impl_.trait_.clone(), trait_: impl_.trait_.clone(),
struct_name: impl_.struct_name.clone(), struct_name: impl_.struct_name.clone(),
struct_type_parameters: impl_.struct_type_parameters.clone(),
functions: impl_.functions.iter().map(|f| self.with_function(&impl_ctx, f)).collect(), functions: impl_.functions.iter().map(|f| self.with_function(&impl_ctx, f)).collect(),
}; };
} }
@@ -215,10 +225,12 @@ impl TypeAliasResolver {
return ast::AssignmentStatement { return ast::AssignmentStatement {
source: match &statement.source { source: match &statement.source {
ast::AssignmentTarget::Variable(variable) => ast::AssignmentTarget::Variable(ast::VariableUsage { ast::AssignmentTarget::Variable(variable) => ast::AssignmentTarget::Variable(ast::VariableUsage {
type_parameters: variable.type_parameters.clone(),
name: variable.name.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 { 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(), attribute: struct_attr.attribute.clone(),
type_: process_type(ctx, &struct_attr.type_), type_: process_type(ctx, &struct_attr.type_),
@@ -247,6 +259,7 @@ impl TypeAliasResolver {
let result = resolve_type( let result = resolve_type(
ctx, ctx,
&ast::NamedTypeUsage { &ast::NamedTypeUsage {
type_parameters: literal_struct.type_parameters.clone(),
name: literal_struct.name.clone(), name: literal_struct.name.clone(),
}, },
); );
@@ -255,6 +268,7 @@ impl TypeAliasResolver {
_ => panic!("LiteralStruct resolved to non-named-type"), _ => panic!("LiteralStruct resolved to non-named-type"),
}; };
ast::Subexpression::LiteralStruct(ast::LiteralStruct { ast::Subexpression::LiteralStruct(ast::LiteralStruct {
type_parameters: literal_struct.type_parameters.clone(),
name: new_name.clone(), name: new_name.clone(),
fields: literal_struct fields: literal_struct
.fields .fields
@@ -270,6 +284,7 @@ impl TypeAliasResolver {
type_: process_type(ctx, &function_call.type_), type_: process_type(ctx, &function_call.type_),
}), }),
ast::Subexpression::VariableUsage(variable_usage) => ast::Subexpression::VariableUsage(ast::VariableUsage { ast::Subexpression::VariableUsage(variable_usage) => ast::Subexpression::VariableUsage(ast::VariableUsage {
type_parameters: variable_usage.type_parameters.clone(),
name: variable_usage.name.clone(), name: variable_usage.name.clone(),
type_: process_type(ctx, &variable_usage.type_), type_: process_type(ctx, &variable_usage.type_),
}), }),
@@ -283,6 +298,7 @@ impl TypeAliasResolver {
type_: process_type(ctx, &if_expression.type_), type_: process_type(ctx, &if_expression.type_),
}), }),
ast::Subexpression::StructGetter(struct_getter) => ast::Subexpression::StructGetter(ast::StructGetter { 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(), attribute: struct_getter.attribute.clone(),
type_: process_type(ctx, &struct_getter.type_), type_: process_type(ctx, &struct_getter.type_),

View File

@@ -579,6 +579,7 @@ impl TypeChecker {
return Ok(( return Ok((
ast::Function { ast::Function {
declaration: ast::FunctionDeclaration { declaration: ast::FunctionDeclaration {
generic: declaration.generic.clone(),
name: declaration.name.clone(), name: declaration.name.clone(),
arguments: declaration.arguments.iter().map(|arg| arg.clone()).collect(), arguments: declaration.arguments.iter().map(|arg| arg.clone()).collect(),
return_type: declaration.return_type.clone(), return_type: declaration.return_type.clone(),
@@ -636,6 +637,7 @@ impl TypeChecker {
} }
Ok(( Ok((
ast::TraitTypeDeclaration { ast::TraitTypeDeclaration {
generic: trait_.generic.clone(),
name: trait_.name.clone(), name: trait_.name.clone(),
functions: result_functions, functions: result_functions,
}, },
@@ -653,6 +655,7 @@ impl TypeChecker {
}); });
} }
return Ok(ast::StructTypeDeclaration { return Ok(ast::StructTypeDeclaration {
generic: struct_.generic.clone(),
name: struct_.name.clone(), name: struct_.name.clone(),
fields: fields, fields: fields,
}); });
@@ -665,7 +668,7 @@ 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()))?; 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)?;
@@ -740,8 +743,11 @@ impl TypeChecker {
} }
return Ok(( return Ok((
ast::Impl { ast::Impl {
generic: impl_.generic.clone(),
trait_type_parameters: impl_.trait_type_parameters.clone(),
trait_: impl_.trait_.clone(), trait_: impl_.trait_.clone(),
struct_name: impl_.struct_name.clone(), struct_name: impl_.struct_name.clone(),
struct_type_parameters: impl_.struct_type_parameters.clone(),
functions: functions, functions: functions,
}, },
substitutions, substitutions,
@@ -888,6 +894,7 @@ impl TypeChecker {
ast::AssignmentTarget::Variable(variable) => { ast::AssignmentTarget::Variable(variable) => {
substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable.type_, &expr.type_)?)?; substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable.type_, &expr.type_)?)?;
ast::AssignmentTarget::Variable(ast::VariableUsage { ast::AssignmentTarget::Variable(ast::VariableUsage {
type_parameters: variable.type_parameters.clone(),
name: variable.name.clone(), name: variable.name.clone(),
type_: apply_substitution(ctx, &substitution, &variable.type_)?, type_: apply_substitution(ctx, &substitution, &variable.type_)?,
}) })
@@ -913,6 +920,7 @@ impl TypeChecker {
&unify(ctx, &struct_attr.type_, &expr.type_)?, &unify(ctx, &struct_attr.type_, &expr.type_)?,
)?; )?;
ast::AssignmentTarget::StructAttr(ast::StructGetter { ast::AssignmentTarget::StructAttr(ast::StructGetter {
type_parameters: struct_attr.type_parameters.clone(),
source: source, source: source,
attribute: struct_attr.attribute.clone(), attribute: struct_attr.attribute.clone(),
type_: apply_substitution(ctx, &substitution, &struct_attr.type_)?, type_: apply_substitution(ctx, &substitution, &struct_attr.type_)?,
@@ -1091,6 +1099,7 @@ impl TypeChecker {
} }
Ok(( Ok((
ast::LiteralStruct { ast::LiteralStruct {
type_parameters: literal_struct.type_parameters.clone(),
name: literal_struct.name.clone(), name: literal_struct.name.clone(),
fields: fields, fields: fields,
type_: apply_substitution(ctx, &substitution, &literal_struct.type_)?, type_: apply_substitution(ctx, &substitution, &literal_struct.type_)?,
@@ -1164,6 +1173,7 @@ impl TypeChecker {
} }
Ok(( Ok((
ast::VariableUsage { ast::VariableUsage {
type_parameters: variable_usage.type_parameters.clone(),
name: variable_usage.name.clone(), name: variable_usage.name.clone(),
type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?, type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?,
}, },
@@ -1276,6 +1286,7 @@ impl TypeChecker {
Ok(( Ok((
ast::StructGetter { ast::StructGetter {
type_parameters: struct_getter.type_parameters.clone(),
source: source, source: source,
attribute: struct_getter.attribute.clone(), attribute: struct_getter.attribute.clone(),
type_: apply_substitution(ctx, &substitution, &struct_getter.type_)?, type_: apply_substitution(ctx, &substitution, &struct_getter.type_)?,