diff --git a/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala b/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala
index 0dee55827..be04abc67 100644
--- a/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala
+++ b/shared/src/main/scala/io/kaitai/struct/ClassTypeProvider.scala
@@ -4,17 +4,24 @@ import io.kaitai.struct.datatype.DataType
 import io.kaitai.struct.datatype.DataType._
 import io.kaitai.struct.exprlang.Ast
 import io.kaitai.struct.format._
-import io.kaitai.struct.precompile.{EnumNotFoundError, FieldNotFoundError, TypeNotFoundError, TypeUndecidedError}
+import io.kaitai.struct.precompile.{EnumNotFoundError, ExpressionError, FieldNotFoundError, TypeNotFoundError, TypeUndecidedError}
 import io.kaitai.struct.translators.TypeProvider
 
 class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends TypeProvider {
   var nowClass = topClass
   val allClasses: ClassSpecs = classSpecs
 
-  var _currentIteratorType: Option[DataType] = None
+  /**
+    * Type of the `_` variable in the expression. That variable is defined in
+    * `repeat-until` and `valid: expr` contexts and refers to the attribute
+    * just parsed.
+    */
+  var _lastParsedType: Option[DataType] = None
+  /**
+    * Type of the `_on` variable in the expression. That variable is defined in
+    * `cases.<case>` contexts and refers to the value of `switch-on` expression.
+    */
   var _currentSwitchType: Option[DataType] = None
-  def currentIteratorType: DataType = _currentIteratorType.get
-  def currentSwitchType: DataType = _currentSwitchType.get
 
   override def determineType(attrName: String): DataType = {
     determineType(nowClass, attrName)
@@ -30,14 +37,20 @@ class ClassTypeProvider(classSpecs: ClassSpecs, var topClass: ClassSpec) extends
         topClass.toDataType
       case Identifier.PARENT =>
         if (inClass.parentClass == UnknownClassSpec)
-          throw new RuntimeException(s"Unable to derive ${Identifier.PARENT} type in ${inClass.name.mkString("::")}")
+          throw new ExpressionError(s"Unable to derive '${Identifier.PARENT}' type in '${inClass.nameAsStr}'")
         inClass.parentClass.toDataType
       case Identifier.IO =>
         KaitaiStreamType
       case Identifier.ITERATOR =>
-        currentIteratorType
+        _lastParsedType match {
+          case Some(value) => value
+          case None => throw new ExpressionError(s"Context variable '$attrName' is available only in the 'repeat-until' and 'valid/expr' attributes")
+        }
       case Identifier.SWITCH_ON =>
-        currentSwitchType
+        _currentSwitchType match {
+          case Some(value) => value
+          case None => throw new ExpressionError(s"Context variable '$attrName' is available only in the 'cases.<case>' expressions")
+        }
       case Identifier.INDEX =>
         CalcIntType
       case Identifier.SIZEOF =>
diff --git a/shared/src/main/scala/io/kaitai/struct/ConstructClassCompiler.scala b/shared/src/main/scala/io/kaitai/struct/ConstructClassCompiler.scala
index 4637773bd..8725ec9ed 100644
--- a/shared/src/main/scala/io/kaitai/struct/ConstructClassCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/ConstructClassCompiler.scala
@@ -87,7 +87,7 @@ class ConstructClassCompiler(classSpecs: ClassSpecs, topClass: ClassSpec) extend
     case RepeatExpr(expr) =>
       s"Array(${translator.translate(expr)}, $typeStr)"
     case RepeatUntil(expr) =>
-      provider._currentIteratorType = Some(dataType)
+      provider._lastParsedType = Some(dataType)
       s"RepeatUntil(lambda obj_, list_, this: ${translator.translate(expr)}, $typeStr)"
     case RepeatEos =>
       s"GreedyRange($typeStr)"
diff --git a/shared/src/main/scala/io/kaitai/struct/GraphvizClassCompiler.scala b/shared/src/main/scala/io/kaitai/struct/GraphvizClassCompiler.scala
index 22c746953..5d8621228 100644
--- a/shared/src/main/scala/io/kaitai/struct/GraphvizClassCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/GraphvizClassCompiler.scala
@@ -196,7 +196,7 @@ class GraphvizClassCompiler(classSpecs: ClassSpecs, topClass: ClassSpec) extends
           case ValidationInEnum() =>
             "must be defined in the enum"
           case ValidationExpr(expr) =>
-            provider._currentIteratorType = Some(dataType)
+            provider._lastParsedType = Some(dataType)
             s"must satisfy ${expression(expr, fullPortName, STYLE_EDGE_VALID)}"
         }
       case None => return
@@ -212,7 +212,7 @@ class GraphvizClassCompiler(classSpecs: ClassSpecs, topClass: ClassSpec) extends
           expression(ex, s"$currentTable:$portName", STYLE_EDGE_REPEAT) +
           " times</TD></TR>")
       case RepeatUntil(ex) =>
