@harmoniclabs/pebble 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/IR/CompilationCtx.d.ts +40 -0
  2. package/dist/IR/CompilationCtx.js +54 -0
  3. package/dist/IR/IRHash.d.ts +23 -2
  4. package/dist/IR/IRHash.js +10 -60
  5. package/dist/IR/IRNodes/IRConst.js +22 -2
  6. package/dist/IR/IRNodes/IRHoisted.d.ts +0 -1
  7. package/dist/IR/IRNodes/IRHoisted.js +4 -6
  8. package/dist/IR/IRNodes/IRLetted.d.ts +0 -1
  9. package/dist/IR/IRNodes/IRLetted.js +4 -6
  10. package/dist/IR/IRNodes/IRNative/IRNativeTag.d.ts +22 -2
  11. package/dist/IR/IRNodes/IRNative/IRNativeTag.js +26 -2
  12. package/dist/IR/IRNodes/IRNative/index.d.ts +16 -1
  13. package/dist/IR/IRNodes/IRNative/index.js +27 -2
  14. package/dist/IR/IRNodes/utils/hashVarSym.d.ts +0 -1
  15. package/dist/IR/IRNodes/utils/hashVarSym.js +27 -33
  16. package/dist/IR/toUPLC/CompilerOptions.d.ts +12 -0
  17. package/dist/IR/toUPLC/CompilerOptions.js +14 -9
  18. package/dist/IR/toUPLC/compileIRToUPLC.js +39 -3
  19. package/dist/IR/toUPLC/subRoutines/inlineSingleUseLetBindingsAndReturnRoot.d.ts +23 -0
  20. package/dist/IR/toUPLC/subRoutines/inlineSingleUseLetBindingsAndReturnRoot.js +263 -0
  21. package/dist/IR/toUPLC/subRoutines/introduceCaseForDualHeadTailAndReturnRoot.d.ts +35 -0
  22. package/dist/IR/toUPLC/subRoutines/introduceCaseForDualHeadTailAndReturnRoot.js +169 -0
  23. package/dist/IR/toUPLC/subRoutines/replaceHoistedWithLetted.d.ts +0 -1
  24. package/dist/IR/toUPLC/subRoutines/replaceHoistedWithLetted.js +6 -6
  25. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.d.ts +2 -3
  26. package/dist/IR/toUPLC/subRoutines/replaceNatives/nativeToIR.js +106 -65
  27. package/dist/IR/toUPLC/subRoutines/rewriteHeadTailInCaseConsAndReturnRoot.d.ts +30 -0
  28. package/dist/IR/toUPLC/subRoutines/rewriteHeadTailInCaseConsAndReturnRoot.js +95 -0
  29. package/dist/IR/toUPLC/subRoutines/rewriteNativesAppliedToConstantsAndReturnRoot.js +36 -5
  30. package/dist/IR/toUPLC/subRoutines/rewriteToCaseOverConstAndReturnRoot.d.ts +35 -0
  31. package/dist/IR/toUPLC/subRoutines/rewriteToCaseOverConstAndReturnRoot.js +169 -0
  32. package/dist/IR/tree_utils/_ir_caseList.d.ts +15 -0
  33. package/dist/IR/tree_utils/_ir_caseList.js +19 -0
  34. package/dist/ast/nodes/statements/declarations/StructDecl.d.ts +16 -2
  35. package/dist/ast/nodes/statements/declarations/StructDecl.js +15 -1
  36. package/dist/compiler/AstCompiler/AstCompiler.d.ts +1 -0
  37. package/dist/compiler/AstCompiler/AstCompiler.js +41 -4
  38. package/dist/compiler/AstCompiler/internal/_deriveContractBody/_deriveContractBody.js +3 -3
  39. package/dist/compiler/AstCompiler/internal/exprs/_compileCallExpr.js +57 -10
  40. package/dist/compiler/AstCompiler/internal/exprs/_compileCaseExpr.js +31 -0
  41. package/dist/compiler/AstCompiler/internal/exprs/_compileIsExpr.js +12 -0
  42. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +36 -0
  43. package/dist/compiler/AstCompiler/internal/exprs/_compileUnaryPrefixExpr.js +13 -1
  44. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileAddExpr.js +18 -5
  45. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileEqualExpr.js +3 -1
  46. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanEqualExpr.js +2 -1
  47. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanExpr.js +2 -1
  48. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanEqualExpr.js +2 -1
  49. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanExpr.js +2 -1
  50. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileMultExpr.js +24 -6
  51. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileNotEqualExpr.js +2 -1
  52. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileSubExpr.js +16 -5
  53. package/dist/compiler/AstCompiler/internal/statements/_compileMatchStmt.js +33 -20
  54. package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +11 -0
  55. package/dist/compiler/Compiler.js +20 -27
  56. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +1 -1
  57. package/dist/compiler/TirCompiler/expressify/expressify.js +30 -2
  58. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.d.ts +2 -1
  59. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +45 -7
  60. package/dist/compiler/TirCompiler/expressify/expressifyVars.d.ts +0 -1
  61. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +23 -8
  62. package/dist/compiler/tir/expressions/TirCaseExpr.d.ts +9 -0
  63. package/dist/compiler/tir/expressions/TirCaseExpr.js +144 -122
  64. package/dist/compiler/tir/expressions/TirElemAccessExpr.js +2 -2
  65. package/dist/compiler/tir/expressions/TirFromDataExpr.js +102 -67
  66. package/dist/compiler/tir/expressions/TirIsExpr.js +14 -1
  67. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +1 -2
  68. package/dist/compiler/tir/expressions/TirNativeFunc.js +2 -12
  69. package/dist/compiler/tir/expressions/TirToDataExpr.js +3 -0
  70. package/dist/compiler/tir/expressions/TirTypeConversionExpr.js +10 -0
  71. package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +2 -3
  72. package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +1 -4
  73. package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +20 -3
  74. package/dist/compiler/tir/expressions/ToIRTermCtx.js +48 -3
  75. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +2 -2
  76. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +45 -8
  77. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.d.ts +19 -0
  78. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.js +24 -0
  79. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.d.ts +2 -1
  80. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.js +2 -0
  81. package/dist/compiler/tir/expressions/unary/TirUnaryMinus.js +4 -1
  82. package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +49 -4
  83. package/dist/compiler/tir/program/stdScope/prelude/preludeTypesSrc.js +35 -2
  84. package/dist/compiler/tir/program/stdScope/stdScope.d.ts +7 -0
  85. package/dist/compiler/tir/program/stdScope/stdScope.js +83 -40
  86. package/dist/compiler/tir/types/TirEnumType.d.ts +21 -0
  87. package/dist/compiler/tir/types/TirEnumType.js +36 -0
  88. package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +4 -2
  89. package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +5 -0
  90. package/dist/compiler/tir/types/TirNativeType/native/array.d.ts +16 -0
  91. package/dist/compiler/tir/types/TirNativeType/native/array.js +38 -0
  92. package/dist/compiler/tir/types/TirNativeType/native/index.d.ts +2 -0
  93. package/dist/compiler/tir/types/TirNativeType/native/index.js +2 -0
  94. package/dist/compiler/tir/types/TirNativeType/native/value.d.ts +18 -0
  95. package/dist/compiler/tir/types/TirNativeType/native/value.js +17 -0
  96. package/dist/compiler/tir/types/TirStructType.js +6 -1
  97. package/dist/compiler/tir/types/TirType.d.ts +3 -2
  98. package/dist/compiler/tir/types/TirType.js +4 -1
  99. package/dist/compiler/tir/types/utils/canAssignTo.js +28 -0
  100. package/dist/compiler/tir/types/utils/canCastTo.js +14 -1
  101. package/dist/compiler/tir/types/utils/getDeconstructableType.d.ts +2 -1
  102. package/dist/compiler/tir/types/utils/getDeconstructableType.js +2 -0
  103. package/dist/compiler/tir/types/utils/inferTypeArgs.js +4 -0
  104. package/dist/compiler/tir/types/utils/normalizeEnumToInt.d.ts +10 -0
  105. package/dist/compiler/tir/types/utils/normalizeEnumToInt.js +17 -0
  106. package/dist/compiler/tir/types/utils/substituteTypeParams.js +5 -0
  107. package/dist/diagnostics/diagnosticMessages.generated.d.ts +5 -0
  108. package/dist/diagnostics/diagnosticMessages.generated.js +10 -0
  109. package/dist/parser/Parser.js +29 -13
  110. package/dist/tokenizer/Token.d.ts +8 -7
  111. package/dist/tokenizer/Token.js +8 -7
  112. package/dist/tokenizer/utils/tokenFromKeyword.js +2 -0
  113. package/dist/version.generated.d.ts +1 -1
  114. package/dist/version.generated.js +1 -1
  115. package/package.json +3 -3
  116. package/dist/IR/tree_utils/_ir_lazyChooseList.d.ts +0 -3
  117. package/dist/IR/tree_utils/_ir_lazyChooseList.js +0 -7
