@elaraai/east 0.0.1-beta.8 → 1.0.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.
- package/LICENSE.md +15 -666
- package/README.md +113 -88
- package/dist/src/analyze.d.ts +3 -0
- package/dist/src/analyze.d.ts.map +1 -1
- package/dist/src/analyze.js +223 -111
- package/dist/src/analyze.js.map +1 -1
- package/dist/src/analyze.spec.d.ts +2 -0
- package/dist/src/analyze.spec.d.ts.map +1 -0
- package/dist/src/analyze.spec.js +445 -0
- package/dist/src/analyze.spec.js.map +1 -0
- package/dist/src/ast.d.ts +54 -35
- package/dist/src/ast.d.ts.map +1 -1
- package/dist/src/ast_to_ir.coerce_to.spec.d.ts +15 -0
- package/dist/src/ast_to_ir.coerce_to.spec.d.ts.map +1 -0
- package/dist/src/ast_to_ir.coerce_to.spec.js +420 -0
- package/dist/src/ast_to_ir.coerce_to.spec.js.map +1 -0
- package/dist/src/ast_to_ir.d.ts +18 -4
- package/dist/src/ast_to_ir.d.ts.map +1 -1
- package/dist/src/ast_to_ir.js +233 -178
- package/dist/src/ast_to_ir.js.map +1 -1
- package/dist/src/builtins.d.ts +1 -1
- package/dist/src/builtins.d.ts.map +1 -1
- package/dist/src/builtins.js +194 -2
- package/dist/src/builtins.js.map +1 -1
- package/dist/src/comparison.d.ts +2 -2
- package/dist/src/comparison.d.ts.map +1 -1
- package/dist/src/comparison.js +115 -40
- package/dist/src/comparison.js.map +1 -1
- package/dist/src/comparison.spec.d.ts +2 -0
- package/dist/src/comparison.spec.d.ts.map +1 -0
- package/dist/src/comparison.spec.js +1200 -0
- package/dist/src/comparison.spec.js.map +1 -0
- package/dist/src/compile.d.ts +31 -9
- package/dist/src/compile.d.ts.map +1 -1
- package/dist/src/compile.js +1048 -548
- package/dist/src/compile.js.map +1 -1
- package/dist/src/containers/matrix.d.ts +15 -0
- package/dist/src/containers/matrix.d.ts.map +1 -0
- package/dist/src/containers/matrix.js +15 -0
- package/dist/src/containers/matrix.js.map +1 -0
- package/dist/src/containers/ref.d.ts.map +1 -1
- package/dist/src/containers/ref.js +1 -1
- package/dist/src/containers/ref.js.map +1 -1
- package/dist/src/containers/sortedmap.spec.d.ts +2 -0
- package/dist/src/containers/sortedmap.spec.d.ts.map +1 -0
- package/dist/src/containers/sortedmap.spec.js +180 -0
- package/dist/src/containers/sortedmap.spec.js.map +1 -0
- package/dist/src/containers/sortedset.spec.d.ts +2 -0
- package/dist/src/containers/sortedset.spec.d.ts.map +1 -0
- package/dist/src/containers/sortedset.spec.js +228 -0
- package/dist/src/containers/sortedset.spec.js.map +1 -0
- package/dist/src/containers/variant.d.ts.map +1 -1
- package/dist/src/containers/variant.js +1 -1
- package/dist/src/containers/variant.js.map +1 -1
- package/dist/src/containers/variant.spec.d.ts +2 -0
- package/dist/src/containers/variant.spec.d.ts.map +1 -0
- package/dist/src/containers/variant.spec.js +217 -0
- package/dist/src/containers/variant.spec.js.map +1 -0
- package/dist/src/datetime_format/parse.spec.d.ts +6 -0
- package/dist/src/datetime_format/parse.spec.d.ts.map +1 -0
- package/dist/src/datetime_format/parse.spec.js +379 -0
- package/dist/src/datetime_format/parse.spec.js.map +1 -0
- package/dist/src/datetime_format/print.spec.d.ts +6 -0
- package/dist/src/datetime_format/print.spec.d.ts.map +1 -0
- package/dist/src/datetime_format/print.spec.js +257 -0
- package/dist/src/datetime_format/print.spec.js.map +1 -0
- package/dist/src/datetime_format/tokenize.spec.d.ts +2 -0
- package/dist/src/datetime_format/tokenize.spec.d.ts.map +1 -0
- package/dist/src/datetime_format/tokenize.spec.js +508 -0
- package/dist/src/datetime_format/tokenize.spec.js.map +1 -0
- package/dist/src/datetime_format/types.d.ts +23 -23
- package/dist/src/default.d.ts.map +1 -1
- package/dist/src/default.js +33 -0
- package/dist/src/default.js.map +1 -1
- package/dist/src/default.spec.d.ts +2 -0
- package/dist/src/default.spec.d.ts.map +1 -0
- package/dist/src/default.spec.js +178 -0
- package/dist/src/default.spec.js.map +1 -0
- package/dist/src/eastir.d.ts +7 -0
- package/dist/src/eastir.d.ts.map +1 -1
- package/dist/src/eastir.js +55 -7
- package/dist/src/eastir.js.map +1 -1
- package/dist/src/error.d.ts +14 -4
- package/dist/src/error.d.ts.map +1 -1
- package/dist/src/error.js +28 -3
- package/dist/src/error.js.map +1 -1
- package/dist/src/example.d.ts +87 -0
- package/dist/src/example.d.ts.map +1 -0
- package/dist/src/example.js +18 -0
- package/dist/src/example.js.map +1 -0
- package/dist/src/expr/array.d.ts +43 -1
- package/dist/src/expr/array.d.ts.map +1 -1
- package/dist/src/expr/array.js +103 -53
- package/dist/src/expr/array.js.map +1 -1
- package/dist/src/expr/ast.d.ts +1 -1
- package/dist/src/expr/ast.d.ts.map +1 -1
- package/dist/src/expr/ast.js +112 -54
- package/dist/src/expr/ast.js.map +1 -1
- package/dist/src/expr/asyncfunction.d.ts.map +1 -1
- package/dist/src/expr/asyncfunction.js +6 -4
- package/dist/src/expr/asyncfunction.js.map +1 -1
- package/dist/src/expr/blob.d.ts +48 -0
- package/dist/src/expr/blob.d.ts.map +1 -1
- package/dist/src/expr/blob.js +63 -8
- package/dist/src/expr/blob.js.map +1 -1
- package/dist/src/expr/block.d.ts +213 -12
- package/dist/src/expr/block.d.ts.map +1 -1
- package/dist/src/expr/block.js +796 -293
- package/dist/src/expr/block.js.map +1 -1
- package/dist/src/expr/boolean.d.ts +44 -0
- package/dist/src/expr/boolean.d.ts.map +1 -1
- package/dist/src/expr/boolean.js +58 -6
- package/dist/src/expr/boolean.js.map +1 -1
- package/dist/src/expr/datetime.d.ts +135 -0
- package/dist/src/expr/datetime.d.ts.map +1 -1
- package/dist/src/expr/datetime.js +184 -34
- package/dist/src/expr/datetime.js.map +1 -1
- package/dist/src/expr/dict.d.ts +47 -2
- package/dist/src/expr/dict.d.ts.map +1 -1
- package/dist/src/expr/dict.js +122 -61
- package/dist/src/expr/dict.js.map +1 -1
- package/dist/src/expr/expr.d.ts +3 -1
- package/dist/src/expr/expr.d.ts.map +1 -1
- package/dist/src/expr/expr.js +4 -3
- package/dist/src/expr/expr.js.map +1 -1
- package/dist/src/expr/float.d.ts +153 -0
- package/dist/src/expr/float.d.ts.map +1 -1
- package/dist/src/expr/float.js +191 -17
- package/dist/src/expr/float.js.map +1 -1
- package/dist/src/expr/function.d.ts +7 -2
- package/dist/src/expr/function.d.ts.map +1 -1
- package/dist/src/expr/function.js +6 -4
- package/dist/src/expr/function.js.map +1 -1
- package/dist/src/expr/index.d.ts +186 -2
- package/dist/src/expr/index.d.ts.map +1 -1
- package/dist/src/expr/index.js +183 -2
- package/dist/src/expr/index.js.map +1 -1
- package/dist/src/expr/integer.d.ts +180 -0
- package/dist/src/expr/integer.d.ts.map +1 -1
- package/dist/src/expr/integer.js +189 -18
- package/dist/src/expr/integer.js.map +1 -1
- package/dist/src/expr/libs/array.js +3 -3
- package/dist/src/expr/libs/array.js.map +1 -1
- package/dist/src/expr/libs/blob.js +3 -3
- package/dist/src/expr/libs/blob.js.map +1 -1
- package/dist/src/expr/libs/dict.js +1 -1
- package/dist/src/expr/libs/dict.js.map +1 -1
- package/dist/src/expr/libs/matrix.d.ts +17 -0
- package/dist/src/expr/libs/matrix.d.ts.map +1 -0
- package/dist/src/expr/libs/matrix.js +60 -0
- package/dist/src/expr/libs/matrix.js.map +1 -0
- package/dist/src/expr/libs/set.js +1 -1
- package/dist/src/expr/libs/set.js.map +1 -1
- package/dist/src/expr/libs/string.d.ts.map +1 -1
- package/dist/src/expr/libs/string.js +2 -1
- package/dist/src/expr/libs/string.js.map +1 -1
- package/dist/src/expr/libs/vector.d.ts +16 -0
- package/dist/src/expr/libs/vector.d.ts.map +1 -0
- package/dist/src/expr/libs/vector.js +44 -0
- package/dist/src/expr/libs/vector.js.map +1 -0
- package/dist/src/expr/matrix.d.ts +109 -0
- package/dist/src/expr/matrix.d.ts.map +1 -0
- package/dist/src/expr/matrix.js +224 -0
- package/dist/src/expr/matrix.js.map +1 -0
- package/dist/src/expr/recursive.d.ts +83 -0
- package/dist/src/expr/recursive.d.ts.map +1 -0
- package/dist/src/expr/recursive.js +99 -0
- package/dist/src/expr/recursive.js.map +1 -0
- package/dist/src/expr/ref.js +5 -5
- package/dist/src/expr/ref.js.map +1 -1
- package/dist/src/expr/set.d.ts +44 -2
- package/dist/src/expr/set.d.ts.map +1 -1
- package/dist/src/expr/set.js +102 -52
- package/dist/src/expr/set.js.map +1 -1
- package/dist/src/expr/string.d.ts +134 -0
- package/dist/src/expr/string.d.ts.map +1 -1
- package/dist/src/expr/string.js +173 -23
- package/dist/src/expr/string.js.map +1 -1
- package/dist/src/expr/struct.d.ts +1 -1
- package/dist/src/expr/struct.d.ts.map +1 -1
- package/dist/src/expr/struct.js +2 -2
- package/dist/src/expr/struct.js.map +1 -1
- package/dist/src/expr/types.d.ts +12 -9
- package/dist/src/expr/types.d.ts.map +1 -1
- package/dist/src/expr/variant.d.ts +108 -11
- package/dist/src/expr/variant.d.ts.map +1 -1
- package/dist/src/expr/variant.js +76 -38
- package/dist/src/expr/variant.js.map +1 -1
- package/dist/src/expr/vector.d.ts +102 -0
- package/dist/src/expr/vector.d.ts.map +1 -0
- package/dist/src/expr/vector.js +202 -0
- package/dist/src/expr/vector.js.map +1 -0
- package/dist/src/fuzz.d.ts +36 -2
- package/dist/src/fuzz.d.ts.map +1 -1
- package/dist/src/fuzz.js +409 -77
- package/dist/src/fuzz.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal.d.ts +12 -2
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +13 -2
- package/dist/src/internal.js.map +1 -1
- package/dist/src/ir.d.ts +1754 -1484
- package/dist/src/ir.d.ts.map +1 -1
- package/dist/src/ir.js +51 -34
- package/dist/src/ir.js.map +1 -1
- package/dist/src/ir.spec.d.ts +2 -0
- package/dist/src/ir.spec.d.ts.map +1 -0
- package/dist/src/ir.spec.js +35 -0
- package/dist/src/ir.spec.js.map +1 -0
- package/dist/src/location.d.ts +56 -17
- package/dist/src/location.d.ts.map +1 -1
- package/dist/src/location.js +226 -29
- package/dist/src/location.js.map +1 -1
- package/dist/src/location.spec.d.ts +2 -0
- package/dist/src/location.spec.d.ts.map +1 -0
- package/dist/src/location.spec.js +102 -0
- package/dist/src/location.spec.js.map +1 -0
- package/dist/src/patch/apply.d.ts +15 -0
- package/dist/src/patch/apply.d.ts.map +1 -0
- package/dist/src/patch/apply.js +352 -0
- package/dist/src/patch/apply.js.map +1 -0
- package/dist/src/patch/compose.d.ts +15 -0
- package/dist/src/patch/compose.d.ts.map +1 -0
- package/dist/src/patch/compose.js +448 -0
- package/dist/src/patch/compose.js.map +1 -0
- package/dist/src/patch/diff.d.ts +15 -0
- package/dist/src/patch/diff.d.ts.map +1 -0
- package/dist/src/patch/diff.js +347 -0
- package/dist/src/patch/diff.js.map +1 -0
- package/dist/src/patch/fuzz.d.ts +73 -0
- package/dist/src/patch/fuzz.d.ts.map +1 -0
- package/dist/src/patch/fuzz.js +159 -0
- package/dist/src/patch/fuzz.js.map +1 -0
- package/dist/src/patch/index.d.ts +32 -0
- package/dist/src/patch/index.d.ts.map +1 -0
- package/dist/src/patch/index.js +48 -0
- package/dist/src/patch/index.js.map +1 -0
- package/dist/src/patch/invert.d.ts +15 -0
- package/dist/src/patch/invert.d.ts.map +1 -0
- package/dist/src/patch/invert.js +284 -0
- package/dist/src/patch/invert.js.map +1 -0
- package/dist/src/patch/merge.d.ts +56 -0
- package/dist/src/patch/merge.d.ts.map +1 -0
- package/dist/src/patch/merge.js +586 -0
- package/dist/src/patch/merge.js.map +1 -0
- package/dist/src/patch/merge.spec.d.ts +2 -0
- package/dist/src/patch/merge.spec.d.ts.map +1 -0
- package/dist/src/patch/merge.spec.js +1139 -0
- package/dist/src/patch/merge.spec.js.map +1 -0
- package/dist/src/patch/patch.spec.d.ts +2 -0
- package/dist/src/patch/patch.spec.d.ts.map +1 -0
- package/dist/src/patch/patch.spec.js +452 -0
- package/dist/src/patch/patch.spec.js.map +1 -0
- package/dist/src/patch/path.d.ts +115 -0
- package/dist/src/patch/path.d.ts.map +1 -0
- package/dist/src/patch/path.js +192 -0
- package/dist/src/patch/path.js.map +1 -0
- package/dist/src/patch/path.spec.d.ts +6 -0
- package/dist/src/patch/path.spec.d.ts.map +1 -0
- package/dist/src/patch/path.spec.js +322 -0
- package/dist/src/patch/path.spec.js.map +1 -0
- package/dist/src/patch/prune.d.ts +77 -0
- package/dist/src/patch/prune.d.ts.map +1 -0
- package/dist/src/patch/prune.js +115 -0
- package/dist/src/patch/prune.js.map +1 -0
- package/dist/src/patch/prune.spec.d.ts +6 -0
- package/dist/src/patch/prune.spec.d.ts.map +1 -0
- package/dist/src/patch/prune.spec.js +473 -0
- package/dist/src/patch/prune.spec.js.map +1 -0
- package/dist/src/patch/type_of_patch.d.ts +25 -0
- package/dist/src/patch/type_of_patch.d.ts.map +1 -0
- package/dist/src/patch/type_of_patch.js +144 -0
- package/dist/src/patch/type_of_patch.js.map +1 -0
- package/dist/src/patch/types.d.ts +220 -0
- package/dist/src/patch/types.d.ts.map +1 -0
- package/dist/src/patch/types.js +62 -0
- package/dist/src/patch/types.js.map +1 -0
- package/dist/src/patch/validate.d.ts +44 -0
- package/dist/src/patch/validate.d.ts.map +1 -0
- package/dist/src/patch/validate.js +190 -0
- package/dist/src/patch/validate.js.map +1 -0
- package/dist/src/patch/validate.spec.d.ts +6 -0
- package/dist/src/patch/validate.spec.d.ts.map +1 -0
- package/dist/src/patch/validate.spec.js +225 -0
- package/dist/src/patch/validate.spec.js.map +1 -0
- package/dist/src/patch/walk.d.ts +121 -0
- package/dist/src/patch/walk.d.ts.map +1 -0
- package/dist/src/patch/walk.js +385 -0
- package/dist/src/patch/walk.js.map +1 -0
- package/dist/src/patch/walk.spec.d.ts +6 -0
- package/dist/src/patch/walk.spec.d.ts.map +1 -0
- package/dist/src/patch/walk.spec.js +621 -0
- package/dist/src/patch/walk.spec.js.map +1 -0
- package/dist/src/platform.d.ts +6 -0
- package/dist/src/platform.d.ts.map +1 -1
- package/dist/src/platform.spec.d.ts +2 -0
- package/dist/src/platform.spec.d.ts.map +1 -0
- package/dist/src/platform.spec.js +330 -0
- package/dist/src/platform.spec.js.map +1 -0
- package/dist/src/serialization/beast.d.ts.map +1 -1
- package/dist/src/serialization/beast.js +12 -0
- package/dist/src/serialization/beast.js.map +1 -1
- package/dist/src/serialization/beast.spec.d.ts +6 -0
- package/dist/src/serialization/beast.spec.d.ts.map +1 -0
- package/dist/src/serialization/beast.spec.js +406 -0
- package/dist/src/serialization/beast.spec.js.map +1 -0
- package/dist/src/serialization/beast2/index.d.ts +50 -0
- package/dist/src/serialization/beast2/index.d.ts.map +1 -0
- package/dist/src/serialization/beast2/index.js +756 -0
- package/dist/src/serialization/beast2/index.js.map +1 -0
- package/dist/src/serialization/beast2/index.spec.d.ts +6 -0
- package/dist/src/serialization/beast2/index.spec.d.ts.map +1 -0
- package/dist/src/serialization/beast2/index.spec.js +528 -0
- package/dist/src/serialization/beast2/index.spec.js.map +1 -0
- package/dist/src/serialization/beast2/sourcemap-table.d.ts +29 -0
- package/dist/src/serialization/beast2/sourcemap-table.d.ts.map +1 -0
- package/dist/src/serialization/beast2/sourcemap-table.js +82 -0
- package/dist/src/serialization/beast2/sourcemap-table.js.map +1 -0
- package/dist/src/serialization/beast2/string-table.d.ts +16 -0
- package/dist/src/serialization/beast2/string-table.d.ts.map +1 -0
- package/dist/src/serialization/beast2/string-table.js +38 -0
- package/dist/src/serialization/beast2/string-table.js.map +1 -0
- package/dist/src/serialization/beast2/type-table.d.ts +86 -0
- package/dist/src/serialization/beast2/type-table.d.ts.map +1 -0
- package/dist/src/serialization/beast2/type-table.js +618 -0
- package/dist/src/serialization/beast2/type-table.js.map +1 -0
- package/dist/src/serialization/beast2/value-table.d.ts +40 -0
- package/dist/src/serialization/beast2/value-table.d.ts.map +1 -0
- package/dist/src/serialization/beast2/value-table.js +157 -0
- package/dist/src/serialization/beast2/value-table.js.map +1 -0
- package/dist/src/serialization/binary-utils.d.ts +33 -0
- package/dist/src/serialization/binary-utils.d.ts.map +1 -1
- package/dist/src/serialization/binary-utils.js +157 -0
- package/dist/src/serialization/binary-utils.js.map +1 -1
- package/dist/src/serialization/csv.d.ts +17 -17
- package/dist/src/serialization/csv.d.ts.map +1 -1
- package/dist/src/serialization/csv.js +10 -8
- package/dist/src/serialization/csv.js.map +1 -1
- package/dist/src/serialization/csv.spec.d.ts +2 -0
- package/dist/src/serialization/csv.spec.d.ts.map +1 -0
- package/dist/src/serialization/csv.spec.js +556 -0
- package/dist/src/serialization/csv.spec.js.map +1 -0
- package/dist/src/serialization/east-inferred.spec.d.ts +2 -0
- package/dist/src/serialization/east-inferred.spec.d.ts.map +1 -0
- package/dist/src/serialization/east-inferred.spec.js +322 -0
- package/dist/src/serialization/east-inferred.spec.js.map +1 -0
- package/dist/src/serialization/east.d.ts +1 -1
- package/dist/src/serialization/east.d.ts.map +1 -1
- package/dist/src/serialization/east.js +178 -26
- package/dist/src/serialization/east.js.map +1 -1
- package/dist/src/serialization/east.spec.d.ts +2 -0
- package/dist/src/serialization/east.spec.d.ts.map +1 -0
- package/dist/src/serialization/east.spec.js +1548 -0
- package/dist/src/serialization/east.spec.js.map +1 -0
- package/dist/src/serialization/index.d.ts +1 -2
- package/dist/src/serialization/index.d.ts.map +1 -1
- package/dist/src/serialization/index.js +1 -2
- package/dist/src/serialization/index.js.map +1 -1
- package/dist/src/serialization/json.d.ts +1 -1
- package/dist/src/serialization/json.d.ts.map +1 -1
- package/dist/src/serialization/json.js +123 -24
- package/dist/src/serialization/json.js.map +1 -1
- package/dist/src/serialization/json.spec.d.ts +2 -0
- package/dist/src/serialization/json.spec.d.ts.map +1 -0
- package/dist/src/serialization/json.spec.js +1297 -0
- package/dist/src/serialization/json.spec.js.map +1 -0
- package/dist/src/type_of_type.d.ts +72 -35
- package/dist/src/type_of_type.d.ts.map +1 -1
- package/dist/src/type_of_type.is_data.spec.d.ts +6 -0
- package/dist/src/type_of_type.is_data.spec.d.ts.map +1 -0
- package/dist/src/type_of_type.is_data.spec.js +221 -0
- package/dist/src/type_of_type.is_data.spec.js.map +1 -0
- package/dist/src/type_of_type.js +355 -80
- package/dist/src/type_of_type.js.map +1 -1
- package/dist/src/type_of_type.to_etv.spec.d.ts +6 -0
- package/dist/src/type_of_type.to_etv.spec.d.ts.map +1 -0
- package/dist/src/type_of_type.to_etv.spec.js +263 -0
- package/dist/src/type_of_type.to_etv.spec.js.map +1 -0
- package/dist/src/types.d.ts +82 -12
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.error.spec.d.ts +2 -0
- package/dist/src/types.error.spec.d.ts.map +1 -0
- package/dist/src/types.error.spec.js +665 -0
- package/dist/src/types.error.spec.js.map +1 -0
- package/dist/src/types.js +663 -156
- package/dist/src/types.js.map +1 -1
- package/dist/src/types.spec.d.ts +2 -0
- package/dist/src/types.spec.d.ts.map +1 -0
- package/dist/src/types.spec.js +946 -0
- package/dist/src/types.spec.js.map +1 -0
- package/dist/src/walker.d.ts +65 -0
- package/dist/src/walker.d.ts.map +1 -0
- package/dist/src/walker.js +165 -0
- package/dist/src/walker.js.map +1 -0
- package/dist/src/walker.spec.d.ts +6 -0
- package/dist/src/walker.spec.d.ts.map +1 -0
- package/dist/src/walker.spec.js +109 -0
- package/dist/src/walker.spec.js.map +1 -0
- package/package.json +16 -38
- package/dist/src/serialization/beast2-stream.d.ts +0 -38
- package/dist/src/serialization/beast2-stream.d.ts.map +0 -1
- package/dist/src/serialization/beast2-stream.js +0 -670
- package/dist/src/serialization/beast2-stream.js.map +0 -1
- package/dist/src/serialization/beast2.d.ts +0 -41
- package/dist/src/serialization/beast2.d.ts.map +0 -1
- package/dist/src/serialization/beast2.js +0 -495
- package/dist/src/serialization/beast2.js.map +0 -1
package/dist/src/types.js
CHANGED
|
@@ -6,6 +6,58 @@ import { isRef } from "./containers/ref.js";
|
|
|
6
6
|
import { SortedMap } from "./containers/sortedmap.js";
|
|
7
7
|
import { SortedSet } from "./containers/sortedset.js";
|
|
8
8
|
import { variant_symbol } from "./containers/variant.js";
|
|
9
|
+
import { isMatrix } from "./containers/matrix.js";
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Type identity — every EastType gets a unique integer ID via a Symbol property.
|
|
12
|
+
// This enables O(1) identity-based lookup across independently constructed
|
|
13
|
+
// type objects that are structurally identical. Mirrors east-c's pointer interning.
|
|
14
|
+
// =============================================================================
|
|
15
|
+
export const type_id_symbol = Symbol.for("@elaraai/east/type_id");
|
|
16
|
+
let _next_type_id = 0;
|
|
17
|
+
/** Assign a unique type_id to an EastType. Called by every type constructor. */
|
|
18
|
+
export function assignTypeId(type) {
|
|
19
|
+
type[type_id_symbol] = _next_type_id++;
|
|
20
|
+
return type;
|
|
21
|
+
}
|
|
22
|
+
/** Get the type_id of an EastType, EastTypeValue, or any stamped object. */
|
|
23
|
+
export function getTypeId(type) {
|
|
24
|
+
return type?.[type_id_symbol];
|
|
25
|
+
}
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// Type interning — ensures structurally identical compound types share identity.
|
|
28
|
+
// Mirrors east-c's pointer-based hash table interning.
|
|
29
|
+
// Uses integer hashing of child type_ids for O(1) lookup with zero GC pressure.
|
|
30
|
+
// =============================================================================
|
|
31
|
+
function hashCombine(h, v) {
|
|
32
|
+
return ((h ^ v) * 0x01000193) | 0;
|
|
33
|
+
}
|
|
34
|
+
// Intern table: hash → type. On collision we chain (store array).
|
|
35
|
+
const _intern = new Map();
|
|
36
|
+
function internLookup(hash, verify) {
|
|
37
|
+
const entry = _intern.get(hash);
|
|
38
|
+
if (entry === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
if (Array.isArray(entry)) {
|
|
41
|
+
for (const candidate of entry) {
|
|
42
|
+
if (verify(candidate))
|
|
43
|
+
return candidate;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return verify(entry) ? entry : undefined;
|
|
48
|
+
}
|
|
49
|
+
function internStore(hash, type) {
|
|
50
|
+
const existing = _intern.get(hash);
|
|
51
|
+
if (existing === undefined) {
|
|
52
|
+
_intern.set(hash, type);
|
|
53
|
+
}
|
|
54
|
+
else if (Array.isArray(existing)) {
|
|
55
|
+
existing.push(type);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
_intern.set(hash, [existing, type]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
9
61
|
/**
|
|
10
62
|
* Error thrown when type operations encounter incompatible types.
|
|
11
63
|
*
|
|
@@ -13,28 +65,52 @@ import { variant_symbol } from "./containers/variant.js";
|
|
|
13
65
|
* Used by type union, intersection, and equality operations when types
|
|
14
66
|
* cannot be combined or compared as requested.
|
|
15
67
|
*/
|
|
16
|
-
class TypeMismatchError extends Error {
|
|
17
|
-
|
|
18
|
-
|
|
68
|
+
export class TypeMismatchError extends Error {
|
|
69
|
+
path;
|
|
70
|
+
reason;
|
|
71
|
+
constructor(reason, options) {
|
|
72
|
+
super(reason, options);
|
|
19
73
|
this.name = "TypeMismatchError";
|
|
74
|
+
this.reason = reason;
|
|
75
|
+
this.path = [];
|
|
76
|
+
}
|
|
77
|
+
addPathSegment(segment) {
|
|
78
|
+
this.path.unshift(segment);
|
|
79
|
+
this.message = `at ${this.path.join("")}: ${this.reason}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function withPathSegment(segment, fn) {
|
|
83
|
+
try {
|
|
84
|
+
return fn();
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
if (err instanceof TypeMismatchError)
|
|
88
|
+
err.addPathSegment(segment);
|
|
89
|
+
throw err;
|
|
20
90
|
}
|
|
21
91
|
}
|
|
22
92
|
/** Singleton instance of the Never type. */
|
|
23
|
-
export const NeverType = { type: "Never" };
|
|
93
|
+
export const NeverType = assignTypeId({ type: "Never" });
|
|
24
94
|
/** Singleton instance of the Null type. */
|
|
25
|
-
export const NullType = { type: "Null" };
|
|
95
|
+
export const NullType = assignTypeId({ type: "Null" });
|
|
26
96
|
/** Singleton instance of the Boolean type. */
|
|
27
|
-
export const BooleanType = { type: "Boolean" };
|
|
97
|
+
export const BooleanType = assignTypeId({ type: "Boolean" });
|
|
28
98
|
/** Singleton instance of the Integer type. */
|
|
29
|
-
export const IntegerType = { type: "Integer" };
|
|
99
|
+
export const IntegerType = assignTypeId({ type: "Integer" });
|
|
30
100
|
/** Singleton instance of the Float type. */
|
|
31
|
-
export const FloatType = { type: "Float" };
|
|
101
|
+
export const FloatType = assignTypeId({ type: "Float" });
|
|
32
102
|
/** Singleton instance of the String type. */
|
|
33
|
-
export const StringType = { type: "String" };
|
|
103
|
+
export const StringType = assignTypeId({ type: "String" });
|
|
34
104
|
/** Singleton instance of the DateTime type. */
|
|
35
|
-
export const DateTimeType = { type: "DateTime" };
|
|
105
|
+
export const DateTimeType = assignTypeId({ type: "DateTime" });
|
|
36
106
|
/** Singleton instance of the Blob type. */
|
|
37
|
-
export const BlobType = { type: "Blob" };
|
|
107
|
+
export const BlobType = assignTypeId({ type: "Blob" });
|
|
108
|
+
/** Returns true if the type is a primitive (no child types, no refs possible). */
|
|
109
|
+
export function isPrimitiveType(type) {
|
|
110
|
+
const t = type.type;
|
|
111
|
+
return t === "Never" || t === "Null" || t === "Boolean" || t === "Integer" ||
|
|
112
|
+
t === "Float" || t === "String" || t === "DateTime" || t === "Blob";
|
|
113
|
+
}
|
|
38
114
|
/**
|
|
39
115
|
* Constructs a reference (or cell) type with the specified element type.
|
|
40
116
|
*
|
|
@@ -48,7 +124,13 @@ export const BlobType = { type: "Blob" };
|
|
|
48
124
|
* @throws When the element type contains functions
|
|
49
125
|
*/
|
|
50
126
|
export function RefType(type) {
|
|
51
|
-
|
|
127
|
+
const h = hashCombine(0x52, type?.[type_id_symbol] ?? 0);
|
|
128
|
+
const cached = internLookup(h, (c) => c.type === "Ref" && c.value === type);
|
|
129
|
+
if (cached)
|
|
130
|
+
return cached;
|
|
131
|
+
const result = assignTypeId({ type: "Ref", value: type });
|
|
132
|
+
internStore(h, result);
|
|
133
|
+
return result;
|
|
52
134
|
}
|
|
53
135
|
;
|
|
54
136
|
/**
|
|
@@ -60,7 +142,13 @@ export function RefType(type) {
|
|
|
60
142
|
* @throws When the element type contains functions
|
|
61
143
|
*/
|
|
62
144
|
export function ArrayType(type) {
|
|
63
|
-
|
|
145
|
+
const h = hashCombine(0x41, type?.[type_id_symbol] ?? 0);
|
|
146
|
+
const cached = internLookup(h, (c) => c.type === "Array" && c.value === type);
|
|
147
|
+
if (cached)
|
|
148
|
+
return cached;
|
|
149
|
+
const result = assignTypeId({ type: "Array", value: type });
|
|
150
|
+
internStore(h, result);
|
|
151
|
+
return result;
|
|
64
152
|
}
|
|
65
153
|
;
|
|
66
154
|
/**
|
|
@@ -75,7 +163,13 @@ export function SetType(type) {
|
|
|
75
163
|
if (typeof type !== "string" && !isImmutableType(type)) {
|
|
76
164
|
throw new Error(`Set key type must be an immutable type, got ${printType(type)}`);
|
|
77
165
|
}
|
|
78
|
-
|
|
166
|
+
const h = hashCombine(0x53, type?.[type_id_symbol] ?? 0);
|
|
167
|
+
const cached = internLookup(h, (c) => c.type === "Set" && c.key === type);
|
|
168
|
+
if (cached)
|
|
169
|
+
return cached;
|
|
170
|
+
const result = assignTypeId({ type: "Set", key: type });
|
|
171
|
+
internStore(h, result);
|
|
172
|
+
return result;
|
|
79
173
|
}
|
|
80
174
|
;
|
|
81
175
|
/**
|
|
@@ -92,7 +186,14 @@ export function DictType(key, value) {
|
|
|
92
186
|
if (typeof key !== "string" && !isImmutableType(key)) {
|
|
93
187
|
throw new Error(`Dict key type must be an immutable type, got ${printType(key)}`);
|
|
94
188
|
}
|
|
95
|
-
|
|
189
|
+
let h = hashCombine(0x44, key?.[type_id_symbol] ?? 0);
|
|
190
|
+
h = hashCombine(h, value?.[type_id_symbol] ?? 0);
|
|
191
|
+
const cached = internLookup(h, (c) => c.type === "Dict" && c.key === key && c.value === value);
|
|
192
|
+
if (cached)
|
|
193
|
+
return cached;
|
|
194
|
+
const result = assignTypeId({ type: "Dict", key, value });
|
|
195
|
+
internStore(h, result);
|
|
196
|
+
return result;
|
|
96
197
|
}
|
|
97
198
|
;
|
|
98
199
|
/**
|
|
@@ -103,7 +204,35 @@ export function DictType(key, value) {
|
|
|
103
204
|
* @returns A Struct type
|
|
104
205
|
*/
|
|
105
206
|
export function StructType(field_types) {
|
|
106
|
-
|
|
207
|
+
// Intern: structurally identical struct types (same field order, same names,
|
|
208
|
+
// same child type_ids) share a single canonical object. This mirrors the
|
|
209
|
+
// existing interning for Array/Dict/Function etc. and is required for the
|
|
210
|
+
// beast2 v2 encoder to produce a canonical type table — otherwise calling
|
|
211
|
+
// StructType({ x: Int, y: Int }) twice would yield two distinct entries.
|
|
212
|
+
const keys = Object.keys(field_types);
|
|
213
|
+
let h = hashCombine(0x09, keys.length);
|
|
214
|
+
for (const k of keys) {
|
|
215
|
+
h = hashCombine(h, field_types[k]?.[type_id_symbol] ?? 0);
|
|
216
|
+
}
|
|
217
|
+
const cached = internLookup(h, (c) => {
|
|
218
|
+
if (c.type !== "Struct")
|
|
219
|
+
return false;
|
|
220
|
+
const ck = Object.keys(c.fields);
|
|
221
|
+
if (ck.length !== keys.length)
|
|
222
|
+
return false;
|
|
223
|
+
for (let i = 0; i < keys.length; i++) {
|
|
224
|
+
if (ck[i] !== keys[i])
|
|
225
|
+
return false;
|
|
226
|
+
if (c.fields[keys[i]] !== field_types[keys[i]])
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
});
|
|
231
|
+
if (cached)
|
|
232
|
+
return cached;
|
|
233
|
+
const result = assignTypeId({ type: "Struct", fields: field_types });
|
|
234
|
+
internStore(h, result);
|
|
235
|
+
return result;
|
|
107
236
|
}
|
|
108
237
|
;
|
|
109
238
|
/**
|
|
@@ -116,7 +245,33 @@ export function StructType(field_types) {
|
|
|
116
245
|
export function VariantType(case_types) {
|
|
117
246
|
// Cases are sorted alphabetically by their name
|
|
118
247
|
const cases_sorted = Object.fromEntries(Object.entries(case_types).sort((x, y) => x[0] < y[0] ? -1 : x[0] === y[0] ? 0 : 1));
|
|
119
|
-
|
|
248
|
+
// Intern: match Struct. Hash is computed over the sorted keys so two calls
|
|
249
|
+
// with cases in different orders produce the same hash, and verify confirms
|
|
250
|
+
// identical names and child type_ids.
|
|
251
|
+
const keys = Object.keys(cases_sorted);
|
|
252
|
+
let h = hashCombine(0x08, keys.length);
|
|
253
|
+
for (const k of keys) {
|
|
254
|
+
h = hashCombine(h, cases_sorted[k]?.[type_id_symbol] ?? 0);
|
|
255
|
+
}
|
|
256
|
+
const cached = internLookup(h, (c) => {
|
|
257
|
+
if (c.type !== "Variant")
|
|
258
|
+
return false;
|
|
259
|
+
const ck = Object.keys(c.cases);
|
|
260
|
+
if (ck.length !== keys.length)
|
|
261
|
+
return false;
|
|
262
|
+
for (let i = 0; i < keys.length; i++) {
|
|
263
|
+
if (ck[i] !== keys[i])
|
|
264
|
+
return false;
|
|
265
|
+
if (c.cases[keys[i]] !== cases_sorted[keys[i]])
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
return true;
|
|
269
|
+
});
|
|
270
|
+
if (cached)
|
|
271
|
+
return cached;
|
|
272
|
+
const result = assignTypeId({ type: "Variant", cases: cases_sorted });
|
|
273
|
+
internStore(h, result);
|
|
274
|
+
return result;
|
|
120
275
|
}
|
|
121
276
|
;
|
|
122
277
|
/**
|
|
@@ -197,6 +352,9 @@ function validateNotMutuallyRecursive(type, allowedMarker) {
|
|
|
197
352
|
t.inputs.forEach(input => check(input, allowed));
|
|
198
353
|
check(t.output, allowed);
|
|
199
354
|
}
|
|
355
|
+
else if (t.type === "Vector" || t.type === "Matrix") {
|
|
356
|
+
check(t.element, allowed);
|
|
357
|
+
}
|
|
200
358
|
// Primitive types don't need recursion
|
|
201
359
|
}
|
|
202
360
|
check(type, true);
|
|
@@ -237,14 +395,24 @@ function validateNotMutuallyRecursive(type, allowedMarker) {
|
|
|
237
395
|
* ```
|
|
238
396
|
*/
|
|
239
397
|
export function RecursiveType(f) {
|
|
240
|
-
const ret = { type: "Recursive", node: undefined };
|
|
398
|
+
const ret = assignTypeId({ type: "Recursive", node: undefined });
|
|
241
399
|
const type = f(ret);
|
|
242
400
|
ret.node = type;
|
|
243
401
|
// Validate SCC size 1 (no nested RecursiveTypes with cross-references)
|
|
244
402
|
validateNotMutuallyRecursive(type, ret);
|
|
403
|
+
// Intern: if a structurally identical RecursiveType already exists, reuse it.
|
|
404
|
+
// This ensures two independently-created RecursiveTypes with the same structure
|
|
405
|
+
// share a single type_id, making id-based Recursive refs work correctly.
|
|
406
|
+
for (const existing of _recursiveIntern) {
|
|
407
|
+
if (isTypeEqual(existing, ret)) {
|
|
408
|
+
return existing;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
_recursiveIntern.push(ret);
|
|
245
412
|
return ret;
|
|
246
413
|
}
|
|
247
414
|
;
|
|
415
|
+
const _recursiveIntern = [];
|
|
248
416
|
/**
|
|
249
417
|
* Constructs a Function type with the specified input and output types.
|
|
250
418
|
*
|
|
@@ -255,7 +423,17 @@ export function RecursiveType(f) {
|
|
|
255
423
|
* @see {@link AsyncFunctionType} for asynchronous functions.
|
|
256
424
|
*/
|
|
257
425
|
export function FunctionType(inputs, output) {
|
|
258
|
-
|
|
426
|
+
let h = hashCombine(0x46, inputs.length);
|
|
427
|
+
for (const inp of inputs)
|
|
428
|
+
h = hashCombine(h, inp?.[type_id_symbol] ?? 0);
|
|
429
|
+
h = hashCombine(h, output?.[type_id_symbol] ?? 0);
|
|
430
|
+
const cached = internLookup(h, (c) => c.type === "Function" && c.inputs.length === inputs.length && c.output === output &&
|
|
431
|
+
c.inputs.every((inp, i) => inp === inputs[i]));
|
|
432
|
+
if (cached)
|
|
433
|
+
return cached;
|
|
434
|
+
const result = assignTypeId({ type: "Function", inputs, output });
|
|
435
|
+
internStore(h, result);
|
|
436
|
+
return result;
|
|
259
437
|
}
|
|
260
438
|
;
|
|
261
439
|
/**
|
|
@@ -268,7 +446,43 @@ export function FunctionType(inputs, output) {
|
|
|
268
446
|
* @see {@link AsyncFunctionType} for asynchronous functions.
|
|
269
447
|
*/
|
|
270
448
|
export function AsyncFunctionType(inputs, output) {
|
|
271
|
-
|
|
449
|
+
let h = hashCombine(0x61, inputs.length);
|
|
450
|
+
for (const inp of inputs)
|
|
451
|
+
h = hashCombine(h, inp?.[type_id_symbol] ?? 0);
|
|
452
|
+
h = hashCombine(h, output?.[type_id_symbol] ?? 0);
|
|
453
|
+
const cached = internLookup(h, (c) => c.type === "AsyncFunction" && c.inputs.length === inputs.length && c.output === output &&
|
|
454
|
+
c.inputs.every((inp, i) => inp === inputs[i]));
|
|
455
|
+
if (cached)
|
|
456
|
+
return cached;
|
|
457
|
+
const result = assignTypeId({ type: "AsyncFunction", inputs, output });
|
|
458
|
+
internStore(h, result);
|
|
459
|
+
return result;
|
|
460
|
+
}
|
|
461
|
+
;
|
|
462
|
+
export function VectorType(element) {
|
|
463
|
+
if (typeof element !== "string" && element.type !== "Float" && element.type !== "Integer" && element.type !== "Boolean") {
|
|
464
|
+
throw new Error(`Vector element type must be Float, Integer, or Boolean, got ${printType(element)}`);
|
|
465
|
+
}
|
|
466
|
+
const h = hashCombine(0x56, element?.[type_id_symbol] ?? 0);
|
|
467
|
+
const cached = internLookup(h, (c) => c.type === "Vector" && c.element === element);
|
|
468
|
+
if (cached)
|
|
469
|
+
return cached;
|
|
470
|
+
const result = assignTypeId({ type: "Vector", element });
|
|
471
|
+
internStore(h, result);
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
;
|
|
475
|
+
export function MatrixType(element) {
|
|
476
|
+
if (typeof element !== "string" && element.type !== "Float" && element.type !== "Integer" && element.type !== "Boolean") {
|
|
477
|
+
throw new Error(`Matrix element type must be Float, Integer, or Boolean, got ${printType(element)}`);
|
|
478
|
+
}
|
|
479
|
+
const h = hashCombine(0x4d, element?.[type_id_symbol] ?? 0);
|
|
480
|
+
const cached = internLookup(h, (c) => c.type === "Matrix" && c.element === element);
|
|
481
|
+
if (cached)
|
|
482
|
+
return cached;
|
|
483
|
+
const result = assignTypeId({ type: "Matrix", element });
|
|
484
|
+
internStore(h, result);
|
|
485
|
+
return result;
|
|
272
486
|
}
|
|
273
487
|
;
|
|
274
488
|
/**
|
|
@@ -319,6 +533,9 @@ export function isDataType(type, recursive_type) {
|
|
|
319
533
|
else if (type.type === "Recursive") {
|
|
320
534
|
return type.node === recursive_type ? true : isDataType(type.node, type);
|
|
321
535
|
}
|
|
536
|
+
else if (type.type === "Vector" || type.type === "Matrix") {
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
322
539
|
else if (type.type === "Function") {
|
|
323
540
|
return false;
|
|
324
541
|
}
|
|
@@ -361,6 +578,9 @@ export function isImmutableType(type, recursive_type) {
|
|
|
361
578
|
// Dict are mutable
|
|
362
579
|
return false;
|
|
363
580
|
}
|
|
581
|
+
else if (type.type === "Vector" || type.type === "Matrix") {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
364
584
|
else if (type.type === "Struct") {
|
|
365
585
|
for (const field_type of Object.values(type.fields)) {
|
|
366
586
|
if (!isImmutableType(field_type, recursive_type)) {
|
|
@@ -424,6 +644,9 @@ export function EastTypeOf(value) {
|
|
|
424
644
|
if (value instanceof Date) {
|
|
425
645
|
return DateTimeType;
|
|
426
646
|
}
|
|
647
|
+
else if (value instanceof Uint8ClampedArray) {
|
|
648
|
+
return VectorType(BooleanType);
|
|
649
|
+
}
|
|
427
650
|
else if (value instanceof Uint8Array) {
|
|
428
651
|
return BlobType;
|
|
429
652
|
}
|
|
@@ -472,28 +695,32 @@ export function EastTypeOf(value) {
|
|
|
472
695
|
* For {@link RecursiveType}, uses cycle tracking to handle recursive references.
|
|
473
696
|
*/
|
|
474
697
|
// Cache for memoizing isTypeEqual results (top-level calls only)
|
|
475
|
-
const typeEqualCache = new
|
|
698
|
+
const typeEqualCache = new Map();
|
|
476
699
|
export function isTypeEqual(t1, t2, r1 = t1, r2 = t2) {
|
|
477
700
|
// Fast path: reference equality
|
|
478
701
|
if (t1 === t2)
|
|
479
702
|
return true;
|
|
703
|
+
// Fast path: type_id equality (interned types with same id are structurally equal)
|
|
704
|
+
const tid1 = getTypeId(t1);
|
|
705
|
+
const tid2 = getTypeId(t2);
|
|
706
|
+
if (tid1 !== undefined && tid1 === tid2)
|
|
707
|
+
return true;
|
|
480
708
|
// Memoization for top-level calls only (r1/r2 are just for internal cycle detection)
|
|
481
709
|
const isTopLevel = r1 === t1 && r2 === t2;
|
|
482
|
-
if (isTopLevel) {
|
|
483
|
-
const innerCache = typeEqualCache.get(
|
|
710
|
+
if (isTopLevel && tid1 !== undefined && tid2 !== undefined) {
|
|
711
|
+
const innerCache = typeEqualCache.get(tid1);
|
|
484
712
|
if (innerCache) {
|
|
485
|
-
const cached = innerCache.get(
|
|
713
|
+
const cached = innerCache.get(tid2);
|
|
486
714
|
if (cached !== undefined)
|
|
487
715
|
return cached;
|
|
488
716
|
}
|
|
489
717
|
const result = isTypeEqualImpl(t1, t2, r1, r2);
|
|
490
|
-
|
|
491
|
-
let cache = typeEqualCache.get(t1);
|
|
718
|
+
let cache = typeEqualCache.get(tid1);
|
|
492
719
|
if (!cache) {
|
|
493
|
-
cache = new
|
|
494
|
-
typeEqualCache.set(
|
|
720
|
+
cache = new Map();
|
|
721
|
+
typeEqualCache.set(tid1, cache);
|
|
495
722
|
}
|
|
496
|
-
cache.set(
|
|
723
|
+
cache.set(tid2, result);
|
|
497
724
|
return result;
|
|
498
725
|
}
|
|
499
726
|
return isTypeEqualImpl(t1, t2, r1, r2);
|
|
@@ -576,6 +803,22 @@ function isTypeEqualImpl(t1, t2, r1, r2) {
|
|
|
576
803
|
return false;
|
|
577
804
|
}
|
|
578
805
|
}
|
|
806
|
+
else if (t1.type === "Vector") {
|
|
807
|
+
if (t2.type === "Vector") {
|
|
808
|
+
return isTypeEqual(t1.element, t2.element, r1, r2);
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else if (t1.type === "Matrix") {
|
|
815
|
+
if (t2.type === "Matrix") {
|
|
816
|
+
return isTypeEqual(t1.element, t2.element, r1, r2);
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
579
822
|
else if (t1.type === "Struct") {
|
|
580
823
|
if (t2.type === "Struct") {
|
|
581
824
|
const e1 = Object.entries(t1.fields);
|
|
@@ -766,6 +1009,26 @@ export function isValueOf(value, type, node_type, nodes_visited) {
|
|
|
766
1009
|
;
|
|
767
1010
|
return isValueOf(value.value, t, node_type, nodes_visited);
|
|
768
1011
|
}
|
|
1012
|
+
else if (type.type === "Vector") {
|
|
1013
|
+
if (type.element.type === "Float")
|
|
1014
|
+
return value instanceof Float64Array;
|
|
1015
|
+
if (type.element.type === "Integer")
|
|
1016
|
+
return value instanceof BigInt64Array;
|
|
1017
|
+
if (type.element.type === "Boolean")
|
|
1018
|
+
return value instanceof Uint8ClampedArray;
|
|
1019
|
+
return false;
|
|
1020
|
+
}
|
|
1021
|
+
else if (type.type === "Matrix") {
|
|
1022
|
+
if (!isMatrix(value))
|
|
1023
|
+
return false;
|
|
1024
|
+
if (type.element.type === "Float")
|
|
1025
|
+
return value.data instanceof Float64Array;
|
|
1026
|
+
if (type.element.type === "Integer")
|
|
1027
|
+
return value.data instanceof BigInt64Array;
|
|
1028
|
+
if (type.element.type === "Boolean")
|
|
1029
|
+
return value.data instanceof Uint8ClampedArray;
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
769
1032
|
else if (type.type === "Recursive") {
|
|
770
1033
|
if (node_type === type.node) {
|
|
771
1034
|
if (nodes_visited.has(value)) {
|
|
@@ -866,14 +1129,21 @@ export function printType(type, stack = []) {
|
|
|
866
1129
|
stack.pop();
|
|
867
1130
|
return ret;
|
|
868
1131
|
}
|
|
1132
|
+
else if (type.type === "Vector") {
|
|
1133
|
+
return `.Vector ${printType(type.element, stack)}`;
|
|
1134
|
+
}
|
|
1135
|
+
else if (type.type === "Matrix") {
|
|
1136
|
+
return `.Matrix ${printType(type.element, stack)}`;
|
|
1137
|
+
}
|
|
869
1138
|
else if (type.type === "Recursive") {
|
|
870
|
-
|
|
871
|
-
const idx = stack.indexOf(type.node);
|
|
1139
|
+
const idx = stack.indexOf(type);
|
|
872
1140
|
if (idx !== -1) {
|
|
873
|
-
|
|
874
|
-
return `.Recursive ${stack.length - idx}`;
|
|
1141
|
+
return `.Recursive .ref ${getTypeId(type)}`;
|
|
875
1142
|
}
|
|
876
|
-
|
|
1143
|
+
stack.push(type);
|
|
1144
|
+
const inner = printType(type.node, stack);
|
|
1145
|
+
stack.pop();
|
|
1146
|
+
return `.Recursive .wrapper (id=${getTypeId(type)}, inner=${inner})`;
|
|
877
1147
|
}
|
|
878
1148
|
else if (type.type === "Function") {
|
|
879
1149
|
// Note: functions can't be inside recursive types
|
|
@@ -893,6 +1163,140 @@ export function printType(type, stack = []) {
|
|
|
893
1163
|
throw new Error(`Unknown type encountered during type printing: ${type.type}`);
|
|
894
1164
|
}
|
|
895
1165
|
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Converts an East type to a truncated string representation for error messages.
|
|
1168
|
+
*
|
|
1169
|
+
* @param type - The {@link EastType} to print
|
|
1170
|
+
* @param maxDepth - Maximum depth to recurse into compound types (default 1)
|
|
1171
|
+
* @param maxFields - Maximum number of fields/cases to show before truncating (default 3)
|
|
1172
|
+
* @param stack - Internal parameter for tracking recursive types
|
|
1173
|
+
* @returns A human-readable, truncated string representation of the type
|
|
1174
|
+
*
|
|
1175
|
+
* @remarks
|
|
1176
|
+
* Like {@link printType} but truncates large types for readable error messages.
|
|
1177
|
+
* At depth 0, compound types show summary form (e.g., `.Struct [N fields]`).
|
|
1178
|
+
* Shows first `maxFields` entries then `... and N more`.
|
|
1179
|
+
*/
|
|
1180
|
+
export function printTypeSummary(type, maxDepth = 1, maxFields = 3, stack = []) {
|
|
1181
|
+
if (type.type === "Never") {
|
|
1182
|
+
return ".Never";
|
|
1183
|
+
}
|
|
1184
|
+
else if (type.type === "Null") {
|
|
1185
|
+
return ".Null";
|
|
1186
|
+
}
|
|
1187
|
+
else if (type.type === "Boolean") {
|
|
1188
|
+
return ".Boolean";
|
|
1189
|
+
}
|
|
1190
|
+
else if (type.type === "Integer") {
|
|
1191
|
+
return ".Integer";
|
|
1192
|
+
}
|
|
1193
|
+
else if (type.type === "Float") {
|
|
1194
|
+
return ".Float";
|
|
1195
|
+
}
|
|
1196
|
+
else if (type.type === "String") {
|
|
1197
|
+
return ".String";
|
|
1198
|
+
}
|
|
1199
|
+
else if (type.type === "DateTime") {
|
|
1200
|
+
return ".DateTime";
|
|
1201
|
+
}
|
|
1202
|
+
else if (type.type === "Blob") {
|
|
1203
|
+
return ".Blob";
|
|
1204
|
+
}
|
|
1205
|
+
else if (type.type === "Ref") {
|
|
1206
|
+
if (maxDepth <= 0)
|
|
1207
|
+
return ".Ref ...";
|
|
1208
|
+
stack.push(type);
|
|
1209
|
+
const ret = `.Ref ${printTypeSummary(type.value, maxDepth - 1, maxFields, stack)}`;
|
|
1210
|
+
stack.pop();
|
|
1211
|
+
return ret;
|
|
1212
|
+
}
|
|
1213
|
+
else if (type.type === "Array") {
|
|
1214
|
+
if (maxDepth <= 0)
|
|
1215
|
+
return ".Array ...";
|
|
1216
|
+
stack.push(type);
|
|
1217
|
+
const ret = `.Array ${printTypeSummary(type.value, maxDepth - 1, maxFields, stack)}`;
|
|
1218
|
+
stack.pop();
|
|
1219
|
+
return ret;
|
|
1220
|
+
}
|
|
1221
|
+
else if (type.type === "Set") {
|
|
1222
|
+
if (maxDepth <= 0)
|
|
1223
|
+
return ".Set ...";
|
|
1224
|
+
stack.push(type);
|
|
1225
|
+
const ret = `.Set ${printTypeSummary(type.key, maxDepth - 1, maxFields, stack)}`;
|
|
1226
|
+
stack.pop();
|
|
1227
|
+
return ret;
|
|
1228
|
+
}
|
|
1229
|
+
else if (type.type === "Dict") {
|
|
1230
|
+
if (maxDepth <= 0)
|
|
1231
|
+
return ".Dict ...";
|
|
1232
|
+
stack.push(type);
|
|
1233
|
+
const ret = `.Dict (key=${printTypeSummary(type.key, maxDepth - 1, maxFields, stack)}, value=${printTypeSummary(type.value, maxDepth - 1, maxFields, stack)})`;
|
|
1234
|
+
stack.pop();
|
|
1235
|
+
return ret;
|
|
1236
|
+
}
|
|
1237
|
+
else if (type.type === "Struct") {
|
|
1238
|
+
const entries = Object.entries(type.fields);
|
|
1239
|
+
if (maxDepth <= 0)
|
|
1240
|
+
return `.Struct [${entries.length} fields]`;
|
|
1241
|
+
stack.push(type);
|
|
1242
|
+
const shown = entries.slice(0, maxFields).map(([k, t]) => `(name=${JSON.stringify(k)}, type=${printTypeSummary(t, maxDepth - 1, maxFields, stack)})`);
|
|
1243
|
+
stack.pop();
|
|
1244
|
+
const remaining = entries.length - maxFields;
|
|
1245
|
+
if (remaining > 0) {
|
|
1246
|
+
return `.Struct [${shown.join(", ")}, ... and ${remaining} more]`;
|
|
1247
|
+
}
|
|
1248
|
+
return `.Struct [${shown.join(", ")}]`;
|
|
1249
|
+
}
|
|
1250
|
+
else if (type.type === "Variant") {
|
|
1251
|
+
const entries = Object.entries(type.cases);
|
|
1252
|
+
if (maxDepth <= 0) {
|
|
1253
|
+
return `.Variant (${entries.map(([k]) => k).join(" | ")})`;
|
|
1254
|
+
}
|
|
1255
|
+
stack.push(type);
|
|
1256
|
+
const shown = entries.slice(0, maxFields).map(([k, t]) => `(name=${JSON.stringify(k)}, type=${printTypeSummary(t, maxDepth - 1, maxFields, stack)})`);
|
|
1257
|
+
stack.pop();
|
|
1258
|
+
const remaining = entries.length - maxFields;
|
|
1259
|
+
if (remaining > 0) {
|
|
1260
|
+
return `.Variant [${shown.join(", ")}, ... and ${remaining} more]`;
|
|
1261
|
+
}
|
|
1262
|
+
return `.Variant [${shown.join(", ")}]`;
|
|
1263
|
+
}
|
|
1264
|
+
else if (type.type === "Vector") {
|
|
1265
|
+
return `.Vector ${printTypeSummary(type.element, maxDepth, maxFields, stack)}`;
|
|
1266
|
+
}
|
|
1267
|
+
else if (type.type === "Matrix") {
|
|
1268
|
+
return `.Matrix ${printTypeSummary(type.element, maxDepth, maxFields, stack)}`;
|
|
1269
|
+
}
|
|
1270
|
+
else if (type.type === "Recursive") {
|
|
1271
|
+
const idx = stack.indexOf(type);
|
|
1272
|
+
if (idx !== -1) {
|
|
1273
|
+
return `.Recursive .ref ${getTypeId(type)}`;
|
|
1274
|
+
}
|
|
1275
|
+
stack.push(type);
|
|
1276
|
+
const inner = printTypeSummary(type.node, maxDepth, maxFields, stack);
|
|
1277
|
+
stack.pop();
|
|
1278
|
+
return `.Recursive .wrapper (id=${getTypeId(type)}, inner=${inner})`;
|
|
1279
|
+
}
|
|
1280
|
+
else if (type.type === "Function") {
|
|
1281
|
+
if (maxDepth <= 0)
|
|
1282
|
+
return `.Function ...`;
|
|
1283
|
+
stack.push(type);
|
|
1284
|
+
const ret = `.Function (inputs=[${type.inputs.map(t => printTypeSummary(t, maxDepth - 1, maxFields, stack)).join(", ")}], output=${printTypeSummary(type.output, maxDepth - 1, maxFields, stack)})`;
|
|
1285
|
+
stack.pop();
|
|
1286
|
+
return ret;
|
|
1287
|
+
}
|
|
1288
|
+
else if (type.type === "AsyncFunction") {
|
|
1289
|
+
if (maxDepth <= 0)
|
|
1290
|
+
return `.AsyncFunction ...`;
|
|
1291
|
+
stack.push(type);
|
|
1292
|
+
const ret = `.AsyncFunction (inputs=[${type.inputs.map(t => printTypeSummary(t, maxDepth - 1, maxFields, stack)).join(", ")}], output=${printTypeSummary(type.output, maxDepth - 1, maxFields, stack)})`;
|
|
1293
|
+
stack.pop();
|
|
1294
|
+
return ret;
|
|
1295
|
+
}
|
|
1296
|
+
else {
|
|
1297
|
+
throw new Error(`Unknown type encountered during type printing: ${type.type}`);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
896
1300
|
/**
|
|
897
1301
|
* Checks if one East type is a subtype of another.
|
|
898
1302
|
*
|
|
@@ -908,27 +1312,34 @@ export function printType(type, stack = []) {
|
|
|
908
1312
|
* - {@link FunctionType} uses contravariant inputs and covariant outputs
|
|
909
1313
|
*/
|
|
910
1314
|
// Cache for memoizing isSubtype results
|
|
911
|
-
const isSubtypeCache = new
|
|
1315
|
+
const isSubtypeCache = new Map();
|
|
912
1316
|
export function isSubtype(t1, t2) {
|
|
913
1317
|
// Fast path: reference equality (reflexivity)
|
|
914
1318
|
if (t1 === t2)
|
|
915
1319
|
return true;
|
|
1320
|
+
// Fast path: type_id equality
|
|
1321
|
+
const tid1 = getTypeId(t1);
|
|
1322
|
+
const tid2 = getTypeId(t2);
|
|
1323
|
+
if (tid1 !== undefined && tid1 === tid2)
|
|
1324
|
+
return true;
|
|
916
1325
|
// Check cache
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
1326
|
+
if (tid1 !== undefined && tid2 !== undefined) {
|
|
1327
|
+
const innerCache = isSubtypeCache.get(tid1);
|
|
1328
|
+
if (innerCache) {
|
|
1329
|
+
const cached = innerCache.get(tid2);
|
|
1330
|
+
if (cached !== undefined)
|
|
1331
|
+
return cached;
|
|
1332
|
+
}
|
|
1333
|
+
const result = isSubtypeImpl(t1, t2);
|
|
1334
|
+
let cache = isSubtypeCache.get(tid1);
|
|
1335
|
+
if (!cache) {
|
|
1336
|
+
cache = new Map();
|
|
1337
|
+
isSubtypeCache.set(tid1, cache);
|
|
1338
|
+
}
|
|
1339
|
+
cache.set(tid2, result);
|
|
1340
|
+
return result;
|
|
1341
|
+
}
|
|
1342
|
+
return isSubtypeImpl(t1, t2);
|
|
932
1343
|
}
|
|
933
1344
|
function isSubtypeImpl(t1, t2) {
|
|
934
1345
|
// Equi-recursive type subtyping: unfold recursive types when only one side is recursive
|
|
@@ -988,6 +1399,22 @@ function isSubtypeImpl(t1, t2) {
|
|
|
988
1399
|
return false;
|
|
989
1400
|
}
|
|
990
1401
|
}
|
|
1402
|
+
else if (t1.type === "Vector") {
|
|
1403
|
+
if (t2.type === "Vector") {
|
|
1404
|
+
return isTypeEqual(t1.element, t2.element);
|
|
1405
|
+
}
|
|
1406
|
+
else {
|
|
1407
|
+
return false;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
else if (t1.type === "Matrix") {
|
|
1411
|
+
if (t2.type === "Matrix") {
|
|
1412
|
+
return isTypeEqual(t1.element, t2.element);
|
|
1413
|
+
}
|
|
1414
|
+
else {
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
991
1418
|
else if (t1.type === "Set") {
|
|
992
1419
|
if (t2.type === "Set") {
|
|
993
1420
|
return isTypeEqual(t1.key, t2.key);
|
|
@@ -1074,6 +1501,8 @@ function isSubtypeImpl(t1, t2) {
|
|
|
1074
1501
|
* Error messages include the full type path for debugging.
|
|
1075
1502
|
*/
|
|
1076
1503
|
export function TypeUnion(t1, t2) {
|
|
1504
|
+
if (t1 === t2)
|
|
1505
|
+
return t1;
|
|
1077
1506
|
// TODO this is broken for recursive types (need to do cycle tracking in tandem with TypeEqual/TypeIntersect)
|
|
1078
1507
|
try {
|
|
1079
1508
|
if (t1.type === "Never") {
|
|
@@ -1093,7 +1522,7 @@ export function TypeUnion(t1, t2) {
|
|
|
1093
1522
|
if (isSubtype(t2, t1.node)) {
|
|
1094
1523
|
return t1;
|
|
1095
1524
|
}
|
|
1096
|
-
throw new TypeMismatchError(`
|
|
1525
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1097
1526
|
}
|
|
1098
1527
|
}
|
|
1099
1528
|
else if (t2.type === "Recursive") {
|
|
@@ -1101,38 +1530,54 @@ export function TypeUnion(t1, t2) {
|
|
|
1101
1530
|
if (isSubtype(t1, t2.node)) {
|
|
1102
1531
|
return t2;
|
|
1103
1532
|
}
|
|
1104
|
-
throw new TypeMismatchError(`
|
|
1533
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1105
1534
|
}
|
|
1106
1535
|
else if (t1.type === "Ref") {
|
|
1107
1536
|
if (t2.type === "Ref") {
|
|
1108
|
-
return RefType(TypeEqual(t1.value, t2.value));
|
|
1537
|
+
return RefType(withPathSegment("[ref]", () => TypeEqual(t1.value, t2.value)));
|
|
1109
1538
|
}
|
|
1110
1539
|
else {
|
|
1111
|
-
throw new TypeMismatchError(`
|
|
1540
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1112
1541
|
}
|
|
1113
1542
|
}
|
|
1114
1543
|
else if (t1.type === "Array") {
|
|
1115
1544
|
if (t2.type === "Array") {
|
|
1116
|
-
return ArrayType(TypeEqual(t1.value, t2.value));
|
|
1545
|
+
return ArrayType(withPathSegment("[element]", () => TypeEqual(t1.value, t2.value)));
|
|
1546
|
+
}
|
|
1547
|
+
else {
|
|
1548
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
else if (t1.type === "Vector") {
|
|
1552
|
+
if (t2.type === "Vector") {
|
|
1553
|
+
return VectorType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element)));
|
|
1117
1554
|
}
|
|
1118
1555
|
else {
|
|
1119
|
-
throw new TypeMismatchError(`
|
|
1556
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
else if (t1.type === "Matrix") {
|
|
1560
|
+
if (t2.type === "Matrix") {
|
|
1561
|
+
return MatrixType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element)));
|
|
1562
|
+
}
|
|
1563
|
+
else {
|
|
1564
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1120
1565
|
}
|
|
1121
1566
|
}
|
|
1122
1567
|
else if (t1.type === "Set") {
|
|
1123
1568
|
if (t2.type === "Set") {
|
|
1124
|
-
return SetType(TypeEqual(t1.key, t2.key));
|
|
1569
|
+
return SetType(withPathSegment("[key]", () => TypeEqual(t1.key, t2.key)));
|
|
1125
1570
|
}
|
|
1126
1571
|
else {
|
|
1127
|
-
throw new TypeMismatchError(`
|
|
1572
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1128
1573
|
}
|
|
1129
1574
|
}
|
|
1130
1575
|
else if (t1.type === "Dict") {
|
|
1131
1576
|
if (t2.type === "Dict") {
|
|
1132
|
-
return DictType(TypeEqual(t1.key, t2.key), TypeEqual(t1.value, t2.value));
|
|
1577
|
+
return DictType(withPathSegment("[key]", () => TypeEqual(t1.key, t2.key)), withPathSegment("[value]", () => TypeEqual(t1.value, t2.value)));
|
|
1133
1578
|
}
|
|
1134
1579
|
else {
|
|
1135
|
-
throw new TypeMismatchError(`
|
|
1580
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1136
1581
|
}
|
|
1137
1582
|
}
|
|
1138
1583
|
else if (t1.type === "Struct") {
|
|
@@ -1140,20 +1585,20 @@ export function TypeUnion(t1, t2) {
|
|
|
1140
1585
|
const e1 = Object.entries(t1.fields);
|
|
1141
1586
|
const e2 = Object.entries(t2.fields);
|
|
1142
1587
|
if (e1.length !== e2.length)
|
|
1143
|
-
throw new TypeMismatchError(`
|
|
1588
|
+
throw new TypeMismatchError(`structs contain different number of fields (${e1.length} vs ${e2.length})`);
|
|
1144
1589
|
let i = 0;
|
|
1145
1590
|
const e = {};
|
|
1146
1591
|
for (const [k1, f1] of e1) {
|
|
1147
1592
|
const [k2, f2] = e2[i];
|
|
1148
1593
|
if (k1 !== k2)
|
|
1149
|
-
throw new TypeMismatchError(`
|
|
1150
|
-
e[k1] = TypeUnion(f1, f2);
|
|
1594
|
+
throw new TypeMismatchError(`struct field ${i} has mismatched names ${printIdentifier(k1)} and ${printIdentifier(k2)}`);
|
|
1595
|
+
e[k1] = withPathSegment(`.${k1}`, () => TypeUnion(f1, f2));
|
|
1151
1596
|
i += 1;
|
|
1152
1597
|
}
|
|
1153
1598
|
return StructType(e);
|
|
1154
1599
|
}
|
|
1155
1600
|
else {
|
|
1156
|
-
throw new TypeMismatchError(`
|
|
1601
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1157
1602
|
}
|
|
1158
1603
|
}
|
|
1159
1604
|
else if (t1.type === "Variant") {
|
|
@@ -1165,7 +1610,7 @@ export function TypeUnion(t1, t2) {
|
|
|
1165
1610
|
cases[k1] = f1;
|
|
1166
1611
|
}
|
|
1167
1612
|
else {
|
|
1168
|
-
cases[k1] = TypeUnion(f1, f2);
|
|
1613
|
+
cases[k1] = withPathSegment(`.${k1}`, () => TypeUnion(f1, f2));
|
|
1169
1614
|
}
|
|
1170
1615
|
}
|
|
1171
1616
|
for (const [k2, f2] of Object.entries(t2.cases)) {
|
|
@@ -1177,41 +1622,41 @@ export function TypeUnion(t1, t2) {
|
|
|
1177
1622
|
return VariantType(cases);
|
|
1178
1623
|
}
|
|
1179
1624
|
else {
|
|
1180
|
-
throw new TypeMismatchError(`
|
|
1625
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1181
1626
|
}
|
|
1182
1627
|
}
|
|
1183
1628
|
else if (t1.type === "Function") {
|
|
1184
1629
|
if (t2.type === "Function") {
|
|
1185
1630
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1186
|
-
throw new TypeMismatchError(`
|
|
1631
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1187
1632
|
}
|
|
1188
|
-
return FunctionType(t1.inputs.map((t, i) => TypeIntersect(t, t2.inputs[i])), TypeUnion(t1.output, t2.output));
|
|
1633
|
+
return FunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeIntersect(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeUnion(t1.output, t2.output)));
|
|
1189
1634
|
}
|
|
1190
1635
|
else if (t2.type === "AsyncFunction") {
|
|
1191
1636
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1192
|
-
throw new TypeMismatchError(`
|
|
1637
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1193
1638
|
}
|
|
1194
|
-
return AsyncFunctionType(t1.inputs.map((t, i) => TypeIntersect(t, t2.inputs[i])), TypeUnion(t1.output, t2.output));
|
|
1639
|
+
return AsyncFunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeIntersect(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeUnion(t1.output, t2.output)));
|
|
1195
1640
|
}
|
|
1196
1641
|
else {
|
|
1197
|
-
throw new TypeMismatchError(`
|
|
1642
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1198
1643
|
}
|
|
1199
1644
|
}
|
|
1200
1645
|
else if (t1.type === "AsyncFunction") {
|
|
1201
1646
|
if (t2.type === "Function") {
|
|
1202
1647
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1203
|
-
throw new TypeMismatchError(`
|
|
1648
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1204
1649
|
}
|
|
1205
|
-
return AsyncFunctionType(t1.inputs.map((t, i) => TypeIntersect(t, t2.inputs[i])), TypeUnion(t1.output, t2.output));
|
|
1650
|
+
return AsyncFunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeIntersect(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeUnion(t1.output, t2.output)));
|
|
1206
1651
|
}
|
|
1207
1652
|
else if (t2.type === "AsyncFunction") {
|
|
1208
1653
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1209
|
-
throw new TypeMismatchError(`
|
|
1654
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1210
1655
|
}
|
|
1211
|
-
return AsyncFunctionType(t1.inputs.map((t, i) => TypeIntersect(t, t2.inputs[i])), TypeUnion(t1.output, t2.output));
|
|
1656
|
+
return AsyncFunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeIntersect(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeUnion(t1.output, t2.output)));
|
|
1212
1657
|
}
|
|
1213
1658
|
else {
|
|
1214
|
-
throw new TypeMismatchError(`
|
|
1659
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1215
1660
|
}
|
|
1216
1661
|
}
|
|
1217
1662
|
else {
|
|
@@ -1219,7 +1664,7 @@ export function TypeUnion(t1, t2) {
|
|
|
1219
1664
|
return t1;
|
|
1220
1665
|
}
|
|
1221
1666
|
else {
|
|
1222
|
-
throw new TypeMismatchError(`
|
|
1667
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1223
1668
|
}
|
|
1224
1669
|
}
|
|
1225
1670
|
}
|
|
@@ -1227,7 +1672,7 @@ export function TypeUnion(t1, t2) {
|
|
|
1227
1672
|
if (cause instanceof TypeMismatchError) {
|
|
1228
1673
|
throw cause; // Don't wrap our own errors - they already have the full path
|
|
1229
1674
|
}
|
|
1230
|
-
throw new TypeMismatchError(`
|
|
1675
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}`, { cause });
|
|
1231
1676
|
}
|
|
1232
1677
|
}
|
|
1233
1678
|
/**
|
|
@@ -1245,6 +1690,8 @@ export function TypeUnion(t1, t2) {
|
|
|
1245
1690
|
* For {@link VariantType}, returns {@link NeverType} if no common cases exist.
|
|
1246
1691
|
*/
|
|
1247
1692
|
export function TypeIntersect(t1, t2) {
|
|
1693
|
+
if (t1 === t2)
|
|
1694
|
+
return t1;
|
|
1248
1695
|
// TODO this is broken for recursive types (need to do cycle tracking in tandem with TypeEqual/TypeUnion)
|
|
1249
1696
|
try {
|
|
1250
1697
|
if (t1.type === "Never") {
|
|
@@ -1263,7 +1710,7 @@ export function TypeIntersect(t1, t2) {
|
|
|
1263
1710
|
if (isSubtype(t2, t1.node)) {
|
|
1264
1711
|
return t2;
|
|
1265
1712
|
}
|
|
1266
|
-
throw new TypeMismatchError(`
|
|
1713
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1267
1714
|
}
|
|
1268
1715
|
}
|
|
1269
1716
|
else if (t2.type === "Recursive") {
|
|
@@ -1271,38 +1718,54 @@ export function TypeIntersect(t1, t2) {
|
|
|
1271
1718
|
if (isSubtype(t1, t2.node)) {
|
|
1272
1719
|
return t1;
|
|
1273
1720
|
}
|
|
1274
|
-
throw new TypeMismatchError(`
|
|
1721
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1275
1722
|
}
|
|
1276
1723
|
else if (t1.type === "Ref") {
|
|
1277
1724
|
if (t2.type === "Ref") {
|
|
1278
|
-
return RefType(TypeEqual(t1.value, t2.value));
|
|
1725
|
+
return RefType(withPathSegment("[ref]", () => TypeEqual(t1.value, t2.value)));
|
|
1279
1726
|
}
|
|
1280
1727
|
else {
|
|
1281
|
-
throw new TypeMismatchError(`
|
|
1728
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1282
1729
|
}
|
|
1283
1730
|
}
|
|
1284
1731
|
else if (t1.type === "Array") {
|
|
1285
1732
|
if (t2.type === "Array") {
|
|
1286
|
-
return ArrayType(TypeEqual(t1.value, t2.value));
|
|
1733
|
+
return ArrayType(withPathSegment("[element]", () => TypeEqual(t1.value, t2.value)));
|
|
1734
|
+
}
|
|
1735
|
+
else {
|
|
1736
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
else if (t1.type === "Vector") {
|
|
1740
|
+
if (t2.type === "Vector") {
|
|
1741
|
+
return VectorType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element)));
|
|
1742
|
+
}
|
|
1743
|
+
else {
|
|
1744
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
else if (t1.type === "Matrix") {
|
|
1748
|
+
if (t2.type === "Matrix") {
|
|
1749
|
+
return MatrixType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element)));
|
|
1287
1750
|
}
|
|
1288
1751
|
else {
|
|
1289
|
-
throw new TypeMismatchError(`
|
|
1752
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1290
1753
|
}
|
|
1291
1754
|
}
|
|
1292
1755
|
else if (t1.type === "Set") {
|
|
1293
1756
|
if (t2.type === "Set") {
|
|
1294
|
-
return SetType(TypeEqual(t1.key, t2.key));
|
|
1757
|
+
return SetType(withPathSegment("[key]", () => TypeEqual(t1.key, t2.key)));
|
|
1295
1758
|
}
|
|
1296
1759
|
else {
|
|
1297
|
-
throw new TypeMismatchError(`
|
|
1760
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1298
1761
|
}
|
|
1299
1762
|
}
|
|
1300
1763
|
else if (t1.type === "Dict") {
|
|
1301
1764
|
if (t2.type === "Dict") {
|
|
1302
|
-
return DictType(TypeEqual(t1.key, t2.key), TypeEqual(t1.value, t2.value));
|
|
1765
|
+
return DictType(withPathSegment("[key]", () => TypeEqual(t1.key, t2.key)), withPathSegment("[value]", () => TypeEqual(t1.value, t2.value)));
|
|
1303
1766
|
}
|
|
1304
1767
|
else {
|
|
1305
|
-
throw new TypeMismatchError(`
|
|
1768
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1306
1769
|
}
|
|
1307
1770
|
}
|
|
1308
1771
|
else if (t1.type === "Struct") {
|
|
@@ -1310,20 +1773,20 @@ export function TypeIntersect(t1, t2) {
|
|
|
1310
1773
|
const e1 = Object.entries(t1.fields);
|
|
1311
1774
|
const e2 = Object.entries(t2.fields);
|
|
1312
1775
|
if (e1.length !== e2.length)
|
|
1313
|
-
throw new TypeMismatchError(`
|
|
1776
|
+
throw new TypeMismatchError(`structs contain different number of fields (${e1.length} vs ${e2.length})`);
|
|
1314
1777
|
let i = 0;
|
|
1315
1778
|
const e = {};
|
|
1316
1779
|
for (const [k1, f1] of e1) {
|
|
1317
1780
|
const [k2, f2] = e2[i];
|
|
1318
1781
|
if (k1 !== k2)
|
|
1319
|
-
throw new TypeMismatchError(`
|
|
1320
|
-
e[k1] = TypeIntersect(f1, f2);
|
|
1782
|
+
throw new TypeMismatchError(`struct field ${i} has mismatched names ${printIdentifier(k1)} and ${printIdentifier(k2)}`);
|
|
1783
|
+
e[k1] = withPathSegment(`.${k1}`, () => TypeIntersect(f1, f2));
|
|
1321
1784
|
i += 1;
|
|
1322
1785
|
}
|
|
1323
1786
|
return StructType(e);
|
|
1324
1787
|
}
|
|
1325
1788
|
else {
|
|
1326
|
-
throw new TypeMismatchError(`
|
|
1789
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1327
1790
|
}
|
|
1328
1791
|
}
|
|
1329
1792
|
else if (t1.type === "Variant") {
|
|
@@ -1333,51 +1796,51 @@ export function TypeIntersect(t1, t2) {
|
|
|
1333
1796
|
for (const [k1, f1] of Object.entries(t1.cases)) {
|
|
1334
1797
|
const f2 = t2.cases[k1];
|
|
1335
1798
|
if (f2 !== undefined) {
|
|
1336
|
-
cases[k1] = TypeIntersect(f1, f2);
|
|
1799
|
+
cases[k1] = withPathSegment(`.${k1}`, () => TypeIntersect(f1, f2));
|
|
1337
1800
|
empty = false;
|
|
1338
1801
|
}
|
|
1339
1802
|
}
|
|
1340
1803
|
if (empty) {
|
|
1341
|
-
throw new TypeMismatchError(`
|
|
1804
|
+
throw new TypeMismatchError(`variants have no overlapping cases`);
|
|
1342
1805
|
}
|
|
1343
1806
|
return VariantType(cases);
|
|
1344
1807
|
}
|
|
1345
1808
|
else {
|
|
1346
|
-
throw new TypeMismatchError(`
|
|
1809
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1347
1810
|
}
|
|
1348
1811
|
}
|
|
1349
1812
|
else if (t1.type === "Function") {
|
|
1350
1813
|
if (t2.type === "Function") {
|
|
1351
1814
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1352
|
-
throw new TypeMismatchError(`
|
|
1815
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1353
1816
|
}
|
|
1354
|
-
return FunctionType(t1.inputs.map((t, i) => TypeUnion(t, t2.inputs[i])), TypeIntersect(t1.output, t2.output));
|
|
1817
|
+
return FunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeUnion(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeIntersect(t1.output, t2.output)));
|
|
1355
1818
|
}
|
|
1356
1819
|
else if (t2.type === "AsyncFunction") {
|
|
1357
1820
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1358
|
-
throw new TypeMismatchError(`
|
|
1821
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1359
1822
|
}
|
|
1360
|
-
return FunctionType(t1.inputs.map((t, i) => TypeUnion(t, t2.inputs[i])), TypeIntersect(t1.output, t2.output));
|
|
1823
|
+
return FunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeUnion(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeIntersect(t1.output, t2.output)));
|
|
1361
1824
|
}
|
|
1362
1825
|
else {
|
|
1363
|
-
throw new TypeMismatchError(`
|
|
1826
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1364
1827
|
}
|
|
1365
1828
|
}
|
|
1366
1829
|
else if (t1.type === "AsyncFunction") {
|
|
1367
1830
|
if (t2.type === "Function") {
|
|
1368
1831
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1369
|
-
throw new TypeMismatchError(`
|
|
1832
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1370
1833
|
}
|
|
1371
|
-
return FunctionType(t1.inputs.map((t, i) => TypeUnion(t, t2.inputs[i])), TypeIntersect(t1.output, t2.output));
|
|
1834
|
+
return FunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeUnion(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeIntersect(t1.output, t2.output)));
|
|
1372
1835
|
}
|
|
1373
1836
|
else if (t2.type === "AsyncFunction") {
|
|
1374
1837
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1375
|
-
throw new TypeMismatchError(`
|
|
1838
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1376
1839
|
}
|
|
1377
|
-
return AsyncFunctionType(t1.inputs.map((t, i) => TypeUnion(t, t2.inputs[i])), TypeIntersect(t1.output, t2.output));
|
|
1840
|
+
return AsyncFunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeUnion(t, t2.inputs[i]))), withPathSegment("[output]", () => TypeIntersect(t1.output, t2.output)));
|
|
1378
1841
|
}
|
|
1379
1842
|
else {
|
|
1380
|
-
throw new TypeMismatchError(`
|
|
1843
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1381
1844
|
}
|
|
1382
1845
|
}
|
|
1383
1846
|
else {
|
|
@@ -1385,7 +1848,7 @@ export function TypeIntersect(t1, t2) {
|
|
|
1385
1848
|
return t1;
|
|
1386
1849
|
}
|
|
1387
1850
|
else {
|
|
1388
|
-
throw new TypeMismatchError(`
|
|
1851
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1389
1852
|
}
|
|
1390
1853
|
}
|
|
1391
1854
|
}
|
|
@@ -1393,7 +1856,7 @@ export function TypeIntersect(t1, t2) {
|
|
|
1393
1856
|
if (cause instanceof TypeMismatchError) {
|
|
1394
1857
|
throw cause; // Don't wrap our own errors - they already have the full path
|
|
1395
1858
|
}
|
|
1396
|
-
throw new TypeMismatchError(`
|
|
1859
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}`, { cause });
|
|
1397
1860
|
}
|
|
1398
1861
|
}
|
|
1399
1862
|
/**
|
|
@@ -1414,38 +1877,56 @@ export function TypeIntersect(t1, t2) {
|
|
|
1414
1877
|
* Unlike {@link isTypeEqual}, this throws rather than returning a boolean.
|
|
1415
1878
|
*/
|
|
1416
1879
|
export function TypeEqual(t1, t2, r1 = t1, r2 = t2) {
|
|
1880
|
+
if (t1 === t2)
|
|
1881
|
+
return t1;
|
|
1417
1882
|
// TODO this is broken for recursive types (need to do cycle tracking in tandem with TypeUnion/TypeIntersect)
|
|
1418
1883
|
try {
|
|
1419
1884
|
if (t1.type === "Ref") {
|
|
1420
1885
|
if (t2.type === "Ref") {
|
|
1421
|
-
return RefType(TypeEqual(t1.value, t2.value, r1, r2));
|
|
1886
|
+
return RefType(withPathSegment("[ref]", () => TypeEqual(t1.value, t2.value, r1, r2)));
|
|
1422
1887
|
}
|
|
1423
1888
|
else {
|
|
1424
|
-
throw new TypeMismatchError(
|
|
1889
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1425
1890
|
}
|
|
1426
1891
|
}
|
|
1427
1892
|
else if (t1.type === "Array") {
|
|
1428
1893
|
if (t2.type === "Array") {
|
|
1429
|
-
return ArrayType(TypeEqual(t1.value, t2.value, r1, r2));
|
|
1894
|
+
return ArrayType(withPathSegment("[element]", () => TypeEqual(t1.value, t2.value, r1, r2)));
|
|
1895
|
+
}
|
|
1896
|
+
else {
|
|
1897
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
else if (t1.type === "Vector") {
|
|
1901
|
+
if (t2.type === "Vector") {
|
|
1902
|
+
return VectorType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element, r1, r2)));
|
|
1903
|
+
}
|
|
1904
|
+
else {
|
|
1905
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
else if (t1.type === "Matrix") {
|
|
1909
|
+
if (t2.type === "Matrix") {
|
|
1910
|
+
return MatrixType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element, r1, r2)));
|
|
1430
1911
|
}
|
|
1431
1912
|
else {
|
|
1432
|
-
throw new TypeMismatchError(
|
|
1913
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1433
1914
|
}
|
|
1434
1915
|
}
|
|
1435
1916
|
else if (t1.type === "Set") {
|
|
1436
1917
|
if (t2.type === "Set") {
|
|
1437
|
-
return SetType(TypeEqual(t1.key, t2.key, r1, r2));
|
|
1918
|
+
return SetType(withPathSegment("[key]", () => TypeEqual(t1.key, t2.key, r1, r2)));
|
|
1438
1919
|
}
|
|
1439
1920
|
else {
|
|
1440
|
-
throw new TypeMismatchError(
|
|
1921
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1441
1922
|
}
|
|
1442
1923
|
}
|
|
1443
1924
|
else if (t1.type === "Dict") {
|
|
1444
1925
|
if (t2.type === "Dict") {
|
|
1445
|
-
return DictType(TypeEqual(t1.key, t2.key, r1, r2), TypeEqual(t1.value, t2.value, r1, r2));
|
|
1926
|
+
return DictType(withPathSegment("[key]", () => TypeEqual(t1.key, t2.key, r1, r2)), withPathSegment("[value]", () => TypeEqual(t1.value, t2.value, r1, r2)));
|
|
1446
1927
|
}
|
|
1447
1928
|
else {
|
|
1448
|
-
throw new TypeMismatchError(
|
|
1929
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1449
1930
|
}
|
|
1450
1931
|
}
|
|
1451
1932
|
else if (t1.type === "Struct") {
|
|
@@ -1453,20 +1934,20 @@ export function TypeEqual(t1, t2, r1 = t1, r2 = t2) {
|
|
|
1453
1934
|
const e1 = Object.entries(t1.fields);
|
|
1454
1935
|
const e2 = Object.entries(t2.fields);
|
|
1455
1936
|
if (e1.length !== e2.length)
|
|
1456
|
-
throw new TypeMismatchError(
|
|
1937
|
+
throw new TypeMismatchError(`structs contain different number of fields (${e1.length} vs ${e2.length})`);
|
|
1457
1938
|
let i = 0;
|
|
1458
1939
|
const e = {};
|
|
1459
1940
|
for (const [k1, f1] of e1) {
|
|
1460
1941
|
const [k2, f2] = e2[i];
|
|
1461
1942
|
if (k1 !== k2)
|
|
1462
|
-
throw new TypeMismatchError(
|
|
1463
|
-
e[k1] = TypeEqual(f1, f2, r1, r2);
|
|
1943
|
+
throw new TypeMismatchError(`struct field ${i} has mismatched names ${printIdentifier(k1)} and ${printIdentifier(k2)}`);
|
|
1944
|
+
e[k1] = withPathSegment(`.${k1}`, () => TypeEqual(f1, f2, r1, r2));
|
|
1464
1945
|
i += 1;
|
|
1465
1946
|
}
|
|
1466
1947
|
return StructType(e);
|
|
1467
1948
|
}
|
|
1468
1949
|
else {
|
|
1469
|
-
throw new TypeMismatchError(
|
|
1950
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1470
1951
|
}
|
|
1471
1952
|
}
|
|
1472
1953
|
else if (t1.type === "Variant") {
|
|
@@ -1474,27 +1955,37 @@ export function TypeEqual(t1, t2, r1 = t1, r2 = t2) {
|
|
|
1474
1955
|
if (t2.type === "Variant") {
|
|
1475
1956
|
const e1 = Object.entries(t1.cases);
|
|
1476
1957
|
const e2 = Object.entries(t2.cases);
|
|
1477
|
-
if (e1.length !== e2.length)
|
|
1478
|
-
|
|
1958
|
+
if (e1.length !== e2.length) {
|
|
1959
|
+
let msg = `variants contain different number of cases (${e1.length} vs ${e2.length})`;
|
|
1960
|
+
const names1 = new Set(e1.map(([k]) => k));
|
|
1961
|
+
const names2 = new Set(e2.map(([k]) => k));
|
|
1962
|
+
const onlyIn1 = e1.map(([k]) => k).filter(k => !names2.has(k));
|
|
1963
|
+
const onlyIn2 = e2.map(([k]) => k).filter(k => !names1.has(k));
|
|
1964
|
+
if (onlyIn1.length > 0)
|
|
1965
|
+
msg += `; only in expected: ${onlyIn1.join(", ")}`;
|
|
1966
|
+
if (onlyIn2.length > 0)
|
|
1967
|
+
msg += `; only in actual: ${onlyIn2.join(", ")}`;
|
|
1968
|
+
throw new TypeMismatchError(msg);
|
|
1969
|
+
}
|
|
1479
1970
|
let i = 0;
|
|
1480
1971
|
const e = {};
|
|
1481
1972
|
for (const [k1, f1] of e1) {
|
|
1482
1973
|
const [k2, f2] = e2[i];
|
|
1483
1974
|
if (k1 !== k2) {
|
|
1484
1975
|
if (k1 < k2) {
|
|
1485
|
-
throw new TypeMismatchError(
|
|
1976
|
+
throw new TypeMismatchError(`variant case ${k1} is not present in both variants`);
|
|
1486
1977
|
}
|
|
1487
1978
|
else {
|
|
1488
|
-
throw new TypeMismatchError(
|
|
1979
|
+
throw new TypeMismatchError(`variant case ${k2} is not present in both variants`);
|
|
1489
1980
|
}
|
|
1490
1981
|
}
|
|
1491
|
-
e[k1] = TypeEqual(f1, f2, r1, r2);
|
|
1982
|
+
e[k1] = withPathSegment(`.${k1}`, () => TypeEqual(f1, f2, r1, r2));
|
|
1492
1983
|
i += 1;
|
|
1493
1984
|
}
|
|
1494
1985
|
return VariantType(e);
|
|
1495
1986
|
}
|
|
1496
1987
|
else {
|
|
1497
|
-
throw new TypeMismatchError(
|
|
1988
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1498
1989
|
}
|
|
1499
1990
|
}
|
|
1500
1991
|
else if (t1.type === "Recursive") {
|
|
@@ -1504,39 +1995,39 @@ export function TypeEqual(t1, t2, r1 = t1, r2 = t2) {
|
|
|
1504
1995
|
return t1; // both are references to the same recursive type
|
|
1505
1996
|
}
|
|
1506
1997
|
else {
|
|
1507
|
-
throw new TypeMismatchError(
|
|
1998
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: recursive types do not match`);
|
|
1508
1999
|
}
|
|
1509
2000
|
}
|
|
1510
2001
|
else if (t2.node === r2) {
|
|
1511
|
-
throw new TypeMismatchError(
|
|
2002
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: recursive types do not match`);
|
|
1512
2003
|
}
|
|
1513
2004
|
// this is the root of a new recursive type - assert the node types are equal
|
|
1514
2005
|
return RecursiveType(() => TypeEqual(t1.node, t2.node, t1.node, t2.node));
|
|
1515
2006
|
}
|
|
1516
2007
|
else {
|
|
1517
|
-
throw new TypeMismatchError(
|
|
2008
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1518
2009
|
}
|
|
1519
2010
|
}
|
|
1520
2011
|
else if (t1.type === "Function") {
|
|
1521
2012
|
if (t2.type === "Function") {
|
|
1522
2013
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1523
|
-
throw new TypeMismatchError(
|
|
2014
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1524
2015
|
}
|
|
1525
|
-
return FunctionType(t1.inputs.map((t, i) => TypeEqual(t, t2.inputs[i], r1, r2)), TypeEqual(t1.output, t2.output, r1, r2));
|
|
2016
|
+
return FunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeEqual(t, t2.inputs[i], r1, r2))), withPathSegment("[output]", () => TypeEqual(t1.output, t2.output, r1, r2)));
|
|
1526
2017
|
}
|
|
1527
2018
|
else {
|
|
1528
|
-
throw new TypeMismatchError(
|
|
2019
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1529
2020
|
}
|
|
1530
2021
|
}
|
|
1531
2022
|
else if (t1.type === "AsyncFunction") {
|
|
1532
2023
|
if (t2.type === "AsyncFunction") {
|
|
1533
2024
|
if (t1.inputs.length !== t2.inputs.length) {
|
|
1534
|
-
throw new TypeMismatchError(
|
|
2025
|
+
throw new TypeMismatchError(`functions take different number of arguments (${t1.inputs.length} vs ${t2.inputs.length})`);
|
|
1535
2026
|
}
|
|
1536
|
-
return AsyncFunctionType(t1.inputs.map((t, i) => TypeEqual(t, t2.inputs[i], r1, r2)), TypeEqual(t1.output, t2.output, r1, r2));
|
|
2027
|
+
return AsyncFunctionType(t1.inputs.map((t, i) => withPathSegment(`[input ${i}]`, () => TypeEqual(t, t2.inputs[i], r1, r2))), withPathSegment("[output]", () => TypeEqual(t1.output, t2.output, r1, r2)));
|
|
1537
2028
|
}
|
|
1538
2029
|
else {
|
|
1539
|
-
throw new TypeMismatchError(
|
|
2030
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1540
2031
|
}
|
|
1541
2032
|
}
|
|
1542
2033
|
else {
|
|
@@ -1544,7 +2035,7 @@ export function TypeEqual(t1, t2, r1 = t1, r2 = t2) {
|
|
|
1544
2035
|
return t1;
|
|
1545
2036
|
}
|
|
1546
2037
|
else {
|
|
1547
|
-
throw new TypeMismatchError(
|
|
2038
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1548
2039
|
}
|
|
1549
2040
|
}
|
|
1550
2041
|
}
|
|
@@ -1552,7 +2043,7 @@ export function TypeEqual(t1, t2, r1 = t1, r2 = t2) {
|
|
|
1552
2043
|
if (cause instanceof TypeMismatchError) {
|
|
1553
2044
|
throw cause; // Don't wrap our own errors - they already have the full path
|
|
1554
2045
|
}
|
|
1555
|
-
throw new TypeMismatchError(
|
|
2046
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}`, { cause });
|
|
1556
2047
|
}
|
|
1557
2048
|
}
|
|
1558
2049
|
/**
|
|
@@ -1577,41 +2068,57 @@ export function TypeWiden(t1, t2) {
|
|
|
1577
2068
|
return t1;
|
|
1578
2069
|
}
|
|
1579
2070
|
else if (t1.type === "Recursive") {
|
|
1580
|
-
throw new TypeMismatchError(`
|
|
2071
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: recursive types not supported`);
|
|
1581
2072
|
}
|
|
1582
2073
|
else if (t2.type === "Recursive") {
|
|
1583
|
-
throw new TypeMismatchError(`
|
|
2074
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: recursive types not supported`);
|
|
1584
2075
|
}
|
|
1585
2076
|
else if (t1.type === "Ref") {
|
|
1586
2077
|
if (t2.type === "Ref") {
|
|
1587
|
-
return RefType(TypeWiden(t1.value, t2.value));
|
|
2078
|
+
return RefType(withPathSegment("[ref]", () => TypeWiden(t1.value, t2.value)));
|
|
1588
2079
|
}
|
|
1589
2080
|
else {
|
|
1590
|
-
throw new TypeMismatchError(`
|
|
2081
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1591
2082
|
}
|
|
1592
2083
|
}
|
|
1593
2084
|
else if (t1.type === "Array") {
|
|
1594
2085
|
if (t2.type === "Array") {
|
|
1595
|
-
return ArrayType(TypeWiden(t1.value, t2.value));
|
|
2086
|
+
return ArrayType(withPathSegment("[element]", () => TypeWiden(t1.value, t2.value)));
|
|
2087
|
+
}
|
|
2088
|
+
else {
|
|
2089
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
else if (t1.type === "Vector") {
|
|
2093
|
+
if (t2.type === "Vector") {
|
|
2094
|
+
return VectorType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element)));
|
|
2095
|
+
}
|
|
2096
|
+
else {
|
|
2097
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
else if (t1.type === "Matrix") {
|
|
2101
|
+
if (t2.type === "Matrix") {
|
|
2102
|
+
return MatrixType(withPathSegment("[element]", () => TypeEqual(t1.element, t2.element)));
|
|
1596
2103
|
}
|
|
1597
2104
|
else {
|
|
1598
|
-
throw new TypeMismatchError(`
|
|
2105
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1599
2106
|
}
|
|
1600
2107
|
}
|
|
1601
2108
|
else if (t1.type === "Set") {
|
|
1602
2109
|
if (t2.type === "Set") {
|
|
1603
|
-
return SetType(TypeWiden(t1.key, t2.key));
|
|
2110
|
+
return SetType(withPathSegment("[key]", () => TypeWiden(t1.key, t2.key)));
|
|
1604
2111
|
}
|
|
1605
2112
|
else {
|
|
1606
|
-
throw new TypeMismatchError(`
|
|
2113
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1607
2114
|
}
|
|
1608
2115
|
}
|
|
1609
2116
|
else if (t1.type === "Dict") {
|
|
1610
2117
|
if (t2.type === "Dict") {
|
|
1611
|
-
return DictType(TypeWiden(t1.key, t2.key), TypeWiden(t1.value, t2.value));
|
|
2118
|
+
return DictType(withPathSegment("[key]", () => TypeWiden(t1.key, t2.key)), withPathSegment("[value]", () => TypeWiden(t1.value, t2.value)));
|
|
1612
2119
|
}
|
|
1613
2120
|
else {
|
|
1614
|
-
throw new TypeMismatchError(`
|
|
2121
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1615
2122
|
}
|
|
1616
2123
|
}
|
|
1617
2124
|
else if (t1.type === "Struct") {
|
|
@@ -1619,20 +2126,20 @@ export function TypeWiden(t1, t2) {
|
|
|
1619
2126
|
const e1 = Object.entries(t1.fields);
|
|
1620
2127
|
const e2 = Object.entries(t2.fields);
|
|
1621
2128
|
if (e1.length !== e2.length)
|
|
1622
|
-
throw new TypeMismatchError(`
|
|
2129
|
+
throw new TypeMismatchError(`structs contain different number of fields (${e1.length} vs ${e2.length})`);
|
|
1623
2130
|
let i = 0;
|
|
1624
2131
|
const e = {};
|
|
1625
2132
|
for (const [k1, f1] of e1) {
|
|
1626
2133
|
const [k2, f2] = e2[i];
|
|
1627
2134
|
if (k1 !== k2)
|
|
1628
|
-
throw new TypeMismatchError(`
|
|
1629
|
-
e[k1] = TypeWiden(f1, f2);
|
|
2135
|
+
throw new TypeMismatchError(`struct field ${i} has mismatched names ${printIdentifier(k1)} and ${printIdentifier(k2)}`);
|
|
2136
|
+
e[k1] = withPathSegment(`.${k1}`, () => TypeWiden(f1, f2));
|
|
1630
2137
|
i += 1;
|
|
1631
2138
|
}
|
|
1632
2139
|
return StructType(e);
|
|
1633
2140
|
}
|
|
1634
2141
|
else {
|
|
1635
|
-
throw new TypeMismatchError(`
|
|
2142
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1636
2143
|
}
|
|
1637
2144
|
}
|
|
1638
2145
|
else if (t1.type === "Variant") {
|
|
@@ -1644,7 +2151,7 @@ export function TypeWiden(t1, t2) {
|
|
|
1644
2151
|
cases[k1] = f1;
|
|
1645
2152
|
}
|
|
1646
2153
|
else {
|
|
1647
|
-
cases[k1] = TypeWiden(f1, f2);
|
|
2154
|
+
cases[k1] = withPathSegment(`.${k1}`, () => TypeWiden(f1, f2));
|
|
1648
2155
|
}
|
|
1649
2156
|
}
|
|
1650
2157
|
for (const [k2, f2] of Object.entries(t2.cases)) {
|
|
@@ -1656,21 +2163,21 @@ export function TypeWiden(t1, t2) {
|
|
|
1656
2163
|
return VariantType(cases);
|
|
1657
2164
|
}
|
|
1658
2165
|
else {
|
|
1659
|
-
throw new TypeMismatchError(`
|
|
2166
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1660
2167
|
}
|
|
1661
2168
|
}
|
|
1662
2169
|
else if (t1.type === "Function") {
|
|
1663
|
-
throw new TypeMismatchError(`
|
|
2170
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: functions not supported`);
|
|
1664
2171
|
}
|
|
1665
2172
|
else if (t1.type === "AsyncFunction") {
|
|
1666
|
-
throw new TypeMismatchError(`
|
|
2173
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: functions not supported`);
|
|
1667
2174
|
}
|
|
1668
2175
|
else {
|
|
1669
2176
|
if (t1.type === t2.type) {
|
|
1670
2177
|
return t1;
|
|
1671
2178
|
}
|
|
1672
2179
|
else {
|
|
1673
|
-
throw new TypeMismatchError(`
|
|
2180
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}: incompatible types`);
|
|
1674
2181
|
}
|
|
1675
2182
|
}
|
|
1676
2183
|
}
|
|
@@ -1678,7 +2185,7 @@ export function TypeWiden(t1, t2) {
|
|
|
1678
2185
|
if (cause instanceof TypeMismatchError) {
|
|
1679
2186
|
throw cause; // Don't wrap our own errors - they already have the full path
|
|
1680
2187
|
}
|
|
1681
|
-
throw new TypeMismatchError(`
|
|
2188
|
+
throw new TypeMismatchError(`expected ${printTypeSummary(t1)} but got ${printTypeSummary(t2)}`, { cause });
|
|
1682
2189
|
}
|
|
1683
2190
|
}
|
|
1684
2191
|
/**
|