diff --git a/compiler/src/sugar.rs b/compiler/src/sugar.rs index 54bb8de..25a9ae0 100644 --- a/compiler/src/sugar.rs +++ b/compiler/src/sugar.rs @@ -9,7 +9,7 @@ use crate::error::{Cause, Error, ResultSpan}; use crate::scope::{Reference, Scope, TypeId, Value}; use crate::symbol::{FunctionSignature, FunctionSignatureBuilder}; use crate::transform::ExprTransformer; -use crate::typechecker::{type_of, Callable, TypedAst, TypedExpr}; +use crate::typechecker::{type_of, Callable, TypedAst, TypedExpr, TypedExprExt}; pub struct Desugar<'a> { pool: &'a mut ConstantPool, @@ -146,17 +146,44 @@ impl<'a> ExprTransformer for Desugar<'a> { let mut seq = self.on_seq(seq)?; let array = self.on_expr(array)?; - let arr_type = type_of(&array, self.scope, self.pool)?; - let arr_local = self.fresh_local(&arr_type).with_span(span)?; + let array_type = type_of(&array, self.scope, self.pool)?; + let array_ref_type = TypeId::ScriptRef(array_type.clone().into()); + let array_local = self.fresh_local(&array_ref_type).with_span(span)?; + let array_deref = || { + Expr::Call( + Callable::Intrinsic(Intrinsic::Deref, array_type.clone()), + [].into(), + [Expr::Ident(array_local.clone(), span)].into(), + span, + ) + }; let counter_type = self.scope.resolve_type(&TypeName::INT32, self.pool).with_span(span)?; let counter_local = self.fresh_local(&counter_type).with_span(span)?; + let array_lvalue = if array.is_prvalue() { + let tmp_local = self.fresh_local(&array_type).with_span(span)?; + self.add_prefix(Expr::Assign( + Box::new(Expr::Ident(tmp_local.clone(), span)), + Box::new(array), + span, + )); + Expr::Ident(tmp_local, span) + } else { + array + }; + self.add_prefix(Expr::Assign( - Box::new(Expr::Ident(arr_local.clone(), span)), - Box::new(array), + Box::new(Expr::Ident(array_local.clone(), span)), + Box::new(Expr::Call( + Callable::Intrinsic(Intrinsic::AsRef, array_ref_type), + [].into(), + [array_lvalue].into(), + span, + )), span, )); + self.add_prefix(Expr::Assign( Box::new(Expr::Ident(counter_local.clone(), span)), Box::new(Expr::Constant(Constant::I32(0), span)), @@ -181,12 +208,7 @@ impl<'a> ExprTransformer for Desugar<'a> { [].into(), [ Expr::Ident(counter_local.clone(), span), - Expr::Call( - array_size, - [].into(), - [Expr::Ident(arr_local.clone(), span)].into(), - span, - ), + Expr::Call(array_size, [].into(), [array_deref()].into(), span), ] .into(), span, @@ -194,7 +216,7 @@ impl<'a> ExprTransformer for Desugar<'a> { let assign_iter_value = Expr::Assign( Box::new(Expr::Ident(Reference::Value(Value::Local(name)), span)), Box::new(Expr::ArrayElem( - Box::new(Expr::Ident(arr_local, span)), + Box::new(array_deref()), Box::new(Expr::Ident(counter_local.clone(), span)), span, )), diff --git a/compiler/tests/bytecode.rs b/compiler/tests/bytecode.rs index 8b8c406..1b5c763 100644 --- a/compiler/tests/bytecode.rs +++ b/compiler/tests/bytecode.rs @@ -146,33 +146,93 @@ fn compile_for_loop() { let check = check_code![ mem!(ArrayResize(int_array_type)), - mem!(Local(tmp_array)), + mem!(Local(array)), pat!(U64Const(2)), pat!(Assign), mem!(ArrayElement(int_array_type)), - mem!(Local(tmp_array)), + mem!(Local(array)), pat!(U64Const(0)), pat!(I32Const(0)), pat!(Assign), mem!(ArrayElement(int_array_type)), - mem!(Local(tmp_array)), + mem!(Local(array)), pat!(U64Const(1)), pat!(I32Const(1)), pat!(Assign), + mem!(Local(array_ref)), + mem!(AsRef(int_array_type)), mem!(Local(array)), + pat!(Assign), + mem!(Local(counter)), + pat!(I32Const(0)), + pat!(JumpIfFalse(Offset { value: 168 })), + pat!(InvokeStatic(Offset { value: 52 }, 1, _, 0)), + mem!(Local(counter)), + mem!(ArraySize(int_type)), + mem!(Deref(int_array_type)), + mem!(Local(array_ref)), + pat!(ParamEnd), + pat!(Assign), + mem!(Local(i)), + mem!(ArrayElement(int_type)), + mem!(Deref(int_array_type)), + mem!(Local(array_ref)), + mem!(Local(counter)), + pat!(InvokeStatic(Offset { value: 34 }, 1, _, 0)), + pat!(ToString(_)), + mem!(Local(i)), + pat!(ParamEnd), + pat!(InvokeStatic(Offset { value: 30 }, 1, _, 0)), + mem!(Local(counter)), + pat!(I32Const(1)), + pat!(ParamEnd), + pat!(Jump(Offset { value: -165 })), + pat!(Nop) + ]; + TestContext::compiled(vec![sources]).unwrap().run("Testing", check); +} + +#[test] +fn compile_for_loop_with_tmp_array() { + let sources = " + func Testing() { + for i in GetArray() { + Log(ToString(i)); + } + } + + func GetArray() -> array { + return [0, 1]; + } + + native func Log(str: String) + native func OperatorAssignAdd(out l: Int32, r: Int32) -> Int32 + native func OperatorLess(l: Int32, r: Int32) -> Bool + "; + + let check = check_code![ + pat!(Assign), + mem!(Local(tmp_array)), + pat!(InvokeStatic(Offset { value: 16 }, 1, _, 0)), + pat!(ParamEnd), + pat!(Assign), + mem!(Local(array_ref)), + mem!(AsRef(int_array_type)), mem!(Local(tmp_array)), pat!(Assign), mem!(Local(counter)), pat!(I32Const(0)), - pat!(JumpIfFalse(Offset { value: 150 })), - pat!(InvokeStatic(Offset { value: 43 }, 1, _, 0)), + pat!(JumpIfFalse(Offset { value: 168 })), + pat!(InvokeStatic(Offset { value: 52 }, 1, _, 0)), mem!(Local(counter)), - mem!(ArraySize(elem_type)), - mem!(Local(array)), + mem!(ArraySize(int_type)), + mem!(Deref(int_array_type)), + mem!(Local(array_ref)), pat!(ParamEnd), pat!(Assign), mem!(Local(i)), - mem!(ArrayElement(elem_type)), + mem!(ArrayElement(int_type)), + mem!(Deref(int_array_type)), mem!(Local(array)), mem!(Local(counter)), pat!(InvokeStatic(Offset { value: 34 }, 1, _, 0)), @@ -183,7 +243,7 @@ fn compile_for_loop() { mem!(Local(counter)), pat!(I32Const(1)), pat!(ParamEnd), - pat!(Jump(Offset { value: -147 })), + pat!(Jump(Offset { value: -165 })), pat!(Nop) ]; TestContext::compiled(vec![sources]).unwrap().run("Testing", check); diff --git a/compiler/tests/utils.rs b/compiler/tests/utils.rs index 92deaaa..c623e51 100644 --- a/compiler/tests/utils.rs +++ b/compiler/tests/utils.rs @@ -34,6 +34,7 @@ impl TestContext { Ok(res) } + #[track_caller] pub fn match_index(&mut self, idx: PoolIndex, name: &str) { match self.indexes.get(name) { Some(val) if *val == idx => (),