Implement type inferencing

This commit is contained in:
Jeff 2024-06-19 00:05:58 -04:00
parent ccdcc7c791
commit aa79bea9a7
6 changed files with 75 additions and 12 deletions

View File

@ -128,10 +128,38 @@ impl AbstractNode for FunctionCall {
} }
impl ExpectedType for FunctionCall { impl ExpectedType for FunctionCall {
fn expected_type(&self, _context: &mut Context) -> Result<Type, ValidationError> { fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
let function_node_type = self.function.expected_type(_context)?; let function_node_type = self.function.expected_type(context)?;
if let Type::Function {
return_type,
type_parameters,
..
} = function_node_type
{
for (constructor, identifier) in self
.type_arguments
.as_ref()
.unwrap()
.into_iter()
.zip(type_parameters.unwrap().into_iter())
{
if let Type::Generic {
identifier: return_identifier,
..
} = *return_type.clone()
{
if return_identifier == identifier {
let concrete_type = constructor.clone().construct(&context)?;
return Ok(Type::Generic {
identifier,
concrete_type: Some(Box::new(concrete_type)),
});
}
}
}
if let Type::Function { return_type, .. } = function_node_type {
Ok(*return_type) Ok(*return_type)
} else { } else {
Err(ValidationError::ExpectedFunction { Err(ValidationError::ExpectedFunction {

View File

@ -21,7 +21,10 @@ pub enum Type {
value_parameters: Vec<Type>, value_parameters: Vec<Type>,
return_type: Box<Type>, return_type: Box<Type>,
}, },
Generic(Option<Box<Type>>), Generic {
identifier: Identifier,
concrete_type: Option<Box<Type>>,
},
Integer, Integer,
List { List {
length: usize, length: usize,
@ -50,7 +53,16 @@ impl Type {
| (Type::None, Type::None) | (Type::None, Type::None)
| (Type::Range, Type::Range) | (Type::Range, Type::Range)
| (Type::String, Type::String) => return Ok(()), | (Type::String, Type::String) => return Ok(()),
(Type::Generic(left), Type::Generic(right)) => match (left, right) { (
Type::Generic {
concrete_type: left,
..
},
Type::Generic {
concrete_type: right,
..
},
) => match (left, right) {
(Some(left), Some(right)) => { (Some(left), Some(right)) => {
if left.check(&right).is_ok() { if left.check(&right).is_ok() {
return Ok(()); return Ok(());
@ -61,6 +73,14 @@ impl Type {
} }
_ => {} _ => {}
}, },
(Type::Generic { concrete_type, .. }, other)
| (other, Type::Generic { concrete_type, .. }) => {
if let Some(concrete_type) = concrete_type {
if other == concrete_type.as_ref() {
return Ok(());
}
}
}
(Type::ListOf(left), Type::ListOf(right)) => { (Type::ListOf(left), Type::ListOf(right)) => {
if left.check(&right).is_ok() { if left.check(&right).is_ok() {
return Ok(()); return Ok(());
@ -207,11 +227,11 @@ impl Display for Type {
Type::Any => write!(f, "any"), Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"), Type::Boolean => write!(f, "bool"),
Type::Float => write!(f, "float"), Type::Float => write!(f, "float"),
Type::Generic(type_option) => { Type::Generic { concrete_type, .. } => {
if let Some(concrete_type) = type_option { if let Some(r#type) = concrete_type {
write!(f, "implied to be {concrete_type}") write!(f, "implied to be {}", r#type)
} else { } else {
todo!() write!(f, "unknown")
} }
} }
Type::Integer => write!(f, "int"), Type::Integer => write!(f, "int"),

View File

@ -82,9 +82,15 @@ impl TypeConstructor {
node: identifier, .. node: identifier, ..
}) => { }) => {
if let Some(r#type) = context.get_type(&identifier)? { if let Some(r#type) = context.get_type(&identifier)? {
Type::Generic(Some(Box::new(r#type))) Type::Generic {
identifier,
concrete_type: Some(Box::new(r#type)),
}
} else { } else {
Type::Generic(None) Type::Generic {
identifier,
concrete_type: None,
}
} }
} }
TypeConstructor::List(positioned_constructor) => { TypeConstructor::List(positioned_constructor) => {

View File

@ -68,7 +68,13 @@ impl AbstractNode for ValueNode {
if let Some(type_parameters) = type_parameters { if let Some(type_parameters) = type_parameters {
for identifier in type_parameters { for identifier in type_parameters {
function_context.set_type(identifier.clone(), Type::Generic(None))?; function_context.set_type(
identifier.clone(),
Type::Generic {
identifier: identifier.clone(),
concrete_type: None,
},
)?;
} }
} }

View File

@ -18,3 +18,4 @@ while count <= 15 {
count += 1 count += 1
} }

View File

@ -0,0 +1,2 @@
foo = fn |T| (x: T) -> T { x }
bar: str = foo::(str)::("hi")