added generics without type instantiation
This commit is contained in:
@@ -48,6 +48,10 @@ type User struct {
|
|||||||
id: i64,
|
id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Generic[T] struct {
|
||||||
|
value: T,
|
||||||
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
fn new(id: i64): Self {
|
fn new(id: i64): Self {
|
||||||
return Self{
|
return Self{
|
||||||
|
|||||||
@@ -358,10 +358,8 @@ 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 generic: Generic,
|
||||||
pub trait_type_parameters: Option<GenericUsage>,
|
pub struct_: NamedTypeUsage,
|
||||||
pub trait_: Option<Identifier>,
|
pub trait_: Option<NamedTypeUsage>,
|
||||||
pub struct_name: Identifier,
|
|
||||||
pub struct_type_parameters: GenericUsage,
|
|
||||||
pub functions: Vec<Function>,
|
pub functions: Vec<Function>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,11 +207,15 @@ pub Block: ast::Block = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub TypeUsage: ast::TypeUsage = {
|
pub NamedTypeUsage: ast::NamedTypeUsage = {
|
||||||
<n:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
<n:SpannedIdentifier> <gu:GenericUsage?> => match gu {
|
||||||
Some(tp) => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: tp, name: n}),
|
Some(tp) => ast::NamedTypeUsage{type_parameters: tp, name: n},
|
||||||
None => ast::TypeUsage::Named(ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n}),
|
None => ast::NamedTypeUsage{type_parameters: ast::GenericUsage::Unknown, name: n},
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub TypeUsage: ast::TypeUsage = {
|
||||||
|
<n:NamedTypeUsage> => ast::TypeUsage::Named(n),
|
||||||
"fn" "(" <args:Comma<TypeUsage>> ")" => ast::TypeUsage::Function(ast::FunctionTypeUsage{arguments: args, return_type: Box::new(ast::new_unit())}),
|
"fn" "(" <args:Comma<TypeUsage>> ")" => 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)}),
|
||||||
};
|
};
|
||||||
@@ -272,31 +276,19 @@ pub TypeDeclaration: ast::TypeDeclaration = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub Impl: ast::Impl = {
|
pub Impl: ast::Impl = {
|
||||||
"impl" <g:Generic?> <i:SpannedIdentifier> <sgu:GenericUsage?> "{" <f:Function*> "}" => {
|
"impl" <g:Generic?> <s:NamedTypeUsage> "{" <f:Function*> "}" => {
|
||||||
let generic = match g {
|
let generic = match g {
|
||||||
Some(g) => g,
|
Some(g) => g,
|
||||||
None => ast::Generic{parameters: vec!()},
|
None => ast::Generic{parameters: vec!()},
|
||||||
};
|
};
|
||||||
let struct_type_params = match sgu {
|
ast::Impl{generic: generic, trait_: None, struct_: s, functions: f}
|
||||||
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*> "}" => {
|
"impl" <g:Generic?> <t:NamedTypeUsage> "for" <s:NamedTypeUsage> "{" <f:Function*> "}" => {
|
||||||
let generic = match g {
|
let generic = match g {
|
||||||
Some(g) => g,
|
Some(g) => g,
|
||||||
None => ast::Generic{parameters: vec!()},
|
None => ast::Generic{parameters: vec!()},
|
||||||
};
|
};
|
||||||
let struct_type_params = match sgu {
|
ast::Impl{generic: generic, trait_: Some(t), struct_: s, functions: f}
|
||||||
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}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ impl Context {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
ast::ModuleItem::Impl(impl_) => {
|
ast::ModuleItem::Impl(impl_) => {
|
||||||
ctx.impls.insert(impl_.struct_name.name.value.to_string(), impl_.clone());
|
ctx.impls.insert(impl_.struct_.name.name.value.to_string(), impl_.clone());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -451,7 +451,7 @@ impl TreeWalkInterpreter {
|
|||||||
for module_item in &ctx.current_module.items {
|
for module_item in &ctx.current_module.items {
|
||||||
match module_item {
|
match module_item {
|
||||||
ast::ModuleItem::Impl(impl_) => {
|
ast::ModuleItem::Impl(impl_) => {
|
||||||
if impl_.struct_name.name.value == s.source.name.name.value {
|
if impl_.struct_.name.name.value == s.source.name.name.value {
|
||||||
for method in &impl_.functions {
|
for method in &impl_.functions {
|
||||||
if method.declaration.name.name.value == struct_getter.attribute.name.value {
|
if method.declaration.name.name.value == struct_getter.attribute.name.value {
|
||||||
// if first type matches, partial apply self
|
// if first type matches, partial apply self
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ struct Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_builtins() -> HashMap<String, ast::TraitTypeDeclaration> {
|
fn create_builtins() -> HashMap<String, ast::TraitTypeDeclaration> {
|
||||||
let mut result = HashMap::<String, ast::TraitTypeDeclaration>::new();
|
let result = HashMap::<String, ast::TraitTypeDeclaration>::new();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,12 +100,12 @@ impl TraitChecker {
|
|||||||
match &impl_.trait_ {
|
match &impl_.trait_ {
|
||||||
Some(trait_) => {
|
Some(trait_) => {
|
||||||
// assert trait functions satisfied
|
// assert trait functions satisfied
|
||||||
if !ctx.environment_traits.contains_key(&trait_.name.value) {
|
if !ctx.environment_traits.contains_key(&trait_.name.name.value) {
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
identifier: trait_.clone(),
|
identifier: trait_.name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let trait_declaration = &ctx.environment_traits[&trait_.name.value];
|
let trait_declaration = &ctx.environment_traits[&trait_.name.name.value];
|
||||||
for trait_item in trait_declaration.functions.iter() {
|
for trait_item in trait_declaration.functions.iter() {
|
||||||
match trait_item {
|
match trait_item {
|
||||||
ast::TraitItem::FunctionDeclaration(declaration) => {
|
ast::TraitItem::FunctionDeclaration(declaration) => {
|
||||||
@@ -116,14 +116,14 @@ impl TraitChecker {
|
|||||||
compare_struct_trait(
|
compare_struct_trait(
|
||||||
&impl_function.declaration.to_type(),
|
&impl_function.declaration.to_type(),
|
||||||
&declaration.to_type(),
|
&declaration.to_type(),
|
||||||
&impl_.struct_name,
|
&impl_.struct_.name,
|
||||||
&trait_,
|
&trait_.name,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found == false {
|
if found == false {
|
||||||
return Err(errors::TypingError::MissingTraitFunction {
|
return Err(errors::TypingError::MissingTraitFunction {
|
||||||
struct_name: impl_.struct_name.clone(),
|
struct_name: impl_.struct_.name.clone(),
|
||||||
function_name: declaration.name.clone(),
|
function_name: declaration.name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -135,8 +135,8 @@ impl TraitChecker {
|
|||||||
compare_struct_trait(
|
compare_struct_trait(
|
||||||
&impl_function.declaration.to_type(),
|
&impl_function.declaration.to_type(),
|
||||||
&function.declaration.to_type(),
|
&function.declaration.to_type(),
|
||||||
&impl_.struct_name,
|
&impl_.struct_.name,
|
||||||
&trait_,
|
&trait_.name,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,17 +166,12 @@ impl TypeAliasResolver {
|
|||||||
value: "Self".to_string(),
|
value: "Self".to_string(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
replaces: ast::TypeUsage::Named(ast::NamedTypeUsage {
|
replaces: ast::TypeUsage::Named(impl_.struct_.clone()),
|
||||||
type_parameters: ast::GenericUsage::Unknown,
|
|
||||||
name: impl_.struct_name.clone(),
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
return ast::Impl {
|
return ast::Impl {
|
||||||
generic: impl_.generic.clone(),
|
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_: impl_.struct_.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(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,6 +285,32 @@ impl Context {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_generic(&self, generic: &ast::Generic) -> Result<Context> {
|
||||||
|
let mut ctx = self.clone();
|
||||||
|
for parameter in generic.parameters.iter() {
|
||||||
|
let mut env_type = EnvType{
|
||||||
|
is_a: TypeType::Trait,
|
||||||
|
fields: HashMap::new(),
|
||||||
|
impls: vec!(),
|
||||||
|
};
|
||||||
|
for bound in parameter.bounds.iter() {
|
||||||
|
if !self.environment.contains_key(&bound.name.value) {
|
||||||
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
|
identifier: bound.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
match &self.environment[&bound.name.value] {
|
||||||
|
NamedEntity::NamedType(named_type) => {
|
||||||
|
env_type.impls.push(named_type.impls[0].clone());
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ctx.environment.insert(parameter.name.name.value.clone(), NamedEntity::NamedType(env_type));
|
||||||
|
}
|
||||||
|
return Ok(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
|
fn add_impl(&self, impl_: &ast::Impl, traits: &HashMap<String, ast::TraitTypeDeclaration>) -> Result<Context> {
|
||||||
let mut functions = HashMap::new();
|
let mut functions = HashMap::new();
|
||||||
for func in impl_.functions.iter() {
|
for func in impl_.functions.iter() {
|
||||||
@@ -292,13 +318,13 @@ impl Context {
|
|||||||
}
|
}
|
||||||
// fill out defaults
|
// fill out defaults
|
||||||
match &impl_.trait_ {
|
match &impl_.trait_ {
|
||||||
Some(trait_name) => {
|
Some(trait_) => {
|
||||||
if !traits.contains_key(&trait_name.name.value) {
|
if !traits.contains_key(&trait_.name.name.value) {
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
identifier: trait_name.clone(),
|
identifier: trait_.name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for func in traits[&trait_name.name.value].functions.iter() {
|
for func in traits[&trait_.name.name.value].functions.iter() {
|
||||||
match func {
|
match func {
|
||||||
ast::TraitItem::Function(default_function) => {
|
ast::TraitItem::Function(default_function) => {
|
||||||
if !functions.contains_key(&default_function.declaration.name.name.value) {
|
if !functions.contains_key(&default_function.declaration.name.name.value) {
|
||||||
@@ -315,23 +341,23 @@ impl Context {
|
|||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
let mut result = self.clone();
|
let mut result = self.clone();
|
||||||
let mut env_named = result.environment[&impl_.struct_name.name.value].clone();
|
let mut env_named = result.environment[&impl_.struct_.name.name.value].clone();
|
||||||
match &mut env_named {
|
match &mut env_named {
|
||||||
NamedEntity::NamedType(env_type) => {
|
NamedEntity::NamedType(env_type) => {
|
||||||
env_type.impls.push(EnvImpl {
|
env_type.impls.push(EnvImpl {
|
||||||
trait_: match &impl_.trait_ {
|
trait_: match &impl_.trait_ {
|
||||||
Some(trait_) => Some(trait_.name.value.to_string()),
|
Some(trait_) => Some(trait_.name.name.value.to_string()),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
functions: functions,
|
functions: functions,
|
||||||
});
|
});
|
||||||
result
|
result
|
||||||
.environment
|
.environment
|
||||||
.insert(impl_.struct_name.name.value.to_string(), NamedEntity::NamedType(env_type.clone()));
|
.insert(impl_.struct_.name.name.value.to_string(), NamedEntity::NamedType(env_type.clone()));
|
||||||
}
|
}
|
||||||
NamedEntity::Variable(_) => {
|
NamedEntity::Variable(_) => {
|
||||||
return Err(errors::TypingError::TypeDoesNotExist {
|
return Err(errors::TypingError::TypeDoesNotExist {
|
||||||
identifier: impl_.struct_name.clone(),
|
identifier: impl_.struct_.name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,9 +564,9 @@ impl TypeChecker {
|
|||||||
for item in module.items.iter() {
|
for item in module.items.iter() {
|
||||||
match item {
|
match item {
|
||||||
ast::ModuleItem::Impl(impl_) => {
|
ast::ModuleItem::Impl(impl_) => {
|
||||||
if !ctx.environment.contains_key(&impl_.struct_name.name.value) {
|
if !ctx.environment.contains_key(&impl_.struct_.name.name.value) {
|
||||||
return Err(errors::TypingError::IdentifierIsNotType {
|
return Err(errors::TypingError::IdentifierIsNotType {
|
||||||
identifier: impl_.struct_name.clone(),
|
identifier: impl_.struct_.name.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ctx = ctx.add_impl(&impl_, &traits)?;
|
ctx = ctx.add_impl(&impl_, &traits)?;
|
||||||
@@ -588,9 +614,10 @@ impl TypeChecker {
|
|||||||
incoming_substitutions: &SubstitutionMap,
|
incoming_substitutions: &SubstitutionMap,
|
||||||
function: &ast::Function,
|
function: &ast::Function,
|
||||||
) -> Result<(ast::Function, SubstitutionMap)> {
|
) -> Result<(ast::Function, SubstitutionMap)> {
|
||||||
let declaration = self.with_function_declaration(ctx, &function.declaration)?;
|
let gen_ctx = ctx.add_generic(&function.declaration.generic)?;
|
||||||
|
let declaration = self.with_function_declaration(&gen_ctx, &function.declaration)?;
|
||||||
// add args to env
|
// add args to env
|
||||||
let mut function_ctx = ctx.set_current_function_return(&declaration.return_type.clone());
|
let mut function_ctx = gen_ctx.set_current_function_return(&declaration.return_type.clone());
|
||||||
for arg in declaration.arguments.iter() {
|
for arg in declaration.arguments.iter() {
|
||||||
function_ctx = function_ctx.add_variable(arg.name.name.value.to_string(), &arg.type_.clone());
|
function_ctx = function_ctx.add_variable(arg.name.name.value.to_string(), &arg.type_.clone());
|
||||||
}
|
}
|
||||||
@@ -660,16 +687,17 @@ impl TypeChecker {
|
|||||||
incoming_substitutions: &SubstitutionMap,
|
incoming_substitutions: &SubstitutionMap,
|
||||||
trait_: &ast::TraitTypeDeclaration,
|
trait_: &ast::TraitTypeDeclaration,
|
||||||
) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> {
|
) -> Result<(ast::TraitTypeDeclaration, SubstitutionMap)> {
|
||||||
|
let gen_ctx = ctx.add_generic(&trait_.generic)?;
|
||||||
let mut substitutions = incoming_substitutions.clone();
|
let mut substitutions = incoming_substitutions.clone();
|
||||||
let mut result_functions = vec![];
|
let mut result_functions = vec![];
|
||||||
for item in &trait_.functions {
|
for item in &trait_.functions {
|
||||||
match item {
|
match item {
|
||||||
ast::TraitItem::FunctionDeclaration(declaration) => {
|
ast::TraitItem::FunctionDeclaration(declaration) => {
|
||||||
let result_declaration = self.with_function_declaration(ctx, declaration)?;
|
let result_declaration = self.with_function_declaration(&gen_ctx, declaration)?;
|
||||||
result_functions.push(ast::TraitItem::FunctionDeclaration(result_declaration));
|
result_functions.push(ast::TraitItem::FunctionDeclaration(result_declaration));
|
||||||
}
|
}
|
||||||
ast::TraitItem::Function(function) => {
|
ast::TraitItem::Function(function) => {
|
||||||
let (function_result, susbt) = self.with_function(ctx, incoming_substitutions, function)?;
|
let (function_result, susbt) = self.with_function(&gen_ctx, incoming_substitutions, function)?;
|
||||||
substitutions = compose_substitutions(ctx, &substitutions, &susbt)?;
|
substitutions = compose_substitutions(ctx, &substitutions, &susbt)?;
|
||||||
result_functions.push(ast::TraitItem::Function(function_result));
|
result_functions.push(ast::TraitItem::Function(function_result));
|
||||||
}
|
}
|
||||||
@@ -686,9 +714,10 @@ impl TypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> Result<ast::StructTypeDeclaration> {
|
fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> Result<ast::StructTypeDeclaration> {
|
||||||
|
let struct_ctx = ctx.add_generic(&struct_.generic)?;
|
||||||
let mut fields = vec![];
|
let mut fields = vec![];
|
||||||
for field in struct_.fields.iter() {
|
for field in struct_.fields.iter() {
|
||||||
type_exists(ctx, &field.type_)?;
|
type_exists(&struct_ctx, &field.type_)?;
|
||||||
fields.push(ast::StructField {
|
fields.push(ast::StructField {
|
||||||
name: field.name.clone(),
|
name: field.name.clone(),
|
||||||
type_: field.type_.clone(),
|
type_: field.type_.clone(),
|
||||||
@@ -707,24 +736,24 @@ impl TypeChecker {
|
|||||||
incoming_substitutions: &SubstitutionMap,
|
incoming_substitutions: &SubstitutionMap,
|
||||||
impl_: &ast::Impl,
|
impl_: &ast::Impl,
|
||||||
) -> Result<(ast::Impl, SubstitutionMap)> {
|
) -> Result<(ast::Impl, SubstitutionMap)> {
|
||||||
|
let impl_ctx = ctx.add_generic(&impl_.generic)?;
|
||||||
|
|
||||||
let mut substitutions = incoming_substitutions.clone();
|
let mut substitutions = incoming_substitutions.clone();
|
||||||
type_exists(
|
type_exists(
|
||||||
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),
|
||||||
)?;
|
)?;
|
||||||
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(&impl_ctx, &substitutions, function)?;
|
||||||
substitutions = compose_substitutions(ctx, &substitutions, &function_subs)?;
|
substitutions = compose_substitutions(&impl_ctx, &substitutions, &function_subs)?;
|
||||||
functions.push(result);
|
functions.push(result);
|
||||||
}
|
}
|
||||||
return Ok((
|
return Ok((
|
||||||
ast::Impl {
|
ast::Impl {
|
||||||
generic: impl_.generic.clone(),
|
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_: impl_.struct_.clone(),
|
||||||
struct_type_parameters: impl_.struct_type_parameters.clone(),
|
|
||||||
functions: functions,
|
functions: functions,
|
||||||
},
|
},
|
||||||
substitutions,
|
substitutions,
|
||||||
|
|||||||
Reference in New Issue
Block a user