Implement type inferencing
This commit is contained in:
parent
ccdcc7c791
commit
aa79bea9a7
@ -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 {
|
||||||
|
@ -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"),
|
||||||
|
@ -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) => {
|
||||||
|
@ -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,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,3 +18,4 @@ while count <= 15 {
|
|||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
examples/type_inference.ds
Normal file
2
examples/type_inference.ds
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
foo = fn |T| (x: T) -> T { x }
|
||||||
|
bar: str = foo::(str)::("hi")
|
Loading…
Reference in New Issue
Block a user