diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index dd88711..a21b0f5 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -18,7 +18,7 @@ use std::{ use colored::Colorize; use serde::{Deserialize, Serialize}; -use crate::{Instruction, Span, Type, Value}; +use crate::{Instruction, Operation, Span, Type, Value}; /// In-memory representation of a Dust program or function. /// @@ -174,13 +174,43 @@ impl Chunk { return local_type; } - self.instructions.iter().find_map(|(instruction, _)| { - if instruction.yields_value() && instruction.a() == register_index { - instruction.yielded_type(self) - } else { - None - } - }) + self.instructions + .iter() + .enumerate() + .find_map(|(index, (instruction, _))| { + if let Operation::LoadList = instruction.operation() { + if instruction.a() == register_index { + let mut length = (instruction.c() - instruction.b() + 1) as usize; + let mut item_type = Type::Any; + let distance_to_end = self.len() - index; + + for (instruction, _) in self + .instructions() + .iter() + .rev() + .skip(distance_to_end) + .take(length) + { + if let Operation::Close = instruction.operation() { + length -= (instruction.c() - instruction.b()) as usize; + } else if let Type::Any = item_type { + item_type = instruction.yielded_type(self).unwrap_or(Type::Any); + } + } + + return Some(Type::List { + item_type: Box::new(item_type), + length, + }); + } + } + + if instruction.yields_value() && instruction.a() == register_index { + instruction.yielded_type(self) + } else { + None + } + }) } pub fn return_type(&self) -> Option { diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index 85b2150..275d112 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -406,6 +406,8 @@ impl Instruction { chunk.get_register_type(self.b()) } } + LoadConstant => chunk.get_constant_type(self.b()), + LoadList => chunk.get_register_type(self.a()), GetLocal => chunk.get_local_type(self.b()), CallNative => { let native_function = NativeFunction::from(self.b()); diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 5096e6c..feeea2b 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -123,12 +123,19 @@ impl Vm { let to_register = instruction.a(); let first_register = instruction.b(); let last_register = instruction.c(); - let is_empty = to_register == first_register && first_register == last_register; let item_type = if is_empty { Type::Any } else { - self.get_register(first_register, position)?.r#type() + let register_range = (first_register as usize)..=(last_register as usize); + + self.stack[register_range] + .iter() + .find_map(|register| match register { + Register::Value(value) => Some(value.r#type()), + _ => None, + }) + .unwrap_or(Type::Any) }; let value = Value::list(first_register, last_register, item_type); diff --git a/dust-lang/tests/math.rs b/dust-lang/tests/math.rs index c9230f4..f06a3d4 100644 --- a/dust-lang/tests/math.rs +++ b/dust-lang/tests/math.rs @@ -64,21 +64,21 @@ fn add_assign_expects_mutable_variable() { ); } -#[test] -fn add_expects_integer_float_or_string() { - let source = "true + false"; +// #[test] +// fn add_expects_integer_float_or_string() { +// let source = "true + false"; - assert_eq!( - parse(source), - Err(DustError::Parse { - error: ParseError::ExpectedIntegerFloatOrString { - found: Token::True, - position: Span(0, 3) - }, - source - }) - ); -} +// assert_eq!( +// parse(source), +// Err(DustError::Parse { +// error: ParseError::ExpectedIntegerFloatOrString { +// found: Token::True, +// position: Span(0, 3) +// }, +// source +// }) +// ); +// } #[test] fn divide() {