-        provider._currentIteratorType = Some(dataType)
+        provider._lastParsedType = Some(dataType)
         out.puts("<TR><TD COLSPAN=\"4\" PORT=\"" + portName + "\">repeat until " +
           expression(ex, s"$currentTable:$portName", STYLE_EDGE_REPEAT) +
           "</TD></TR>")
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala
index 97693c473..3a1090d0f 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/CSharpCompiler.scala
@@ -280,7 +280,7 @@ class CSharpCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)} = new ${kaitaiType2NativeType(ArrayTypeInStream(dataType))}();")
   }
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("{")
     out.inc
     out.puts("var i = 0;")
@@ -300,8 +300,8 @@ class CSharpCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("}")
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: expr): Unit = {
-    out.puts(s"for (var i = 0; i < ${expression(repeatExpr)}; i++)")
+  override def condRepeatExprHeader(countExpr: expr): Unit = {
+    out.puts(s"for (var i = 0, _end = ${expression(countExpr)}; i < _end; ++i)")
     out.puts("{")
     out.inc
   }
@@ -311,12 +311,12 @@ class CSharpCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
 
   override def condRepeatExprFooter: Unit = fileFooter(null)
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
     out.puts("{")
     out.inc
     out.puts("var i = 0;")
-    out.puts(s"${kaitaiType2NativeType(dataType)} ${translator.doName("_")};")
-    out.puts("do {")
+    out.puts(s"${kaitaiType2NativeType(itemType)} ${translator.doName(Identifier.ITERATOR)};")
+    out.puts("while (true) {")
     out.inc
   }
 
@@ -330,13 +330,17 @@ class CSharpCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)}.Add($tempVar);")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
-    out.puts("i++;")
-    out.dec
-    out.puts(s"} while (!(${expression(untilExpr)}));")
+  override def condRepeatUntilFooter(untilExpr: expr): Unit = {
+    out.puts(s"if (${expression(untilExpr)}) {")
+    out.inc
+    out.puts("break;")
     out.dec
     out.puts("}")
+    out.puts("++i;")
+    out.dec
+    out.puts("}") // close while (true)
+    out.dec
+    out.puts("}") // close scope of i and _ variables
   }
 
   override def handleAssignmentSimple(id: Identifier, expr: String): Unit =
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala
index b0fdee657..b162c1645 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/CppCompiler.scala
@@ -571,7 +571,7 @@ class CppCompiler(
     outSrc.puts(s"${privateMemberName(id)} = ${newVector(dataType)};")
   }
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     outSrc.puts("{")
     outSrc.inc
     outSrc.puts("int i = 0;")
@@ -591,10 +591,8 @@ class CppCompiler(
     outSrc.puts("}")
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: Ast.expr): Unit = {
-    val lenVar = s"l_${idToStr(id)}"
-    outSrc.puts(s"const int $lenVar = ${expression(repeatExpr)};")
-    outSrc.puts(s"for (int i = 0; i < $lenVar; i++) {")
+  override def condRepeatExprHeader(countExpr: Ast.expr): Unit = {
+    outSrc.puts(s"for (int i = 0, _end = ${expression(countExpr)}; i < _end; ++i) {")
     outSrc.inc
   }
 
@@ -606,12 +604,12 @@ class CppCompiler(
     outSrc.puts("}")
   }
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
     outSrc.puts("{")
     outSrc.inc
     outSrc.puts("int i = 0;")
-    outSrc.puts(s"${kaitaiType2NativeType(dataType.asNonOwning())} ${translator.doName("_")};")
-    outSrc.puts("do {")
+    outSrc.puts(s"${kaitaiType2NativeType(itemType.asNonOwning())} ${translator.doName(Identifier.ITERATOR)};")
+    outSrc.puts("while (true) {")
     outSrc.inc
   }
 
