Improve type inference
This commit is contained in:
parent
0de25215b8
commit
fecc62811d
@ -52,8 +52,13 @@ impl Evaluate for Assignment {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let statement = self
|
||||||
|
.statement
|
||||||
|
.last_child_statement()
|
||||||
|
.unwrap_or(&self.statement);
|
||||||
|
|
||||||
if let (Some(constructor), Statement::Expression(Expression::FunctionCall(function_call))) =
|
if let (Some(constructor), Statement::Expression(Expression::FunctionCall(function_call))) =
|
||||||
(&self.constructor, self.statement.as_ref())
|
(&self.constructor, statement)
|
||||||
{
|
{
|
||||||
let declared_type = constructor.clone().construct(context)?;
|
let declared_type = constructor.clone().construct(context)?;
|
||||||
let function_type = function_call.node.function().expected_type(context)?;
|
let function_type = function_call.node.function().expected_type(context)?;
|
||||||
@ -79,18 +84,6 @@ impl Evaluate for Assignment {
|
|||||||
position: function_call.position,
|
position: function_call.position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if let Some(constructor) = &self.constructor {
|
|
||||||
let r#type = constructor.clone().construct(&context)?;
|
|
||||||
|
|
||||||
r#type
|
|
||||||
.check(&statement_type)
|
|
||||||
.map_err(|conflict| ValidationError::TypeCheck {
|
|
||||||
conflict,
|
|
||||||
actual_position: self.statement.position(),
|
|
||||||
expected_position: Some(constructor.position()),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
context.set_type(self.identifier.node.clone(), r#type.clone())?;
|
|
||||||
} else {
|
} else {
|
||||||
context.set_type(self.identifier.node.clone(), statement_type)?;
|
context.set_type(self.identifier.node.clone(), statement_type)?;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,10 @@ impl Loop {
|
|||||||
pub fn new(statements: Vec<Statement>) -> Self {
|
pub fn new(statements: Vec<Statement>) -> Self {
|
||||||
Self { statements }
|
Self { statements }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn last_statement(&self) -> &Statement {
|
||||||
|
self.statements.last().unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for Loop {
|
impl Evaluate for Loop {
|
||||||
|
@ -39,6 +39,14 @@ impl Statement {
|
|||||||
Statement::While(inner) => inner.position,
|
Statement::While(inner) => inner.position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn last_child_statement(&self) -> Option<&Self> {
|
||||||
|
match self {
|
||||||
|
Statement::Block(block) => Some(block.node.last_statement()),
|
||||||
|
Statement::Loop(r#loop) => Some(r#loop.node.last_statement()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Evaluate for Statement {
|
impl Evaluate for Statement {
|
||||||
|
@ -41,6 +41,15 @@ pub enum ValueNode {
|
|||||||
|
|
||||||
impl Evaluate for ValueNode {
|
impl Evaluate for ValueNode {
|
||||||
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
|
if let ValueNode::EnumInstance { type_name, .. } = self {
|
||||||
|
if let Some(_) = context.get_type(&type_name.node)? {
|
||||||
|
} else {
|
||||||
|
return Err(ValidationError::EnumDefinitionNotFound(
|
||||||
|
type_name.node.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let ValueNode::Map(map_assignments) = self {
|
if let ValueNode::Map(map_assignments) = self {
|
||||||
for (_identifier, constructor_option, expression) in map_assignments {
|
for (_identifier, constructor_option, expression) in map_assignments {
|
||||||
expression.validate(context, _manage_memory)?;
|
expression.validate(context, _manage_memory)?;
|
||||||
@ -147,7 +156,6 @@ impl Evaluate for ValueNode {
|
|||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
||||||
|
|
||||||
ValueNode::EnumInstance {
|
ValueNode::EnumInstance {
|
||||||
type_name,
|
type_name,
|
||||||
variant,
|
variant,
|
||||||
|
@ -13,7 +13,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use abstract_tree::{AbstractTree, Type};
|
use abstract_tree::{AbstractTree, Type};
|
||||||
use ariadne::{Color, Fmt, Label, Report, ReportKind};
|
use ariadne::{Color, Config, Fmt, Label, Report, ReportKind};
|
||||||
use chumsky::prelude::*;
|
use chumsky::prelude::*;
|
||||||
use context::Context;
|
use context::Context;
|
||||||
use error::{DustError, RuntimeError, TypeConflict, ValidationError};
|
use error::{DustError, RuntimeError, TypeConflict, ValidationError};
|
||||||
@ -429,6 +429,8 @@ impl InterpreterError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder = builder.with_config(Config::default().with_multiline_arrows(false));
|
||||||
|
|
||||||
let report = builder.finish();
|
let report = builder.finish();
|
||||||
|
|
||||||
reports.push(report);
|
reports.push(report);
|
||||||
|
@ -21,3 +21,26 @@ fn simple_enum() {
|
|||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn big_enum() {
|
||||||
|
assert_eq!(
|
||||||
|
interpret(
|
||||||
|
"test",
|
||||||
|
"
|
||||||
|
type FooBarBaz = enum |T, U, V| {
|
||||||
|
Foo(T),
|
||||||
|
Bar(U),
|
||||||
|
Baz(V),
|
||||||
|
}
|
||||||
|
|
||||||
|
FooBarBaz::Baz(42.0)
|
||||||
|
"
|
||||||
|
),
|
||||||
|
Ok(Some(Value::enum_instance(
|
||||||
|
Identifier::new("FooBarBaz"),
|
||||||
|
Identifier::new("Baz"),
|
||||||
|
Some(vec![Value::float(42.0)]),
|
||||||
|
)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -14,3 +14,7 @@ x = json.parse::(int)::("1")
|
|||||||
|
|
||||||
// Use type annotation
|
// Use type annotation
|
||||||
x: int = json.parse("1")
|
x: int = json.parse("1")
|
||||||
|
|
||||||
|
x: int = {
|
||||||
|
json.parse("1")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user