Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -12743,6 +12743,11 @@ class MLIRGenImpl
// next pass; see mlirGen(FunctionDeclaration)
std::map<std::string, std::pair<FunctionDeclaration, mlir::Operation *>> declaredFunctions;

// Set while an imported source file is generated (mlirGenInclude): the errors of the file go
// here instead of being printed, and the import hands them to the importer, whose
// processStatements tries a failed import again and prints only what the last attempt left.
mlir::SmallVector<std::unique_ptr<mlir::Diagnostic>> *importDiagnostics = nullptr;

// set while an `import { a as b }` alias is resolved to its target (resolveImportAlias)
bool resolvingImportAlias = false;

Expand Down
33 changes: 29 additions & 4 deletions tslang/lib/TypeScript/MLIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,8 +783,15 @@ namespace mlirgen
mlir::LogicalResult MLIRGenImpl::outputDiagnostics(mlir::SmallVector<std::unique_ptr<mlir::Diagnostic>> &postponedMessages,
int notResolved)
{
// print errors
if (notResolved)
// print errors, or hand them to the importer of this file
if (notResolved && importDiagnostics)
{
for (auto &diag : postponedMessages)
{
importDiagnostics->push_back(std::move(diag));
}
}
else if (notResolved)
{
printDiagnostics(sourceMgrHandler, postponedMessages, compileOptions.disableWarnings);
}
Expand Down Expand Up @@ -1117,8 +1124,26 @@ namespace mlirgen
// we need to override filename to track it in DBG info
SourceFileScope sourceFileScope(*this, importSource);

if (mlir::succeeded(mlirDiscoverAllDependencies(importSource, importIncludeFiles)) &&
mlir::succeeded(mlirCodeGenModule(importSource, importIncludeFiles, false, false)))
// An import cycle (a imports b imports a) fails b on its first attempt: a has not declared
// what b needs yet. a's processStatements tries the import again once it has, so b's errors
// are the importer's to report, and only if the import still fails.
mlir::SmallVector<std::unique_ptr<mlir::Diagnostic>> diagnostics;
auto generated = false;
{
MLIRValueGuard<mlir::SmallVector<std::unique_ptr<mlir::Diagnostic>> *> diagnosticsGuard(importDiagnostics);
importDiagnostics = &diagnostics;

generated = mlir::succeeded(mlirDiscoverAllDependencies(importSource, importIncludeFiles)) &&
mlir::succeeded(mlirCodeGenModule(importSource, importIncludeFiles, false, false));
}

// the import's own diagnostic handlers are gone: these reach the importer's
for (auto &diag : diagnostics)
{
builder.getContext()->getDiagEngine().emit(std::move(*diag));
}

if (generated)
{
// only now: an import that failed is tried again on the next pass, and must fail
// again rather than find itself already done. Its library declarations, if a
Expand Down
9 changes: 9 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2435,6 +2435,15 @@ tslang_add_import_tests(reference-path-import-and-reference "${reference_path_di
tslang_add_import_tests(reference-path-two-imports "${reference_path_dir}" two_imports module_left module_right)
tslang_add_import_tests(reference-path-import-diamond "${reference_path_dir}" import_diamond plain_module via_module)
tslang_add_import_tests(reference-path-import-cycle "${reference_path_dir}" import_cycle cycle_module_a cycle_module_b)
# Static linking only: a -shared library of these two modules declares Node twice to its importer
# ("redefinition of symbol named 'Node..new'"), a separate gap.
tslang_add_test(NAME test-compile-reference-path-import-cycle-class COMMAND test-runner "${reference_path_dir}/import_cycle_class.ts" "${reference_path_dir}/cycle_class_node.ts" "${reference_path_dir}/cycle_class_text.ts")
# The first attempt at an import in a cycle fails and is tried again; its errors were printed
# although the compile succeeded.
add_test(NAME test-compile-reference-path-import-cycle-quiet
COMMAND $<TARGET_FILE:tslang> --emit=obj --no-default-lib
"${reference_path_dir}/cycle_class_node.ts" -o "${CMAKE_CURRENT_BINARY_DIR}/cycle_class_node.obj")
set_tests_properties(test-compile-reference-path-import-cycle-quiet PROPERTIES FAIL_REGULAR_EXPRESSION "error:")

# `import { a as b }` and `import * as M` - each used to be "can't resolve name".
set(import_bindings_dir "${PROJECT_SOURCE_DIR}/test/tester/import-bindings")
Expand Down
26 changes: 26 additions & 0 deletions tslang/test/tester/reference-path/cycle_class_node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// cycle_class_node and cycle_class_text import each other, and TextNode extends Node: the first
// attempt at cycle_class_text fails (Node is not declared yet) and is tried again. That attempt's
// errors used to be printed although the compile then succeeded.
import { TextNode } from "./cycle_class_text";

export class Node {
childNodes: Node[] = [];

get textContent(): string {
let t = "";
for (let i = 0; i < this.childNodes.length; i++) {
const c = this.childNodes[i];
if (c instanceof TextNode) {
t += c.data;
} else {
t += c.textContent;
}
}

return t;
}

addText(s: string) {
this.childNodes.push(new TextNode(s));
}
}
10 changes: 10 additions & 0 deletions tslang/test/tester/reference-path/cycle_class_text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Node } from "./cycle_class_node";

export class TextNode extends Node {
data: string;

constructor(d: string) {
super();
this.data = d;
}
}
13 changes: 13 additions & 0 deletions tslang/test/tester/reference-path/import_cycle_class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Node } from "./cycle_class_node";

function main() {
const n = new Node();
n.addText("a");
n.addText("b");
const inner = new Node();
inner.addText("c");
n.childNodes.push(inner);
assert(n.textContent == "abc");

print("done.");
}
Loading