diff --git a/src/main/wacc/Error.scala b/src/main/wacc/Error.scala
index 89e03d9..ba810f5 100644
--- a/src/main/wacc/Error.scala
+++ b/src/main/wacc/Error.scala
@@ -35,7 +35,7 @@ def printError(error: Error)(using errorContent: String): Unit = {
       highlight(pos, 1)
     case Error.TypeMismatch(pos, expected, got, msg) =>
       printPosition(pos)
-      println(msg)
+      println(s"Type mismatch: $msg\nExpected: $expected\nGot: $got")
       highlight(pos, 1)
     case Error.SemanticError(pos, msg) =>
       printPosition(pos)
diff --git a/src/main/wacc/ast.scala b/src/main/wacc/ast.scala
index 8ea99d7..f885843 100644
--- a/src/main/wacc/ast.scala
+++ b/src/main/wacc/ast.scala
@@ -60,35 +60,45 @@ object ast {
   object Chr extends ParserBridgePos1[Expr6, Chr]
 
   // Binary operators
-  sealed trait BinaryOp extends Expr {
+  sealed trait BinaryOp(val name: String) extends Expr {
     val x: Expr
     val y: Expr
   }
-  case class Add(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp
+  case class Add(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp("addition")
   object Add extends ParserBridgePos2[Expr4, Expr5, Add]
-  case class Sub(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp
+  case class Sub(x: Expr4, y: Expr5)(val pos: Position) extends Expr4 with BinaryOp("subtraction")
   object Sub extends ParserBridgePos2[Expr4, Expr5, Sub]
-  case class Mul(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp
+  case class Mul(x: Expr5, y: Expr6)(val pos: Position)
+      extends Expr5
+      with BinaryOp("multiplication")
   object Mul extends ParserBridgePos2[Expr5, Expr6, Mul]
-  case class Div(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp
+  case class Div(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp("division")
   object Div extends ParserBridgePos2[Expr5, Expr6, Div]
-  case class Mod(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp
+  case class Mod(x: Expr5, y: Expr6)(val pos: Position) extends Expr5 with BinaryOp("modulus")
   object Mod extends ParserBridgePos2[Expr5, Expr6, Mod]
-  case class Greater(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp
+  case class Greater(x: Expr4, y: Expr4)(val pos: Position)
+      extends Expr3
+      with BinaryOp("strictly greater than")
   object Greater extends ParserBridgePos2[Expr4, Expr4, Greater]
-  case class GreaterEq(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp
+  case class GreaterEq(x: Expr4, y: Expr4)(val pos: Position)
+      extends Expr3
+      with BinaryOp("greater than or equal to")
   object GreaterEq extends ParserBridgePos2[Expr4, Expr4, GreaterEq]
-  case class Less(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp
+  case class Less(x: Expr4, y: Expr4)(val pos: Position)
+      extends Expr3
+      with BinaryOp("strictly less than")
   object Less extends ParserBridgePos2[Expr4, Expr4, Less]
-  case class LessEq(x: Expr4, y: Expr4)(val pos: Position) extends Expr3 with BinaryOp
+  case class LessEq(x: Expr4, y: Expr4)(val pos: Position)
+      extends Expr3
+      with BinaryOp("less than or equal to")
   object LessEq extends ParserBridgePos2[Expr4, Expr4, LessEq]
-  case class Eq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp
+  case class Eq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp("equality")
   object Eq extends ParserBridgePos2[Expr3, Expr3, Eq]
-  case class Neq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp
+  case class Neq(x: Expr3, y: Expr3)(val pos: Position) extends Expr2 with BinaryOp("inequality")
   object Neq extends ParserBridgePos2[Expr3, Expr3, Neq]
-  case class And(x: Expr2, y: Expr1)(val pos: Position) extends Expr1 with BinaryOp
+  case class And(x: Expr2, y: Expr1)(val pos: Position) extends Expr1 with BinaryOp("logical and")
   object And extends ParserBridgePos2[Expr2, Expr1, And]
-  case class Or(x: Expr1, y: Expr)(val pos: Position) extends Expr with BinaryOp
+  case class Or(x: Expr1, y: Expr)(val pos: Position) extends Expr with BinaryOp("logical or")
   object Or extends ParserBridgePos2[Expr1, Expr, Or]
 
   // Types
diff --git a/src/main/wacc/typeChecker.scala b/src/main/wacc/typeChecker.scala
index 38b34e3..8c01379 100644
--- a/src/main/wacc/typeChecker.scala
+++ b/src/main/wacc/typeChecker.scala
@@ -159,24 +159,25 @@ object typeChecker {
       ctx.typeOf(id).satisfies(constraint, id.pos)
     case ArrayElem(id, indices) =>
       val arrayTy = ctx.typeOf(id)
-      val elemTy = indices.toList.foldRight(arrayTy) { (elem, acc) =>
+      val elemTy = indices.foldLeftM(arrayTy) { (acc, elem) =>
         checkValue(elem, Constraint.Is(KnownType.Int, "array index must be an int"))
         acc match {
-          case KnownType.Array(innerTy) => innerTy
-          case _ =>
+          case KnownType.Array(innerTy) => Some(innerTy)
+          case nonArrayTy =>
             ctx.error(
               Error.TypeMismatch(elem.pos, KnownType.Array(?), acc, "cannot index into a non-array")
             )
+            None
         }
       }
-      elemTy.satisfies(constraint, id.pos)
+      elemTy.getOrElse(?).satisfies(constraint, id.pos)
     case Parens(expr) => checkValue(expr, constraint)
     case l @ ArrayLiter(elems) =>
       KnownType
-        .Array(elems.foldRight[SemType](?) { case (elem, acc) =>
+        .Array(elems.foldLeft[SemType](?) { case (acc, elem) =>
           checkValue(
             elem,
-            Constraint.IsSymmetricCompatible(acc, "array elements must have the same type")
+            Constraint.IsSymmetricCompatible(acc, s"array elements must have the same type")
           )
         })
         .satisfies(constraint, l.pos)
@@ -233,13 +234,16 @@ object typeChecker {
 
     // Binary operators
     case op: (Add | Sub | Mul | Div | Mod) =>
-      val operand = Constraint.Is(KnownType.Int, "binary operator must be applied to an int")
+      val operand = Constraint.Is(KnownType.Int, s"${op.name} operator must be applied to an int")
       checkValue(op.x, operand)
       checkValue(op.y, operand)
       KnownType.Int.satisfies(constraint, op.pos)
     case op: (Eq | Neq) =>
       val xTy = checkValue(op.x, Constraint.Unconstrained)
-      checkValue(op.y, Constraint.Is(xTy, "equality must be applied to values of the same type"))
+      checkValue(
+        op.y,
+        Constraint.Is(xTy, s"${op.name} operator must be applied to values of the same type")
+      )
       KnownType.Bool.satisfies(constraint, op.pos)
     case op: (Less | LessEq | Greater | GreaterEq) =>
       val xTy = checkValue(
@@ -247,13 +251,16 @@ object typeChecker {
         Constraint.IsEither(
           KnownType.Int,
           KnownType.Char,
-          "comparison must be applied to an int or char"
+          s"${op.name} operator must be applied to an int or char"
         )
       )
-      checkValue(op.y, Constraint.Is(xTy, "comparison must be applied to values of the same type"))
+      checkValue(
+        op.y,
+        Constraint.Is(xTy, s"${op.name} operator must be applied to values of the same type")
+      )
       KnownType.Bool.satisfies(constraint, op.pos)
     case op: (And | Or) =>
-      val operand = Constraint.Is(KnownType.Bool, "logical operator must be applied to a bool")
+      val operand = Constraint.Is(KnownType.Bool, s"${op.name} operator must be applied to a bool")
       checkValue(op.x, operand)
       checkValue(op.y, operand)
       KnownType.Bool.satisfies(constraint, op.pos)
diff --git a/src/main/wacc/types.scala b/src/main/wacc/types.scala
index 41d4124..549d8a1 100644
--- a/src/main/wacc/types.scala
+++ b/src/main/wacc/types.scala
@@ -9,9 +9,11 @@ object types {
       case KnownType.Bool              => "bool"
       case KnownType.Char              => "char"
       case KnownType.String            => "string"
+      case KnownType.Array(?)          => "array"
       case KnownType.Array(elem)       => s"$elem[]"
+      case KnownType.Pair(?, ?)        => "pair"
       case KnownType.Pair(left, right) => s"pair($left, $right)"
-      case ?                           => "?"
+      case ?                           => "<unknown-type>"
     }
   }