merged arrays and such from devel
M src/ast.rs +5 -0
@@ 217,6 217,11 @@ pub enum Expr {
     ArrayCtor {
         body: Vec<Expr>,
     },
+    /// Array element reference
+    ArrayRef {
+        expr: Box<Expr>,
+        idx: Box<Expr>,
+    },
     /// Tuple element reference
     TupleRef {
         expr: Box<Expr>,

          
M src/backend/rust.rs +8 -0
@@ 478,6 478,14 @@ fn compile_expr(expr: &hir::ExprNode, tc
             accm += ")\n";
             accm
         }
+        E::ArrayRef { expr, idx } => {
+            // TODO: We don't actually have usize types yet, so...
+            format!(
+                "{}[{} as usize]",
+                compile_expr(expr, tck),
+                compile_expr(idx, tck)
+            )
+        }
         E::StructRef { expr, elt } => {
             // panic!("Should never happen, structs should always be tuples by now!");
             format!("{}.{}", compile_expr(expr, tck), elt)

          
M src/format.rs +6 -0
@@ 233,6 233,12 @@ fn unparse_expr(e: &Expr, indent: usize,
             }
             write!(out, "}}")
         }
+        E::ArrayRef { expr, idx } => {
+            unparse_expr(&*expr, indent, out)?;
+            write!(out, "[")?;
+            unparse_expr(&*idx, 0, out)?;
+            write!(out, "]")
+        }
         E::TupleRef { expr, elt } => {
             unparse_expr(&*expr, indent, out)?;
             write!(out, ".{}", elt)

          
M src/hir.rs +6 -2
@@ 240,7 240,7 @@ pub enum Expr {
         elt: Sym,
     },
     ArrayRef {
-        e: ExprNode,
+        expr: ExprNode,
         idx: ExprNode,
     },
     Assign {

          
@@ 438,7 438,7 @@ impl Expr {
                 expr.write(0, f)?;
                 write!(f, " {})", elt)?;
             }
-            ArrayRef { e, idx } => {
+            ArrayRef { expr: e, idx } => {
                 write!(f, "(arrayref ")?;
                 e.write(0, f)?;
                 write!(f, " ")?;

          
@@ 670,6 670,10 @@ fn lower_expr(expr: &ast::Expr) -> ExprN
                 .collect();
             Expr::StructCtor { body: lowered_body }
         }
+        E::ArrayRef { expr, idx } => Expr::ArrayRef {
+            expr: lower_expr(expr),
+            idx: lower_expr(idx),
+        },
         E::TupleRef { expr, elt } => Expr::TupleRef {
             expr: lower_expr(expr),
             elt: *elt,

          
M src/parser.rs +11 -0
@@ 1021,6 1021,15 @@ impl<'input> Parser<'input> {
                             typeparams: vec![],
                         }
                     }
+                    T::LBracket => {
+                        self.expect(T::LBracket);
+                        let param = self.parse_expr(0)?;
+                        self.expect(T::RBracket);
+                        ast::Expr::ArrayRef {
+                            expr: Box::new(lhs),
+                            idx: Box::new(param),
+                        }
+                    }
                     T::Dollar => {
                         self.expect(T::Dollar);
                         ast::Expr::TypeUnwrap {

          
@@ 1369,6 1378,8 @@ fn postfix_binding_power(op: &TokenKind)
         T::LBrace => Some((119, ())),
         // ":" universal function call syntax
         T::Colon => Some((115, ())),
+        // "[" array index
+        T::LBracket => Some((114, ())),
         // "^" for pointer derefs.  TODO: Check precedence?
         // This gets a little weird since it's postfix, not used
         // to thinking about it.  So it's like...

          
M src/passes.rs +2 -2
@@ 143,8 143,8 @@ fn expr_map(expr: ExprNode, f: &mut dyn 
             expr: expr_map(expr, f),
             elt,
         },
-        E::ArrayRef { e, idx } => E::ArrayRef {
-            e: expr_map(e, f),
+        E::ArrayRef { expr, idx } => E::ArrayRef {
+            expr: expr_map(expr, f),
             idx,
         },
         E::Assign { lhs, rhs } => E::Assign {

          
M src/typeck.rs +43 -8
@@ 38,7 38,7 @@ pub enum TypeInfo {
     Struct(BTreeMap<Sym, TypeId>),
     /// Definitely a sum type
     Sum(BTreeMap<Sym, TypeId>),
-    Array(TypeId, usize),
+    Array(TypeId, Option<usize>),
     /// This is some generic type that has a name like @A
     /// AKA a type parameter.
     TypeParam(Sym),

          
@@ 100,7 100,14 @@ impl TypeInfo {
                 accm += "end\n";
                 accm.into()
             }
-            Array(id, len) => Cow::Owned(format!("{}[{}]", tck.vars[id].get_name(tck), len)),
+            Array(id, len) => {
+                // Output something intelligible if we don't know the
+                // length of the array.
+                let len_str = len
+                    .map(|l| format!("{}", l))
+                    .unwrap_or_else(|| format!("unknown"));
+                Cow::Owned(format!("{}[{}]", tck.vars[id].get_name(tck), len_str))
+            }
             TypeParam(sym) => Cow::Owned(format!("@{}", &*sym.val())),
         }
     }

          
@@ 385,7 392,7 @@ impl Tck {
             Type::Generic(s) => TypeInfo::TypeParam(*s),
             Type::Array(ty, len) => {
                 let new_body = self.insert_known(&ty);
-                TypeInfo::Array(new_body, *len)
+                TypeInfo::Array(new_body, Some(*len))
             }
             // TODO: Generics?
             Type::Struct(body, _names) => {

          
@@ 598,8 605,8 @@ impl Tck {
                 }
                 Ok(())
             }
+            // Same as struct types
             (Sum(body1), Sum(body2)) => {
-                // Same as struct types
                 for (nm, t1) in body1.iter() {
                     let t2 = body2[nm];
                     self.unify(symtbl, *t1, t2)?;

          
@@ 610,6 617,21 @@ impl Tck {
                 }
                 Ok(())
             }
+            // Either both array lengths are the same or both are
+            // unknown.  The latter might need to be an error, we will see.
+            (Array(body1, len1), Array(body2, len2)) if len1 == len2 => {
+                self.unify(symtbl, body1, body2)
+            }
+            (Array(body1, None), Array(body2, Some(_len2))) => {
+                self.vars.insert(a, TypeInfo::Ref(b));
+                self.unify(symtbl, body1, body2)
+                //todo!("propegate array lengths")
+            }
+            (Array(body1, Some(_len1)), Array(body2, None)) => {
+                self.vars.insert(b, TypeInfo::Ref(a));
+                self.unify(symtbl, body1, body2)
+                // todo!("propegate array lengths")
+            }
             (Array(body1, len1), Array(body2, len2)) if len1 == len2 => {
                 self.unify(symtbl, body1, body2)
             }

          
@@ 672,7 694,7 @@ impl Tck {
             }
             Array(ty, len) => {
                 let real_body = self.reconstruct(*ty)?;
-                Ok(Type::Array(Box::new(real_body), *len))
+                Ok(Type::Array(Box::new(real_body), len.unwrap()))
             }
             Sum(body) => {
                 let real_body: Result<BTreeMap<_, _>, TypeError> = body

          
@@ 745,7 767,7 @@ impl Tck {
                 }
                 Type::Array(ty, len) => {
                     let inst_ty = helper(tck, named_types, &*ty);
-                    TypeInfo::Array(inst_ty, *len)
+                    TypeInfo::Array(inst_ty, Some(*len))
                 }
                 Type::Sum(body, _names) => {
                     let inst_body = body

          
@@ 1517,11 1539,24 @@ fn typecheck_expr(
                 let expr_type = typecheck_expr(tck, symtbl, func_rettype, expr)?;
                 tck.unify(symtbl, body_type, expr_type)?;
             }
-            let arr_type = tck.insert(TypeInfo::Array(body_type, len));
+            let arr_type = tck.insert(TypeInfo::Array(body_type, Some(len)));
             tck.set_expr_type(expr, arr_type);
             Ok(arr_type)
         }
-        ArrayRef { e: _, idx: _ } => todo!(),
+        ArrayRef {
+            expr: arr_expr,
+            idx,
+        } => {
+            let expr_type = typecheck_expr(tck, symtbl, func_rettype, arr_expr)?;
+            let idx_type = typecheck_expr(tck, symtbl, func_rettype, idx)?;
+            let elt_type = tck.insert(TypeInfo::Unknown);
+            let expected_expr_type = tck.insert(TypeInfo::Array(elt_type, None));
+            let expected_idx_type = tck.insert(TypeInfo::Prim(PrimType::UnknownInt));
+            tck.unify(symtbl, expr_type, expected_expr_type)?;
+            tck.unify(symtbl, idx_type, expected_idx_type)?;
+            tck.set_expr_type(expr, elt_type);
+            Ok(elt_type)
+        }
         Typecast { e: _, to: _ } => todo!(),
     };
     if let Err(e) = rettype {

          
A => tests/programs/test_array4.gt +32 -0
@@ 0,0 1,32 @@ 
+-- Compile:
+--   status: success
+-- Run:
+--  status: success
+--  stdout:
+--    1
+--    5
+--    15
+
+fn actually_use_array(arr I32[5]) I32 =
+    let mut i I32 = 0
+    let mut summ = 0
+    loop
+        if i == 5 then break end
+        summ = summ + arr[i]
+        i = i + 1
+        
+    end
+    summ
+end
+
+fn main() {} =
+    let x I32[3] = [1, 2, 3]
+    let y I32 = x[0]
+    __println(y)
+    let a I32[3][3] = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
+    let b = a[1][1]
+    __println(b)
+
+    __println(actually_use_array([1, 2, 3, 4, 5]))
+
+end

          
A => tests/programs/test_eq_module.gt +32 -0
@@ 0,0 1,32 @@ 
+-- Compile:
+--   status: error
+
+type Eq(@T) = struct
+    eq: fn(@T, @T) Bool,
+end
+
+const IntEq Eq(I32) = Eq {
+    .eq = fn(lhs I32, rhs I32) Bool = lhs == rhs end,
+}
+
+const BoolEq Eq(Bool) = Eq {
+    .eq = fn(lhs Bool, rhs Bool) Bool = lhs == rhs end,
+}
+
+fn all(eq_impl Eq(@T), val @T, array @T[3] | @T) Bool =
+	let mut i I32 = 0
+	loop
+		if i == 3 then break end
+		let val2 = array[i]
+		if not eq_impl$.eq(val, val2) then return false end
+		i = i + 1
+	end
+	true
+end
+
+fn main() {} =
+	let t1 = all(IntEq, 3, [1, 2, 3])                -- returns false
+	let t2 = all(BoolEq, true, [true, true, true])   -- returns true
+	__println_bool(t1)
+	__println_bool(t2)
+end

          
M tests/programs/test_result1.gt +4 -0
@@ 1,3 1,6 @@ 
+-- Compile:
+--   status: error
+
 type Result(@T, @E) = sum
     Ok @T,
     Err @E,

          
@@ 8,4 11,5 @@ fn main() {} =
     let y = Result.Err true
     let res = x == y 
     __println_bool(res)
+    {}
 end