@@ -640,13 +638,17 @@ class CppCompiler(
     outSrc.puts(s"${privateMemberName(id)}->push_back($wrappedTempVar);")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
-    outSrc.puts("i++;")
-    outSrc.dec
-    outSrc.puts(s"} while (!(${expression(untilExpr)}));")
+  override def condRepeatUntilFooter(untilExpr: expr): Unit = {
+    outSrc.puts(s"if (${expression(untilExpr)}) {")
+    outSrc.inc
+    outSrc.puts("break;")
     outSrc.dec
     outSrc.puts("}")
+    outSrc.puts("++i;")
+    outSrc.dec
+    outSrc.puts("}") // close while (true)
+    outSrc.dec
+    outSrc.puts("}") // close scope of i and _ variables
   }
 
   override def handleAssignmentSimple(id: Identifier, expr: String): Unit = {
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala
index 49e4343e1..a6da11992 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/GoCompiler.scala
@@ -300,12 +300,12 @@ class GoCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     // function works even on `nil` slices (https://go.dev/tour/moretypes/15)
   }
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts(s"for i := 0;; i++ {")
     out.inc
 
     val eofVar = translator.allocateLocalVar()
-    out.puts(s"${translator.localVarName(eofVar)}, err := this._io.EOF()")
+    out.puts(s"${translator.localVarName(eofVar)}, err := $io.EOF()")
     translator.outAddErrCheck()
     out.puts(s"if ${translator.localVarName(eofVar)} {")
     out.inc
@@ -320,8 +320,8 @@ class GoCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"$name = append($name, $expr)")
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: Ast.expr): Unit = {
-    out.puts(s"for i := 0; i < int(${expression(repeatExpr)}); i++ {")
+  override def condRepeatExprHeader(countExpr: Ast.expr): Unit = {
+    out.puts(s"for i, _end := 0, int(${expression(countExpr)}); i < _end; i++ {")
     out.inc
     // FIXME: Go throws a fatal compile error when the `i` variable is not used (unused variables
     // can only use the blank identifier `_`, see https://go.dev/doc/effective_go#blank), so we have
@@ -334,8 +334,11 @@ class GoCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def handleAssignmentRepeatExpr(id: Identifier, r: TranslatorResult): Unit =
     handleAssignmentRepeatEos(id, r)
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
-    out.puts(s"for i := 1;; i++ {")
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
+    out.puts("{")
+    out.inc
+    out.puts("i := 0")
+    out.puts(s"for {")
     out.inc
   }
 
@@ -346,15 +349,17 @@ class GoCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)} = append(${privateMemberName(id)}, $tempVar)")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatUntilFooter(untilExpr: Ast.expr): Unit = {
     out.puts(s"if ${expression(untilExpr)} {")
     out.inc
     out.puts("break")
     out.dec
     out.puts("}")
+    out.puts("i++;")
     out.dec
-    out.puts("}")
+    out.puts("}") // close for
+    out.dec
+    out.puts("}") // close scope of i variable
   }
 
   private def castToType(r: TranslatorResult, dataType: DataType): TranslatorResult = {
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala
index ee19058d3..7f087bc08 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala
@@ -355,7 +355,7 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit =
     out.puts(s"${privateMemberName(id)} = new ${kaitaiType2JavaType(ArrayTypeInStream(dataType))}();")
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("{")
     out.inc
     out.puts("int i = 0;")
@@ -377,8 +377,8 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("}")
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: expr): Unit = {
-    out.puts(s"for (int i = 0; i < ${expression(repeatExpr)}; i++) {")
+  override def condRepeatExprHeader(countExpr: expr): Unit = {
+    out.puts(s"for (int i = 0, _end = ${expression(countExpr)}; i < _end; ++i) {")
     out.inc
 
     importList.add("java.util.ArrayList")
@@ -387,12 +387,12 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def handleAssignmentRepeatExpr(id: Identifier, expr: String): Unit =
     handleAssignmentRepeatEos(id, expr)
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
     out.puts("{")
     out.inc
-    out.puts(s"${kaitaiType2JavaType(dataType)} ${translator.doName("_")};")
+    out.puts(s"${kaitaiType2JavaType(itemType)} ${translator.doName(Identifier.ITERATOR)};")
     out.puts("int i = 0;")
-    out.puts("do {")
+    out.puts("while (true) {")
     out.inc
 
     importList.add("java.util.ArrayList")
@@ -408,13 +408,17 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)}.add($tempVar);")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
-    out.puts("i++;")
-    out.dec
-    out.puts(s"} while (!(${expression(untilExpr)}));")
+  override def condRepeatUntilFooter(untilExpr: expr): Unit = {
+    out.puts(s"if (${expression(untilExpr)}) {")
+    out.inc
+    out.puts("break;")
     out.dec
     out.puts("}")
+    out.puts("++i;")
+    out.dec
+    out.puts("}") // close while (true)
+    out.dec
+    out.puts("}") // close scope of i and _ variables
   }
 
   override def handleAssignmentSimple(id: Identifier, expr: String): Unit =
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala
index a039b4560..86836b244 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/JavaScriptCompiler.scala
@@ -303,7 +303,7 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit =
     out.puts(s"${privateMemberName(id)} = [];")
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("var i = 0;")
     out.puts(s"while (!$io.isEof()) {")
     out.inc
