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; +}