@harmoniclabs/pebble 0.2.0 → 0.3.0

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 (116) 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/_compileCaseExpr.js +31 -0
  40. package/dist/compiler/AstCompiler/internal/exprs/_compileIsExpr.js +12 -0
  41. package/dist/compiler/AstCompiler/internal/exprs/_compilePropAccessExpr.js +36 -0
  42. package/dist/compiler/AstCompiler/internal/exprs/_compileUnaryPrefixExpr.js +13 -1
  43. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileAddExpr.js +18 -5
  44. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileEqualExpr.js +3 -1
  45. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanEqualExpr.js +2 -1
  46. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileGreaterThanExpr.js +2 -1
  47. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanEqualExpr.js +2 -1
  48. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileLessThanExpr.js +2 -1
  49. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileMultExpr.js +24 -6
  50. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileNotEqualExpr.js +2 -1
  51. package/dist/compiler/AstCompiler/internal/exprs/binary/_compileSubExpr.js +16 -5
  52. package/dist/compiler/AstCompiler/internal/statements/_compileMatchStmt.js +33 -20
  53. package/dist/compiler/AstCompiler/utils/getPropAccessReturnType.js +11 -0
  54. package/dist/compiler/Compiler.js +20 -27
  55. package/dist/compiler/TirCompiler/expressify/ExpressifyCtx.js +1 -1
  56. package/dist/compiler/TirCompiler/expressify/expressify.js +30 -2
  57. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.d.ts +2 -1
  58. package/dist/compiler/TirCompiler/expressify/expressifyForStmt.js +45 -7
  59. package/dist/compiler/TirCompiler/expressify/expressifyVars.d.ts +0 -1
  60. package/dist/compiler/TirCompiler/expressify/expressifyVars.js +23 -8
  61. package/dist/compiler/tir/expressions/TirCaseExpr.d.ts +9 -0
  62. package/dist/compiler/tir/expressions/TirCaseExpr.js +144 -122
  63. package/dist/compiler/tir/expressions/TirElemAccessExpr.js +2 -2
  64. package/dist/compiler/tir/expressions/TirFromDataExpr.js +102 -67
  65. package/dist/compiler/tir/expressions/TirIsExpr.js +14 -1
  66. package/dist/compiler/tir/expressions/TirNativeFunc.d.ts +1 -2
  67. package/dist/compiler/tir/expressions/TirNativeFunc.js +2 -12
  68. package/dist/compiler/tir/expressions/TirToDataExpr.js +3 -0
  69. package/dist/compiler/tir/expressions/TirTypeConversionExpr.js +10 -0
  70. package/dist/compiler/tir/expressions/TirVariableAccessExpr.d.ts +2 -3
  71. package/dist/compiler/tir/expressions/TirVariableAccessExpr.js +1 -4
  72. package/dist/compiler/tir/expressions/ToIRTermCtx.d.ts +20 -3
  73. package/dist/compiler/tir/expressions/ToIRTermCtx.js +48 -3
  74. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.d.ts +2 -2
  75. package/dist/compiler/tir/expressions/binary/TirBinaryExpr.js +45 -8
  76. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.d.ts +19 -0
  77. package/dist/compiler/tir/expressions/litteral/TirLitEnumMemberExpr.js +24 -0
  78. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.d.ts +2 -1
  79. package/dist/compiler/tir/expressions/litteral/TirLitteralExpr.js +2 -0
  80. package/dist/compiler/tir/expressions/unary/TirUnaryMinus.js +4 -1
  81. package/dist/compiler/tir/program/stdScope/populateStdNamespace.js +49 -4
  82. package/dist/compiler/tir/program/stdScope/prelude/preludeTypesSrc.js +35 -2
  83. package/dist/compiler/tir/program/stdScope/stdScope.d.ts +7 -0
  84. package/dist/compiler/tir/program/stdScope/stdScope.js +83 -40
  85. package/dist/compiler/tir/types/TirEnumType.d.ts +21 -0
  86. package/dist/compiler/tir/types/TirEnumType.js +36 -0
  87. package/dist/compiler/tir/types/TirNativeType/TirNativeType.d.ts +4 -2
  88. package/dist/compiler/tir/types/TirNativeType/TirNativeType.js +5 -0
  89. package/dist/compiler/tir/types/TirNativeType/native/array.d.ts +16 -0
  90. package/dist/compiler/tir/types/TirNativeType/native/array.js +38 -0
  91. package/dist/compiler/tir/types/TirNativeType/native/index.d.ts +2 -0
  92. package/dist/compiler/tir/types/TirNativeType/native/index.js +2 -0
  93. package/dist/compiler/tir/types/TirNativeType/native/value.d.ts +18 -0
  94. package/dist/compiler/tir/types/TirNativeType/native/value.js +17 -0
  95. package/dist/compiler/tir/types/TirStructType.js +6 -1
  96. package/dist/compiler/tir/types/TirType.d.ts +3 -2
  97. package/dist/compiler/tir/types/TirType.js +4 -1
  98. package/dist/compiler/tir/types/utils/canAssignTo.js +28 -0
  99. package/dist/compiler/tir/types/utils/canCastTo.js +14 -1
  100. package/dist/compiler/tir/types/utils/getDeconstructableType.d.ts +2 -1
  101. package/dist/compiler/tir/types/utils/getDeconstructableType.js +2 -0
  102. package/dist/compiler/tir/types/utils/inferTypeArgs.js +4 -0
  103. package/dist/compiler/tir/types/utils/normalizeEnumToInt.d.ts +10 -0
  104. package/dist/compiler/tir/types/utils/normalizeEnumToInt.js +17 -0
  105. package/dist/compiler/tir/types/utils/substituteTypeParams.js +5 -0
  106. package/dist/diagnostics/diagnosticMessages.generated.d.ts +5 -0
  107. package/dist/diagnostics/diagnosticMessages.generated.js +10 -0
  108. package/dist/parser/Parser.js +29 -13
  109. package/dist/tokenizer/Token.d.ts +8 -7
  110. package/dist/tokenizer/Token.js +8 -7
  111. package/dist/tokenizer/utils/tokenFromKeyword.js +2 -0
  112. package/dist/version.generated.d.ts +1 -1
  113. package/dist/version.generated.js +1 -1
  114. package/package.json +3 -3
  115. package/dist/IR/tree_utils/_ir_lazyChooseList.d.ts +0 -3
  116. package/dist/IR/tree_utils/_ir_lazyChooseList.js +0 -7
