diff --git a/tslang/lib/TypeScript/MLIRGenImpl.h b/tslang/lib/TypeScript/MLIRGenImpl.h index bfacf7354..b62a7b92e 100644 --- a/tslang/lib/TypeScript/MLIRGenImpl.h +++ b/tslang/lib/TypeScript/MLIRGenImpl.h @@ -161,7 +161,8 @@ class MLIRGenImpl path(pathParam), declarationMode(false), tempEntryBlock(nullptr), - overwriteLoc(mlir::UnknownLoc::get(builder.getContext())) + overwriteLoc(mlir::UnknownLoc::get(builder.getContext())), + generatedNodesAnchor(mlir::UnknownLoc::get(builder.getContext())) { setCompileOptions(compileOptions); @@ -1157,6 +1158,10 @@ class MLIRGenImpl mlir::LogicalResult mlirGenDisposeOne(mlir::Location location, ts::VariableDeclarationDOM::TypePtr varDecl, mlir::Value varValue, const GenContext &genContext) { + // the call is made at the scope's exit, but an error in it belongs to the declaration + MLIRLocationGuard anchorGuard(generatedNodesAnchor); + generatedNodesAnchor = stripMetadata(varDecl->getLoc()); + auto disposeGuard = varDecl->getDisposeGuard(); if (!disposeGuard) { @@ -13947,13 +13952,23 @@ class MLIRGenImpl return mlir::UnknownLoc::get(builder.getContext()); } + // a node the compiler made (a for...of's loop, a `using`'s dispose call) has no position: + // it is where the code it was made for is, not at the start of the file + if (loc->isTextRangeEmpty() && !isa(generatedNodesAnchor)) + { + return locFuseWithScope(combine(overwriteLoc, generatedNodesAnchor)); + } + + return locFuseWithScope(combine(overwriteLoc, locWithoutScope(loc))); + } + + // where the node is in the source, without the debug scope and the overwriteLoc loc() adds + mlir::Location locWithoutScope(TextRange loc) + { auto pos = loc->pos.textPos > 0 ? loc->pos.textPos : loc->pos.pos; //return loc1(sourceFile, fileName.str(), pos, loc->_end - pos); //return loc2(sourceFile, fileName.str(), pos, loc->_end - pos); - return locFuseWithScope( - combine( - overwriteLoc, - loc2Fuse(sourceFile, mainSourceFileName.str(), pos, loc->_end - pos))); + return loc2Fuse(sourceFile, mainSourceFileName.str(), pos, loc->_end - pos); } mlir::Location loc1(ts::SourceFile sourceFile, std::string fileName, int start, int length) @@ -14375,6 +14390,9 @@ class MLIRGenImpl mlir::ModuleOp tempModule; mlir_ts::FuncOp tempFuncOp; mlir::Location overwriteLoc; + // where the innermost statement being generated is (no debug scope: loc() adds the current + // one): the location of the nodes the compiler makes for it, which have none of their own + mlir::Location generatedNodesAnchor; }; } // namespace mlirgen } // namespace typescript diff --git a/tslang/lib/TypeScript/MLIRGenStatements.cpp b/tslang/lib/TypeScript/MLIRGenStatements.cpp index c77e5015b..6eae033d5 100644 --- a/tslang/lib/TypeScript/MLIRGenStatements.cpp +++ b/tslang/lib/TypeScript/MLIRGenStatements.cpp @@ -292,6 +292,14 @@ namespace mlirgen mlir::LogicalResult MLIRGenImpl::mlirGen(Statement statementAST, const GenContext &genContext) { + // what the compiler makes for this statement is reported where the statement is; a + // statement it made itself keeps the anchor of the one it was made for + MLIRLocationGuard anchorGuard(generatedNodesAnchor); + if (!statementAST->isTextRangeEmpty()) + { + generatedNodesAnchor = locWithoutScope(statementAST); + } + auto kind = (SyntaxKind)statementAST; if (kind == SyntaxKind::FunctionDeclaration) { diff --git a/tslang/test/tester/CMakeLists.txt b/tslang/test/tester/CMakeLists.txt index 5feb2e703..e92db2eb9 100644 --- a/tslang/test/tester/CMakeLists.txt +++ b/tslang/test/tester/CMakeLists.txt @@ -2947,6 +2947,26 @@ set_tests_properties(test-compile-diagnostic-location-implicit-constructor PROPERTIES PASS_REGULAR_EXPRESSION "implicit_constructor\\.ts:9:1: error: Class constructor is not accessable" FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed|implicit_constructor\\.ts:1:") +# An error in the code the compiler makes for a statement (a for...of's or for...in's loop) is +# reported at the statement, and one in a `using`'s dispose call at the declaration - not at 1:1, +# as a node the compiler makes has no position of its own. +set(diagnostic_location_statement_cases + "for_of|for_of\\.ts:6:5: error: Can't resolve property 'length' of type s32" + "for_in|for_in\\.ts:6:5: error: Can't resolve property 'length' of type s32" + "using|using\\.ts:5:11: error: Can't resolve property 'dispose' of type s32") +foreach(diagnostic_location_case ${diagnostic_location_statement_cases}) + string(REPLACE "|" ";" diagnostic_location_parts "${diagnostic_location_case}") + list(GET diagnostic_location_parts 0 diagnostic_location_name) + list(GET diagnostic_location_parts 1 diagnostic_location_error) + add_test(NAME test-compile-diagnostic-location-${diagnostic_location_name} + COMMAND $ --emit=obj --no-default-lib -mm=none + "${PROJECT_SOURCE_DIR}/test/tester/diagnostic-location/${diagnostic_location_name}.ts" + -o "${CMAKE_CURRENT_BINARY_DIR}/diagnostic-location-${diagnostic_location_name}.obj") + set_tests_properties(test-compile-diagnostic-location-${diagnostic_location_name} + PROPERTIES PASS_REGULAR_EXPRESSION "${diagnostic_location_error}" + FAIL_REGULAR_EXPRESSION "Stack dump|Assertion failed|${diagnostic_location_name}\\.ts:1:") +endforeach() + # `ns.name` is the namespace's member or an error: a local or an outer namespace's `name` isn't it. foreach(namespace_member_case missing_member outer_member) add_test(NAME test-compile-namespace-member-${namespace_member_case} diff --git a/tslang/test/tester/diagnostic-location/for_in.ts b/tslang/test/tester/diagnostic-location/for_in.ts new file mode 100644 index 000000000..1a20a9e1e --- /dev/null +++ b/tslang/test/tester/diagnostic-location/for_in.ts @@ -0,0 +1,9 @@ +// A for...in over something without a length was reported at the start of the file: the loop +// the compiler makes for it had no position. + +function main() { + const n = 5; + for (const k in n) { + print(k); + } +} diff --git a/tslang/test/tester/diagnostic-location/for_of.ts b/tslang/test/tester/diagnostic-location/for_of.ts new file mode 100644 index 000000000..1c5b8abc4 --- /dev/null +++ b/tslang/test/tester/diagnostic-location/for_of.ts @@ -0,0 +1,9 @@ +// A for...of over something that isn't iterable was reported at the start of the file: the loop +// the compiler makes for it had no position. + +function main() { + const n = 5; + for (const x of n) { + print(x); + } +} diff --git a/tslang/test/tester/diagnostic-location/using.ts b/tslang/test/tester/diagnostic-location/using.ts new file mode 100644 index 000000000..efe694eab --- /dev/null +++ b/tslang/test/tester/diagnostic-location/using.ts @@ -0,0 +1,6 @@ +// A `using` of a value with no dispose method was reported at the start of the file: the dispose +// call the compiler makes for it had no position. + +function main() { + using x = 5; +}