@@ -319,8 +319,8 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("}")
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: expr): Unit = {
-    out.puts(s"for (var i = 0; i < ${expression(repeatExpr)}; i++) {")
+  override def condRepeatExprHeader(countExpr: expr): Unit = {
+    out.puts(s"for (var i = 0, _end = ${expression(countExpr)}; i < _end; ++i) {")
     out.inc
   }
 
@@ -332,9 +332,10 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("}")
   }
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
+    // "var" variables in any case have a scope of surrounding function, no need a scope to isolate them
     out.puts("var i = 0;")
-    out.puts("do {")
+    out.puts("while (true) {")
     out.inc
   }
 
@@ -344,11 +345,15 @@ class JavaScriptCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)}.push($tmpName);")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
-    out.puts("i++;")
+  override def condRepeatUntilFooter(untilExpr: expr): Unit = {
+    out.puts(s"if (${expression(untilExpr)}) {")
+    out.inc
+    out.puts("break;")
+    out.dec
+    out.puts("}")
+    out.puts("++i;")
     out.dec
-    out.puts(s"} while (!(${expression(untilExpr)}));")
+    out.puts("}") // close while (true)
   }
 
   override def handleAssignmentSimple(id: Identifier, expr: String): Unit = {
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala
index 1f24674e9..5fd88d3d2 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/LuaCompiler.scala
@@ -170,7 +170,7 @@ class LuaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)} = {}")
   }
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("local i = 0")
     out.puts(s"while not $io:is_eof() do")
     out.inc
@@ -181,8 +181,8 @@ class LuaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("end")
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: Ast.expr): Unit = {
-    out.puts(s"for i = 0, ${expression(repeatExpr)} - 1 do")
+  override def condRepeatExprHeader(countExpr: Ast.expr): Unit = {
+    out.puts(s"for i = 0, ${expression(countExpr)} - 1 do")
     out.inc
   }
   override def condRepeatExprFooter: Unit = {
@@ -190,13 +190,13 @@ class LuaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("end")
   }
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
+    // Lua allows shadowing of variables, no need a scope to isolate them
     out.puts("local i = 0")
     out.puts("while true do")
     out.inc
   }
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatUntilFooter(untilExpr: Ast.expr): Unit = {
     out.puts(s"if ${expression(untilExpr)} then")
     out.inc
     out.puts("break")
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala
index 21868c146..8822391ff 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/NimCompiler.scala
@@ -155,7 +155,7 @@ class NimCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     // empty sequences (see https://narimiran.github.io/nim-basics/#_result_variable)
   }
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("block:")
     out.inc
     out.puts("var i: int")