@@ -1,20 +1,33 @@
1
1
  import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.generated.js";
2
2
  import { TirAddExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
+ import { TirValueT } from "../../../../tir/types/TirNativeType/native/value.js";
3
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { getUnaliased } from "../../../../tir/types/utils/getUnaliased.js";
4
6
  import { _compileExpr } from "../_compileExpr.js";
5
7
  export function _compileAddExpr(ctx, expr, _typeHint) {
6
8
  const int_t = ctx.program.stdTypes.int;
7
- const left = _compileExpr(ctx, expr.left, int_t);
8
- if (!left)
9
+ // Probe the left first with no hint; if it turns out to be a Value, we
10
+ // accept the same on the right and lower to `unionValue` in TirAddExpr.
11
+ const leftProbe = _compileExpr(ctx, expr.left, undefined);
12
+ if (!leftProbe)
9
13
  return undefined;
10
- if (!canAssignTo(left.type, int_t))
11
- return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
14
+ const leftTy = getUnaliased(leftProbe.type);
15
+ if (leftTy instanceof TirValueT) {
16
+ const right = _compileExpr(ctx, expr.right, leftProbe.type);
17
+ if (!right)
18
+ return undefined;
19
+ if (!(getUnaliased(right.type) instanceof TirValueT))
20
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.right.range, right.type.toString(), "Value");
21
+ return new TirAddExpr(leftProbe, right, expr.range);
22
+ }
23
+ if (!canAssignTo(leftProbe.type, int_t))
24
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, leftProbe.type.toString(), int_t.toString());
12
25
  const right = _compileExpr(ctx, expr.right, int_t);
13
26
  if (!right)
14
27
  return undefined;
15
28
  if (!canAssignTo(right.type, int_t))
16
29
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.right.range, right.type.toString(), int_t.toString());
17
- return new TirAddExpr(left, right,
30
+ return new TirAddExpr(leftProbe, right,
18
31
  // implicit int type,
19
32
  expr.range);
20
33
  }
@@ -1,12 +1,14 @@
1
1
  import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.generated.js";
