diff --git a/grammar.ebnf b/grammar.ebnf index 10502584..e3b47a3f 100644 --- a/grammar.ebnf +++ b/grammar.ebnf @@ -38,7 +38,7 @@ expression = function_call | function_call_failed | identifier | - list | + array | null | number | parentheses | @@ -119,10 +119,10 @@ boolean = 'true' | 'false' ; (* `Null` literal *) null = 'null' ; -(* `List` literal *) -empty_list = '[', TYPE, ']' ; -full_list = '[', [ expression, { ',', expression } ], ']' ; -list = empty_list | full_list ; +(* `Array` literal *) +empty_array = '[', [ TYPE ], ']' ; +full_array = '[', [ expression, { ',', expression } ], ']' ; +array = empty_array | full_array ; (* Command expression *) (* The ordering of command modifiers doesn't matter *) diff --git a/src/modules/expression/binop/add.rs b/src/modules/expression/binop/add.rs index 0e6860d1..15ed59ec 100644 --- a/src/modules/expression/binop/add.rs +++ b/src/modules/expression/binop/add.rs @@ -55,7 +55,7 @@ impl TypeCheckModule for Add { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - self.kind = Self::typecheck_allowed_types(meta, "addition", &self.left, &self.right, &[ + self.kind = Self::typecheck_allowed_types(meta, "addition", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, Type::Text, diff --git a/src/modules/expression/binop/and.rs b/src/modules/expression/binop/and.rs index edd430bc..2ce1dfde 100644 --- a/src/modules/expression/binop/and.rs +++ b/src/modules/expression/binop/and.rs @@ -52,7 +52,9 @@ impl TypeCheckModule for And { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_equality(meta, &self.left, &self.right)?; + Self::typecheck_allowed_types(meta, "logical AND", &mut self.left, &mut self.right, &[ + Type::Bool, + ])?; Ok(()) } } diff --git a/src/modules/expression/binop/div.rs b/src/modules/expression/binop/div.rs index 2a9e89a8..04c4e389 100644 --- a/src/modules/expression/binop/div.rs +++ b/src/modules/expression/binop/div.rs @@ -55,7 +55,7 @@ impl TypeCheckModule for Div { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - self.kind = Self::typecheck_allowed_types(meta, "division", &self.left, &self.right, &[ + self.kind = Self::typecheck_allowed_types(meta, "division", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, ])?; diff --git a/src/modules/expression/binop/eq.rs b/src/modules/expression/binop/eq.rs index bf00e246..83171429 100644 --- a/src/modules/expression/binop/eq.rs +++ b/src/modules/expression/binop/eq.rs @@ -53,7 +53,7 @@ impl TypeCheckModule for Eq { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_equality(meta, &self.left, &self.right)?; + Self::typecheck_equality(meta, &mut self.left, &mut self.right)?; Ok(()) } } diff --git a/src/modules/expression/binop/ge.rs b/src/modules/expression/binop/ge.rs index 9c4407cf..a8a6bc90 100644 --- a/src/modules/expression/binop/ge.rs +++ b/src/modules/expression/binop/ge.rs @@ -52,7 +52,7 @@ impl TypeCheckModule for Ge { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_allowed_types(meta, "comparison", &self.left, &self.right, &[ + Self::typecheck_allowed_types(meta, "comparison", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, Type::Text, diff --git a/src/modules/expression/binop/gt.rs b/src/modules/expression/binop/gt.rs index f34e281e..2108fbed 100644 --- a/src/modules/expression/binop/gt.rs +++ b/src/modules/expression/binop/gt.rs @@ -52,7 +52,7 @@ impl TypeCheckModule for Gt { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_allowed_types(meta, "comparison", &self.left, &self.right, &[ + Self::typecheck_allowed_types(meta, "comparison", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, Type::Text, diff --git a/src/modules/expression/binop/le.rs b/src/modules/expression/binop/le.rs index 739e87f7..6b0c2f4c 100644 --- a/src/modules/expression/binop/le.rs +++ b/src/modules/expression/binop/le.rs @@ -52,7 +52,7 @@ impl TypeCheckModule for Le { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_allowed_types(meta, "comparison", &self.left, &self.right, &[ + Self::typecheck_allowed_types(meta, "comparison", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, Type::Text, diff --git a/src/modules/expression/binop/lt.rs b/src/modules/expression/binop/lt.rs index bd93482b..aa8c5a97 100644 --- a/src/modules/expression/binop/lt.rs +++ b/src/modules/expression/binop/lt.rs @@ -52,7 +52,7 @@ impl TypeCheckModule for Lt { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_allowed_types(meta, "comparison", &self.left, &self.right, &[ + Self::typecheck_allowed_types(meta, "comparison", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, Type::Text, diff --git a/src/modules/expression/binop/mod.rs b/src/modules/expression/binop/mod.rs index 3cc3f91d..1f06d2f2 100644 --- a/src/modules/expression/binop/mod.rs +++ b/src/modules/expression/binop/mod.rs @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*; use crate::modules::types::{Type, Typed}; use crate::utils::metadata::ParserMetadata; use crate::utils::pluralize; -use super::super::expression::expr::Expr; +use super::super::expression::expr::{Expr, ExprType}; use crate::modules::typecheck::TypeCheckModule; pub mod add; @@ -28,8 +28,8 @@ pub trait BinOp: SyntaxModule + TypeCheckModule { fn typecheck_allowed_types( meta: &mut ParserMetadata, operator: &str, - left: &Expr, - right: &Expr, + left: &mut Expr, + right: &mut Expr, allowed_types: &[Type], ) -> Result { let left_type = left.get_type(); @@ -51,13 +51,31 @@ pub trait BinOp: SyntaxModule + TypeCheckModule { fn typecheck_equality( meta: &mut ParserMetadata, - left: &Expr, - right: &Expr, + left: &mut Expr, + right: &mut Expr, ) -> Result { match (left.get_type(), right.get_type()) { (Type::Int, Type::Num) | (Type::Num, Type::Int) => { Ok(Type::Num) } + // Array type inference + (Type::Array(left_inner), Type::Array(right_inner)) if *left_inner == Type::Generic || *right_inner == Type::Generic => { + if *left_inner == Type::Generic && *right_inner != Type::Generic { + if let Some(ExprType::VariableGet(var)) = &left.value { + meta.update_var_type(&var.name, Type::Array(right_inner.clone())); + } + left.kind = Type::Array(right_inner.clone()); + Ok(Type::Array(right_inner)) + } else if *left_inner != Type::Generic && *right_inner == Type::Generic { + if let Some(ExprType::VariableGet(var)) = &right.value { + meta.update_var_type(&var.name, Type::Array(left_inner.clone())); + } + right.kind = Type::Array(left_inner.clone()); + Ok(Type::Array(left_inner)) + } else { + Ok(Type::Array(Box::new(Type::Generic))) + } + } (left_type, right_type) => { if left_type != right_type { let pos = get_binop_position_info(meta, left, right); diff --git a/src/modules/expression/binop/modulo.rs b/src/modules/expression/binop/modulo.rs index 0212186c..47abcdc2 100644 --- a/src/modules/expression/binop/modulo.rs +++ b/src/modules/expression/binop/modulo.rs @@ -53,7 +53,7 @@ impl TypeCheckModule for Modulo { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - self.kind = Self::typecheck_allowed_types(meta, "modulo", &self.left, &self.right, &[ + self.kind = Self::typecheck_allowed_types(meta, "modulo", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, ])?; diff --git a/src/modules/expression/binop/mul.rs b/src/modules/expression/binop/mul.rs index 37c8cdaf..4e4a931e 100644 --- a/src/modules/expression/binop/mul.rs +++ b/src/modules/expression/binop/mul.rs @@ -54,7 +54,7 @@ impl TypeCheckModule for Mul { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - self.kind = Self::typecheck_allowed_types(meta, "multiplication", &self.left, &self.right, &[ + self.kind = Self::typecheck_allowed_types(meta, "multiplication", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, ])?; diff --git a/src/modules/expression/binop/neq.rs b/src/modules/expression/binop/neq.rs index 63432d3e..1a8bda6f 100644 --- a/src/modules/expression/binop/neq.rs +++ b/src/modules/expression/binop/neq.rs @@ -53,7 +53,7 @@ impl TypeCheckModule for Neq { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_equality(meta, &self.left, &self.right)?; + Self::typecheck_equality(meta, &mut self.left, &mut self.right)?; Ok(()) } } diff --git a/src/modules/expression/binop/or.rs b/src/modules/expression/binop/or.rs index b958cb48..09fb9112 100644 --- a/src/modules/expression/binop/or.rs +++ b/src/modules/expression/binop/or.rs @@ -52,7 +52,9 @@ impl TypeCheckModule for Or { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - Self::typecheck_equality(meta, &self.left, &self.right)?; + Self::typecheck_allowed_types(meta, "logical OR", &mut self.left, &mut self.right, &[ + Type::Bool, + ])?; Ok(()) } } diff --git a/src/modules/expression/binop/range.rs b/src/modules/expression/binop/range.rs index e4d3d65b..2e465214 100644 --- a/src/modules/expression/binop/range.rs +++ b/src/modules/expression/binop/range.rs @@ -56,7 +56,7 @@ impl TypeCheckModule for Range { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.from.typecheck(meta)?; self.to.typecheck(meta)?; - Self::typecheck_allowed_types(meta, "range operator", &self.from, &self.to, &[Type::Int])?; + Self::typecheck_allowed_types(meta, "range operator", &mut self.from, &mut self.to, &[Type::Int])?; Ok(()) } } diff --git a/src/modules/expression/binop/sub.rs b/src/modules/expression/binop/sub.rs index 3630451b..e001ee54 100644 --- a/src/modules/expression/binop/sub.rs +++ b/src/modules/expression/binop/sub.rs @@ -54,7 +54,7 @@ impl TypeCheckModule for Sub { fn typecheck(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { self.left.typecheck(meta)?; self.right.typecheck(meta)?; - self.kind = Self::typecheck_allowed_types(meta, "subtraction", &self.left, &self.right, &[ + self.kind = Self::typecheck_allowed_types(meta, "subtraction", &mut self.left, &mut self.right, &[ Type::Num, Type::Int, ])?; diff --git a/src/modules/expression/literal/array.rs b/src/modules/expression/literal/array.rs index 590821a2..f0a034b5 100644 --- a/src/modules/expression/literal/array.rs +++ b/src/modules/expression/literal/array.rs @@ -29,7 +29,8 @@ impl SyntaxModule for Array { token(meta, "[")?; let tok = meta.get_current_token(); if token(meta, "]").is_ok() { - return error!(meta, tok, "Expected array type or value before ']'", "Eg. insert 'Num' for empty array or '1, 2, 3' for array with values") + self.kind = Type::Array(Box::new(Type::Generic)); + return Ok(()) } // Try to parse array type match try_parse_type(meta) { diff --git a/src/modules/expression/ternop/ternary.rs b/src/modules/expression/ternop/ternary.rs index ce2fe436..5fa8dacf 100644 --- a/src/modules/expression/ternop/ternary.rs +++ b/src/modules/expression/ternop/ternary.rs @@ -11,12 +11,13 @@ use super::TernOp; pub struct Ternary { cond: Box, true_expr: Box, - false_expr: Box + false_expr: Box, + kind: Type } impl Typed for Ternary { fn get_type(&self) -> Type { - self.true_expr.get_type() + self.kind.clone() } } @@ -51,7 +52,8 @@ impl SyntaxModule for Ternary { Ternary { cond: Box::new(Expr::new()), true_expr: Box::new(Expr::new()), - false_expr: Box::new(Expr::new()) + false_expr: Box::new(Expr::new()), + kind: Type::Null } } @@ -71,13 +73,34 @@ impl TypeCheckModule for Ternary { self.true_expr.typecheck(meta)?; self.false_expr.typecheck(meta)?; - if self.true_expr.get_type() != self.false_expr.get_type() { + + let true_type = self.true_expr.get_type(); + let false_type = self.false_expr.get_type(); + + if true_type == false_type { + self.kind = true_type; + } else { + // Handle Array type inference + let mut resolved_type = None; + if let (Type::Array(t), Type::Array(f)) = (&true_type, &false_type) { + if **t == Type::Generic && **f != Type::Generic { + resolved_type = Some(false_type.clone()); + } else if **t != Type::Generic && **f == Type::Generic { + resolved_type = Some(true_type.clone()); + } + } + + if let Some(kind) = resolved_type { + self.kind = kind; + return Ok(()); + } + let pos = get_binop_position_info(meta, &self.true_expr, &self.false_expr); let msg = Message::new_err_at_position(meta, pos) .message("Ternary operation can only evaluate to value of one type.") .comment(format!("Provided branches of type '{}' and '{}'.", - self.true_expr.get_type(), - self.false_expr.get_type())); + true_type, + false_type)); return Err(Failure::Loud(msg)); } Ok(()) diff --git a/src/modules/function/invocation.rs b/src/modules/function/invocation.rs index 7fa68d3c..25e79290 100644 --- a/src/modules/function/invocation.rs +++ b/src/modules/function/invocation.rs @@ -126,6 +126,20 @@ impl TypeCheckModule for FunctionInvocation { } } + // Check for type inference on reference arguments + for (arg_expr, fun_arg) in izip!(&mut self.args, &function_unit.args) { + if fun_arg.is_ref { + if let (Type::Array(inner), Type::Array(expected_inner)) = (arg_expr.get_type(), &fun_arg.kind) { + if *inner == Type::Generic && **expected_inner != Type::Generic { + if let Some(ExprType::VariableGet(var)) = &arg_expr.value { + meta.update_var_type(&var.name, Type::array_of(*expected_inner.clone())); + arg_expr.kind = Type::array_of(*expected_inner.clone()); + } + } + } + } + } + // Validate arguments and get function variant let types = self.args.iter().map(Expr::get_type).collect::>(); let var_refs = self.args.iter().map(is_ref).collect::>(); diff --git a/src/modules/shorthand/add.rs b/src/modules/shorthand/add.rs index df07babe..93ac564f 100644 --- a/src/modules/shorthand/add.rs +++ b/src/modules/shorthand/add.rs @@ -4,7 +4,7 @@ use crate::modules::expression::expr::Expr; use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions}; use crate::translate::compute::translate_computation_eval; use crate::translate::{compute::ArithOp, module::TranslateModule}; -use crate::modules::types::Type; +use crate::modules::types::{Type, Typed}; use super::shorthand_typecheck_allowed_types; @@ -52,6 +52,15 @@ impl TypeCheckModule for ShorthandAdd { self.global_id = variable.global_id; self.is_ref = variable.is_ref; + let right_type = self.expr.get_type(); + if let (Type::Array(inner_left), Type::Array(inner_right)) = (&self.kind, &right_type) { + if *inner_left.as_ref() == Type::Generic && *inner_right.as_ref() != Type::Generic { + meta.update_var_type(&self.var, right_type.clone()); + self.kind = right_type; + return Ok(()); + } + } + shorthand_typecheck_allowed_types(meta, "add", &self.kind, &self.expr, &[ Type::Num, Type::Int, diff --git a/src/modules/types.rs b/src/modules/types.rs index 58226009..db7d687e 100644 --- a/src/modules/types.rs +++ b/src/modules/types.rs @@ -35,7 +35,15 @@ impl Type { } pub fn is_allowed_in(&self, other: &Type) -> bool { - self == other || self.is_subset_of(other) + if self == other || self.is_subset_of(other) { + return true; + } + + if let (Type::Array(const_type), Type::Array(other_type)) = (self, other) { + return **const_type == Type::Generic && **other_type != Type::Generic; + } + + false } pub fn is_array(&self) -> bool { @@ -178,6 +186,7 @@ mod tests { let b = Type::Array(Box::new(Type::Generic)); assert!(!b.is_subset_of(&a)); + assert!(b.is_allowed_in(&a)); } #[test] diff --git a/src/modules/variable/set.rs b/src/modules/variable/set.rs index 7f9449b4..7170cc89 100644 --- a/src/modules/variable/set.rs +++ b/src/modules/variable/set.rs @@ -70,15 +70,33 @@ impl TypeCheckModule for VariableSet { if self.index.is_some() { if let Type::Array(kind) = &self.var_type { + // Handle type inference + if **kind == Type::Generic { + let new_type = Type::array_of(right_type.clone()); + meta.update_var_type(&self.name, new_type.clone()); + self.var_type = new_type; + return Ok(()); + } + if !right_type.is_allowed_in(kind) { let tok = self.expr.get_position(); return error_pos!(meta, tok, format!("Cannot assign value of type '{right_type}' to an array of '{kind}'")); } } - } - else if !right_type.is_allowed_in(&self.var_type) { - let tok = self.expr.get_position(); - return error_pos!(meta, tok, format!("Cannot assign value of type '{right_type}' to a variable of type '{}'", self.var_type)); + } else { + // Check for type inference + if let (Type::Array(inner_var), Type::Array(inner_right)) = (&self.var_type, &right_type) { + if **inner_var == Type::Generic && **inner_right != Type::Generic { + meta.update_var_type(&self.name, right_type.clone()); + self.var_type = right_type; + return Ok(()); + } + } + + if !right_type.is_allowed_in(&self.var_type) { + let tok = self.expr.get_position(); + return error_pos!(meta, tok, format!("Cannot assign value of type '{right_type}' to a variable of type '{}'", self.var_type)); + } } Ok(()) diff --git a/src/tests/erroring/type_inference_array_binary_op_mismatch.ab b/src/tests/erroring/type_inference_array_binary_op_mismatch.ab new file mode 100644 index 00000000..77b1ac31 --- /dev/null +++ b/src/tests/erroring/type_inference_array_binary_op_mismatch.ab @@ -0,0 +1,7 @@ +// Output +// Expected both operands to be of the same type, but got '[Int]' and '[Text]'. + +let a = [] +a = a + [1] +a = a + ["test"] +echo a diff --git a/src/tests/erroring/type_inference_array_function_mismatch.ab b/src/tests/erroring/type_inference_array_function_mismatch.ab new file mode 100644 index 00000000..d9bd561d --- /dev/null +++ b/src/tests/erroring/type_inference_array_function_mismatch.ab @@ -0,0 +1,10 @@ +// Output +// 1st argument 'n' of function 'foo' expects type '[Int]', but '[Text]' was given + +fun foo(ref n: [Int]) { + echo n +} + +let a = [] +a = ["test"] +foo(a) diff --git a/src/tests/erroring/type_inference_array_inconsistent_assignment.ab b/src/tests/erroring/type_inference_array_inconsistent_assignment.ab new file mode 100644 index 00000000..8c88d82c --- /dev/null +++ b/src/tests/erroring/type_inference_array_inconsistent_assignment.ab @@ -0,0 +1,7 @@ +// Output +// Cannot assign value of type '[Text]' to a variable of type '[Int]' + +let a = [] +a = [1] +a = ["test"] +echo a diff --git a/src/tests/erroring/type_inference_array_index_assignment.ab b/src/tests/erroring/type_inference_array_index_assignment.ab new file mode 100644 index 00000000..54d3d0ef --- /dev/null +++ b/src/tests/erroring/type_inference_array_index_assignment.ab @@ -0,0 +1,7 @@ +// Output +// Cannot assign value of type '[Text]' to a variable of type '[Int]' + +let a = [] +a[0] = 1 +a = ["test"] +echo a diff --git a/src/tests/validity/modulo_num.ab b/src/tests/validity/modulo_num.ab new file mode 100644 index 00000000..b79b1dae --- /dev/null +++ b/src/tests/validity/modulo_num.ab @@ -0,0 +1,12 @@ +// Output +// 1.5 +// .5 +// 5 + +let a = 5.5 +let b = 2.0 +echo a % b + +let c = 5 +echo a % c +echo c % a diff --git a/src/tests/validity/type_inference_array_binary_op.ab b/src/tests/validity/type_inference_array_binary_op.ab new file mode 100644 index 00000000..a1d75187 --- /dev/null +++ b/src/tests/validity/type_inference_array_binary_op.ab @@ -0,0 +1,10 @@ +// Output +// 1 2 3 +// 4 5 6 + + +let a = [1, 2, 3] + [] +echo a + +let b = [] + [4, 5, 6] +echo b diff --git a/src/tests/validity/type_inference_array_comparison.ab b/src/tests/validity/type_inference_array_comparison.ab new file mode 100644 index 00000000..02ce66e1 --- /dev/null +++ b/src/tests/validity/type_inference_array_comparison.ab @@ -0,0 +1,18 @@ +// Output +// 0 +// 1 +// 0 +// 1 +// 1 + +let a = [] +echo a > [1] +echo a < [1] +echo a >= [1] +echo a <= [1] + +// Persistence of type narrowing +let b = [] +b < [1] +b += [1] +echo b \ No newline at end of file diff --git a/src/tests/validity/type_inference_array_function_param.ab b/src/tests/validity/type_inference_array_function_param.ab new file mode 100644 index 00000000..3ae41400 --- /dev/null +++ b/src/tests/validity/type_inference_array_function_param.ab @@ -0,0 +1,8 @@ +// Output +// 1 + +fun foo(arr: [Int]) { + echo arr + [1] +} + +foo([]) diff --git a/src/tests/validity/type_inference_array_function_ref.ab b/src/tests/validity/type_inference_array_function_ref.ab new file mode 100644 index 00000000..5436744b --- /dev/null +++ b/src/tests/validity/type_inference_array_function_ref.ab @@ -0,0 +1,19 @@ +// Output +// 5 +// Hello + +fun foo(ref arg: [Int]) { + arg += [5] +} + +let a = [] +foo(a) +echo a + +fun bar(ref arg, val) { + arg += [val] +} + +let b = [] +bar(b, "Hello") +echo b diff --git a/src/tests/validity/type_inference_array_reassignment.ab b/src/tests/validity/type_inference_array_reassignment.ab new file mode 100644 index 00000000..ec640420 --- /dev/null +++ b/src/tests/validity/type_inference_array_reassignment.ab @@ -0,0 +1,11 @@ +// Output +// 1 +// 1 2 3 + +let array = [] +array += [1] +echo array + +let array2 = [] +array2 = [1, 2, 3] +echo array2 diff --git a/src/tests/validity/type_inference_array_ref_aliasing.ab b/src/tests/validity/type_inference_array_ref_aliasing.ab new file mode 100644 index 00000000..a13e744c --- /dev/null +++ b/src/tests/validity/type_inference_array_ref_aliasing.ab @@ -0,0 +1,10 @@ +// Output +// 1 2 + +fun two_vars(ref a: [Int], ref b: [Int]) { + a += [1] + b += [2] +} +let z = [] +two_vars(z, z) +echo z diff --git a/src/tests/validity/type_inference_array_ref_deep_2.ab b/src/tests/validity/type_inference_array_ref_deep_2.ab new file mode 100644 index 00000000..2b7f7f92 --- /dev/null +++ b/src/tests/validity/type_inference_array_ref_deep_2.ab @@ -0,0 +1,12 @@ +// Output +// 10 + +fun level2(ref arr: [Int]) { + arr += [10] +} +fun level1(ref arr: [Int]) { + level2(arr) +} +let a = [] +level1(a) +echo a diff --git a/src/tests/validity/type_inference_array_ref_deep_3.ab b/src/tests/validity/type_inference_array_ref_deep_3.ab new file mode 100644 index 00000000..50486c00 --- /dev/null +++ b/src/tests/validity/type_inference_array_ref_deep_3.ab @@ -0,0 +1,15 @@ +// Output +// 99 + +fun deep3(ref arr: [Int]) { + arr += [99] +} +fun deep2(ref arr: [Int]) { + deep3(arr) +} +fun deep1(ref arr: [Int]) { + deep2(arr) +} +let d = [] +deep1(d) +echo d diff --git a/src/tests/validity/type_inference_array_ref_multiple_vars.ab b/src/tests/validity/type_inference_array_ref_multiple_vars.ab new file mode 100644 index 00000000..ee9d6d72 --- /dev/null +++ b/src/tests/validity/type_inference_array_ref_multiple_vars.ab @@ -0,0 +1,13 @@ +// Output +// 1 +// 2 + +fun two_vars(ref a: [Int], ref b: [Int]) { + a += [1] + b += [2] +} +let x = [] +let y = [] +two_vars(x, y) +echo x +echo y diff --git a/src/tests/validity/type_inference_array_ternary.ab b/src/tests/validity/type_inference_array_ternary.ab new file mode 100644 index 00000000..05205aee --- /dev/null +++ b/src/tests/validity/type_inference_array_ternary.ab @@ -0,0 +1,9 @@ +// Output +// 1 2 3 +// 4 5 6 + +let a = true then [1, 2, 3] else [] +echo a + +let b = false then [] else [4, 5, 6] +echo b diff --git a/src/utils/metadata/parser.rs b/src/utils/metadata/parser.rs index 0e4ed55b..0d10a9b8 100644 --- a/src/utils/metadata/parser.rs +++ b/src/utils/metadata/parser.rs @@ -142,6 +142,16 @@ impl ParserMetadata { } } + /// Updates the type of a variable + pub fn update_var_type(&mut self, name: &str, new_type: Type) { + for scope in self.context.scopes.iter_mut().rev() { + if let Some(var) = scope.vars.get_mut(name) { + var.kind = new_type; + return; + } + } + } + /* Functions */ /// Generate a new global function id