@@ -167,19 +167,18 @@ class NimCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.dec
     out.dec
   }
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: Ast.expr): Unit = {
-    out.puts(s"for i in 0 ..< int(${expression(repeatExpr)}):")
+  override def condRepeatExprHeader(countExpr: Ast.expr): Unit = {
+    out.puts(s"for i in 0 ..< int(${expression(countExpr)}):")
     out.inc
   }
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
     out.puts("block:")
     out.inc
     out.puts("var i: int")
     out.puts("while true:")
     out.inc
   }
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatUntilFooter(untilExpr: Ast.expr): Unit = {
     out.puts(s"if ${expression(untilExpr)}:")
     out.inc
     out.puts("break")
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala
index c2c4d1476..64433f7c3 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/PHPCompiler.scala
@@ -282,7 +282,7 @@ class PHPCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit =
     out.puts(s"${privateMemberName(id)} = [];")
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("$i = 0;")
     out.puts(s"while (!$io->isEof()) {")
     out.inc
@@ -297,8 +297,8 @@ class PHPCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     super.condRepeatEosFooter
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: Ast.expr): Unit = {
-    out.puts(s"$$n = ${expression(repeatExpr)};")
+  override def condRepeatExprHeader(countExpr: Ast.expr): Unit = {
+    out.puts(s"$$n = ${expression(countExpr)};")
     out.puts("for ($i = 0; $i < $n; $i++) {")
     out.inc
   }
@@ -306,9 +306,9 @@ class PHPCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def handleAssignmentRepeatExpr(id: Identifier, expr: String): Unit =
     handleAssignmentRepeatEos(id, expr)
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
     out.puts("$i = 0;")
-    out.puts("do {")
+    out.puts("while (1) {")
     out.inc
   }
 
@@ -318,11 +318,17 @@ class PHPCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)}[] = $tmpName;")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatUntilFooter(untilExpr: Ast.expr): Unit = {
+    out.puts(s"if ${expression(untilExpr)} {")
+    out.inc
+    out.puts("break;")
+    out.dec
+    out.puts("}")
     out.puts("$i++;")
     out.dec
-    out.puts(s"} while (!(${expression(untilExpr)}));")
+    out.puts("}") // close while (1)
+    out.dec
+    out.puts("}") // close scope of i variable
   }
 
   override def handleAssignmentSimple(id: Identifier, expr: String): Unit = {
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala
index c8bfe5b0c..1fbb7ec68 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/PerlCompiler.scala
@@ -246,7 +246,9 @@ class PerlCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit =
     out.puts(s"${privateMemberName(id)} = [];")
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
+    // Perl allows shadowing of variables, no need a scope to isolate them
+    out.puts("my $i = 0;")
     out.puts(s"while (!$io->is_eof()) {")
     out.inc
   }
@@ -254,18 +256,24 @@ class PerlCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def handleAssignmentRepeatEos(id: Identifier, expr: String): Unit =
     out.puts(s"push @{${privateMemberName(id)}}, $expr;")
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: expr): Unit = {
-    val nVar = s"$$n_${idToStr(id)}"
-    out.puts(s"my $nVar = ${expression(repeatExpr)};")
-    out.puts(s"for (my $$i = 0; $$i < $nVar; $$i++) {")
+  override def condRepeatEosFooter: Unit = {
+    out.puts("$i++;")
+    out.dec
+    out.puts("}")
+  }
+
+  override def condRepeatExprHeader(countExpr: expr): Unit = {
+    out.puts(s"for (my $$i = 0, $$_end = ${expression(countExpr)}; $$i < $$_end; ++$$i) {")
     out.inc
   }
 
   override def handleAssignmentRepeatExpr(id: Identifier, expr: String): Unit =
     handleAssignmentRepeatEos(id, expr)
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    out.puts("do {")
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
+    // Perl allows shadowing of variables, no need a scope to isolate them
+    out.puts("my $i = 0;")
+    out.puts("while (1) {")
     out.inc
   }
 
@@ -279,10 +287,11 @@ class PerlCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"push @{${privateMemberName(id)}}, $tmpName;")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatUntilFooter(untilExpr: expr): Unit = {
+    out.puts(s"last if (${expression(untilExpr)});")
+    out.puts("$i++;")
     out.dec
-    out.puts(s"} until (${expression(untilExpr)});")
+    out.puts("}") // close while (1)
   }
 
   override def handleAssignmentSimple(id: Identifier, expr: String): Unit =