2
2
  import { TirEqualExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
4
+ import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
4
5
  import { _compileExpr } from "../_compileExpr.js";
5
6
  export function _compileEqualExpr(ctx, expr, typeHint) {
6
7
  const left = _compileExpr(ctx, expr.left, typeHint);
7
8
  if (!left)
8
9
  return undefined;
9
- const leftType = left.type;
10
+ // enums lower to ints at runtime, so allow comparing against ints
11
+ const leftType = normalizeEnumToInt(left.type, ctx.program.stdTypes.int);
10
12
  const right = _compileExpr(ctx, expr.right, leftType);
11
13
  if (!right)
12
14
  return undefined;
@@ -2,6 +2,7 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirGreaterThanEqualExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
5
6
  import { _compileExpr } from "../_compileExpr.js";
6
7
  // only aviable for ints and bytes
7
8
  export function _compileGreaterThanEqualExpr(ctx, expr, typeHint) {
@@ -13,7 +14,7 @@ export function _compileGreaterThanEqualExpr(ctx, expr, typeHint) {
13
14
  if (!canAssignTo(left.type, int_t)
14
15
  && !canAssignTo(left.type, bytes_t))
15
16
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
16
- let leftType = left.type;
17
+ let leftType = normalizeEnumToInt(left.type, int_t);
17
18
  while (leftType instanceof TirAliasType)
18
19
  leftType = leftType.aliased;
19
20
  const right = _compileExpr(ctx, expr.right, leftType);
@@ -2,6 +2,7 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirGreaterThanExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
5
6
  import { _compileExpr } from "../_compileExpr.js";
6
7
  export function _compileGreaterThanExpr(ctx, expr, typeHint) {
7
8
  const int_t = ctx.program.stdTypes.int;
@@ -12,7 +13,7 @@ export function _compileGreaterThanExpr(ctx, expr, typeHint) {
12
13
  if (!canAssignTo(left.type, int_t)
13
14
  && !canAssignTo(left.type, bytes_t))
14
15
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
15
- let leftType = left.type;
16
+ let leftType = normalizeEnumToInt(left.type, int_t);
16
17
  while (leftType instanceof TirAliasType)
17
18
  leftType = leftType.aliased;
18
19
  const right = _compileExpr(ctx, expr.right, leftType);
@@ -2,6 +2,7 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirLessThanEqualExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
5
6
  import { int_t, bytes_t } from "../../../../tir/program/stdScope/stdScope.js";
6
7
  import { _compileExpr } from "../_compileExpr.js";
7
8
  export function _compileLessThanEqualExpr(ctx, expr, typeHint) {
@@ -11,7 +12,7 @@ export function _compileLessThanEqualExpr(ctx, expr, typeHint) {
11
12
  if (!canAssignTo(left.type, int_t)
12
13
  && !canAssignTo(left.type, bytes_t))
13
14
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
14
- let leftType = left.type;
15
+ let leftType = normalizeEnumToInt(left.type, int_t);
15
16
  while (leftType instanceof TirAliasType)
16
17
  leftType = leftType.aliased;
17
18
  const right = _compileExpr(ctx, expr.right, leftType);
@@ -2,6 +2,7 @@ import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.ge
2
2
  import { TirLessThanExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { TirAliasType } from "../../../../tir/types/TirAliasType.js";
4
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
5
6
  import { _compileExpr } from "../_compileExpr.js";
6
7
  export function _compileLessThanExpr(ctx, expr, typeHint) {
7
8
  const int_t = ctx.program.stdTypes.int;
@@ -12,7 +13,7 @@ export function _compileLessThanExpr(ctx, expr, typeHint) {
12
13
  if (!canAssignTo(left.type, int_t)
13
14
  && !canAssignTo(left.type, bytes_t))
14
15
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
15
- let leftType = left.type;
16
+ let leftType = normalizeEnumToInt(left.type, int_t);
16
17
  while (leftType instanceof TirAliasType)
17
18
  leftType = leftType.aliased;
18
19
  const right = _compileExpr(ctx, expr.right, leftType);
@@ -1,20 +1,38 @@
1
1
  import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.generated.js";
2
2
  import { TirMultExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
+ import { TirValueT } from "../../../../tir/types/TirNativeType/native/value.js";
3
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { getUnaliased } from "../../../../tir/types/utils/getUnaliased.js";
4
6
  import { _compileExpr } from "../_compileExpr.js";
5
7
  export function _compileMultExpr(ctx, expr, _typeHint) {
6
8
  const int_t = ctx.program.stdTypes.int;
7
- const left = _compileExpr(ctx, expr.left, int_t);
8
- if (!left)
9
+ // Probe both sides without hints so we can disambiguate
10
+ // (int * Value) / (Value * int) / (int * int).
11
+ const leftProbe = _compileExpr(ctx, expr.left, undefined);
12
+ if (!leftProbe)
9
13
  return undefined;
10
- if (!canAssignTo(left.type, int_t))
11
- return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
12
- const right = _compileExpr(ctx, expr.right, int_t);
14
+ const leftTy = getUnaliased(leftProbe.type);
15
+ if (leftTy instanceof TirValueT) {
16
+ const right = _compileExpr(ctx, expr.right, int_t);
17
+ if (!right)
18
+ return undefined;
19
+ if (!canAssignTo(right.type, int_t))
20
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.right.range, right.type.toString(), int_t.toString());
21
+ return new TirMultExpr(leftProbe, right, expr.range);
22
+ }
23
+ if (!canAssignTo(leftProbe.type, int_t))
24
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, leftProbe.type.toString(), int_t.toString());
25
+ // left is int — right may be int (regular product) or Value (scaleValue).
26
+ const right = _compileExpr(ctx, expr.right, undefined);
13
27
  if (!right)
14
28
  return undefined;
29
+ const rightTy = getUnaliased(right.type);
30
+ if (rightTy instanceof TirValueT) {
31
+ return new TirMultExpr(leftProbe, right, expr.range);
32
+ }
15
33
  if (!canAssignTo(right.type, int_t))
16
34
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.right.range, right.type.toString(), int_t.toString());
17
- return new TirMultExpr(left, right,
35
+ return new TirMultExpr(leftProbe, right,
18
36
  // implicit int type,
19
37
  expr.range);
20
38
  }
@@ -1,12 +1,13 @@
1
1
  import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.generated.js";
2
2
  import { TirNotEqualExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
3
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
4
+ import { normalizeEnumToInt } from "../../../../tir/types/utils/normalizeEnumToInt.js";
4
5
  import { _compileExpr } from "../_compileExpr.js";
5
6
  export function _compileNotEqualExpr(ctx, expr, typeHint) {
6
7
  const left = _compileExpr(ctx, expr.left, typeHint);
7
8
  if (!left)
8
9
  return undefined;
9
- const leftType = left.type;
10
+ const leftType = normalizeEnumToInt(left.type, ctx.program.stdTypes.int);
10
11
  const right = _compileExpr(ctx, expr.right, leftType);
11
12
  if (!right)
12
13
  return undefined;
@@ -1,20 +1,31 @@
1
1
  import { DiagnosticCode } from "../../../../../diagnostics/diagnosticMessages.generated.js";
2
2
  import { TirSubExpr } from "../../../../tir/expressions/binary/TirBinaryExpr.js";
3
+ import { TirValueT } from "../../../../tir/types/TirNativeType/native/value.js";
3
4
  import { canAssignTo } from "../../../../tir/types/utils/canAssignTo.js";
5
+ import { getUnaliased } from "../../../../tir/types/utils/getUnaliased.js";
4
6
  import { _compileExpr } from "../_compileExpr.js";
5
7
  export function _compileSubExpr(ctx, expr, _typeHint) {
6
8
  const int_t = ctx.program.stdTypes.int;
7
- const left = _compileExpr(ctx, expr.left, int_t);
8
- if (!left)
9
+ const leftProbe = _compileExpr(ctx, expr.left, undefined);
10
+ if (!leftProbe)
9
11
  return undefined;
10
- if (!canAssignTo(left.type, int_t))
11
- return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, left.type.toString(), int_t.toString());
12
+ const leftTy = getUnaliased(leftProbe.type);
13
+ if (leftTy instanceof TirValueT) {
14
+ const right = _compileExpr(ctx, expr.right, leftProbe.type);
15
+ if (!right)
16
+ return undefined;
17
+ if (!(getUnaliased(right.type) instanceof TirValueT))
18
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.right.range, right.type.toString(), "Value");
19
+ return new TirSubExpr(leftProbe, right, expr.range);
20
+ }
21
+ if (!canAssignTo(leftProbe.type, int_t))
22
+ return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.left.range, leftProbe.type.toString(), int_t.toString());
12
23
  const right = _compileExpr(ctx, expr.right, int_t);
13
24
  if (!right)
14
25
  return undefined;
15
26
  if (!canAssignTo(right.type, int_t))
16
27
  return ctx.error(DiagnosticCode.Type_0_is_not_assignable_to_type_1, expr.right.range, right.type.toString(), int_t.toString());
17
- return new TirSubExpr(left, right,
28
+ return new TirSubExpr(leftProbe, right,
18
29
  // implicit int type,
19
30
  expr.range);
20
31
  }
@@ -11,6 +11,7 @@ import { TirDataT } from "../../../tir/types/TirNativeType/native/data.js";
11
11
  import { TirDataOptT } from "../../../tir/types/TirNativeType/native/Optional/data.js";
12
12
  import { TirSopOptT } from "../../../tir/types/TirNativeType/native/Optional/sop.js";
13
13
  import { isTirStructType, TirDataStructType, TirSoPStructType } from "../../../tir/types/TirStructType.js";
14
+ import { TirEnumType } from "../../../tir/types/TirEnumType.js";
14
15
  import { getDeconstructableType } from "../../../tir/types/utils/getDeconstructableType.js";
15
16
  import { wrapManyStatements } from "../../utils/wrapManyStatementsOrReturnSame.js";
16
17
  import { _compileExpr } from "../exprs/_compileExpr.js";
@@ -32,11 +33,13 @@ export function _compileMatchStmt(ctx, stmt) {
32
33
  if (!deconstructableType)
33
34
  return ctx.error(DiagnosticCode.A_value_of_type_0_cannot_be_deconstructed, stmt.matchExpr.range, matchExprType.toString());
34
35
  // TODO: add support for all deconstructable types
35
- if (!isTirStructType(deconstructableType)) {
36
- return ctx.error(DiagnosticCode.Not_implemented_0, stmt.matchExpr.range, "only structs supported for now, sorry!");
36
+ if (!isTirStructType(deconstructableType) && !(deconstructableType instanceof TirEnumType)) {
37
+ return ctx.error(DiagnosticCode.Not_implemented_0, stmt.matchExpr.range, "only structs and enums supported for now, sorry!");
37
38
  }
38
- const ctors = deconstructableType.constructors;
39
- const ctorNames = ctors.map(c => c.name);
39
+ const ctorNames = deconstructableType instanceof TirEnumType
40
+ ? deconstructableType.members.slice()
41
+ : deconstructableType.constructors.map(c => c.name);
42
+ const totalCtors = ctorNames.length;
40
43
  const missingCtors = ctorNames.slice();
41
44
  if (stmt.cases.length === 0)
42
45
  return ctx.error(DiagnosticCode.A_match_statement_must_have_at_least_one_case, stmt.range);
@@ -70,7 +73,7 @@ export function _compileMatchStmt(ctx, stmt) {
70
73
  return undefined;
71
74
  wildcardCase = new TirMatchStmtWildcardCase(branchBody, matchCase.range);
72
75
  }
73
- if (!wildcardCase && cases.length < ctors.length) {
76
+ if (!wildcardCase && cases.length < totalCtors) {
74
77
  return ctx.error(DiagnosticCode.Match_cases_are_not_exhaustive, stmt.range);
75
78
  }
76
79
  return [new TirMatchStmt(matchExpr, cases, wildcardCase, stmt.range)];
@@ -82,23 +85,21 @@ export function _compileTirMatchStmtCase(ctx, matchCase, deconstructableType, co
82
85
  //*/
83
86
  const pattern = matchCase.pattern;
84
87
  if (pattern instanceof SimpleVarDecl) {
85
- /*
86
- if( pattern.name.text === "_" ) {
88
+ // bare-name pattern: only valid for enum scrutinees (`when Apple: ...`)
89
+ if (deconstructableType instanceof TirEnumType) {
90
+ const memberName = pattern.name.text;
91
+ const memberIdx = deconstructableType.indexOf(memberName);
92
+ if (memberIdx < 0)
93
+ return ctx.error(DiagnosticCode.Unknown_0_constructor_1, pattern.name.range, deconstructableType.toString(), memberName);
94
+ if (constrNamesAlreadySpecified.includes(memberName))
95
+ return ctx.error(DiagnosticCode.Constructor_0_was_already_specified, pattern.name.range, memberName);
96
+ constrNamesAlreadySpecified.push(memberName);
87
97
  const branchCtx = ctx.newBranchChildScope();
88
- const branchBody = wrapManyStatements(
89
- _compileStatement(
90
- branchCtx,
91
- matchCase.body
92
- ),
93
- matchCase.body.range
94
- );
95
- if( !branchBody ) return undefined;
96
- return new TirMatchStmtWildcardCase(
97
- branchBody,
98
- matchCase.range
99
- );
98
+ const branchBody = wrapManyStatements(_compileStatement(branchCtx, matchCase.body), matchCase.body.range);
99
+ if (!branchBody)
100
+ return undefined;
101
+ return new TirMatchStmtCase(new TirNamedDeconstructVarDecl(memberName, new Map(), undefined, deconstructableType, undefined, true, pattern.name.range, pattern.name.range), branchBody, matchCase.range);
100
102
  }
101
- //*/
102
103
  return ctx.error(DiagnosticCode.The_argument_of_a_match_statement_branch_must_be_deconstructed, matchCase.pattern.range);
103
104
  }
104
105
  else if (pattern instanceof NamedDeconstructVarDecl) {
@@ -107,6 +108,18 @@ export function _compileTirMatchStmtCase(ctx, matchCase, deconstructableType, co
107
108
  if (constrNamesAlreadySpecified.includes(deconstructedCtorName))
108
109
  return ctx.error(DiagnosticCode.Constructor_0_was_already_specified, deconstructedCtorIdentifier.range, deconstructedCtorName);
109
110
  constrNamesAlreadySpecified.push(deconstructedCtorName);
111
+ if (deconstructableType instanceof TirEnumType) {
112
+ const memberIdx = deconstructableType.indexOf(deconstructedCtorName);
113
+ if (memberIdx < 0)
114
+ return ctx.error(DiagnosticCode.Unknown_0_constructor_1, pattern.name.range, deconstructableType.toString(), deconstructedCtorName);
115
+ if (pattern.fields.size > 0 || pattern.rest)
116
+ return ctx.error(DiagnosticCode.Enum_member_pattern_cannot_have_fields, pattern.range);
117
+ const branchCtx = ctx.newBranchChildScope();
118
+ const branchBody = wrapManyStatements(_compileStatement(branchCtx, matchCase.body), matchCase.body.range);
119
+ if (!branchBody)
120
+ return undefined;
121
+ return new TirMatchStmtCase(new TirNamedDeconstructVarDecl(deconstructedCtorName, new Map(), undefined, deconstructableType, undefined, true, pattern.range, pattern.name.range), branchBody, matchCase.range);
122
+ }
110
123
  if (deconstructableType instanceof TirSoPStructType
111
124
  || deconstructableType instanceof TirDataStructType) {
112
125
  const localIdx = deconstructableType.constructors.findIndex(c => c.name === deconstructedCtorName);
@@ -1,5 +1,6 @@
1
1
  import { TirAliasType } from "../../tir/types/TirAliasType.js";
2
2
  import { isTirStructType } from "../../tir/types/TirStructType.js";
3
+ import { TirEnumType } from "../../tir/types/TirEnumType.js";
3
4
  import { TirTypeParam } from "../../tir/types/TirTypeParam.js";
4
5
  import { int_t, bytes_t, bool_t, string_t } from "../../tir/program/stdScope/stdScope.js";
5
6
  import { TirBlsG1T, TirBlsG2T, TirMlResultT, TirUnConstrDataResultT, TirPairDataT } from "../../tir/types/TirNativeType/index.js";
@@ -8,6 +9,8 @@ import { TirBytesT } from "../../tir/types/TirNativeType/native/bytes.js";
8
9
  import { TirDataT } from "../../tir/types/TirNativeType/native/data.js";
9
10
  import { TirFuncT } from "../../tir/types/TirNativeType/native/function.js";
10
11
  import { TirIntT } from "../../tir/types/TirNativeType/native/int.js";
12
+ import { TirArrayT } from "../../tir/types/TirNativeType/native/array.js";
13
+ import { TirValueT } from "../../tir/types/TirNativeType/native/value.js";
11
14
  import { TirLinearMapT } from "../../tir/types/TirNativeType/native/linearMap.js";
12
15
  import { TirLinearMapEntryT } from "../../tir/types/TirNativeType/native/linearMapEntry.js";
13
16
  import { TirListT } from "../../tir/types/TirNativeType/native/list.js";
@@ -84,6 +87,14 @@ export function getPropAccessReturnType(ctx, objType, propId) {
84
87
  return undefined;
85
88
  if (objType instanceof TirMlResultT)
86
89
  return undefined;
90
+ // Native Value / Array<T> — methods are reached through prelude/std
91
+ // aliases, not via direct prop-access on the native type.
92
+ if (objType instanceof TirValueT)
93
+ return undefined;
94
+ if (objType instanceof TirArrayT)
95
+ return undefined;
96
+ if (objType instanceof TirEnumType)
97
+ return undefined;
87
98
  const tsEnsureExhaustiveCheck = objType;
88
99
  console.error(objType);
89
100
  throw new Error("unreachable::getPropAccessReturnType");
@@ -7,12 +7,7 @@ import { semverSatisfies } from "../utils/semverSatisfies.js";
7
7
  import { AstCompiler } from "./AstCompiler/AstCompiler.js";
8
8
  import { createMemoryCompilerIoApi } from "./io/CompilerIoApi.js";
9
9
  import { compileTypedProgram } from "./TirCompiler/compileTirProgram.js";
10
- import { __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION } from "../IR/IRHash.js";
11
- import { __VERY_UNSAFE_FORGET_VAR_SYM_HASHES_ONLY_USE_AT_END_OF_UPLC_COMPILATION } from "../IR/IRNodes/utils/hashVarSym.js";
12
- import { __unsafe_clear_hoisted_hash_to_symbol } from "../IR/IRNodes/IRHoisted.js";
13
- import { __unsafe_clear_letted_hash_to_symbol } from "../IR/IRNodes/IRLetted.js";
14
- import { __unsafe_clear_hoisted_cache } from "../IR/toUPLC/subRoutines/replaceHoistedWithLetted.js";
15
- import { __unsafe_clear_mapToType_cache } from "./TirCompiler/expressify/expressifyVars.js";
10
+ import { CompilationCtx, withCompilationCtx } from "../IR/CompilationCtx.js";
16
11
  import { compileIRToUPLC } from "../IR/toUPLC/compileIRToUPLC.js";
17
12
  import { TirFuncExpr } from "./tir/expressions/TirFuncExpr.js";
18
13
  import { addBudget, zeroBudget, } from "./test/TestResult.js";
@@ -57,7 +52,6 @@ export class Compiler extends DiagnosticEmitter {
57
52
  const program = await astCompiler.compile();
58
53
  if (this.diagnostics.length > 0) {
59
54
  let msg;
60
- // globalThis.console && console.log( this.diagnostics );
61
55
  const fstErrorMsg = this.diagnostics[0].toString();
62
56
  const nDiags = this.diagnostics.length;
63
57
  for (msg of this.diagnostics) {
@@ -82,7 +76,6 @@ export class Compiler extends DiagnosticEmitter {
82
76
  const program = await astCompiler.export(cfg.functionName, cfg.entry);
83
77
  if (this.diagnostics.length > 0) {
84
78
  let msg;
85
- globalThis.console && console.log(this.diagnostics);
86
79
  const fstErrorMsg = this.diagnostics[0].toString();
87
80
  const nDiags = this.diagnostics.length;
88
81
  while (msg = this.diagnostics.shift()) {
@@ -103,7 +96,6 @@ export class Compiler extends DiagnosticEmitter {
103
96
  const program = await astCompiler.run();
104
97
  if (this.diagnostics.length > 0) {
105
98
  let msg;
106
- globalThis.console && console.log(this.diagnostics);
107
99
  const fstErrorMsg = this.diagnostics[0].toString();
108
100
  const nDiags = this.diagnostics.length;
109
101
  while (msg = this.diagnostics.shift()) {
@@ -288,7 +280,6 @@ export class Compiler extends DiagnosticEmitter {
288
280
  const program = await astCompiler.runRepl();
289
281
  if (this.diagnostics.length > 0) {
290
282
  let msg;
291
- globalThis.console && console.log(this.diagnostics);
292
283
  const fstErrorMsg = this.diagnostics[0].toString();
293
284
  const nDiags = this.diagnostics.length;
294
285
  while (msg = this.diagnostics.shift()) {
@@ -303,23 +294,25 @@ export class Compiler extends DiagnosticEmitter {
303
294
  return Machine.eval(new Force(uplcProgram.body));
304
295
  }
305
296
  _compileBackend(cfg, program, skipFileOutput = false) {
306
- // backend starts here
307
- const ir = compileTypedProgram(cfg, program);
308
- const uplc = compileIRToUPLC(ir, cfg);
309
- const serialized = compileUPLC(new UPLCProgram(cfg.targetUplcVersion, uplc));
310
- if (!skipFileOutput) {
311
- const outDir = cfg.outDir;
312
- const outPath = outDir + (outDir.endsWith("/") ? "" : "/") + "out.flat";
313
- this.io.writeFile(outPath, serialized, cfg.root);
314
- this.io.stdout.write(`compiled program written to ${outPath}\n`);
315
- }
316
- __VERY_UNSAFE_FORGET_IRHASH_ONLY_USE_AT_END_OF_UPLC_COMPILATION();
317
- __VERY_UNSAFE_FORGET_VAR_SYM_HASHES_ONLY_USE_AT_END_OF_UPLC_COMPILATION();
318
- __unsafe_clear_hoisted_hash_to_symbol();
319
- __unsafe_clear_letted_hash_to_symbol();
320
- __unsafe_clear_hoisted_cache();
321
- __unsafe_clear_mapToType_cache();
322
- return serialized;
297
+ // Run the whole backend under a fresh per-compilation context. All
298
+ // node-level caches (hoisted/letted naming, hoisted->letted lowering,
299
+ // the mapToType helper cache) live on this context, so they cannot
300
+ // leak into or be perturbed by any other compilation — and they are
301
+ // dropped automatically when this scope exits, even on throw. The
302
+ // content-addressed `IRHash` has no global state at all, so there is
303
+ // nothing else to reset.
304
+ return withCompilationCtx(new CompilationCtx(), () => {
305
+ const ir = compileTypedProgram(cfg, program);
306
+ const uplc = compileIRToUPLC(ir, cfg);
307
+ const serialized = compileUPLC(new UPLCProgram(cfg.targetUplcVersion, uplc));
308
+ if (!skipFileOutput) {
309
+ const outDir = cfg.outDir;
310
+ const outPath = outDir + (outDir.endsWith("/") ? "" : "/") + "out.flat";
311
+ this.io.writeFile(outPath, serialized, cfg.root);
312
+ this.io.stdout.write(`compiled program written to ${outPath}\n`);
313
+ }
314
+ return serialized;
315
+ });
323
316
  }
324
317
  }
325
318
  function _failedTestResult(desc, msg, kind = "unit") {
@@ -303,7 +303,7 @@ export class ExpressifyCtx {
303
303
  if (stmt.rest) {
304
304
  if (isDestructuredField)
305
305
  throw new Error("rest is not implemented in destructured field array-like deconstruct. TODO: map data elems to elem type");
306
- const lettedRest = this.introduceLettedConstant(stmt.rest, new TirCallExpr(TirNativeFunc._dropList(elemsType), [
306
+ const lettedRest = this.introduceLettedConstant(stmt.rest, new TirCallExpr(TirNativeFunc.dropList(elemsType), [
307
307
  new TirLitIntExpr(BigInt(nElems), stmt.range),
308
308
  lettedArrayExpr
309
309
  ], new TirListT(elemsType), stmt.range), stmt.range);
@@ -200,7 +200,7 @@ loopReplacements, assertions = []) {
200
200
  }
201
201
  if (stmt.rest) {
202
202
  const uniqueRestName = getUniqueInternalName(stmt.rest);
203
- const restLetted = ctx.introduceLettedConstant(uniqueRestName, new TirCallExpr(TirNativeFunc._dropList(elemType), [
203
+ const restLetted = ctx.introduceLettedConstant(uniqueRestName, new TirCallExpr(TirNativeFunc.dropList(elemType), [
204
204
  new TirLitIntExpr(BigInt(stmt.elements.length % modTails), stmt.range),
205
205
  lettedArr
206
206
  ], listType, stmt.range), stmt.range);
@@ -395,8 +395,36 @@ loopReplacements, assertions = []) {
395
395
  const returnTypeAndInvalidInit = getBranchStmtReturnType(reassignedAndFlow, ctx, stmt.range);
396
396
  const forStmt = loopToForStmt(stmt);
397
397
  const { bodyStateType, initState } = getBodyStateType(returnTypeAndInvalidInit, forStmt);
398
+ // Optimization: when the loop reassigns exactly one variable
399
+ // and has no user-written `return` inside, skip the SoP wrap
400
+ // around the loop's result. The recursive loop function then
401
+ // returns the bare variable's type, saving one `Reassigns{…}`
402
+ // constructor build per iteration and one IRCase at the exit.
403
+ // Requires the loop to be non-terminating (terminating loops
404
+ // are tail-positioned and their value must match the outer
405
+ // function's expected return type — we don't try to reconcile
406
+ // that here).
407
+ const canBareLower = (reassignedAndFlow.reassigned.length === 1
408
+ && !reassignedAndFlow.returns
409
+ && !definitelyTerminates);
398
410
  const loopExprCtx = ctx.newChild();
399
- const loopExpr = expressifyForStmt(loopExprCtx, forStmt, returnTypeAndInvalidInit.sop, bodyStateType, initState);
411
+ const bareReturnType = canBareLower
412
+ ? bodyStateType.constructors[0].fields[0].type
413
+ : undefined;
414
+ const loopExpr = expressifyForStmt(loopExprCtx, forStmt, returnTypeAndInvalidInit.sop, bodyStateType, initState, bareReturnType);
415
+ if (canBareLower) {
416
+ // Bind the loop's bare result as the variable's new SSA
417
+ // name, then evaluate the rest of the body. No outer
418
+ // case-match needed. Use a fresh internal name so the
419
+ // existing `letted[varName] = initialValue` binding (from
420
+ // the original `let varName = ...` statement) isn't
421
+ // shadowed by a no-op `introduceLettedConstant` call.
422
+ const [varName] = reassignedAndFlow.reassigned;
423
+ const loopResultName = getUniqueInternalName(varName);
424
+ const lettedExpr = ctx.introduceLettedConstant(loopResultName, loopExpr, stmt.range);
425
+ ctx.setNewVariableName(varName, lettedExpr.varName);
426
+ return TirAssertAndContinueExpr.fromStmtsAndContinuation(assertions, expressifyFuncBody(ctx, bodyStmts, loopReplacements));
427
+ }
400
428
  const result = TirAssertAndContinueExpr.fromStmtsAndContinuation(assertions, definitelyTerminates ? loopExpr : wrapNonTerminatingFinalStmtAsCaseExpr(loopExpr, returnTypeAndInvalidInit.sop, ctx, stmt.range, reassignedAndFlow, bodyStmts, loopReplacements));
401
429
  return result;
402
430
  }
@@ -4,6 +4,7 @@ import { TirForOfStmt } from "../../tir/statements/TirForOfStmt.js";
4
4
  import { TirForStmt } from "../../tir/statements/TirForStmt.js";
5
5
  import { TirWhileStmt } from "../../tir/statements/TirWhileStmt.js";
6
6
  import { TirSoPStructType } from "../../tir/types/TirStructType.js";
7
+ import { TirType } from "../../tir/types/TirType.js";
7
8
  import { ExpressifyCtx } from "./ExpressifyCtx.js";
8
9
  export declare function loopToForStmt(stmt: TirWhileStmt | TirForOfStmt | TirForStmt): TirForStmt;
9
- export declare function expressifyForStmt(ctx: ExpressifyCtx, stmt: TirForStmt, returnType: TirSoPStructType, bodyStateType: TirSoPStructType, initState: TirLitNamedObjExpr): TirCallExpr;
10
+ export declare function expressifyForStmt(ctx: ExpressifyCtx, stmt: TirForStmt, returnType: TirSoPStructType, bodyStateType: TirSoPStructType, initState: TirLitNamedObjExpr, bareReturnType?: TirType): TirCallExpr;
@@ -68,7 +68,16 @@ export function loopToForStmt(stmt) {
68
68
  stmt.body, // loopBody
69
69
  stmt.range);
70
70
  }
71
- export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initState) {
71
+ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initState,
72
+ // Optimization: when the loop has exactly one reassigned variable
73
+ // and no user-written `return` inside its body, the SoP wrap
74
+ // (`Reassigns{var}`) on every iteration is unnecessary. The caller
75
+ // can opt into a bare-value lowering by passing the variable's type
76
+ // here; the loop function then returns that type directly, and the
77
+ // call site is expected to bind the result without a case-match.
78
+ bareReturnType) {
79
+ const effectiveReturnType = bareReturnType ?? returnType;
80
+ const isBareMode = bareReturnType !== undefined;
72
81
  let loopBody = stmt.body instanceof TirBlockStmt ? stmt.body : new TirBlockStmt([stmt.body], stmt.range);
73
82
  loopBody = new TirBlockStmt(loopBody.stmts.slice(), loopBody.range);
74
83
  // add final loop updates
@@ -88,9 +97,27 @@ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initStat
88
97
  ], loopBody.range);
89
98
  }
90
99
  const loopFuncName = getUniqueInternalName("loop");
91
- const loopFuncType = new TirFuncT(bodyStateType.constructors[0].fields.map(f => f.type), returnType);
100
+ const loopFuncType = new TirFuncT(bodyStateType.constructors[0].fields.map(f => f.type), effectiveReturnType);
92
101
  const loopReplacements = {
93
102
  compileBreak(ctx, stmt) {
103
+ if (isBareMode) {
104
+ // Bare-value mode: the loop's return type IS the single
105
+ // user variable's type. `break` yields that var's current
106
+ // value directly, no SoP construction.
107
+ const userVarField = bodyStateType.constructors[0].fields[0];
108
+ const resolved = ctx.getVariable(userVarField.name);
109
+ if (isExpressifyFuncParam(resolved)) {
110
+ return new TirVariableAccessExpr({
111
+ variableInfos: {
112
+ name: resolved.name,
113
+ type: resolved.type,
114
+ isConstant: false
115
+ },
116
+ isDefinedOutsideFuncScope: false
117
+ }, stmt.range);
118
+ }
119
+ return resolved;
120
+ }
94
121
  // return first constructor of the return type
95
122
  const ctor = returnType.constructors[0];
96
123
  return new TirLitNamedObjExpr(new Identifier(ctor.name, stmt.range), ctor.fields.map(f => new Identifier(f.name, stmt.range)), bodyStateType.constructors[0].fields
@@ -111,10 +138,21 @@ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initStat
111
138
  }), returnType, stmt.range);
112
139
  },
113
140
  replaceReturnValue(ctx, stmt) {
114
- // return second constructor of the return type
141
+ // Synthetic returns inserted by `expressifyIfBranch` (and
142
+ // analogous callers) carry the inner-if's SoP value as the
143
+ // continuation of the ternary they participate in — they are
144
+ // NOT user-written returns escaping the loop. When the loop
145
+ // has no user-written `return` in its body, `returnType` has
146
+ // only the "break/continue" constructor: in that case the
147
+ // value flowing through is already the right type and we
148
+ // must leave it untouched. (Previously this threw "No return
149
+ // constructor found in return type" when a for-of body
150
+ // contained an `if` that mutated a captured `let` — the
151
+ // synthesized branch-tail returns hit this path even though
152
+ // the user had no `return` inside the loop.)
115
153
  const ctor = returnType.constructors[1];
116
154
  if (!ctor) {
117
- throw new Error("No return constructor found in return type");
155
+ return stmt.value;
118
156
  }
119
157
  return new TirLitNamedObjExpr(new Identifier(ctor.name, stmt.range), [new Identifier(ctor.fields[0].name, stmt.range)], [stmt.value], returnType, stmt.range);
120
158
  },
@@ -149,7 +187,7 @@ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initStat
149
187
  }, stmt.range);
150
188
  }
151
189
  return resolved;
152
- }), returnType, stmt.range);
190
+ }), effectiveReturnType, stmt.range);
153
191
  },
154
192
  };
155
193
  const loopCompilationCtx = ctx.newChild();
@@ -165,7 +203,7 @@ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initStat
165
203
  false, // is constant
166
204
  stmt.range)),
167
205
  // func return type
168
- returnType,
206
+ effectiveReturnType,
169
207
  // func body
170
208
  new TirBlockStmt([
171
209
  new TirReturnStmt(expressifyFuncBody(loopCompilationCtx, loopBody.stmts, loopReplacements, [] // assertions
@@ -176,5 +214,5 @@ export function expressifyForStmt(ctx, stmt, returnType, bodyStateType, initStat
176
214
  );
177
215
  return new TirCallExpr(loopFuncExpr,
178
216
  // loop call init args
179
- initState.values.map(v => expressifyVars(ctx, v.clone())), returnType, stmt.range);
217
+ initState.values.map(v => expressifyVars(ctx, v.clone())), effectiveReturnType, stmt.range);
180
218
  }
@@ -8,4 +8,3 @@ import { ExpressifyCtx } from "./ExpressifyCtx.js";
8
8
  * @returns a the modified expression
9
9
  **/
10
10
  export declare function expressifyVars(ctx: ExpressifyCtx, expr: TirExpr): TirExpr;
11
- export declare function __unsafe_clear_mapToType_cache(): void;