diff --git a/tag.bat b/tag.bat index 591312038..6da3e2773 100644 --- a/tag.bat +++ b/tag.bat @@ -1,2 +1,2 @@ -git tag -a v0.0-pre-alpha83 -m "pre alpha v0.0-83" +git tag -a v0.0-pre-alpha84 -m "pre alpha v0.0-84" git push origin --tags diff --git a/tag_del.bat b/tag_del.bat index 0b6a7571f..bc79d08df 100644 --- a/tag_del.bat +++ b/tag_del.bat @@ -1,2 +1,2 @@ -git push --delete origin v0.0-pre-alpha83 -git tag -d v0.0-pre-alpha83 +git push --delete origin v0.0-pre-alpha84 +git tag -d v0.0-pre-alpha84 diff --git a/tslang/include/TypeScript/MLIRLogic/MLIRTypeHelper.h b/tslang/include/TypeScript/MLIRLogic/MLIRTypeHelper.h index c333773f5..1f71c5035 100644 --- a/tslang/include/TypeScript/MLIRLogic/MLIRTypeHelper.h +++ b/tslang/include/TypeScript/MLIRLogic/MLIRTypeHelper.h @@ -1790,6 +1790,23 @@ class MLIRTypeHelper } // TODO: review using canCast in detecting base Type. index, int, number + // The element of a nested array literal is an array itself (`[[1, 2]]` holds `array`), so what + // has to widen is the element type inside it. Only a constant array asks this: MLIRGen rebuilds one + // element by element (castConstArrayToArray), which is what makes the wider element type reachable - + // an array that is not a literal is still not converted element-wise. + bool canWideConstArrayElementWithoutDataLoss(mlir::Type srcElementType, mlir::Type dstElementType) + { + if (auto srcArrayType = dyn_cast(srcElementType)) + { + if (auto dstArrayType = dyn_cast(dstElementType)) + { + return canWideConstArrayElementWithoutDataLoss(srcArrayType.getElementType(), dstArrayType.getElementType()); + } + } + + return canWideTypeWithoutDataLoss(srcElementType, dstElementType); + } + bool canWideTypeWithoutDataLoss(mlir::Type srcType, mlir::Type dstType) { if (!srcType || !dstType) @@ -1885,9 +1902,9 @@ class MLIRTypeHelper return true; } - return canWideTypeWithoutDataLoss(constArrayType.getElementType(), arrayType.getElementType()); + return canWideConstArrayElementWithoutDataLoss(constArrayType.getElementType(), arrayType.getElementType()); } - } + } // native types auto destIntType = dyn_cast(dstType); diff --git a/tslang/lib/TypeScript/MLIRGenCast.cpp b/tslang/lib/TypeScript/MLIRGenCast.cpp index 656d5beff..46d4301f2 100644 --- a/tslang/lib/TypeScript/MLIRGenCast.cpp +++ b/tslang/lib/TypeScript/MLIRGenCast.cpp @@ -930,16 +930,44 @@ namespace mlirgen auto constOp = value.getDefiningOp(); auto elementAttrs = constOp ? dyn_cast(constOp.getValue()) : mlir::ArrayAttr(); - if (!elementAttrs || llvm::any_of(elementAttrs, [](mlir::Attribute attr) { return isa(attr); })) + if (!elementAttrs) { - // not a literal, or nested arrays: left to the cast below + // not a literal: left to the cast below return std::nullopt; } + // `[[1, 2]]` holds arrays, kept as nested attributes. Their own elements need the same + // conversion, so each is made a constant array again and cast here in turn. + auto sourceElementType = constArrayType.getElementType(); + mlir::Type nestedElementType; + if (auto nestedArrayType = dyn_cast(sourceElementType)) + { + nestedElementType = nestedArrayType.getElementType(); + } + else if (auto nestedConstArrayType = dyn_cast(sourceElementType)) + { + nestedElementType = nestedConstArrayType.getElementType(); + } + SmallVector elements; for (auto elementAttr : elementAttrs) { - auto element = builder.create(location, constArrayType.getElementType(), elementAttr); + mlir::Value element; + if (auto nestedAttrs = dyn_cast(elementAttr)) + { + if (!nestedElementType) + { + return std::nullopt; + } + + element = builder.create( + location, getConstArrayType(nestedElementType, nestedAttrs.size()), nestedAttrs); + } + else + { + element = builder.create(location, sourceElementType, elementAttr); + } + CAST_A(castedElement, location, arrayType.getElementType(), element, genContext); elements.push_back(castedElement); } diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index 39df3dbf4..8400f039a 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -175,6 +175,7 @@ add_test(NAME test-compile-00-typeof-function-narrowing COMMAND test-runner "${P add_test(NAME test-compile-00-typeof-static-fold-conditions COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00typeof_static_fold_conditions.ts") add_test(NAME test-compile-00-typeof-union-narrowing COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00typeof_union_narrowing.ts") add_test(NAME test-compile-00-const-array-to-array-elements COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_array_to_array_elements.ts") +add_test(NAME test-compile-00-const-array-nested-elements COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_array_nested_elements.ts") add_test(NAME test-compile-00-array-move-wide-elements COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_move_wide_elements.ts") add_test(NAME test-compile-00-funcs-expression-generic COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_expression_generic.ts") add_test(NAME test-compile-00-funcs-expression-iterator COMMAND test-runner "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_expression_iterator.ts") @@ -596,6 +597,7 @@ add_test(NAME test-jit-00-typeof-function-narrowing COMMAND test-runner -jit "${ add_test(NAME test-jit-00-typeof-static-fold-conditions COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00typeof_static_fold_conditions.ts") add_test(NAME test-jit-00-typeof-union-narrowing COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00typeof_union_narrowing.ts") add_test(NAME test-jit-00-const-array-to-array-elements COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_array_to_array_elements.ts") +add_test(NAME test-jit-00-const-array-nested-elements COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00const_array_nested_elements.ts") add_test(NAME test-jit-00-array-move-wide-elements COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00array_move_wide_elements.ts") add_test(NAME test-jit-00-funcs-expression-generic COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_expression_generic.ts") add_test(NAME test-jit-00-funcs-expression-iterator COMMAND test-runner -jit "${PROJECT_SOURCE_DIR}/test/tester/tests/00funcs_expression_iterator.ts") @@ -1324,6 +1326,7 @@ add_test(NAME test-jit-none-strings COMMAND test-runner -jit -mm=none "${PROJECT set(TSLANG_CORPUS 00add_promotes_both_operands.ts 00conditional_owned_result.ts + 00const_array_nested_elements.ts 00const_array_to_array_elements.ts 00owned_array_splice.ts 00alloc_in_catch.ts diff --git a/tslang/test/tester/tests/00const_array_nested_elements.ts b/tslang/test/tester/tests/00const_array_nested_elements.ts new file mode 100644 index 000000000..bd1680228 --- /dev/null +++ b/tslang/test/tester/tests/00const_array_nested_elements.ts @@ -0,0 +1,27 @@ +// A nested integer array literal that is not built for one array type - a const variable, or a +// literal meeting a union - keeps `s32` elements in its inner arrays. Casting it to `number[][]` +// copied those as they were: inner elements came out as garbage, and the union case did not compile +// at all ("'ts.Cast' op ... can't be stored in"). +function main() { + const c = [[1, 2], [3, 4]]; + let fromConst: number[][] = c; + assert(fromConst.length == 2, "const variable: outer length"); + assert(fromConst[0].length == 2, "const variable: inner length"); + assert(fromConst[1][1] == 4, "const variable: inner element"); + assert(fromConst[0][0] / 2 == 0.5, "const variable: element is a number"); + + let u: number[][] | string = [[5, 6]]; + if (typeof u === "array") { + assert(u.length == 1, "union: outer length"); + assert(u[0][1] == 6, "union: inner element"); + } else { + assert(false, "union: wrong branch"); + } + + // three levels deep + const deep = [[[7, 8]]]; + let fromDeep: number[][][] = deep; + assert(fromDeep[0][0][1] == 8, "three levels"); + + print("done."); +}