@@ -352,7 +361,6 @@ class PerlCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def switchRequiresIfs(onType: DataType): Boolean = true
 
   override def switchIfStart(id: Identifier, on: Ast.expr, onType: DataType): Unit = {
-    typeProvider._currentSwitchType = Some(translator.detectType(on))
     out.puts(s"my $$_on = ${expression(on)};")
   }
 
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala
index 37a75f323..adbb82262 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/PythonCompiler.scala
@@ -300,7 +300,7 @@ class PythonCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit =
     out.puts(s"${privateMemberName(id)} = []")
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("i = 0")
     out.puts(s"while not $io.is_eof():")
     out.inc
@@ -313,14 +313,14 @@ class PythonCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     universalFooter
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: expr): Unit = {
-    out.puts(s"for i in range(${expression(repeatExpr)}):")
+  override def condRepeatExprHeader(countExpr: expr): Unit = {
+    out.puts(s"for i in range(${expression(countExpr)}):")
     out.inc
   }
   override def handleAssignmentRepeatExpr(id: Identifier, expr: String): Unit =
     handleAssignmentRepeatEos(id, expr)
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
     out.puts("i = 0")
     out.puts("while True:")
     out.inc
@@ -332,8 +332,7 @@ class PythonCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)}.append($tmpName)")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatUntilFooter(untilExpr: expr): Unit = {
     out.puts(s"if ${expression(untilExpr)}:")
     out.inc
     out.puts("break")
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala
index ccda2646e..7a3398e97 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/RubyCompiler.scala
@@ -306,7 +306,7 @@ class RubyCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
   override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit =
     out.puts(s"${privateMemberName(id)} = []")
 
-  override def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit = {
+  override def condRepeatEosHeader(io: String): Unit = {
     out.puts("i = 0")
     out.puts(s"while not $io.eof?")
     out.inc
@@ -319,8 +319,8 @@ class RubyCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     super.condRepeatEosFooter
   }
 
-  override def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: expr): Unit = {
-    out.puts(s"(${expression(repeatExpr)}).times { |i|")
+  override def condRepeatExprHeader(countExpr: expr): Unit = {
+    out.puts(s"(${expression(countExpr)}).times { |i|")
     out.inc
   }
   override def handleAssignmentRepeatExpr(id: Identifier, expr: String): Unit =
@@ -331,9 +331,9 @@ class RubyCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("}")
   }
 
-  override def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
     out.puts("i = 0")
-    out.puts("begin")
+    out.puts("while true")
     out.inc
   }
 
@@ -343,11 +343,11 @@ class RubyCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"${privateMemberName(id)} << $tmpName")
   }
 
-  override def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: expr): Unit = {
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatUntilFooter(untilExpr: expr): Unit = {
+    out.puts(s"break if ${expression(untilExpr)}")
     out.puts("i += 1")
     out.dec
-    out.puts(s"end until ${expression(untilExpr)}")
+    out.puts("end")
   }
 
   override def handleAssignmentSimple(id: Identifier, expr: String): Unit =
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala
index b0e885e7b..3503cb8ab 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/RustCompiler.scala
@@ -273,19 +273,14 @@ class RustCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.inc
   }
 
