diff --git a/tslang/lib/TypeScript/MLIRGenImpl.h b/tslang/lib/TypeScript/MLIRGenImpl.h index c4b942158..fd6f64934 100644 --- a/tslang/lib/TypeScript/MLIRGenImpl.h +++ b/tslang/lib/TypeScript/MLIRGenImpl.h @@ -6192,6 +6192,13 @@ class MLIRGenImpl else { LLVM_DEBUG(dbgs() << "\n!! left expr.: " << leftExpressionValueBeforeCast << " ...\n";); + // `p[i]` of a `Ref` is the reference to the element (as a read gives it), not the element + if (leftExpressionValueBeforeCast.getDefiningOp()) + { + emitError(location, "indexing a 'Ref' gives a reference to the element; store through it with 'Deref(p[i]) = value'"); + return mlir::failure(); + } + emitError(location, "saving to constant object"); return mlir::failure(); } diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index 891d8b56e..9f77f13a2 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -2699,6 +2699,16 @@ add_test(NAME test-compile-integer-literal-truncation-quiet set_tests_properties(test-compile-integer-literal-truncation-quiet PROPERTIES FAIL_REGULAR_EXPRESSION "warning:|error:|Stack dump|Assertion failed") +# A store to an indexed Ref (`bytes[i] = x`) names the form that stores, `Deref(bytes[i]) = x`, +# instead of "saving to constant object". +add_test(NAME test-compile-ref-index-store + COMMAND $ --emit=obj --no-default-lib -mm=none + "${PROJECT_SOURCE_DIR}/test/tester/ref-index-store/store.ts" + -o "${CMAKE_CURRENT_BINARY_DIR}/ref-index-store.obj") +set_tests_properties(test-compile-ref-index-store + PROPERTIES PASS_REGULAR_EXPRESSION "store\\.ts:8:5: error: indexing a 'Ref' gives a reference to the element; store through it with 'Deref\\(p\\[i\\]\\) = value'" + FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed") + # A number, string, boolean or array passed where an interface with members is expected is an # error; it compiled to a cast lowering could not make, and the callee read garbage. An interface # without members still takes any value. diff --git a/tslang/test/tester/ref-index-store/store.ts b/tslang/test/tester/ref-index-store/store.ts new file mode 100644 index 000000000..0dd2fa3ae --- /dev/null +++ b/tslang/test/tester/ref-index-store/store.ts @@ -0,0 +1,9 @@ +// Indexing a Ref gives the element's reference, as a read does (`Deref(bytes[i])`), so a store +// to it is an error that names the form that stores: `Deref(bytes[i]) = value`. +type Str = [buf: [_0: u64, _1: u64], size: index]; + +function main() { + let value: Str = [[0, 0], 0]; + let bytes = >Ref(value); + bytes[0] = 65; +}