@@ -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;
@@ -5,6 +5,7 @@ import { TirLitFailExpr } from "../../tir/expressions/litteral/TirLitFailExpr.js
5
5
  import { TirLitFalseExpr } from "../../tir/expressions/litteral/TirLitFalseExpr.js";
6
6
  import { TirLitHexBytesExpr } from "../../tir/expressions/litteral/TirLitHexBytesExpr.js";
7
7
  import { TirLitIntExpr } from "../../tir/expressions/litteral/TirLitIntExpr.js";
8
+ import { TirLitEnumMemberExpr } from "../../tir/expressions/litteral/TirLitEnumMemberExpr.js";
8
9
  import { TirLitNamedObjExpr } from "../../tir/expressions/litteral/TirLitNamedObjExpr.js";
9
10
  import { TirLitObjExpr } from "../../tir/expressions/litteral/TirLitObjExpr.js";
10
11
  import { TirLitStrExpr } from "../../tir/expressions/litteral/TirLitStrExpr.js";
@@ -38,8 +39,9 @@ import { TirUnaryMinus } from "../../tir/expressions/unary/TirUnaryMinus.js";
38
39
  import { TirUnaryPlus } from "../../tir/expressions/unary/TirUnaryPlus.js";
39
40
  import { isTirUnaryPrefixExpr } from "../../tir/expressions/unary/TirUnaryPrefixExpr.js";
40
41
  import { TirUnaryTilde } from "../../tir/expressions/unary/TirUnaryTilde.js";
41
- import { bool_t, bytes_t, data_t, int_t, valueAmountOfName } from "../../tir/program/stdScope/stdScope.js";
42
+ import { bool_t, bytes_t, data_t, int_t, valueMapAmountOfName } from "../../tir/program/stdScope/stdScope.js";
42
43
  import { IRNativeTag } from "../../../IR/IRNodes/IRNative/IRNativeTag.js";
44
+ import { currentCompilationCtx } from "../../../IR/CompilationCtx.js";
43
45
  import { TirReturnStmt } from "../../tir/statements/TirReturnStmt.js";
44
46
  import { TirArrayLikeDeconstr } from "../../tir/statements/TirVarDecl/TirArrayLikeDeconstr.js";
45
47
  import { TirNamedDeconstructVarDecl } from "../../tir/statements/TirVarDecl/TirNamedDeconstructVarDecl.js";
