From f906667da44893cda64783c181482af550caceff Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Sat, 17 Oct 2026 14:53:34 +0100 Subject: [PATCH] `delete` of a local holding a number is an error `const n = 5; delete n;` compiled with no diagnostic. mlirGen(Expression) dropped the delete's failure, so the error it had made ("must be optional") was never shown. The failure now reaches the statement, and an identifier that names no class instance, array or `new` value gets TypeScript's message: the operand must be a property reference. Deleting a class instance, an array or a `new` value stays. Propagating the failure showed one more dropped error: under rc and own, the null stored into a deleted variable's slot (so that its release at scope exit does nothing) failed the strict-null cast, and the store was never made. That cast now skips the strict-null check: it is not a null the program stores. -mm=own's "'delete' is not supported" error is reached again. Co-Authored-By: Claude Opus 5.5 --- tslang/lib/TypeScript/MLIRGenExpressions.cpp | 17 ++++++++++++++--- tslang/test/tester/CMakeLists.txt | 10 ++++++++++ .../tester/diagnostic-location/delete_local.ts | 10 ++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 tslang/test/tester/diagnostic-location/delete_local.ts diff --git a/tslang/lib/TypeScript/MLIRGenExpressions.cpp b/tslang/lib/TypeScript/MLIRGenExpressions.cpp index 546bb34b0..1dd87fd72 100644 --- a/tslang/lib/TypeScript/MLIRGenExpressions.cpp +++ b/tslang/lib/TypeScript/MLIRGenExpressions.cpp @@ -129,7 +129,8 @@ namespace mlirgen } else if (kind == SyntaxKind::DeleteExpression) { - mlirGen(expressionAST.as(), genContext); + // its failure was dropped, and with it the error: `delete n` of a local compiled + EXIT_IF_FAILED(mlirGen(expressionAST.as(), genContext)); return mlir::success(); } else if (kind == SyntaxKind::ThisKeyword) @@ -1365,6 +1366,13 @@ namespace mlirgen { CAST(expr, location, mlir_ts::RefType::get(arrayType.getElementType()), expr, genContext); } + else if (deleteExpression->expression == SyntaxKind::Identifier) + { + // `delete n` of a local holding a number: nothing to free (a class instance, an + // array or a value made by `new`, which can be freed, took the paths above) + emitError(location, "The operand of a 'delete' operator must be a property reference"); + return mlir::failure(); + } else { // e.g. `delete obj.a` where `a` is a plain, non-optional field of a value-tuple @@ -1409,8 +1417,11 @@ namespace mlirgen if (reference && isOwningSlot(location, reference)) { auto nullValue = builder.create(location, getNullType()); - mlir::Value clearedValue; - CAST(clearedValue, location, expr.getType(), nullValue, genContext); + // not a null the program stores, so no strict-null check: it failed this cast for + // `let c = new C()`, and the store was never made + auto clearedResult = cast(location, expr.getType(), nullValue, genContext, /*disableStrictNullCheck*/ true); + EXIT_IF_FAILED_OR_NO_VALUE(clearedResult) + auto clearedValue = V(clearedResult); builder.create(location, clearedValue, reference); } } diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index e92db2eb9..14db02d49 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -2930,6 +2930,16 @@ set_tests_properties(test-compile-diagnostic-location-generated-cast PROPERTIES PASS_REGULAR_EXPRESSION "generated_cast\\.ts:6:23: error: can't cast from 'null' to 'string'" FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed|generated_cast\\.ts:1:") +# `delete` of a local holding a number is an error: it compiled, as the error made for it was +# dropped. A class instance (or an array, or a value made by `new`) can still be deleted. +add_test(NAME test-compile-diagnostic-location-delete-local + COMMAND $ --emit=obj --no-default-lib -mm=none + "${PROJECT_SOURCE_DIR}/test/tester/diagnostic-location/delete_local.ts" + -o "${CMAKE_CURRENT_BINARY_DIR}/diagnostic-location-delete-local.obj") +set_tests_properties(test-compile-diagnostic-location-delete-local + PROPERTIES PASS_REGULAR_EXPRESSION "delete_local\\.ts:9:5: error: The operand of a 'delete' operator must be a property reference" + FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed|delete_local\\.ts:7:") + # An error in a field initializer, or in a derived class's implicit constructor, is reported at the # field or the class - not at 1:1, where the code the compiler generates for them had put it. add_test(NAME test-compile-diagnostic-location-field-initializer diff --git a/tslang/test/tester/diagnostic-location/delete_local.ts b/tslang/test/tester/diagnostic-location/delete_local.ts new file mode 100644 index 000000000..b1704e9e1 --- /dev/null +++ b/tslang/test/tester/diagnostic-location/delete_local.ts @@ -0,0 +1,10 @@ +// `delete` of a local holding a number compiled with no error: the error was made and dropped. + +class C {} + +function main() { + const c = new C(); + delete c; + const n = 5; + delete n; +}