-   override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = {
-    // this line required for handleAssignmentRepeatUntil
-    typeProvider._currentIteratorType = Some(dataType)
+  override def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit = {
     out.puts(s"*${RustCompiler.privateMemberName(id, writeAccess = true)} = Vec::new();")
   }
 
-  override def condRepeatEosHeader(id: Identifier,
-                                   io: String,
-                                   dataType: DataType): Unit = {
-    out.puts("{")
-    out.inc
+  override def condRepeatEosHeader(io: String): Unit = {
+    // Rust allows shadowing of variables, no need a scope to isolate them
     out.puts(s"let mut _i = 0;")
-    out.puts(s"while !_io.is_eof() {")
+    out.puts(s"while !$io.is_eof() {")
     out.inc
   }
 
@@ -297,28 +292,18 @@ class RustCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts("_i += 1;")
     out.dec
     out.puts("}")
-    out.dec
-    out.puts("}")
   }
 
-  override def condRepeatExprHeader(id: Identifier,
-                                    io: String,
-                                    dataType: DataType,
-                                    repeatExpr: Ast.expr): Unit = {
-    val lenVar = s"l_${idToStr(id)}"
-    out.puts(s"let $lenVar = ${expression(repeatExpr)};")
-    out.puts(s"for _i in 0..$lenVar {")
+  override def condRepeatExprHeader(countExpr: Ast.expr): Unit = {
+    out.puts(s"let _end = ${expression(countExpr)};")
+    out.puts(s"for _i in 0.._end {")
     out.inc
   }
 
-  override def condRepeatUntilHeader(id: Identifier,
-                                     io: String,
-                                     dataType: DataType,
-                                     repeatExpr: Ast.expr): Unit = {
-    out.puts("{")
-    out.inc
+  override def condRepeatUntilHeader(itemType: DataType): Unit = {
+    // Rust allows shadowing of variables, no need a scope to isolate them
     out.puts("let mut _i = 0;")
-    out.puts("while {")
+    out.puts("loop {")
     out.inc
   }
 
@@ -331,7 +316,8 @@ class RustCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
                                            isRaw: Boolean): Unit = {
     out.puts(s"${RustCompiler.privateMemberName(id, writeAccess = true)}.push($expr);")
     var copy_type = ""
-    if (typeProvider._currentIteratorType.isDefined && translator.is_copy_type(typeProvider._currentIteratorType.get)) {
+    // typeProvider._lastParsedType is set in CommonReads.attrParse0
+    if (translator.is_copy_type(typeProvider._lastParsedType.get)) {
       copy_type = "*"
     }
     val t = localTemporaryName(id)
@@ -339,19 +325,15 @@ class RustCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts(s"let ${translator.doLocalName(Identifier.ITERATOR)} = $copy_type$t.last().unwrap();")
   }
 
-  override def condRepeatUntilFooter(id: Identifier,
-                                     io: String,
-                                     dataType: DataType,
-                                     repeatExpr: Ast.expr): Unit = {
-    // this line required by kaitai code
-    typeProvider._currentIteratorType = Some(dataType)
-    out.puts("_i += 1;")
-    out.puts(s"let x = !(${expression(repeatExpr)});")
-    out.puts("x")
-    out.dec
-    out.puts("} {}")
+  override def condRepeatUntilFooter(untilExpr: Ast.expr): Unit = {
+    out.puts(s"if ${expression(untilExpr)} {")
+    out.inc
+    out.puts("break")
     out.dec
     out.puts("}")
+    out.puts("_i += 1;")
+    out.dec
+    out.puts("}") // close loop
   }
 
   def getRawIdExpr(varName: Identifier, rep: RepeatSpec): String = {
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala
index de049dc14..41f45661e 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/components/CommonReads.scala
@@ -64,11 +64,11 @@ trait CommonReads extends LanguageCompiler {
       (ExtraAttrs.forAttr(attr, this) ++ List(attr)).foreach(a => condRepeatInitAttr(a.id, a.dataType))
     attr.cond.repeat match {
       case RepeatEos =>
-        condRepeatEosHeader(id, io, attr.dataType)
-      case RepeatExpr(repeatExpr: Ast.expr) =>
-        condRepeatExprHeader(id, io, attr.dataType, repeatExpr)
-      case RepeatUntil(untilExpr: Ast.expr) =>
-        condRepeatUntilHeader(id, io, attr.dataType, untilExpr)
+        condRepeatEosHeader(io)
+      case RepeatExpr(countExpr: Ast.expr) =>
+        condRepeatExprHeader(countExpr)
+      case RepeatUntil(_) =>
+        condRepeatUntilHeader(attr.dataType)
       case NoRepeat =>
     }
 
@@ -88,7 +88,9 @@ trait CommonReads extends LanguageCompiler {
       case _: RepeatExpr =>
         condRepeatExprFooter
       case RepeatUntil(untilExpr: Ast.expr) =>
-        condRepeatUntilFooter(id, io, attr.dataType, untilExpr)
+        // Set the type of the `_` variable in expression
+        typeProvider._lastParsedType = Some(attr.dataType)
+        condRepeatUntilFooter(untilExpr)
       case NoRepeat =>
     }
   }
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala
index 9beb9f707..bb9f2fc82 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala
@@ -133,14 +133,47 @@ abstract class LanguageCompiler(
 
   def condRepeatInitAttr(id: Identifier, dataType: DataType): Unit
 
-  def condRepeatEosHeader(id: Identifier, io: String, dataType: DataType): Unit
+  /**
+    * Generates start of loop until end-of-stream is reached.
+    *
+    * @param io rendered expression that evaluates to reference of a stream which
+    *        should be checked
+    */
+  def condRepeatEosHeader(io: String): Unit
+  /**
+    * Generates end of loop until end-of-stream is reached.
+    */
   def condRepeatEosFooter: Unit
 
-  def condRepeatExprHeader(id: Identifier, io: String, dataType: DataType, repeatExpr: Ast.expr): Unit
+  /**
+    * Generates start of "for 0..<count>" loop which loops specified count of times.
+    *
+    * @param countExpr expression that evaluates into number of repetitions.
+    *        That expression should be evaluated only once before loop is started
+    */
+  def condRepeatExprHeader(countExpr: Ast.expr): Unit
+  /**
+    * Generates end of "for 0..<count>" loop.
+    */
   def condRepeatExprFooter: Unit
 
-  def condRepeatUntilHeader(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit
-  def condRepeatUntilFooter(id: Identifier, io: String, dataType: DataType, untilExpr: Ast.expr): Unit
+  /**
+    * Generates start of "repeat ... until" loop which parses element of type `itemType`
+    * on each iteration.
+    *
+    * @param itemType Type of the element that can be used to declare variable for
+    *        holding that element so it will accessible in the condition in the footer.
+    *        In most languages condition in special "repeat ... until" loop cannot
+    *        access variables, defined in body of loop
+    */
+  def condRepeatUntilHeader(itemType: DataType): Unit
+  /**
+    * Generates end of "repeat ... until" loop which checks the specified condition.
+    *
+    * @param untilExpr condition that evaluates to boolean value where `true` means
+    *        that loop will be finished
+    */
+  def condRepeatUntilFooter(untilExpr: Ast.expr): Unit
 
   def attrProcess(proc: ProcessExpr, varSrc: Identifier, varDest: Identifier, rep: RepeatSpec): Unit
 
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/ValidateOps.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/ValidateOps.scala
index 2c346726b..632cc1781 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/components/ValidateOps.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/components/ValidateOps.scala
@@ -62,7 +62,7 @@ trait ValidateOps extends ExceptionNames {
         )
       case ValidationExpr(expr) =>
         blockScopeHeader
-        typeProvider._currentIteratorType = Some(attr.dataType)
+        typeProvider._lastParsedType = Some(attr.dataType)
         handleAssignmentTempVar(
           attr.dataType,
           translator.translate(Ast.expr.Name(Ast.identifier(Identifier.ITERATOR))),
diff --git a/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala b/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala
index 1ac6035bb..3a5a9e6e3 100644
--- a/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala
+++ b/shared/src/main/scala/io/kaitai/struct/precompile/Exceptions.scala
@@ -8,7 +8,7 @@ import io.kaitai.struct.translators.MethodArgType
  * Base class for all expression-related errors, not localized to a certain path
  * in source file.
  */
-sealed abstract class ExpressionError(msg: String) extends RuntimeException(msg)
+sealed class ExpressionError(msg: String) extends RuntimeException(msg)
 class TypeMismatchError(msg: String) extends ExpressionError(msg)
 class TypeUndecidedError(msg: String) extends ExpressionError(msg)
 class WrongMethodCall(val dataType: MethodArgType, val methodName: String, val expectedSigs: Iterable[String], val actualSig: String)
diff --git a/shared/src/main/scala/io/kaitai/struct/precompile/TypeValidator.scala b/shared/src/main/scala/io/kaitai/struct/precompile/TypeValidator.scala
index d80741484..bacde295a 100644
--- a/shared/src/main/scala/io/kaitai/struct/precompile/TypeValidator.scala
+++ b/shared/src/main/scala/io/kaitai/struct/precompile/TypeValidator.scala
@@ -70,11 +70,11 @@ class TypeValidator(specs: ClassSpecs) extends PrecompileStep {
       checkAssert[BooleanType](ifExpr, "boolean", path, "if")
     )
 
-    provider._currentIteratorType = Some(attr.dataType)
     val problemsRepeat: Iterable[CompilationProblem] = attr.cond.repeat match {
       case RepeatExpr(expr) =>
         checkAssert[IntType](expr, "integer", path, "repeat-expr")
       case RepeatUntil(expr) =>
+        provider._lastParsedType = Some(attr.dataType)
         checkAssert[BooleanType](expr, "boolean", path, "repeat-until")
       case RepeatEos | NoRepeat =>
         None