@@ -76,6 +78,7 @@ export function expressifyVars(ctx, expr) {
76
78
  || expr instanceof TirLitThisExpr
77
79
  || expr instanceof TirLitStrExpr
78
80
  || expr instanceof TirLitIntExpr
81
+ || expr instanceof TirLitEnumMemberExpr
79
82
  || expr instanceof TirLitHexBytesExpr
80
83
  || expr instanceof TirNativeFunc
81
84
  // hoisted expressions are necessarily closed, so no external variables
@@ -266,6 +269,7 @@ function expressifyPropAccess(ctx, propAccessExpr) {
266
269
  || expr instanceof TirLitArrExpr
267
270
  || expr instanceof TirLitStrExpr
268
271
  || expr instanceof TirLitIntExpr
272
+ || expr instanceof TirLitEnumMemberExpr
269
273
  || expr instanceof TirLitHexBytesExpr
270
274
  || expr instanceof TirNativeFunc
271
275
  || expr instanceof TirPropAccessExpr // `expressifyVars` is called recursively on the object before this check
@@ -372,6 +376,20 @@ function expressifyPropAccess(ctx, propAccessExpr) {
372
376
  throw new Error(`Property '${prop}' does not exist on type '${objType.toString()}'`);
373
377
  const fName = ctor.fields[fIdx].name;
374
378
  const fType = ctor.fields[fIdx].type;
379
+ // Untagged data structs encode as `listData(fields)` rather than
380
+ // `constrData(0, fields)`. Field access lowers directly to
381
+ // `unIData (or _inlineFromData) <$> headList (dropList idx (unListData v))`
382
+ // — no case-rewrite needed, no constructor index to check.
383
+ if (objType instanceof TirDataStructType
384
+ && objType.untagged) {
385
+ const fieldsListT = new TirListT(data_t);
386
+ return new TirFromDataExpr(new TirCallExpr(TirNativeFunc.headList(data_t), [
387
+ new TirCallExpr(TirNativeFunc.dropList(data_t), [
388
+ new TirLitIntExpr(BigInt(fIdx), propAccessExpr.range),
389
+ new TirCallExpr(TirNativeFunc.unListData, [expr], fieldsListT, propAccessExpr.range)
390
+ ], fieldsListT, propAccessExpr.range)
391
+ ], data_t, propAccessExpr.range), fType, propAccessExpr.range);
392
+ }
375
393
  return new TirCaseExpr(expr, [
376
394
  new TirCaseMatcher(new TirNamedDeconstructVarDecl(ctor.name, new Map([
377
395
  [fName, new TirSimpleVarDecl(fName, fType, undefined, true, propAccessExpr.range)]
@@ -412,7 +430,7 @@ function expressifyMethodCall(ctx, methodCall) {
412
430
  // fast-path: `Value.amountOf(policy, name)` compiles directly to
413
431
  // `_amountOfValue(eqByteString(policy))(value)(eqByteString(name))`
414
432
  // skipping the wrapper function indirection.
415
- if (tirMethodName === valueAmountOfName
433
+ if (tirMethodName === valueMapAmountOfName
416
434
  && methodCall.args.length === 2) {
417
435
  const [policyArg, nameArg] = methodCall.args;
418
436
  const bytesToBoolT = new TirFuncT([bytes_t], bool_t);
@@ -582,7 +600,8 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
582
600
  throw new Error(`Argument 1 of method 'map' of type 'list' must be a function, got '${arg.type.toString()}'`);
583
601
  const mapReturnT = argFuncType.returnType;
584
602
  const elemTypeTirName = elemsType.toTirTypeKey();
585
- let base_mapToType = _base_mapToType_cache.get(elemTypeTirName)?.clone();
603
+ const mapToTypeCache = currentCompilationCtx().mapToTypeCache;
604
+ let base_mapToType = mapToTypeCache.get(elemTypeTirName)?.clone();
586
605
  if (!base_mapToType) {
587
606
  base_mapToType = new TirHoistedExpr("_map_to_list_of_" + elemTypeTirName, new TirCallExpr(TirNativeFunc._mkMap(elemsType, mapReturnT), [new TirLitArrExpr([], new TirListT(mapReturnT), SourceRange.unknown)], new TirFuncT([
588
607
  // mapping function
@@ -593,7 +612,7 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
593
612
  new TirListT(elemsType)
594
613
  ], new TirListT(mapReturnT)), SourceRange.unknown));
595
614
  base_mapToType.varName; // precompute hash and symbol
596
- _base_mapToType_cache.set(elemTypeTirName, base_mapToType.clone());
615
+ mapToTypeCache.set(elemTypeTirName, base_mapToType.clone());
597
616
  }
598
617
  return new TirCallExpr(base_mapToType, [methodCall.args[0], objectExpr], methodCall.type, exprRange);
599
618
  }
@@ -605,7 +624,3 @@ function expressifyListMethodCall(ctx, objectExpr, methodCall, methodName, listT
605
624
  };
606
625
  */
607
626
  }
608
- const _base_mapToType_cache = new Map();
609
- export function __unsafe_clear_mapToType_cache() {
610
- _base_mapToType_cache.clear();
611
- }
@@ -20,6 +20,15 @@ export declare class TirCaseExpr implements ITirExpr {
20
20
  deps(): string[];
21
21
  get isConstant(): boolean;
22
22
  toIR(ctx: ToIRTermCtx): IRTerm;
23
+ /**
24
+ * Lowers a `case` over an untagged data struct (single constructor;
25
+ * runtime form is `listData(fields)`). No constructor dispatch is
26
+ * needed — there's only one possible ctor — so the lowering is just
27
+ * "find the matching arm (or wildcard), extract any bound fields, run
28
+ * the body".
29
+ */
30
+ private _untaggedDataStructToIR;
31
+ private _enumToIR;
23
32
  private _sopStructToIR;
24
33
  private _dataStructToIR;
25
34
  }